diff options
author | Joel Sing <jsing@cvs.openbsd.org> | 2015-09-12 20:56:15 +0000 |
---|---|---|
committer | Joel Sing <jsing@cvs.openbsd.org> | 2015-09-12 20:56:15 +0000 |
commit | 35f7f1cf24317c11b6cf56ab4945821ffccb1bf5 (patch) | |
tree | cb17b636688de634bc5ca3239a61a2f159d32200 | |
parent | e502243451ade3560aef64ea18cf83e28eda2904 (diff) |
Split ssl3_send_client_key_exchange() (387 lines of code) into five
functions. The original was written as a huge if/else if chain -
split out the handling for each key exchange type. This allows us to reduce
two levels of indentation, make the code far more readable and have single
return paths so that we can simplify clean up.
ok beck@
-rw-r--r-- | lib/libssl/src/ssl/s3_clnt.c | 678 |
1 files changed, 351 insertions, 327 deletions
diff --git a/lib/libssl/src/ssl/s3_clnt.c b/lib/libssl/src/ssl/s3_clnt.c index 343b0a8cfec..c2f5ea4e075 100644 --- a/lib/libssl/src/ssl/s3_clnt.c +++ b/lib/libssl/src/ssl/s3_clnt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: s3_clnt.c,v 1.132 2015/09/12 20:23:56 jsing Exp $ */ +/* $OpenBSD: s3_clnt.c,v 1.133 2015/09/12 20:56:14 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -1853,372 +1853,400 @@ ssl3_get_server_done(SSL *s) return (ret); } -int -ssl3_send_client_key_exchange(SSL *s) +static int +ssl3_client_kex_rsa(SSL *s, SESS_CERT *sess_cert, unsigned char *p, int *outlen) { - unsigned char *p, *q; - int n; - unsigned long alg_k; - EVP_PKEY *pkey = NULL; - EC_KEY *clnt_ecdh = NULL; - const EC_POINT *srvr_ecpoint = NULL; - EVP_PKEY *srvr_pub_pkey = NULL; - unsigned char *encodedPoint = NULL; - int encoded_pt_len = 0; - BN_CTX *bn_ctx = NULL; + unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH]; + EVP_PKEY *pkey = NULL; + unsigned char *q; + int ret = -1; + int n; + + pkey = X509_get_pubkey(sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509); + if (pkey == NULL || pkey->type != EVP_PKEY_RSA || + pkey->pkey.rsa == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } - if (s->state == SSL3_ST_CW_KEY_EXCH_A) { - p = ssl3_handshake_msg_start(s, SSL3_MT_CLIENT_KEY_EXCHANGE); + tmp_buf[0] = s->client_version >> 8; + tmp_buf[1] = s->client_version & 0xff; + arc4random_buf(&tmp_buf[2], sizeof(tmp_buf) - 2); - alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + s->session->master_key_length = sizeof(tmp_buf); - if (s->session->sess_cert == NULL) { - ssl3_send_alert(s, SSL3_AL_FATAL, - SSL_AD_UNEXPECTED_MESSAGE); - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } + q = p; + p += 2; - if (alg_k & SSL_kRSA) { - RSA *rsa; - unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH]; + n = RSA_public_encrypt(sizeof(tmp_buf), tmp_buf, p, pkey->pkey.rsa, + RSA_PKCS1_PADDING); + if (n <= 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + SSL_R_BAD_RSA_ENCRYPT); + goto err; + } - pkey = X509_get_pubkey( - s->session->sess_cert->peer_pkeys[ - SSL_PKEY_RSA_ENC].x509); - if ((pkey == NULL) || - (pkey->type != EVP_PKEY_RSA) || - (pkey->pkey.rsa == NULL)) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - EVP_PKEY_free(pkey); - goto err; - } - rsa = pkey->pkey.rsa; - EVP_PKEY_free(pkey); + s2n(n, q); + n += 2; - tmp_buf[0] = s->client_version >> 8; - tmp_buf[1] = s->client_version & 0xff; - arc4random_buf(&tmp_buf[2], sizeof(tmp_buf) - 2); + s->session->master_key_length = + s->method->ssl3_enc->generate_master_secret(s, + s->session->master_key, tmp_buf, sizeof(tmp_buf)); - s->session->master_key_length = sizeof tmp_buf; + *outlen = n; + ret = 1; - q = p; - /* Fix buf for TLS and beyond */ - p += 2; +err: + explicit_bzero(tmp_buf, sizeof(tmp_buf)); + EVP_PKEY_free(pkey); - n = RSA_public_encrypt(sizeof tmp_buf, - tmp_buf, p, rsa, RSA_PKCS1_PADDING); - if (n <= 0) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - SSL_R_BAD_RSA_ENCRYPT); - goto err; - } + return (ret); +} - /* Fix buf for TLS and beyond */ - s2n(n, q); - n += 2; +static int +ssl3_client_kex_dhe(SSL *s, SESS_CERT *sess_cert, unsigned char *p, int *outlen) +{ + DH *dh_srvr = NULL, *dh_clnt = NULL; + int ret = -1; + int n; + + /* Ensure that we have an ephemeral key for DHE. */ + if (sess_cert->peer_dh_tmp == NULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + SSL_R_UNABLE_TO_FIND_DH_PARAMETERS); + goto err; + } + dh_srvr = sess_cert->peer_dh_tmp; - s->session->master_key_length = - s->method->ssl3_enc->generate_master_secret( - s, s->session->master_key, tmp_buf, sizeof tmp_buf); - explicit_bzero(tmp_buf, sizeof tmp_buf); - } else if (alg_k & SSL_kDHE) { - DH *dh_srvr, *dh_clnt; - - /* Ensure that we have an ephemeral key for DHE. */ - if (s->session->sess_cert->peer_dh_tmp == NULL) { - ssl3_send_alert(s, SSL3_AL_FATAL, - SSL_AD_HANDSHAKE_FAILURE); - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - SSL_R_UNABLE_TO_FIND_DH_PARAMETERS); - goto err; - } - dh_srvr = s->session->sess_cert->peer_dh_tmp; + /* Generate a new random key. */ + if ((dh_clnt = DHparams_dup(dh_srvr)) == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); + goto err; + } + if (!DH_generate_key(dh_clnt)) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); + goto err; + } - /* Generate a new random key. */ - if ((dh_clnt = DHparams_dup(dh_srvr)) == NULL) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_DH_LIB); - goto err; - } - if (!DH_generate_key(dh_clnt)) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_DH_LIB); - DH_free(dh_clnt); - goto err; - } + /* + * Use the 'p' output buffer for the DH key, but make sure to clear + * it out afterwards. + */ + n = DH_compute_key(p, dh_srvr->pub_key, dh_clnt); + if (n <= 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); + goto err; + } - /* - * Use the 'p' output buffer for the DH key, but - * make sure to clear it out afterwards. - */ - n = DH_compute_key(p, dh_srvr->pub_key, dh_clnt); - if (n <= 0) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_DH_LIB); - DH_free(dh_clnt); - goto err; - } + /* Generate master key from the result. */ + s->session->master_key_length = + s->method->ssl3_enc->generate_master_secret(s, + s->session->master_key, p, n); - /* Generate master key from the result. */ - s->session->master_key_length = - s->method->ssl3_enc->generate_master_secret(s, - s->session->master_key, p, n); + /* Clean up. */ + explicit_bzero(p, n); - /* Clean up. */ - explicit_bzero(p, n); + /* Send off the data. */ + n = BN_num_bytes(dh_clnt->pub_key); + s2n(n, p); + BN_bn2bin(dh_clnt->pub_key, p); + n += 2; - /* Send off the data. */ - n = BN_num_bytes(dh_clnt->pub_key); - s2n(n, p); - BN_bn2bin(dh_clnt->pub_key, p); - n += 2; + *outlen = n; + ret = 1; - DH_free(dh_clnt); +err: + DH_free(dh_clnt); - /* perhaps clean things up a bit EAY EAY EAY EAY*/ - } else if (alg_k & (SSL_kECDHE|SSL_kECDHr|SSL_kECDHe)) { - const EC_GROUP *srvr_group = NULL; - EC_KEY *tkey; - int field_size = 0; - - /* Ensure that we have an ephemeral key for ECDHE. */ - if ((alg_k & SSL_kECDHE) && - s->session->sess_cert->peer_ecdh_tmp == NULL) { - ssl3_send_alert(s, SSL3_AL_FATAL, - SSL_AD_HANDSHAKE_FAILURE); - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } - tkey = s->session->sess_cert->peer_ecdh_tmp; - - if (alg_k & (SSL_kECDHr|SSL_kECDHe)) { - /* Get the Server Public Key from Cert */ - srvr_pub_pkey = X509_get_pubkey(s->session-> \ - sess_cert->peer_pkeys[SSL_PKEY_ECC].x509); - if (srvr_pub_pkey != NULL && - srvr_pub_pkey->type == EVP_PKEY_EC) - tkey = srvr_pub_pkey->pkey.ec; - } + return (ret); +} - if (tkey == NULL) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } +static int +ssl3_client_kex_ecdh(SSL *s, SESS_CERT *sess_cert, unsigned char *p, + int *outlen) +{ + EC_KEY *clnt_ecdh = NULL; + const EC_GROUP *srvr_group = NULL; + const EC_POINT *srvr_ecpoint = NULL; + EVP_PKEY *srvr_pub_pkey = NULL; + BN_CTX *bn_ctx = NULL; + unsigned char *encodedPoint = NULL; + unsigned long alg_k; + int encoded_pt_len = 0; + int field_size = 0; + EC_KEY *tkey; + int ret = -1; + int n; - srvr_group = EC_KEY_get0_group(tkey); - srvr_ecpoint = EC_KEY_get0_public_key(tkey); + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; - if ((srvr_group == NULL) || (srvr_ecpoint == NULL)) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } + /* Ensure that we have an ephemeral key for ECDHE. */ + if ((alg_k & SSL_kECDHE) && sess_cert->peer_ecdh_tmp == NULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + tkey = sess_cert->peer_ecdh_tmp; + + if (alg_k & (SSL_kECDHr|SSL_kECDHe)) { + /* Get the Server Public Key from certificate. */ + srvr_pub_pkey = X509_get_pubkey( + sess_cert->peer_pkeys[SSL_PKEY_ECC].x509); + if (srvr_pub_pkey != NULL && srvr_pub_pkey->type == EVP_PKEY_EC) + tkey = srvr_pub_pkey->pkey.ec; + } - if ((clnt_ecdh = EC_KEY_new()) == NULL) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_MALLOC_FAILURE); - goto err; - } + if (tkey == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } - if (!EC_KEY_set_group(clnt_ecdh, srvr_group)) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_EC_LIB); - goto err; - } + srvr_group = EC_KEY_get0_group(tkey); + srvr_ecpoint = EC_KEY_get0_public_key(tkey); - /* Generate a new ECDH key pair */ - if (!(EC_KEY_generate_key(clnt_ecdh))) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_ECDH_LIB); - goto err; - } + if (srvr_group == NULL || srvr_ecpoint == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } - /* - * Use the 'p' output buffer for the ECDH key, but - * make sure to clear it out afterwards. - */ - field_size = EC_GROUP_get_degree(srvr_group); - if (field_size <= 0) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_ECDH_LIB); - goto err; - } - n = ECDH_compute_key(p, (field_size + 7) / 8, - srvr_ecpoint, clnt_ecdh, NULL); - if (n <= 0) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_ECDH_LIB); - goto err; - } + if ((clnt_ecdh = EC_KEY_new()) == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } - /* generate master key from the result */ - s->session->master_key_length = - s->method->ssl3_enc->generate_master_secret(s, - s->session->master_key, p, n); + if (!EC_KEY_set_group(clnt_ecdh, srvr_group)) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB); + goto err; + } - /* Clean up. */ - explicit_bzero(p, n); + /* Generate a new ECDH key pair */ + if (!(EC_KEY_generate_key(clnt_ecdh))) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); + goto err; + } - /* - * First check the size of encoding and - * allocate memory accordingly. - */ - encoded_pt_len = EC_POINT_point2oct(srvr_group, - EC_KEY_get0_public_key(clnt_ecdh), - POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); + /* + * Use the 'p' output buffer for the ECDH key, but make sure to clear + * it out afterwards. + */ + field_size = EC_GROUP_get_degree(srvr_group); + if (field_size <= 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); + goto err; + } + n = ECDH_compute_key(p, (field_size + 7) / 8, srvr_ecpoint, clnt_ecdh, + NULL); + if (n <= 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); + goto err; + } - encodedPoint = malloc(encoded_pt_len); + /* Generate master key from the result. */ + s->session->master_key_length = + s->method->ssl3_enc->generate_master_secret(s, + s->session->master_key, p, n); - bn_ctx = BN_CTX_new(); - if ((encodedPoint == NULL) || (bn_ctx == NULL)) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_MALLOC_FAILURE); - goto err; - } + /* Clean up. */ + explicit_bzero(p, n); - /* Encode the public key */ - n = EC_POINT_point2oct(srvr_group, - EC_KEY_get0_public_key(clnt_ecdh), - POINT_CONVERSION_UNCOMPRESSED, encodedPoint, - encoded_pt_len, bn_ctx); - - *p = n; /* length of encoded point */ - /* Encoded point will be copied here */ - p += 1; - - /* copy the point */ - memcpy((unsigned char *)p, encodedPoint, n); - /* increment n to account for length field */ - n += 1; - - /* Free allocated memory */ - BN_CTX_free(bn_ctx); - free(encodedPoint); - EC_KEY_free(clnt_ecdh); - EVP_PKEY_free(srvr_pub_pkey); - } else if (alg_k & SSL_kGOST) { - /* GOST key exchange message creation */ - EVP_PKEY_CTX *pkey_ctx; - X509 *peer_cert; - - size_t msglen; - unsigned int md_len; - unsigned char premaster_secret[32], shared_ukm[32], - tmp[256]; - EVP_MD_CTX *ukm_hash; - EVP_PKEY *pub_key; - int nid; + /* + * First check the size of encoding and allocate memory accordingly. + */ + encoded_pt_len = EC_POINT_point2oct(srvr_group, + EC_KEY_get0_public_key(clnt_ecdh), + POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); + + bn_ctx = BN_CTX_new(); + encodedPoint = malloc(encoded_pt_len); + if (encodedPoint == NULL || bn_ctx == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } - /* Get server sertificate PKEY and create ctx from it */ - peer_cert = s->session->sess_cert->peer_pkeys[SSL_PKEY_GOST01].x509; - if (!peer_cert) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER); - goto err; - } + /* Encode the public key */ + n = EC_POINT_point2oct(srvr_group, EC_KEY_get0_public_key(clnt_ecdh), + POINT_CONVERSION_UNCOMPRESSED, encodedPoint, encoded_pt_len, + bn_ctx); - pub_key = X509_get_pubkey(peer_cert); - pkey_ctx = EVP_PKEY_CTX_new(pub_key, NULL); + *p = n; /* length of encoded point */ + /* Encoded point will be copied here */ + p += 1; - /* - * If we have send a certificate, and certificate key - * parameters match those of server certificate, use - * certificate key for key exchange. - * Otherwise, generate ephemeral key pair. - */ - EVP_PKEY_encrypt_init(pkey_ctx); + /* copy the point */ + memcpy((unsigned char *)p, encodedPoint, n); + /* increment n to account for length field */ + n += 1; - /* Generate session key. */ - arc4random_buf(premaster_secret, 32); + *outlen = n; + ret = 1; - /* - * If we have client certificate, use its secret as - * peer key. - */ - 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(); - } - } +err: + /* Free allocated memory */ + BN_CTX_free(bn_ctx); + free(encodedPoint); + EC_KEY_free(clnt_ecdh); + EVP_PKEY_free(srvr_pub_pkey); + + return (ret); +} + +static int +ssl3_client_kex_gost(SSL *s, SESS_CERT *sess_cert, unsigned char *p, + int *outlen) +{ + unsigned char premaster_secret[32], shared_ukm[32], tmp[256]; + EVP_PKEY *pub_key = NULL; + EVP_PKEY_CTX *pkey_ctx; + X509 *peer_cert; + size_t msglen; + unsigned int md_len; + EVP_MD_CTX *ukm_hash; + int ret = -1; + int nid; + int n; + + /* Get server sertificate PKEY and create ctx from it */ + peer_cert = sess_cert->peer_pkeys[SSL_PKEY_GOST01].x509; + if (peer_cert == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER); + goto err; + } + + pub_key = X509_get_pubkey(peer_cert); + pkey_ctx = EVP_PKEY_CTX_new(pub_key, NULL); + + /* + * If we have send a certificate, and certificate key parameters match + * those of server certificate, use certificate key for key exchange. + * Otherwise, generate ephemeral key pair. + */ + EVP_PKEY_encrypt_init(pkey_ctx); + + /* Generate session key. */ + arc4random_buf(premaster_secret, 32); + /* + * If we have client certificate, use its secret as peer key. + */ + if (s->s3->tmp.cert_req && s->cert->key->privatekey) { + if (EVP_PKEY_derive_set_peer(pkey_ctx, + s->cert->key->privatekey) <=0) { /* - * Compute shared IV and store it in algorithm-specific - * context data. + * If there was an error - just ignore it. + * Ephemeral key would be used. */ - ukm_hash = EVP_MD_CTX_create(); - if (ukm_hash == NULL) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_MALLOC_FAILURE); - explicit_bzero(premaster_secret, - sizeof(premaster_secret)); - goto err; - } + ERR_clear_error(); + } + } - if (ssl_get_algorithm2(s) & SSL_HANDSHAKE_MAC_GOST94) - nid = NID_id_GostR3411_94; - else - nid = NID_id_tc26_gost3411_2012_256; - if (!EVP_DigestInit(ukm_hash, EVP_get_digestbynid(nid))) + /* + * Compute shared IV and store it in algorithm-specific context data. + */ + ukm_hash = EVP_MD_CTX_create(); + if (ukm_hash == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if (ssl_get_algorithm2(s) & SSL_HANDSHAKE_MAC_GOST94) + nid = NID_id_GostR3411_94; + else + nid = NID_id_tc26_gost3411_2012_256; + if (!EVP_DigestInit(ukm_hash, EVP_get_digestbynid(nid))) + goto err; + EVP_DigestUpdate(ukm_hash, s->s3->client_random, SSL3_RANDOM_SIZE); + EVP_DigestUpdate(ukm_hash, s->s3->server_random, SSL3_RANDOM_SIZE); + EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len); + EVP_MD_CTX_destroy(ukm_hash); + if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT, + EVP_PKEY_CTRL_SET_IV, 8, shared_ukm) < 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, SSL_R_LIBRARY_BUG); + goto err; + } + + /* + * Make GOST keytransport blob message, encapsulate it into sequence. + */ + *(p++) = V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED; + 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; + } + 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, + s->session->master_key, premaster_secret, 32); + + *outlen = n; + ret = 1; + +err: + explicit_bzero(premaster_secret, sizeof(premaster_secret)); + EVP_PKEY_free(pub_key); + + return (ret); +} + +int +ssl3_send_client_key_exchange(SSL *s) +{ + SESS_CERT *sess_cert; + unsigned long alg_k; + unsigned char *p; + int n; + + if (s->state == SSL3_ST_CW_KEY_EXCH_A) { + p = ssl3_handshake_msg_start(s, SSL3_MT_CLIENT_KEY_EXCHANGE); + + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + + if ((sess_cert = s->session->sess_cert) == NULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, + SSL_AD_UNEXPECTED_MESSAGE); + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if (alg_k & SSL_kRSA) { + if (ssl3_client_kex_rsa(s, sess_cert, p, &n) != 1) goto err; - EVP_DigestUpdate(ukm_hash, - s->s3->client_random, SSL3_RANDOM_SIZE); - EVP_DigestUpdate(ukm_hash, - s->s3->server_random, SSL3_RANDOM_SIZE); - EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len); - EVP_MD_CTX_destroy(ukm_hash); - if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT, - EVP_PKEY_CTRL_SET_IV, 8, shared_ukm) < 0) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - SSL_R_LIBRARY_BUG); - explicit_bzero(premaster_secret, - sizeof(premaster_secret)); + } else if (alg_k & SSL_kDHE) { + if (ssl3_client_kex_dhe(s, sess_cert, p, &n) != 1) goto err; - } - - /* - * Make GOST keytransport blob message, encapsulate it - * into sequence. - */ - *(p++) = V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED; - 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); + } else if (alg_k & (SSL_kECDHE|SSL_kECDHr|SSL_kECDHe)) { + if (ssl3_client_kex_ecdh(s, sess_cert, p, &n) != 1) + goto err; + } else if (alg_k & SSL_kGOST) { + if (ssl3_client_kex_gost(s, sess_cert, p, &n) != 1) goto err; - } - 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, - s->session->master_key, premaster_secret, 32); - EVP_PKEY_free(pub_key); - explicit_bzero(premaster_secret, - sizeof(premaster_secret)); } else { ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); @@ -2236,10 +2264,6 @@ ssl3_send_client_key_exchange(SSL *s) return (ssl3_handshake_write(s)); err: - BN_CTX_free(bn_ctx); - free(encodedPoint); - EC_KEY_free(clnt_ecdh); - EVP_PKEY_free(srvr_pub_pkey); return (-1); } |