diff options
Diffstat (limited to 'ssl/s3_srvr.c')
-rw-r--r-- | ssl/s3_srvr.c | 290 |
1 files changed, 81 insertions, 209 deletions
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 9ec6885..0e9c7d5 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -148,6 +148,7 @@ #define NETSCAPE_HANG_BUG +#include <assert.h> #include <stdio.h> #include <string.h> @@ -351,7 +352,7 @@ int ssl3_accept(SSL *s) { ret=ssl3_send_server_certificate(s); if (ret <= 0) goto end; - if (s->tlsext_status_expected) + if (s->s3->tmp.certificate_status_expected) s->state=SSL3_ST_SW_CERT_STATUS_A; else s->state=SSL3_ST_SW_KEY_EXCH_A; @@ -485,54 +486,6 @@ int ssl3_accept(SSL *s) goto end; s->state=SSL3_ST_SR_CERT_VRFY_A; s->init_num=0; - - /* TODO(davidben): These two blocks are different - * between SSL and DTLS. Resolve the difference and code - * duplication. */ - if (SSL_USE_SIGALGS(s)) - { - if (!s->session->peer) - break; - /* For sigalgs freeze the handshake buffer - * at this point and digest cached records. - */ - if (!s->s3->handshake_buffer) - { - OPENSSL_PUT_ERROR(SSL, ssl3_accept, ERR_R_INTERNAL_ERROR); - return -1; - } - s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE; - if (!ssl3_digest_cached_records(s)) - return -1; - } - else - { - int offset=0; - int dgst_num; - - /* We need to get hashes here so if there is - * a client cert, it can be verified - * FIXME - digest processing for CertificateVerify - * should be generalized. But it is next step - */ - if (s->s3->handshake_buffer) - if (!ssl3_digest_cached_records(s)) - return -1; - for (dgst_num=0; dgst_num<SSL_MAX_DIGEST;dgst_num++) - if (s->s3->handshake_dgst[dgst_num]) - { - int dgst_size; - - s->method->ssl3_enc->cert_verify_mac(s,EVP_MD_CTX_type(s->s3->handshake_dgst[dgst_num]),&(s->s3->tmp.cert_verify_md[offset])); - dgst_size=EVP_MD_CTX_size(s->s3->handshake_dgst[dgst_num]); - if (dgst_size < 0) - { - ret = -1; - goto end; - } - offset+=dgst_size; - } - } break; case SSL3_ST_SR_CERT_VRFY_A: @@ -547,9 +500,7 @@ int ssl3_accept(SSL *s) case SSL3_ST_SR_CHANGE: { char next_proto_neg = 0; char channel_id = 0; -# if !defined(OPENSSL_NO_NEXTPROTONEG) next_proto_neg = s->s3->next_proto_neg_seen; -# endif channel_id = s->s3->tlsext_channel_id_valid; /* At this point, the next message must be entirely @@ -568,7 +519,6 @@ int ssl3_accept(SSL *s) break; } -#if !defined(OPENSSL_NO_NEXTPROTONEG) case SSL3_ST_SR_NEXT_PROTO_A: case SSL3_ST_SR_NEXT_PROTO_B: ret=ssl3_get_next_proto(s); @@ -579,7 +529,6 @@ int ssl3_accept(SSL *s) else s->state=SSL3_ST_SR_FINISHED_A; break; -#endif case SSL3_ST_SR_CHANNEL_ID_A: case SSL3_ST_SR_CHANNEL_ID_B: @@ -614,12 +563,14 @@ int ssl3_accept(SSL *s) case SSL3_ST_SW_SESSION_TICKET_A: case SSL3_ST_SW_SESSION_TICKET_B: - ret=ssl3_send_newsession_ticket(s); + ret=ssl3_send_new_session_ticket(s); if (ret <= 0) goto end; s->state=SSL3_ST_SW_CHANGE_A; s->init_num=0; break; +#if 0 + // TODO(davidben): Implement OCSP stapling on the server. case SSL3_ST_SW_CERT_STATUS_A: case SSL3_ST_SW_CERT_STATUS_B: ret=ssl3_send_cert_status(s); @@ -627,6 +578,7 @@ int ssl3_accept(SSL *s) s->state=SSL3_ST_SW_KEY_EXCH_A; s->init_num=0; break; +#endif case SSL3_ST_SW_CHANGE_A: case SSL3_ST_SW_CHANGE_B: @@ -778,6 +730,7 @@ int ssl3_get_client_hello(SSL *s) SSL3_ST_SR_CLNT_HELLO_B, SSL3_MT_CLIENT_HELLO, SSL3_RT_MAX_PLAIN_LENGTH, + SSL_GET_MESSAGE_HASH_MESSAGE, &ok); if (!ok) return((int)n); @@ -1187,16 +1140,6 @@ int ssl3_get_client_hello(SSL *s) * s->tmp.new_cipher - the new cipher to use. */ - /* Handles TLS extensions that we couldn't check earlier */ - if (s->version >= SSL3_VERSION) - { - if (ssl_check_clienthello_tlsext_late(s) <= 0) - { - OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_CLIENTHELLO_TLSEXT); - goto err; - } - } - if (ret < 0) ret=-ret; if (0) { @@ -1326,16 +1269,12 @@ int ssl3_send_server_key_exchange(SSL *s) int j,num; unsigned char md_buf[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH]; unsigned int u; -#ifndef OPENSSL_NO_DH DH *dh=NULL,*dhp; -#endif -#ifndef OPENSSL_NO_ECDH EC_KEY *ecdh=NULL, *ecdhp; unsigned char *encodedPoint = NULL; int encodedlen = 0; int curve_id = 0; BN_CTX *bn_ctx = NULL; -#endif const char* psk_identity_hint = NULL; size_t psk_identity_hint_len = 0; EVP_PKEY *pkey; @@ -1372,7 +1311,6 @@ int ssl3_send_server_key_exchange(SSL *s) psk_identity_hint_len = 0; n+=2+psk_identity_hint_len; } -#ifndef OPENSSL_NO_DH if (alg_k & SSL_kEDH) { dhp=cert->dh_tmp; @@ -1424,8 +1362,6 @@ int ssl3_send_server_key_exchange(SSL *s) r[2]=dh->pub_key; } else -#endif -#ifndef OPENSSL_NO_ECDH if (alg_k & SSL_kEECDH) { const EC_GROUP *group; @@ -1550,7 +1486,6 @@ int ssl3_send_server_key_exchange(SSL *s) r[3]=NULL; } else -#endif /* !OPENSSL_NO_ECDH */ if (!(alg_k & SSL_kPSK)) { al=SSL_AD_HANDSHAKE_FAILURE; @@ -1607,7 +1542,6 @@ int ssl3_send_server_key_exchange(SSL *s) } } -#ifndef OPENSSL_NO_ECDH if (alg_k & SSL_kEECDH) { /* XXX: For now, we only support named (not generic) curves. @@ -1631,7 +1565,6 @@ int ssl3_send_server_key_exchange(SSL *s) encodedPoint = NULL; p += encodedlen; } -#endif /* OPENSSL_NO_ECDH */ /* not anonymous */ if (pkey != NULL) @@ -1715,10 +1648,8 @@ int ssl3_send_server_key_exchange(SSL *s) f_err: ssl3_send_alert(s,SSL3_AL_FATAL,al); err: -#ifndef OPENSSL_NO_ECDH if (encodedPoint != NULL) OPENSSL_free(encodedPoint); BN_CTX_free(bn_ctx); -#endif EVP_MD_CTX_cleanup(&md_ctx); return(-1); } @@ -1823,25 +1754,22 @@ int ssl3_get_client_key_exchange(SSL *s) RSA *rsa=NULL; uint8_t *decrypt_buf = NULL; EVP_PKEY *pkey=NULL; -#ifndef OPENSSL_NO_DH BIGNUM *pub=NULL; DH *dh_srvr; -#endif -#ifndef OPENSSL_NO_ECDH EC_KEY *srvr_ecdh = NULL; EVP_PKEY *clnt_pub_pkey = NULL; EC_POINT *clnt_ecpoint = NULL; BN_CTX *bn_ctx = NULL; unsigned int psk_len = 0; unsigned char psk[PSK_MAX_PSK_LEN]; -#endif 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, /* ??? */ + SSL_GET_MESSAGE_HASH_MESSAGE, &ok); if (!ok) return((int)n); @@ -2063,7 +1991,6 @@ int ssl3_get_client_key_exchange(SSL *s) premaster_secret_len = sizeof(rand_premaster_secret); } -#ifndef OPENSSL_NO_DH else if (alg_k & SSL_kEDH) { CBS dh_Yc; @@ -2116,9 +2043,7 @@ int ssl3_get_client_key_exchange(SSL *s) premaster_secret_len = dh_len; } -#endif -#ifndef OPENSSL_NO_ECDH else if (alg_k & SSL_kEECDH) { int field_size = 0, ecdh_len; @@ -2213,7 +2138,6 @@ int ssl3_get_client_key_exchange(SSL *s) premaster_secret_len = ecdh_len; } -#endif else if (alg_k & SSL_kPSK) { /* For plain PSK, other_secret is a block of 0s with the same @@ -2283,41 +2207,34 @@ err: } if (decrypt_buf) OPENSSL_free(decrypt_buf); -#ifndef OPENSSL_NO_ECDH EVP_PKEY_free(clnt_pub_pkey); EC_POINT_free(clnt_ecpoint); if (srvr_ecdh != NULL) EC_KEY_free(srvr_ecdh); BN_CTX_free(bn_ctx); -#endif return(-1); } int ssl3_get_cert_verify(SSL *s) { - EVP_PKEY *pkey=NULL; int al,ok,ret=0; long n; CBS certificate_verify, signature; - int type = 0; X509 *peer = s->session->peer; + EVP_PKEY *pkey = NULL; const EVP_MD *md = NULL; - EVP_MD_CTX mctx; - - EVP_MD_CTX_init(&mctx); - - /* Determine if a CertificateVerify message is expected at all. It is - * important that this be determined before ssl_get_message is called, - * so as not to process the ChangeCipherSpec message early. */ - if (peer != NULL) - { - pkey = X509_get_pubkey(peer); - type = X509_certificate_type(peer,pkey); - } - if (!(type & EVP_PKT_SIGN)) + uint8_t digest[EVP_MAX_MD_SIZE]; + size_t digest_length; + EVP_PKEY_CTX *pctx = NULL; + + /* Only RSA and ECDSA client certificates are supported, so a + * CertificateVerify is required if and only if there's a + * client certificate. */ + if (peer == NULL) { - ret = 1; - goto done_with_buffer; + if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s)) + return -1; + return 1; } n=s->method->ssl_get_message(s, @@ -2325,26 +2242,42 @@ int ssl3_get_cert_verify(SSL *s) SSL3_ST_SR_CERT_VRFY_B, SSL3_MT_CERTIFICATE_VERIFY, SSL3_RT_MAX_PLAIN_LENGTH, + SSL_GET_MESSAGE_DONT_HASH_MESSAGE, &ok); if (!ok) + return (int)n; + + /* Filter out unsupported certificate types. */ + pkey = X509_get_pubkey(peer); + if (!(X509_certificate_type(peer, pkey) & EVP_PKT_SIGN) || + (pkey->type != EVP_PKEY_RSA && pkey->type != EVP_PKEY_EC)) { - ret = (int)n; - goto done; + al = SSL_AD_UNSUPPORTED_CERTIFICATE; + OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE); + goto f_err; } CBS_init(&certificate_verify, s->init_msg, n); - /* We now have a signature that we need to verify. */ - /* TODO(davidben): This should share code with - * ssl3_get_server_key_exchange. */ - + /* Determine the digest type if needbe. */ if (SSL_USE_SIGALGS(s)) { if (!tls12_check_peer_sigalg(&md, &al, s, &certificate_verify, pkey)) goto f_err; } + /* Compute the digest. */ + if (!ssl3_cert_verify_hash(s, digest, &digest_length, &md, pkey)) + goto err; + + /* The handshake buffer is no longer necessary, and we may hash the + * current message.*/ + if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s)) + goto err; + ssl3_hash_current_message(s); + + /* Parse and verify the signature. */ if (!CBS_get_u16_length_prefixed(&certificate_verify, &signature) || CBS_len(&certificate_verify) != 0) { @@ -2353,87 +2286,27 @@ int ssl3_get_cert_verify(SSL *s) goto f_err; } - if (SSL_USE_SIGALGS(s)) - { - size_t hdatalen; - const uint8_t *hdata; - if (!BIO_mem_contents(s->s3->handshake_buffer, &hdata, &hdatalen)) - { - OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, ERR_R_INTERNAL_ERROR); - al=SSL_AD_INTERNAL_ERROR; - goto f_err; - } - if (!EVP_VerifyInit_ex(&mctx, md, NULL) - || !EVP_VerifyUpdate(&mctx, hdata, hdatalen)) - { - OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, ERR_R_EVP_LIB); - al=SSL_AD_INTERNAL_ERROR; - goto f_err; - } - - if (EVP_VerifyFinal(&mctx, - CBS_data(&signature), CBS_len(&signature), - pkey) <= 0) - { - al=SSL_AD_DECRYPT_ERROR; - OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_SIGNATURE); - goto f_err; - } - } - else - if (pkey->type == EVP_PKEY_RSA) - { - if (!RSA_verify(NID_md5_sha1, s->s3->tmp.cert_verify_md, - MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH, - CBS_data(&signature), CBS_len(&signature), - pkey->pkey.rsa)) - { - al = SSL_AD_DECRYPT_ERROR; - OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_RSA_SIGNATURE); - goto f_err; - } - } - else -#ifndef OPENSSL_NO_ECDSA - if (pkey->type == EVP_PKEY_EC) - { - if (!ECDSA_verify(pkey->save_type, - &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]), - SHA_DIGEST_LENGTH, - CBS_data(&signature), CBS_len(&signature), - pkey->pkey.ec)) - { - /* bad signature */ - al = SSL_AD_DECRYPT_ERROR; - OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_ECDSA_SIGNATURE); - goto f_err; - } - } - else -#endif + pctx = EVP_PKEY_CTX_new(pkey, NULL); + if (pctx == NULL) + goto err; + if (!EVP_PKEY_verify_init(pctx) || + !EVP_PKEY_CTX_set_signature_md(pctx, md) || + !EVP_PKEY_verify(pctx, CBS_data(&signature), CBS_len(&signature), + digest, digest_length)) { - OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, ERR_R_INTERNAL_ERROR); - al=SSL_AD_UNSUPPORTED_CERTIFICATE; + al = SSL_AD_DECRYPT_ERROR; + OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_SIGNATURE); goto f_err; } - - ret=1; + ret = 1; if (0) { f_err: ssl3_send_alert(s,SSL3_AL_FATAL,al); } -done_with_buffer: - /* There is no more need for the handshake buffer. */ - if (s->s3->handshake_buffer) - { - BIO_free(s->s3->handshake_buffer); - s->s3->handshake_buffer = NULL; - s->s3->flags &= ~TLS1_FLAGS_KEEP_HANDSHAKE; - } -done: - EVP_MD_CTX_cleanup(&mctx); +err: + EVP_PKEY_CTX_free(pctx); EVP_PKEY_free(pkey); return(ret); } @@ -2453,6 +2326,7 @@ int ssl3_get_client_certificate(SSL *s) SSL3_ST_SR_CERT_B, -1, s->max_cert_list, + SSL_GET_MESSAGE_HASH_MESSAGE, &ok); if (!ok) return((int)n); @@ -2643,7 +2517,7 @@ int ssl3_send_server_certificate(SSL *s) } /* send a new session ticket (not necessarily for a new session) */ -int ssl3_send_newsession_ticket(SSL *s) +int ssl3_send_new_session_ticket(SSL *s) { if (s->state == SSL3_ST_SW_SESSION_TICKET_A) { @@ -2770,6 +2644,7 @@ int ssl3_send_newsession_ticket(SSL *s) return ssl_do_write(s); } +#if 0 int ssl3_send_cert_status(SSL *s) { if (s->state == SSL3_ST_SW_CERT_STATUS_A) @@ -2804,8 +2679,8 @@ int ssl3_send_cert_status(SSL *s) /* SSL3_ST_SW_CERT_STATUS_B */ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); } +#endif -# ifndef OPENSSL_NO_NEXTPROTONEG /* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It * sets the next_proto member in s if found */ int ssl3_get_next_proto(SSL *s) @@ -2827,6 +2702,7 @@ int ssl3_get_next_proto(SSL *s) SSL3_ST_SR_NEXT_PROTO_B, SSL3_MT_NEXT_PROTO, 514, /* See the payload format below */ + SSL_GET_MESSAGE_HASH_MESSAGE, &ok); if (!ok) @@ -2863,13 +2739,15 @@ int ssl3_get_next_proto(SSL *s) return 1; } -# endif /* ssl3_get_channel_id reads and verifies a ClientID handshake message. */ int ssl3_get_channel_id(SSL *s) { int ret = -1, ok; long n; + EVP_MD_CTX md_ctx; + uint8_t channel_id_hash[SHA256_DIGEST_LENGTH]; + unsigned int channel_id_hash_len; const uint8_t *p; uint16_t extension_type, expected_extension_type; EC_GROUP* p256 = NULL; @@ -2879,33 +2757,32 @@ int ssl3_get_channel_id(SSL *s) BIGNUM x, y; CBS encrypted_extensions, extension; - if (s->state == SSL3_ST_SR_CHANNEL_ID_A && s->init_num == 0) - { - /* The first time that we're called we take the current - * handshake hash and store it. */ - EVP_MD_CTX md_ctx; - unsigned int len; - - EVP_MD_CTX_init(&md_ctx); - EVP_DigestInit_ex(&md_ctx, EVP_sha256(), NULL); - if (!tls1_channel_id_hash(&md_ctx, s)) - return -1; - len = sizeof(s->s3->tlsext_channel_id); - EVP_DigestFinal(&md_ctx, s->s3->tlsext_channel_id, &len); - EVP_MD_CTX_cleanup(&md_ctx); - } - n = s->method->ssl_get_message(s, SSL3_ST_SR_CHANNEL_ID_A, SSL3_ST_SR_CHANNEL_ID_B, SSL3_MT_ENCRYPTED_EXTENSIONS, 2 + 2 + TLSEXT_CHANNEL_ID_SIZE, + SSL_GET_MESSAGE_DONT_HASH_MESSAGE, &ok); if (!ok) return((int)n); - ssl3_finish_mac(s, (unsigned char*)s->init_buf->data, s->init_num + 4); + /* Before incorporating the EncryptedExtensions message to the + * handshake hash, compute the hash that should have been signed. */ + channel_id_hash_len = sizeof(channel_id_hash); + EVP_MD_CTX_init(&md_ctx); + if (!EVP_DigestInit_ex(&md_ctx, EVP_sha256(), NULL) || + !tls1_channel_id_hash(&md_ctx, s) || + !EVP_DigestFinal(&md_ctx, channel_id_hash, &channel_id_hash_len)) + { + EVP_MD_CTX_cleanup(&md_ctx); + return -1; + } + EVP_MD_CTX_cleanup(&md_ctx); + assert(channel_id_hash_len == SHA256_DIGEST_LENGTH); + + ssl3_hash_current_message(s); /* s->state doesn't reflect whether ChangeCipherSpec has been received * in this handshake, but s->s3->change_cipher_spec does (will be reset @@ -2978,17 +2855,12 @@ int ssl3_get_channel_id(SSL *s) /* We stored the handshake hash in |tlsext_channel_id| the first time * that we were called. */ - switch (ECDSA_do_verify(s->s3->tlsext_channel_id, SHA256_DIGEST_LENGTH, &sig, key)) { - case 1: - break; - case 0: + if (!ECDSA_do_verify(channel_id_hash, channel_id_hash_len, &sig, key)) + { OPENSSL_PUT_ERROR(SSL, ssl3_get_channel_id, SSL_R_CHANNEL_ID_SIGNATURE_INVALID); s->s3->tlsext_channel_id_valid = 0; goto err; - default: - s->s3->tlsext_channel_id_valid = 0; - goto err; - } + } memcpy(s->s3->tlsext_channel_id, p, 64); ret = 1; |