X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fs3_clnt.c;h=a911bb154a46e711768f8fbe0cfee38bb27829d2;hp=46f9909830ca3a0c3d583fe3ccd7792d5ccebdbc;hb=124037fdc0571b5bd9022412348e9979a1726a31;hpb=4d69f9e69d2f5069ab37da68f4b93a6f337fb13e diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 46f9909830..a911bb154a 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -165,9 +165,7 @@ static int ssl_set_version(SSL *s); static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b); -#ifndef OPENSSL_NO_TLSEXT static int ssl3_check_finished(SSL *s); -#endif static int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, unsigned char *p, int (*put_cb) (const SSL_CIPHER *, @@ -309,12 +307,10 @@ int ssl3_connect(SSL *s) if (s->hit) { s->state = SSL3_ST_CR_FINISHED_A; -#ifndef OPENSSL_NO_TLSEXT if (s->tlsext_ticket_expected) { /* receive renewed session ticket */ s->state = SSL3_ST_CR_SESSION_TICKET_A; } -#endif } else { s->state = SSL3_ST_CR_CERT_A; } @@ -322,7 +318,6 @@ int ssl3_connect(SSL *s) break; case SSL3_ST_CR_CERT_A: case SSL3_ST_CR_CERT_B: -#ifndef OPENSSL_NO_TLSEXT /* Noop (ret = 0) for everything but EAP-FAST. */ ret = ssl3_check_finished(s); if (ret < 0) @@ -333,17 +328,17 @@ int ssl3_connect(SSL *s) s->init_num = 0; break; } -#endif + /* Check if it is anon DH/ECDH, SRP auth */ /* or PSK */ if (! (s->s3->tmp. new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP)) -&& !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { + && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { ret = ssl3_get_server_certificate(s); if (ret <= 0) goto end; -#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_status_expected) s->state = SSL3_ST_CR_CERT_STATUS_A; else @@ -352,12 +347,7 @@ int ssl3_connect(SSL *s) skip = 1; s->state = SSL3_ST_CR_KEY_EXCH_A; } -#else - } else - skip = 1; - s->state = SSL3_ST_CR_KEY_EXCH_A; -#endif s->init_num = 0; break; @@ -470,7 +460,7 @@ int ssl3_connect(SSL *s) if (ret <= 0) goto end; -#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG) +#if defined(OPENSSL_NO_NEXTPROTONEG) s->state = SSL3_ST_CW_FINISHED_A; #else if (s->s3->next_proto_neg_seen) @@ -505,7 +495,7 @@ int ssl3_connect(SSL *s) break; -#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) +#if !defined(OPENSSL_NO_NEXTPROTONEG) case SSL3_ST_CW_NEXT_PROTO_A: case SSL3_ST_CW_NEXT_PROTO_B: ret = ssl3_send_next_proto(s); @@ -538,21 +528,17 @@ int ssl3_connect(SSL *s) s->s3->delay_buf_pop_ret = 0; } } else { -#ifndef OPENSSL_NO_TLSEXT /* * Allow NewSessionTicket if ticket expected */ if (s->tlsext_ticket_expected) s->s3->tmp.next_state = SSL3_ST_CR_SESSION_TICKET_A; else -#endif - s->s3->tmp.next_state = SSL3_ST_CR_FINISHED_A; } s->init_num = 0; break; -#ifndef OPENSSL_NO_TLSEXT case SSL3_ST_CR_SESSION_TICKET_A: case SSL3_ST_CR_SESSION_TICKET_B: ret = ssl3_get_new_session_ticket(s); @@ -570,7 +556,6 @@ int ssl3_connect(SSL *s) s->state = SSL3_ST_CR_KEY_EXCH_A; s->init_num = 0; break; -#endif case SSL3_ST_CR_FINISHED_A: case SSL3_ST_CR_FINISHED_B: @@ -783,15 +768,11 @@ int ssl3_client_hello(SSL *s) goto err; if ((sess == NULL) || (sess->ssl_version != s->version) || -#ifdef OPENSSL_NO_TLSEXT - !sess->session_id_length || -#else /* * In the case of EAP-FAST, we can have a pre-shared * "ticket" without a session ID. */ (!sess->session_id_length && !sess->tlsext_tick) || -#endif (sess->not_resumable)) { if (!ssl_get_new_session(s, 0)) goto err; @@ -922,7 +903,6 @@ int ssl3_client_hello(SSL *s) #endif *(p++) = 0; /* Add the NULL method */ -#ifndef OPENSSL_NO_TLSEXT /* TLS extensions */ if (ssl_prepare_clienthello_tlsext(s) <= 0) { SSLerr(SSL_F_SSL3_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT); @@ -935,7 +915,6 @@ int ssl3_client_hello(SSL *s) SSLerr(SSL_F_SSL3_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); goto err; } -#endif l = p - d; if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l)) { @@ -968,8 +947,7 @@ int ssl3_get_server_hello(SSL *s) * Hello verify request and/or server hello version may not match so set * first packet if we're negotiating version. */ - if (SSL_IS_DTLS(s)) - s->first_packet = 1; + s->first_packet = 1; n = s->method->ssl_get_message(s, SSL3_ST_CR_SRVR_HELLO_A, @@ -978,8 +956,8 @@ int ssl3_get_server_hello(SSL *s) if (!ok) return ((int)n); + s->first_packet = 0; if (SSL_IS_DTLS(s)) { - s->first_packet = 0; if (s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST) { if (s->d1->send_cookie == 0) { s->s3->tmp.reuse_message = 1; @@ -1058,7 +1036,7 @@ int ssl3_get_server_hello(SSL *s) al = SSL_AD_PROTOCOL_VERSION; goto f_err; } - s->version = s->method->version; + s->session->ssl_version = s->version = s->method->version; } else if ((p[0] != (s->version >> 8)) || (p[1] != (s->version & 0xff))) { SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION); s->version = (s->version & 0xff00) | p[1]; @@ -1082,7 +1060,7 @@ int ssl3_get_server_hello(SSL *s) SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_SSL3_SESSION_ID_TOO_LONG); goto f_err; } -#ifndef OPENSSL_NO_TLSEXT + /* * Check if we can resume the session based on external pre-shared secret. * EAP-FAST (RFC 4851) supports two types of session resumption. @@ -1111,7 +1089,6 @@ int ssl3_get_server_hello(SSL *s) goto f_err; } } -#endif /* OPENSSL_NO_TLSEXT */ if (j != 0 && j == s->session->session_id_length && memcmp(p, s->session->session_id, j) == 0) { @@ -1191,7 +1168,7 @@ int ssl3_get_server_hello(SSL *s) * Don't digest cached records if no sigalgs: we may need them for client * authentication. */ - if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s)) + if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s, 0)) goto f_err; /* lets get the compression algorithm */ /* COMPRESSION */ @@ -1237,13 +1214,11 @@ int ssl3_get_server_hello(SSL *s) } #endif -#ifndef OPENSSL_NO_TLSEXT /* TLS extensions */ if (!ssl_parse_serverhello_tlsext(s, &p, d, n)) { SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_PARSE_TLSEXT); goto err; } -#endif if (p != (d + n)) { /* wrong packet length */ @@ -1268,7 +1243,6 @@ int ssl3_get_server_certificate(SSL *s) const unsigned char *q, *p; unsigned char *d; STACK_OF(X509) *sk = NULL; - SESS_CERT *sc; EVP_PKEY *pkey = NULL; n = s->method->ssl_get_message(s, @@ -1347,14 +1321,7 @@ int ssl3_get_server_certificate(SSL *s) goto f_err; } - sc = ssl_sess_cert_new(); - if (sc == NULL) - goto err; - - ssl_sess_cert_free(s->session->sess_cert); - s->session->sess_cert = sc; - - sc->cert_chain = sk; + s->session->peer_chain = sk; /* * Inconsistency alert: cert_chain does include the peer's certificate, * which we don't include in s3_srvr.c @@ -1392,15 +1359,7 @@ int ssl3_get_server_certificate(SSL *s) SSL_R_WRONG_CERTIFICATE_TYPE); goto f_err; } - sc->peer_cert_type = i; - CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); - /* - * Why would the following ever happen? We just created sc a couple - * of lines ago. - */ - X509_free(sc->peer_pkeys[i].x509); - sc->peer_pkeys[i].x509 = x; - sc->peer_key = &(sc->peer_pkeys[i]); + s->session->peer_type = i; X509_free(s->session->peer); CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); @@ -1479,7 +1438,6 @@ int ssl3_get_key_exchange(SSL *s) * problems later. */ if (alg_k & SSL_kPSK) { - s->session->sess_cert = ssl_sess_cert_new(); OPENSSL_free(s->ctx->psk_identity_hint); s->ctx->psk_identity_hint = NULL; } @@ -1489,22 +1447,19 @@ int ssl3_get_key_exchange(SSL *s) } param = p = (unsigned char *)s->init_msg; - if (s->session->sess_cert != NULL) { + #ifndef OPENSSL_NO_RSA - RSA_free(s->session->sess_cert->peer_rsa_tmp); - s->session->sess_cert->peer_rsa_tmp = NULL; + RSA_free(s->s3->peer_rsa_tmp); + s->s3->peer_rsa_tmp = NULL; #endif #ifndef OPENSSL_NO_DH - DH_free(s->session->sess_cert->peer_dh_tmp); - s->session->sess_cert->peer_dh_tmp = NULL; + DH_free(s->s3->peer_dh_tmp); + s->s3->peer_dh_tmp = NULL; #endif #ifndef OPENSSL_NO_EC - EC_KEY_free(s->session->sess_cert->peer_ecdh_tmp); - s->session->sess_cert->peer_ecdh_tmp = NULL; + EC_KEY_free(s->s3->peer_ecdh_tmp); + s->s3->peer_ecdh_tmp = NULL; #endif - } else { - s->session->sess_cert = ssl_sess_cert_new(); - } /* Total length of the parameters including the length prefix */ param_len = 0; @@ -1650,21 +1605,8 @@ int ssl3_get_key_exchange(SSL *s) } /* We must check if there is a certificate */ -# ifndef OPENSSL_NO_RSA - if (alg_a & SSL_aRSA) - pkey = - X509_get_pubkey(s->session-> - sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509); -# else - if (0) ; -# endif -# ifndef OPENSSL_NO_DSA - else if (alg_a & SSL_aDSS) - pkey = - X509_get_pubkey(s->session-> - sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN]. - x509); -# endif + if (alg_a & (SSL_aRSA|SSL_aDSS)) + pkey = X509_get_pubkey(s->session->peer); } else #endif /* !OPENSSL_NO_SRP */ #ifndef OPENSSL_NO_RSA @@ -1722,14 +1664,19 @@ int ssl3_get_key_exchange(SSL *s) /* this should be because we are using an export cipher */ if (alg_a & SSL_aRSA) - pkey = - X509_get_pubkey(s->session-> - sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509); + pkey = X509_get_pubkey(s->session->peer); else { SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); goto err; } - s->session->sess_cert->peer_rsa_tmp = rsa; + + if (EVP_PKEY_bits(pkey) <= SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE); + goto f_err; + } + + s->s3->peer_rsa_tmp = rsa; rsa = NULL; } #else /* OPENSSL_NO_RSA */ @@ -1807,24 +1754,11 @@ int ssl3_get_key_exchange(SSL *s) SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_DH_KEY_TOO_SMALL); goto f_err; } -# ifndef OPENSSL_NO_RSA - if (alg_a & SSL_aRSA) - pkey = - X509_get_pubkey(s->session-> - sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509); -# else - if (0) ; -# endif -# ifndef OPENSSL_NO_DSA - else if (alg_a & SSL_aDSS) - pkey = - X509_get_pubkey(s->session-> - sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN]. - x509); -# endif + if (alg_a & (SSL_aRSA|SSL_aDSS)) + pkey = X509_get_pubkey(s->session->peer); /* else anonymous DH, so no certificate or pkey. */ - s->session->sess_cert->peer_dh_tmp = dh; + s->s3->peer_dh_tmp = dh; dh = NULL; } #endif /* !OPENSSL_NO_DH */ @@ -1923,19 +1857,15 @@ int ssl3_get_key_exchange(SSL *s) if (0) ; # ifndef OPENSSL_NO_RSA else if (alg_a & SSL_aRSA) - pkey = - X509_get_pubkey(s->session-> - sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509); + pkey = X509_get_pubkey(s->session->peer); # endif # ifndef OPENSSL_NO_EC else if (alg_a & SSL_aECDSA) - pkey = - X509_get_pubkey(s->session-> - sess_cert->peer_pkeys[SSL_PKEY_ECC].x509); + pkey = X509_get_pubkey(s->session->peer); # endif /* else anonymous ECDH, so no certificate or pkey. */ EC_KEY_set_public_key(ecdh, srvr_ecpoint); - s->session->sess_cert->peer_ecdh_tmp = ecdh; + s->s3->peer_ecdh_tmp = ecdh; ecdh = NULL; BN_CTX_free(bn_ctx); bn_ctx = NULL; @@ -2100,10 +2030,8 @@ int ssl3_get_certificate_request(SSL *s) * If we get here we don't need any cached handshake records as we * wont be doing client auth. */ - if (s->s3->handshake_buffer) { - if (!ssl3_digest_cached_records(s)) - goto err; - } + if (!ssl3_digest_cached_records(s, 0)) + goto err; return (1); } @@ -2240,7 +2168,6 @@ static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b) return (X509_NAME_cmp(*a, *b)); } -#ifndef OPENSSL_NO_TLSEXT int ssl3_get_new_session_ticket(SSL *s) { int ok, al, ret = 0, ticklen; @@ -2264,6 +2191,38 @@ int ssl3_get_new_session_ticket(SSL *s) } p = d = (unsigned char *)s->init_msg; + + if (s->session->session_id_length > 0) { + int i = s->session_ctx->session_cache_mode; + SSL_SESSION *new_sess; + /* + * We reused an existing session, so we need to replace it with a new + * one + */ + if (i & SSL_SESS_CACHE_CLIENT) { + /* + * Remove the old session from the cache + */ + if (i & SSL_SESS_CACHE_NO_INTERNAL_STORE) { + if (s->session_ctx->remove_session_cb != NULL) + s->session_ctx->remove_session_cb(s->session_ctx, + s->session); + } else { + /* We carry on if this fails */ + SSL_CTX_remove_session(s->session_ctx, s->session); + } + } + + if ((new_sess = ssl_session_dup(s->session, 0)) == 0) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE); + goto f_err; + } + + SSL_SESSION_free(s->session); + s->session = new_sess; + } + n2l(p, s->session->tlsext_tick_lifetime_hint); n2s(p, ticklen); /* ticket_lifetime_hint + ticket_length + ticket */ @@ -2363,7 +2322,6 @@ int ssl3_get_cert_status(SSL *s) s->state = SSL_ST_ERR; return (-1); } -#endif int ssl3_get_server_done(SSL *s) { @@ -2425,7 +2383,7 @@ int ssl3_send_client_key_exchange(SSL *s) if (!pms) goto memerr; - if (s->session->sess_cert == NULL) { + if (s->session->peer == NULL) { /* * We should always have a server certificate with SSL_kRSA. */ @@ -2434,13 +2392,10 @@ int ssl3_send_client_key_exchange(SSL *s) goto err; } - if (s->session->sess_cert->peer_rsa_tmp != NULL) - rsa = s->session->sess_cert->peer_rsa_tmp; + if (s->s3->peer_rsa_tmp != NULL) + rsa = s->s3->peer_rsa_tmp; else { - pkey = - X509_get_pubkey(s->session-> - sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC]. - x509); + pkey = X509_get_pubkey(s->session->peer); if ((pkey == NULL) || (pkey->type != EVP_PKEY_RSA) || (pkey->pkey.rsa == NULL)) { SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, @@ -2483,24 +2438,13 @@ int ssl3_send_client_key_exchange(SSL *s) #ifndef OPENSSL_NO_DH else if (alg_k & (SSL_kDHE | SSL_kDHr | SSL_kDHd)) { DH *dh_srvr, *dh_clnt; - SESS_CERT *scert = s->session->sess_cert; - - if (scert == NULL) { - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - SSL_R_UNEXPECTED_MESSAGE); - goto err; - } - - if (scert->peer_dh_tmp != NULL) - dh_srvr = scert->peer_dh_tmp; + if (s->s3->peer_dh_tmp != NULL) + dh_srvr = s->s3->peer_dh_tmp; else { /* we get them from the cert */ - int idx = scert->peer_cert_type; EVP_PKEY *spkey = NULL; dh_srvr = NULL; - if (idx >= 0) - spkey = X509_get_pubkey(scert->peer_pkeys[idx].x509); + spkey = X509_get_pubkey(s->session->peer); if (spkey) { dh_srvr = EVP_PKEY_get1_DH(spkey); EVP_PKEY_free(spkey); @@ -2546,7 +2490,7 @@ int ssl3_send_client_key_exchange(SSL *s) */ n = DH_compute_key(pms, dh_srvr->pub_key, dh_clnt); - if (scert->peer_dh_tmp == NULL) + if (s->s3->peer_dh_tmp == NULL) DH_free(dh_srvr); if (n <= 0) { @@ -2567,8 +2511,6 @@ int ssl3_send_client_key_exchange(SSL *s) } DH_free(dh_clnt); - - /* perhaps clean things up a bit EAY EAY EAY EAY */ } #endif @@ -2578,14 +2520,6 @@ int ssl3_send_client_key_exchange(SSL *s) EC_KEY *tkey; int ecdh_clnt_cert = 0; int field_size = 0; - - 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, - SSL_R_UNEXPECTED_MESSAGE); - goto err; - } - /* * Did we send out the client's ECDH share for use in premaster * computation as part of client certificate? If so, set @@ -2614,13 +2548,11 @@ int ssl3_send_client_key_exchange(SSL *s) */ } - if (s->session->sess_cert->peer_ecdh_tmp != NULL) { - tkey = s->session->sess_cert->peer_ecdh_tmp; + if (s->s3->peer_ecdh_tmp != NULL) { + tkey = s->s3->peer_ecdh_tmp; } else { /* Get the Server Public Key from Cert */ - srvr_pub_pkey = - X509_get_pubkey(s->session-> - sess_cert->peer_pkeys[SSL_PKEY_ECC].x509); + srvr_pub_pkey = X509_get_pubkey(s->session->peer); if ((srvr_pub_pkey == NULL) || (srvr_pub_pkey->type != EVP_PKEY_EC) || (srvr_pub_pkey->pkey.ec == NULL)) { @@ -2748,7 +2680,6 @@ int ssl3_send_client_key_exchange(SSL *s) X509 *peer_cert; size_t msglen; unsigned int md_len; - int keytype; unsigned char shared_ukm[32], tmp[256]; EVP_MD_CTX *ukm_hash; EVP_PKEY *pub_key; @@ -2761,13 +2692,7 @@ int ssl3_send_client_key_exchange(SSL *s) /* * Get server sertificate PKEY and create ctx from it */ - peer_cert = - s->session-> - sess_cert->peer_pkeys[(keytype = SSL_PKEY_GOST01)].x509; - if (!peer_cert) - peer_cert = - s->session-> - sess_cert->peer_pkeys[(keytype = SSL_PKEY_GOST94)].x509; + peer_cert = s->session->peer; if (!peer_cert) { SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER); @@ -3099,15 +3024,8 @@ int ssl3_send_client_verify(SSL *s) } s2n(u, p); n = u + 4; - /* - * For extended master secret we've already digested cached - * records. - */ - if (s->session->flags & SSL_SESS_FLAG_EXTMS) { - BIO_free(s->s3->handshake_buffer); - s->s3->handshake_buffer = NULL; - s->s3->flags &= ~TLS1_FLAGS_KEEP_HANDSHAKE; - } else if (!ssl3_digest_cached_records(s)) + /* Digest cached records and discard handshake buffer */ + if (!ssl3_digest_cached_records(s, 0)) goto err; } else #ifndef OPENSSL_NO_RSA @@ -3208,15 +3126,14 @@ static int ssl3_check_client_certificate(SSL *s) alg_k = s->s3->tmp.new_cipher->algorithm_mkey; /* See if we can use client certificate for fixed DH */ if (alg_k & (SSL_kDHr | SSL_kDHd)) { - SESS_CERT *scert = s->session->sess_cert; - int i = scert->peer_cert_type; + int i = s->session->peer_type; EVP_PKEY *clkey = NULL, *spkey = NULL; clkey = s->cert->key->privatekey; /* If client key not DH assume it can be used */ if (EVP_PKEY_id(clkey) != EVP_PKEY_DH) return 1; if (i >= 0) - spkey = X509_get_pubkey(scert->peer_pkeys[i].x509); + spkey = X509_get_pubkey(s->session->peer); if (spkey) { /* Compare server and client parameters */ i = EVP_PKEY_cmp_parameters(clkey, spkey); @@ -3290,7 +3207,7 @@ int ssl3_send_client_certificate(SSL *s) return (1); } else { s->s3->tmp.cert_req = 2; - if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s)) { + if (!ssl3_digest_cached_records(s, 0)) { ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); s->state = SSL_ST_ERR; return 0; @@ -3324,13 +3241,14 @@ int ssl3_check_cert_and_algorithm(SSL *s) int i, idx; long alg_k, alg_a; EVP_PKEY *pkey = NULL; - SESS_CERT *sc; + int pkey_bits; #ifndef OPENSSL_NO_RSA RSA *rsa; #endif #ifndef OPENSSL_NO_DH DH *dh; #endif + int al = SSL_AD_HANDSHAKE_FAILURE; alg_k = s->s3->tmp.new_cipher->algorithm_mkey; alg_a = s->s3->tmp.new_cipher->algorithm_auth; @@ -3338,25 +3256,19 @@ int ssl3_check_cert_and_algorithm(SSL *s) /* we don't have a certificate */ if ((alg_a & SSL_aNULL) || (alg_k & SSL_kPSK)) return (1); - - sc = s->session->sess_cert; - if (sc == NULL) { - SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR); - goto err; - } #ifndef OPENSSL_NO_RSA - rsa = s->session->sess_cert->peer_rsa_tmp; + rsa = s->s3->peer_rsa_tmp; #endif #ifndef OPENSSL_NO_DH - dh = s->session->sess_cert->peer_dh_tmp; + dh = s->s3->peer_dh_tmp; #endif /* This is the passed certificate */ - idx = sc->peer_cert_type; + idx = s->session->peer_type; #ifndef OPENSSL_NO_EC if (idx == SSL_PKEY_ECC) { - if (ssl_check_srvr_ecc_cert_and_alg(sc->peer_pkeys[idx].x509, s) == 0) { + if (ssl_check_srvr_ecc_cert_and_alg(s->session->peer, s) == 0) { /* check failed */ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_BAD_ECC_CERT); goto f_err; @@ -3372,8 +3284,9 @@ int ssl3_check_cert_and_algorithm(SSL *s) goto f_err; } #endif - pkey = X509_get_pubkey(sc->peer_pkeys[idx].x509); - i = X509_certificate_type(sc->peer_pkeys[idx].x509, pkey); + pkey = X509_get_pubkey(s->session->peer); + pkey_bits = EVP_PKEY_bits(pkey); + i = X509_certificate_type(s->session->peer, pkey); EVP_PKEY_free(pkey); /* Check that we have a certificate if we require one */ @@ -3390,17 +3303,33 @@ int ssl3_check_cert_and_algorithm(SSL *s) } #endif #ifndef OPENSSL_NO_RSA - if ((alg_k & SSL_kRSA) && - !(has_bits(i, EVP_PK_RSA | EVP_PKT_ENC) || (rsa != NULL))) { - SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, - SSL_R_MISSING_RSA_ENCRYPTING_CERT); - goto f_err; + if (alg_k & SSL_kRSA) { + if (!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && + !has_bits(i, EVP_PK_RSA | EVP_PKT_ENC)) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_RSA_ENCRYPTING_CERT); + goto f_err; + } else if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)) { + if (pkey_bits <= SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) { + if (!has_bits(i, EVP_PK_RSA | EVP_PKT_ENC)) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_RSA_ENCRYPTING_CERT); + goto f_err; + } + if (rsa != NULL) { + /* server key exchange is not allowed. */ + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR); + goto f_err; + } + } + } } #endif #ifndef OPENSSL_NO_DH - if ((alg_k & SSL_kDHE) && - !(has_bits(i, EVP_PK_DH | EVP_PKT_EXCH) || (dh != NULL))) { - SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_MISSING_DH_KEY); + if ((alg_k & SSL_kDHE) && (dh == NULL)) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR); goto f_err; } else if ((alg_k & SSL_kDHr) && !SSL_USE_SIGALGS(s) && !has_bits(i, EVP_PK_DH | EVP_PKS_RSA)) { @@ -3418,12 +3347,18 @@ int ssl3_check_cert_and_algorithm(SSL *s) # endif #endif - if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && !has_bits(i, EVP_PKT_EXP)) { + if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && + pkey_bits > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) { #ifndef OPENSSL_NO_RSA if (alg_k & SSL_kRSA) { - if (rsa == NULL - || RSA_size(rsa) * 8 > + if (rsa == NULL) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_EXPORT_TMP_RSA_KEY); + goto f_err; + } else if (RSA_bits(rsa) > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) { + /* We have a temporary RSA key but it's too large. */ + al = SSL_AD_EXPORT_RESTRICTION; SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_MISSING_EXPORT_TMP_RSA_KEY); goto f_err; @@ -3431,14 +3366,21 @@ int ssl3_check_cert_and_algorithm(SSL *s) } else #endif #ifndef OPENSSL_NO_DH - if (alg_k & (SSL_kDHE | SSL_kDHr | SSL_kDHd)) { - if (dh == NULL - || DH_size(dh) * 8 > + if (alg_k & SSL_kDHE) { + if (DH_bits(dh) > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) { + /* We have a temporary DH key but it's too large. */ + al = SSL_AD_EXPORT_RESTRICTION; SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_MISSING_EXPORT_TMP_DH_KEY); goto f_err; } + } else if (alg_k & (SSL_kDHr | SSL_kDHd)) { + /* The cert should have had an export DH key. */ + al = SSL_AD_EXPORT_RESTRICTION; + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_EXPORT_TMP_DH_KEY); + goto f_err; } else #endif { @@ -3449,12 +3391,10 @@ int ssl3_check_cert_and_algorithm(SSL *s) } return (1); f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); - err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); return (0); } -#ifndef OPENSSL_NO_TLSEXT /* * Normally, we can tell if the server is resuming the session from * the session ID. EAP-FAST (RFC 4851), however, relies on the next server @@ -3504,7 +3444,7 @@ static int ssl3_check_finished(SSL *s) return 0; } -# ifndef OPENSSL_NO_NEXTPROTONEG +#ifndef OPENSSL_NO_NEXTPROTONEG int ssl3_send_next_proto(SSL *s) { unsigned int len, padding_len; @@ -3527,7 +3467,6 @@ int ssl3_send_next_proto(SSL *s) return ssl3_do_write(s, SSL3_RT_HANDSHAKE); } -# endif #endif int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)