diff options
author | Joel Sing <jsing@cvs.openbsd.org> | 2016-11-06 15:06:53 +0000 |
---|---|---|
committer | Joel Sing <jsing@cvs.openbsd.org> | 2016-11-06 15:06:53 +0000 |
commit | 6e9b32b0ca63a07e0fa3680f5666798a225f4b60 (patch) | |
tree | d987881fabbdc5c90df51666921e29da948d62b5 /lib | |
parent | 0db379df0e19e7318958d936554bc6d19df08e72 (diff) |
Split ssl3_get_client_key_exchange() into separate per algorithm functions.
ok beck@
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libssl/s3_srvr.c | 708 |
1 files changed, 388 insertions, 320 deletions
diff --git a/lib/libssl/s3_srvr.c b/lib/libssl/s3_srvr.c index f3649557166..65625cef26b 100644 --- a/lib/libssl/s3_srvr.c +++ b/lib/libssl/s3_srvr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: s3_srvr.c,v 1.131 2016/11/06 14:44:35 jsing Exp $ */ +/* $OpenBSD: s3_srvr.c,v 1.132 2016/11/06 15:06:52 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -1629,369 +1629,443 @@ err: return (-1); } -int -ssl3_get_client_key_exchange(SSL *s) +static int +ssl3_get_client_kex_rsa(SSL *s, unsigned char *p, long n) { - int i, al, ok; - long n; - unsigned long alg_k; - unsigned char *d, *p; + char fakekey[SSL_MAX_MASTER_KEY_LENGTH]; + unsigned char *d; RSA *rsa = NULL; EVP_PKEY *pkey = NULL; - BIGNUM *pub = NULL; - DH *dh_srvr; + int i, al; - EC_KEY *srvr_ecdh = NULL; - EVP_PKEY *clnt_pub_pkey = NULL; - EC_POINT *clnt_ecpoint = NULL; - BN_CTX *bn_ctx = NULL; + d = p; - /* 2048 maxlen is a guess. How long a key does that permit? */ - n = s->method->ssl_get_message(s, SSL3_ST_SR_KEY_EXCH_A, - SSL3_ST_SR_KEY_EXCH_B, SSL3_MT_CLIENT_KEY_EXCHANGE, 2048, &ok); - if (!ok) - return ((int)n); - d = p = (unsigned char *)s->init_msg; - - alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + arc4random_buf(fakekey, sizeof(fakekey)); + fakekey[0] = s->client_version >> 8; + fakekey[1] = s->client_version & 0xff; - if (alg_k & SSL_kRSA) { - char fakekey[SSL_MAX_MASTER_KEY_LENGTH]; + pkey = s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey; + if ((pkey == NULL) || (pkey->type != EVP_PKEY_RSA) || + (pkey->pkey.rsa == NULL)) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_MISSING_RSA_CERTIFICATE); + goto f_err; + } + rsa = pkey->pkey.rsa; - arc4random_buf(fakekey, sizeof(fakekey)); - fakekey[0] = s->client_version >> 8; - fakekey[1] = s->client_version & 0xff; + if (2 > n) + goto truncated; + n2s(p, i); + if (n != i + 2) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG); + goto err; + } else + n = i; - pkey = s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey; - if ((pkey == NULL) || (pkey->type != EVP_PKEY_RSA) || - (pkey->pkey.rsa == NULL)) { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - SSL_R_MISSING_RSA_CERTIFICATE); - goto f_err; - } - rsa = pkey->pkey.rsa; + i = RSA_private_decrypt((int)n, p, p, rsa, RSA_PKCS1_PADDING); - if (2 > n) - goto truncated; - n2s(p, i); - if (n != i + 2) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG); - goto err; - } else - n = i; - - i = RSA_private_decrypt((int)n, p, p, rsa, RSA_PKCS1_PADDING); + ERR_clear_error(); - ERR_clear_error(); + al = -1; - al = -1; + if (i != SSL_MAX_MASTER_KEY_LENGTH) { + al = SSL_AD_DECODE_ERROR; + /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_RSA_DECRYPT); */ + } - if (i != SSL_MAX_MASTER_KEY_LENGTH) { + if (p - d + 2 > n) /* needed in the SSL3 case */ + goto truncated; + if ((al == -1) && !((p[0] == (s->client_version >> 8)) && + (p[1] == (s->client_version & 0xff)))) { + /* + * The premaster secret must contain the same version + * number as the ClientHello to detect version rollback + * attacks (strangely, the protocol does not offer such + * protection for DH ciphersuites). + * However, buggy clients exist that send the negotiated + * protocol version instead if the server does not + * support the requested protocol version. + * If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such + * clients. + */ + if (!((s->options & SSL_OP_TLS_ROLLBACK_BUG) && + (p[0] == (s->version >> 8)) && + (p[1] == (s->version & 0xff)))) { al = SSL_AD_DECODE_ERROR; - /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_RSA_DECRYPT); */ - } + /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_PROTOCOL_VERSION_NUMBER); */ - if (p - d + 2 > n) /* needed in the SSL3 case */ - goto truncated; - if ((al == -1) && !((p[0] == (s->client_version >> 8)) && - (p[1] == (s->client_version & 0xff)))) { /* - * The premaster secret must contain the same version - * number as the ClientHello to detect version rollback - * attacks (strangely, the protocol does not offer such - * protection for DH ciphersuites). - * However, buggy clients exist that send the negotiated - * protocol version instead if the server does not - * support the requested protocol version. - * If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such - * clients. + * The Klima-Pokorny-Rosa extension of + * Bleichenbacher's attack + * (http://eprint.iacr.org/2003/052/) exploits + * the version number check as a "bad version + * oracle" -- an alert would reveal that the + * plaintext corresponding to some ciphertext + * made up by the adversary is properly + * formatted except that the version number is + * wrong. + * To avoid such attacks, we should treat this + * just like any other decryption error. */ - if (!((s->options & SSL_OP_TLS_ROLLBACK_BUG) && - (p[0] == (s->version >> 8)) && - (p[1] == (s->version & 0xff)))) { - al = SSL_AD_DECODE_ERROR; - /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_PROTOCOL_VERSION_NUMBER); */ - - /* - * The Klima-Pokorny-Rosa extension of - * Bleichenbacher's attack - * (http://eprint.iacr.org/2003/052/) exploits - * the version number check as a "bad version - * oracle" -- an alert would reveal that the - * plaintext corresponding to some ciphertext - * made up by the adversary is properly - * formatted except that the version number is - * wrong. - * To avoid such attacks, we should treat this - * just like any other decryption error. - */ - } } + } - if (al != -1) { - /* - * Some decryption failure -- use random value instead - * as countermeasure against Bleichenbacher's attack - * on PKCS #1 v1.5 RSA padding (see RFC 2246, - * section 7.4.7.1). - */ - i = SSL_MAX_MASTER_KEY_LENGTH; - p = fakekey; - } + if (al != -1) { + /* + * Some decryption failure -- use random value instead + * as countermeasure against Bleichenbacher's attack + * on PKCS #1 v1.5 RSA padding (see RFC 2246, + * section 7.4.7.1). + */ + i = SSL_MAX_MASTER_KEY_LENGTH; + p = fakekey; + } - s->session->master_key_length = - s->method->ssl3_enc->generate_master_secret(s, - s->session->master_key, - p, i); - explicit_bzero(p, i); - } else if (alg_k & SSL_kDHE) { - if (2 > n) - goto truncated; - n2s(p, i); - if (n != i + 2) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG); - goto err; - } + s->session->master_key_length = + s->method->ssl3_enc->generate_master_secret(s, + s->session->master_key, p, i); + + explicit_bzero(p, i); + + return (1); +truncated: + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_BAD_PACKET_LENGTH); +f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); +err: + return (-1); +} - if (n == 0L) { - /* the parameters are in the cert */ +static int +ssl3_get_client_kex_dhe(SSL *s, unsigned char *p, long n) +{ + BIGNUM *pub = NULL; + DH *dh_srvr; + int i, al; + + if (2 > n) + goto truncated; + n2s(p, i); + if (n != i + 2) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG); + goto err; + } + + if (n == 0L) { + /* the parameters are in the cert */ + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_UNABLE_TO_DECODE_DH_CERTS); + goto f_err; + } else { + if (s->s3->tmp.dh == NULL) { al = SSL_AD_HANDSHAKE_FAILURE; SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - SSL_R_UNABLE_TO_DECODE_DH_CERTS); + SSL_R_MISSING_TMP_DH_KEY); goto f_err; - } else { - if (s->s3->tmp.dh == NULL) { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - SSL_R_MISSING_TMP_DH_KEY); - goto f_err; - } else - dh_srvr = s->s3->tmp.dh; - } + } else + dh_srvr = s->s3->tmp.dh; + } - pub = BN_bin2bn(p, i, NULL); - if (pub == NULL) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - SSL_R_BN_LIB); - goto err; - } + pub = BN_bin2bn(p, i, NULL); + if (pub == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_BN_LIB); + goto err; + } - i = DH_compute_key(p, pub, dh_srvr); + i = DH_compute_key(p, pub, dh_srvr); - if (i <= 0) { + if (i <= 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_DH_LIB); + BN_clear_free(pub); + goto err; + } + + DH_free(s->s3->tmp.dh); + s->s3->tmp.dh = NULL; + + BN_clear_free(pub); + pub = NULL; + + s->session->master_key_length = + s->method->ssl3_enc->generate_master_secret( + s, s->session->master_key, p, i); + + explicit_bzero(p, i); + + return (1); + + truncated: + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_BAD_PACKET_LENGTH); + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + return (-1); +} + +static int +ssl3_get_client_kex_ecdhe(SSL *s, unsigned char *p, long n) +{ + EC_KEY *srvr_ecdh = NULL; + EVP_PKEY *clnt_pub_pkey = NULL; + EC_POINT *clnt_ecpoint = NULL; + BN_CTX *bn_ctx = NULL; + int i, al; + + int ret = 1; + int key_size; + const EC_KEY *tkey; + const EC_GROUP *group; + const BIGNUM *priv_key; + + /* Initialize structures for server's ECDH key pair. */ + if ((srvr_ecdh = EC_KEY_new()) == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + /* + * Use the ephemeral values we saved when + * generating the ServerKeyExchange message. + */ + tkey = s->s3->tmp.ecdh; + + group = EC_KEY_get0_group(tkey); + priv_key = EC_KEY_get0_private_key(tkey); + + if (!EC_KEY_set_group(srvr_ecdh, group) || + !EC_KEY_set_private_key(srvr_ecdh, priv_key)) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_EC_LIB); + goto err; + } + + /* Let's get client's public key */ + if ((clnt_ecpoint = EC_POINT_new(group)) == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if (n == 0L) { + /* Client Publickey was in Client Certificate */ + if (((clnt_pub_pkey = X509_get_pubkey( + s->session->peer)) == NULL) || + (clnt_pub_pkey->type != EVP_PKEY_EC)) { + /* + * XXX: For now, we do not support client + * authentication using ECDH certificates + * so this branch (n == 0L) of the code is + * never executed. When that support is + * added, we ought to ensure the key + * received in the certificate is + * authorized for key agreement. + * ECDH_compute_key implicitly checks that + * the two ECDH shares are for the same + * group. + */ + al = SSL_AD_HANDSHAKE_FAILURE; SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_DH_LIB); - BN_clear_free(pub); - goto err; + SSL_R_UNABLE_TO_DECODE_ECDH_CERTS); + goto f_err; } - DH_free(s->s3->tmp.dh); - s->s3->tmp.dh = NULL; - - BN_clear_free(pub); - pub = NULL; - s->session->master_key_length = - s->method->ssl3_enc->generate_master_secret( - s, s->session->master_key, p, i); - explicit_bzero(p, i); - } else if (alg_k & SSL_kECDHE) { - int ret = 1; - int key_size; - const EC_KEY *tkey; - const EC_GROUP *group; - const BIGNUM *priv_key; - - /* Initialize structures for server's ECDH key pair. */ - if ((srvr_ecdh = EC_KEY_new()) == NULL) { + if (EC_POINT_copy(clnt_ecpoint, + EC_KEY_get0_public_key(clnt_pub_pkey->pkey.ec)) + == 0) { SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_MALLOC_FAILURE); + ERR_R_EC_LIB); goto err; } - + ret = 2; /* Skip certificate verify processing */ + } else { /* - * Use the ephemeral values we saved when - * generating the ServerKeyExchange message. + * Get client's public key from encoded point + * in the ClientKeyExchange message. */ - tkey = s->s3->tmp.ecdh; + if ((bn_ctx = BN_CTX_new()) == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } - group = EC_KEY_get0_group(tkey); - priv_key = EC_KEY_get0_private_key(tkey); + /* Get encoded point length */ + i = *p; - if (!EC_KEY_set_group(srvr_ecdh, group) || - !EC_KEY_set_private_key(srvr_ecdh, priv_key)) { + p += 1; + if (n != 1 + i) { SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB); goto err; } - - /* Let's get client's public key */ - if ((clnt_ecpoint = EC_POINT_new(group)) == NULL) { + if (EC_POINT_oct2point(group, + clnt_ecpoint, p, i, bn_ctx) == 0) { SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_MALLOC_FAILURE); + ERR_R_EC_LIB); goto err; } + /* + * p is pointing to somewhere in the buffer + * currently, so set it to the start. + */ + p = (unsigned char *)s->init_buf->data; + } - if (n == 0L) { - /* Client Publickey was in Client Certificate */ - if (((clnt_pub_pkey = X509_get_pubkey( - s->session->peer)) == NULL) || - (clnt_pub_pkey->type != EVP_PKEY_EC)) { - /* - * XXX: For now, we do not support client - * authentication using ECDH certificates - * so this branch (n == 0L) of the code is - * never executed. When that support is - * added, we ought to ensure the key - * received in the certificate is - * authorized for key agreement. - * ECDH_compute_key implicitly checks that - * the two ECDH shares are for the same - * group. - */ - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - SSL_R_UNABLE_TO_DECODE_ECDH_CERTS); - goto f_err; - } + /* Compute the shared pre-master secret */ + key_size = ECDH_size(srvr_ecdh); + if (key_size <= 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_ECDH_LIB); + goto err; + } + i = ECDH_compute_key(p, key_size, clnt_ecpoint, srvr_ecdh, + NULL); + if (i <= 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_ECDH_LIB); + goto err; + } - if (EC_POINT_copy(clnt_ecpoint, - EC_KEY_get0_public_key(clnt_pub_pkey->pkey.ec)) - == 0) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_EC_LIB); - goto err; - } - ret = 2; /* Skip certificate verify processing */ - } else { - /* - * Get client's public key from encoded point - * in the ClientKeyExchange message. - */ - if ((bn_ctx = BN_CTX_new()) == NULL) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_MALLOC_FAILURE); - goto err; - } + EVP_PKEY_free(clnt_pub_pkey); + EC_POINT_free(clnt_ecpoint); + EC_KEY_free(srvr_ecdh); + BN_CTX_free(bn_ctx); + EC_KEY_free(s->s3->tmp.ecdh); + s->s3->tmp.ecdh = NULL; - /* Get encoded point length */ - i = *p; + /* Compute the master secret */ + s->session->master_key_length = + s->method->ssl3_enc->generate_master_secret( + s, s->session->master_key, p, i); - p += 1; - if (n != 1 + i) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_EC_LIB); - goto err; - } - if (EC_POINT_oct2point(group, - clnt_ecpoint, p, i, bn_ctx) == 0) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_EC_LIB); - goto err; - } - /* - * p is pointing to somewhere in the buffer - * currently, so set it to the start. - */ - p = (unsigned char *)s->init_buf->data; - } + explicit_bzero(p, i); + return (ret); - /* Compute the shared pre-master secret */ - key_size = ECDH_size(srvr_ecdh); - if (key_size <= 0) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_ECDH_LIB); - goto err; - } - i = ECDH_compute_key(p, key_size, clnt_ecpoint, srvr_ecdh, - NULL); - if (i <= 0) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_ECDH_LIB); - goto err; - } + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + EVP_PKEY_free(clnt_pub_pkey); + EC_POINT_free(clnt_ecpoint); + EC_KEY_free(srvr_ecdh); + BN_CTX_free(bn_ctx); + return (-1); +} - EVP_PKEY_free(clnt_pub_pkey); - EC_POINT_free(clnt_ecpoint); - EC_KEY_free(srvr_ecdh); - BN_CTX_free(bn_ctx); - EC_KEY_free(s->s3->tmp.ecdh); - s->s3->tmp.ecdh = NULL; +static int +ssl3_get_client_kex_gost(SSL *s, unsigned char *p, long n) +{ + EVP_PKEY_CTX *pkey_ctx; + EVP_PKEY *client_pub_pkey = NULL, *pk = NULL; + unsigned char premaster_secret[32], *start; + size_t outlen = 32, inlen; + unsigned long alg_a; + int Ttag, Tclass; + long Tlen; + int al; + int ret = 0; - /* Compute the master secret */ - s->session->master_key_length = s->method->ssl3_enc-> \ - generate_master_secret(s, s->session->master_key, p, i); + /* Get our certificate private key*/ + alg_a = s->s3->tmp.new_cipher->algorithm_auth; + if (alg_a & SSL_aGOST01) + pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey; - explicit_bzero(p, i); + pkey_ctx = EVP_PKEY_CTX_new(pk, 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(); + } + if (2 > n) + goto truncated; + /* Decrypt session key */ + if (ASN1_get_object((const unsigned char **)&p, &Tlen, &Ttag, + &Tclass, n) != V_ASN1_CONSTRUCTED || + Ttag != V_ASN1_SEQUENCE || Tclass != V_ASN1_UNIVERSAL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DECRYPTION_FAILED); + goto gerr; + } + start = p; + inlen = Tlen; + 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 gerr; + } + /* Generate master secret */ + 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 - if (alg_k & SSL_kGOST) { - int ret = 0; - EVP_PKEY_CTX *pkey_ctx; - EVP_PKEY *client_pub_pkey = NULL, *pk = NULL; - unsigned char premaster_secret[32], *start; - size_t outlen = 32, inlen; - unsigned long alg_a; - int Ttag, Tclass; - long Tlen; - - /* Get our certificate private key*/ - alg_a = s->s3->tmp.new_cipher->algorithm_auth; - if (alg_a & SSL_aGOST01) - pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey; - - pkey_ctx = EVP_PKEY_CTX_new(pk, 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(); - } - if (2 > n) - goto truncated; - /* Decrypt session key */ - if (ASN1_get_object((const unsigned char **)&p, &Tlen, &Ttag, - &Tclass, n) != V_ASN1_CONSTRUCTED || - Ttag != V_ASN1_SEQUENCE || Tclass != V_ASN1_UNIVERSAL) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - SSL_R_DECRYPTION_FAILED); - goto gerr; - } - start = p; - inlen = Tlen; - 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 gerr; - } - /* Generate master secret */ - 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 + else + goto err; + + truncated: + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_BAD_PACKET_LENGTH); + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + return (-1); +} + +int +ssl3_get_client_key_exchange(SSL *s) +{ + unsigned long alg_k; + unsigned char *p; + int al, ok; + long n; + + /* 2048 maxlen is a guess. How long a key does that permit? */ + n = s->method->ssl_get_message(s, SSL3_ST_SR_KEY_EXCH_A, + SSL3_ST_SR_KEY_EXCH_B, SSL3_MT_CLIENT_KEY_EXCHANGE, 2048, &ok); + if (!ok) + return ((int)n); + + p = (unsigned char *)s->init_msg; + + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + + if (alg_k & SSL_kRSA) { + if (ssl3_get_client_kex_rsa(s, p, n) != 1) + goto err; + } else if (alg_k & SSL_kDHE) { + if (ssl3_get_client_kex_dhe(s, p, n) != 1) + goto err; + } else if (alg_k & SSL_kECDHE) { + if (ssl3_get_client_kex_ecdhe(s, p, n) != 1) + goto err; + } else if (alg_k & SSL_kGOST) { + if (ssl3_get_client_kex_gost(s, p, n) != 1) goto err; } else { al = SSL_AD_HANDSHAKE_FAILURE; @@ -2001,16 +2075,10 @@ gerr: } return (1); -truncated: - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_BAD_PACKET_LENGTH); -f_err: + + f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); -err: - EVP_PKEY_free(clnt_pub_pkey); - EC_POINT_free(clnt_ecpoint); - EC_KEY_free(srvr_ecdh); - BN_CTX_free(bn_ctx); + err: return (-1); } |