diff options
author | Dr. Stephen Henson <steve@openssl.org> | 2009-06-16 16:38:47 +0000 |
---|---|---|
committer | Dr. Stephen Henson <steve@openssl.org> | 2009-06-16 16:38:47 +0000 |
commit | f0288f05b92c3c206a515691f548b857f6aaa194 (patch) | |
tree | 2894cf72978684a519606752e712d00ccd0fd999 /ssl | |
parent | 31db43df0859210a32af3708df08f0149c46ede0 (diff) |
Submitted by: Artem Chuprina <ran@cryptocom.ru>
Reviewed by: steve@openssl.org
Various GOST ciphersuite and ENGINE fixes. Including...
Allow EVP_PKEY_set_derive_peerkey() in encryption operations.
New flag when certificate verify should be omitted in client key exchange.
Diffstat (limited to 'ssl')
-rw-r--r-- | ssl/s3_clnt.c | 43 | ||||
-rw-r--r-- | ssl/s3_srvr.c | 64 | ||||
-rw-r--r-- | ssl/ssl3.h | 1 |
3 files changed, 83 insertions, 25 deletions
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index e0bfd0ceaf..861ce30138 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -404,6 +404,11 @@ int ssl3_connect(SSL *s) s->state=SSL3_ST_CW_CHANGE_A; s->s3->change_cipher_spec=0; } + if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) + { + s->state=SSL3_ST_CW_CHANGE_A; + s->s3->change_cipher_spec=0; + } s->init_num=0; break; @@ -2416,7 +2421,7 @@ int ssl3_send_client_key_exchange(SSL *s) size_t msglen; unsigned int md_len; int keytype; - unsigned char premaster_secret[32],shared_ukm[32]; + unsigned char premaster_secret[32],shared_ukm[32], tmp[256]; EVP_MD_CTX *ukm_hash; EVP_PKEY *pub_key; @@ -2442,16 +2447,13 @@ int ssl3_send_client_key_exchange(SSL *s) /* Generate session key */ RAND_bytes(premaster_secret,32); /* If we have client certificate, use its secret as peer key */ - if (s->cert->key->privatekey) { - if (EVP_PKEY_derive_set_peer(pkey_ctx,s->cert->key->privatekey) <0) { + if (s->s3->tmp.cert_req && s->cert->key->privatekey) { + if (EVP_PKEY_derive_set_peer(pkey_ctx,s->cert->key->privatekey) <=0) { /* If there was an error - just ignore it. Ephemeral key * would be used */ ERR_clear_error(); - } else { - /* Set flag "client cert key is used for key - * exchange"*/ - } + } } /* Compute shared IV and store it in algorithm-specific * context data */ @@ -2470,15 +2472,30 @@ int ssl3_send_client_key_exchange(SSL *s) /* Make GOST keytransport blob message */ /*Encapsulate it into sequence */ *(p++)=V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED; - *(p++)=0x81; - msglen=256; - if (EVP_PKEY_encrypt(pkey_ctx,(unsigned char *)p+1,&msglen,premaster_secret,32)<0) { + msglen=255; + if (EVP_PKEY_encrypt(pkey_ctx,tmp,&msglen,premaster_secret,32)<0) { SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, SSL_R_LIBRARY_BUG); goto err; - } - *(p++)= msglen & 0xff; - n=msglen+3; + } + if (msglen >= 0x80) + { + *(p++)=0x81; + *(p++)= msglen & 0xff; + n=msglen+3; + } + else + { + *(p++)= msglen & 0xff; + n=msglen+2; + } + memcpy(p, tmp, msglen); + /* Check if pubkey from client certificate was used */ + if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0) + { + /* Set flag "skip certificate verify" */ + s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY; + } EVP_PKEY_CTX_free(pkey_ctx); s->session->master_key_length= s->method->ssl3_enc->generate_master_secret(s, diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 44065d7e89..66c063a7ba 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -514,6 +514,9 @@ int ssl3_accept(SSL *s) * the client sends its ECDH pub key in * a certificate, the CertificateVerify * message is not sent. + * Also for GOST ciphersuites when + * the client uses its key from the certificate + * for key exchange. */ s->state=SSL3_ST_SR_FINISHED_A; s->init_num = 0; @@ -2496,33 +2499,70 @@ int ssl3_get_client_key_exchange(SSL *s) else #endif if (alg_k & SSL_kGOST) - { + { + int ret = 0; EVP_PKEY_CTX *pkey_ctx; - unsigned char premaster_secret[32]; - size_t outlen; + EVP_PKEY *client_pub_pkey = NULL; + unsigned char premaster_secret[32], *start; + size_t outlen, inlen; - /* Get our certificate privatec key*/ + /* Get our certificate private key*/ pkey_ctx = EVP_PKEY_CTX_new(s->cert->key->privatekey,NULL); EVP_PKEY_decrypt_init(pkey_ctx); + /* If client certificate is present and is of the same type, maybe + * use it for key exchange. Don't mind errors from + * EVP_PKEY_derive_set_peer, because it is completely valid to use + * a client certificate for authorization only. */ + client_pub_pkey = X509_get_pubkey(s->session->peer); + if (client_pub_pkey) + { + if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0) + ERR_clear_error(); + } /* Decrypt session key */ - if ((*p!=( V_ASN1_SEQUENCE| V_ASN1_CONSTRUCTED)) || p[1]!=0x81 ) + if ((*p!=( V_ASN1_SEQUENCE| V_ASN1_CONSTRUCTED))) { SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED); - goto err; - } - if (EVP_PKEY_decrypt(pkey_ctx,premaster_secret,&outlen,p+3,p[2]) <0) + goto gerr; + } + if (p[1] == 0x81) + { + start = p+3; + inlen = p[2]; + } + else if (p[1] < 0x80) + { + start = p+2; + inlen = p[1]; + } + else + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED); + goto gerr; + } + if (EVP_PKEY_decrypt(pkey_ctx,premaster_secret,&outlen,start,inlen) <=0) { SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED); - goto err; + goto gerr; } /* Generate master secret */ - EVP_PKEY_CTX_free(pkey_ctx); s->session->master_key_length= s->method->ssl3_enc->generate_master_secret(s, s->session->master_key,premaster_secret,32); - - } + /* Check if pubkey from client certificate was used */ + if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0) + ret = 2; + else + ret = 1; + gerr: + EVP_PKEY_free(client_pub_pkey); + EVP_PKEY_CTX_free(pkey_ctx); + if (ret) + return ret; + else + goto err; + } else { al=SSL_AD_HANDSHAKE_FAILURE; diff --git a/ssl/ssl3.h b/ssl/ssl3.h index c2db3bd636..a4a6ce28c3 100644 --- a/ssl/ssl3.h +++ b/ssl/ssl3.h @@ -375,6 +375,7 @@ typedef struct ssl3_buffer_st #define SSL3_FLAGS_DELAY_CLIENT_FINISHED 0x0002 #define SSL3_FLAGS_POP_BUFFER 0x0004 #define TLS1_FLAGS_TLS_PADDING_BUG 0x0008 +#define TLS1_FLAGS_SKIP_CERT_VERIFY 0x0010 typedef struct ssl3_state_st { |