diff options
Diffstat (limited to 'lib/libssl/s3_clnt.c')
-rw-r--r-- | lib/libssl/s3_clnt.c | 678 |
1 files changed, 351 insertions, 327 deletions
diff --git a/lib/libssl/s3_clnt.c b/lib/libssl/s3_clnt.c index 343b0a8cfec..c2f5ea4e075 100644 --- a/lib/libssl/s3_clnt.c +++ b/lib/libssl/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); } |