diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h index 4ff61c5e..98648c4c 100644 --- a/include/openssl/ssl3.h +++ b/include/openssl/ssl3.h @@ -310,14 +310,12 @@ OPENSSL_COMPILE_ASSERT( #define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A (0x126 | SSL_ST_CONNECT) #define SSL3_ST_CR_CERT_A (0x130 | SSL_ST_CONNECT) #define SSL3_ST_CR_KEY_EXCH_A (0x140 | SSL_ST_CONNECT) -#define SSL3_ST_CR_KEY_EXCH_B (0x141 | SSL_ST_CONNECT) #define SSL3_ST_CR_CERT_REQ_A (0x150 | SSL_ST_CONNECT) #define SSL3_ST_CR_SRVR_DONE_A (0x160 | SSL_ST_CONNECT) /* write to server */ #define SSL3_ST_CW_CERT_A (0x170 | SSL_ST_CONNECT) #define SSL3_ST_CW_KEY_EXCH_A (0x180 | SSL_ST_CONNECT) #define SSL3_ST_CW_CERT_VRFY_A (0x190 | SSL_ST_CONNECT) -#define SSL3_ST_CW_CERT_VRFY_B (0x191 | SSL_ST_CONNECT) #define SSL3_ST_CW_CHANGE (0x1A0 | SSL_ST_CONNECT) #define SSL3_ST_CW_NEXT_PROTO_A (0x200 | SSL_ST_CONNECT) #define SSL3_ST_CW_CHANNEL_ID_A (0x220 | SSL_ST_CONNECT) @@ -344,7 +342,6 @@ OPENSSL_COMPILE_ASSERT( #define SSL3_ST_SW_SRVR_HELLO_A (0x130 | SSL_ST_ACCEPT) #define SSL3_ST_SW_CERT_A (0x140 | SSL_ST_ACCEPT) #define SSL3_ST_SW_KEY_EXCH_A (0x150 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_KEY_EXCH_B (0x151 | SSL_ST_ACCEPT) #define SSL3_ST_SW_SRVR_DONE_A (0x170 | SSL_ST_ACCEPT) /* read from client */ #define SSL3_ST_SR_CERT_A (0x180 | SSL_ST_ACCEPT) diff --git a/ssl/handshake_client.c b/ssl/handshake_client.c index e93af188..61fd9497 100644 --- a/ssl/handshake_client.c +++ b/ssl/handshake_client.c @@ -346,7 +346,6 @@ int ssl3_connect(SSL_HANDSHAKE *hs) { break; case SSL3_ST_CW_CERT_VRFY_A: - case SSL3_ST_CW_CERT_VRFY_B: if (hs->cert_request && ssl_has_certificate(ssl)) { ret = ssl3_send_cert_verify(hs); if (ret <= 0) { @@ -1660,58 +1659,43 @@ static int ssl3_send_cert_verify(SSL_HANDSHAKE *hs) { } size_t sig_len = max_sig_len; - enum ssl_private_key_result_t sign_result; - if (hs->state == SSL3_ST_CW_CERT_VRFY_A) { - /* The SSL3 construction for CertificateVerify does not decompose into a - * single final digest and signature, and must be special-cased. */ - if (ssl3_protocol_version(ssl) == SSL3_VERSION) { - if (ssl->cert->key_method != NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY); - goto err; - } - - uint8_t digest[EVP_MAX_MD_SIZE]; - size_t digest_len; - if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash(&hs->transcript, digest, - &digest_len, hs->new_session, - signature_algorithm)) { - goto err; - } - - sign_result = ssl_private_key_success; - - EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(ssl->cert->privatekey, NULL); - if (pctx == NULL || - !EVP_PKEY_sign_init(pctx) || - !EVP_PKEY_sign(pctx, ptr, &sig_len, digest, digest_len)) { - EVP_PKEY_CTX_free(pctx); - sign_result = ssl_private_key_failure; - goto err; - } - EVP_PKEY_CTX_free(pctx); - } else { - sign_result = ssl_private_key_sign( - ssl, ptr, &sig_len, max_sig_len, signature_algorithm, - (const uint8_t *)hs->transcript.buffer->data, - hs->transcript.buffer->length); + /* The SSL3 construction for CertificateVerify does not decompose into a + * single final digest and signature, and must be special-cased. */ + if (ssl3_protocol_version(ssl) == SSL3_VERSION) { + if (ssl->cert->key_method != NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY); + goto err; } - /* The handshake buffer is no longer necessary. */ - SSL_TRANSCRIPT_free_buffer(&hs->transcript); - } else { - assert(hs->state == SSL3_ST_CW_CERT_VRFY_B); - sign_result = ssl_private_key_complete(ssl, ptr, &sig_len, max_sig_len); - } + uint8_t digest[EVP_MAX_MD_SIZE]; + size_t digest_len; + if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash(&hs->transcript, digest, + &digest_len, hs->new_session, + signature_algorithm)) { + goto err; + } - switch (sign_result) { - case ssl_private_key_success: - break; - case ssl_private_key_failure: - goto err; - case ssl_private_key_retry: - ssl->rwstate = SSL_PRIVATE_KEY_OPERATION; - hs->state = SSL3_ST_CW_CERT_VRFY_B; + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(ssl->cert->privatekey, NULL); + int ok = pctx != NULL && + EVP_PKEY_sign_init(pctx) && + EVP_PKEY_sign(pctx, ptr, &sig_len, digest, digest_len); + EVP_PKEY_CTX_free(pctx); + if (!ok) { goto err; + } + } else { + switch (ssl_private_key_sign(hs, ptr, &sig_len, max_sig_len, + signature_algorithm, + (const uint8_t *)hs->transcript.buffer->data, + hs->transcript.buffer->length)) { + case ssl_private_key_success: + break; + case ssl_private_key_failure: + goto err; + case ssl_private_key_retry: + ssl->rwstate = SSL_PRIVATE_KEY_OPERATION; + goto err; + } } if (!CBB_did_write(&child, sig_len) || @@ -1719,6 +1703,8 @@ static int ssl3_send_cert_verify(SSL_HANDSHAKE *hs) { goto err; } + /* The handshake buffer is no longer necessary. */ + SSL_TRANSCRIPT_free_buffer(&hs->transcript); return 1; err: diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c index 872347de..615302a8 100644 --- a/ssl/handshake_server.c +++ b/ssl/handshake_server.c @@ -186,7 +186,6 @@ static int ssl3_send_server_finished(SSL_HANDSHAKE *hs); int ssl3_accept(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; - uint32_t alg_a; int ret = -1; assert(ssl->handshake_func == ssl3_accept); @@ -257,12 +256,7 @@ int ssl3_accept(SSL_HANDSHAKE *hs) { break; case SSL3_ST_SW_KEY_EXCH_A: - case SSL3_ST_SW_KEY_EXCH_B: - alg_a = hs->new_cipher->algorithm_auth; - - /* PSK ciphers send ServerKeyExchange if there is an identity hint. */ - if (ssl_cipher_requires_server_key_exchange(hs->new_cipher) || - ((alg_a & SSL_aPSK) && ssl->psk_identity_hint)) { + if (hs->server_params_len > 0) { ret = ssl3_send_server_key_exchange(hs); if (ret <= 0) { goto end; @@ -1030,50 +1024,48 @@ static int ssl3_send_server_hello(SSL_HANDSHAKE *hs) { static int ssl3_send_server_certificate(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; - if (!ssl_cipher_uses_certificate_auth(hs->new_cipher)) { - return 1; - } + int ret = -1; + CBB cbb; + CBB_zero(&cbb); - if (!ssl_has_certificate(ssl)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET); - return -1; - } + if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) { + if (!ssl_has_certificate(ssl)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET); + goto err; + } - if (!ssl3_output_cert_chain(ssl)) { - return -1; - } + if (!ssl3_output_cert_chain(ssl)) { + goto err; + } - if (hs->certificate_status_expected) { - CBB cbb, body, ocsp_response; - if (!ssl->method->init_message(ssl, &cbb, &body, - SSL3_MT_CERTIFICATE_STATUS) || - !CBB_add_u8(&body, TLSEXT_STATUSTYPE_ocsp) || - !CBB_add_u24_length_prefixed(&body, &ocsp_response) || - !CBB_add_bytes(&ocsp_response, - CRYPTO_BUFFER_data(ssl->cert->ocsp_response), - CRYPTO_BUFFER_len(ssl->cert->ocsp_response)) || - !ssl_add_message_cbb(ssl, &cbb)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - CBB_cleanup(&cbb); - return -1; + if (hs->certificate_status_expected) { + CBB body, ocsp_response; + if (!ssl->method->init_message(ssl, &cbb, &body, + SSL3_MT_CERTIFICATE_STATUS) || + !CBB_add_u8(&body, TLSEXT_STATUSTYPE_ocsp) || + !CBB_add_u24_length_prefixed(&body, &ocsp_response) || + !CBB_add_bytes(&ocsp_response, + CRYPTO_BUFFER_data(ssl->cert->ocsp_response), + CRYPTO_BUFFER_len(ssl->cert->ocsp_response)) || + !ssl_add_message_cbb(ssl, &cbb)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + goto err; + } } } - return 1; -} + /* Assemble ServerKeyExchange parameters if needed. */ + uint32_t alg_k = hs->new_cipher->algorithm_mkey; + uint32_t alg_a = hs->new_cipher->algorithm_auth; + if (ssl_cipher_requires_server_key_exchange(hs->new_cipher) || + ((alg_a & SSL_aPSK) && ssl->psk_identity_hint)) { -static int ssl3_send_server_key_exchange(SSL_HANDSHAKE *hs) { - SSL *const ssl = hs->ssl; - CBB cbb, child; - CBB_zero(&cbb); - - /* Put together the parameters. */ - if (hs->state == SSL3_ST_SW_KEY_EXCH_A) { - uint32_t alg_k = hs->new_cipher->algorithm_mkey; - uint32_t alg_a = hs->new_cipher->algorithm_auth; - - /* Pre-allocate enough room to comfortably fit an ECDHE public key. */ - if (!CBB_init(&cbb, 128)) { + /* Pre-allocate enough room to comfortably fit an ECDHE public key. Prepend + * the client and server randoms for the signing transcript. */ + CBB child; + if (!CBB_init(&cbb, SSL3_RANDOM_SIZE * 2 + 128) || + !CBB_add_bytes(&cbb, ssl->s3->client_random, SSL3_RANDOM_SIZE) || + !CBB_add_bytes(&cbb, ssl->s3->server_random, SSL3_RANDOM_SIZE)) { goto err; } @@ -1115,11 +1107,22 @@ static int ssl3_send_server_key_exchange(SSL_HANDSHAKE *hs) { } } - /* Assemble the message. */ - CBB body; + ret = 1; + +err: + CBB_cleanup(&cbb); + return ret; +} + +static int ssl3_send_server_key_exchange(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + CBB cbb, body, child; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_KEY_EXCHANGE) || - !CBB_add_bytes(&body, hs->server_params, hs->server_params_len)) { + /* |hs->server_params| contains a prefix for signing. */ + hs->server_params_len < 2 * SSL3_RANDOM_SIZE || + !CBB_add_bytes(&body, hs->server_params + 2 * SSL3_RANDOM_SIZE, + hs->server_params_len - 2 * SSL3_RANDOM_SIZE)) { goto err; } @@ -1152,36 +1155,9 @@ static int ssl3_send_server_key_exchange(SSL_HANDSHAKE *hs) { } size_t sig_len; - enum ssl_private_key_result_t sign_result; - if (hs->state == SSL3_ST_SW_KEY_EXCH_A) { - CBB transcript; - uint8_t *transcript_data; - size_t transcript_len; - if (!CBB_init(&transcript, - 2 * SSL3_RANDOM_SIZE + hs->server_params_len) || - !CBB_add_bytes(&transcript, ssl->s3->client_random, - SSL3_RANDOM_SIZE) || - !CBB_add_bytes(&transcript, ssl->s3->server_random, - SSL3_RANDOM_SIZE) || - !CBB_add_bytes(&transcript, hs->server_params, - hs->server_params_len) || - !CBB_finish(&transcript, &transcript_data, &transcript_len)) { - CBB_cleanup(&transcript); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); - goto err; - } - - sign_result = ssl_private_key_sign(ssl, ptr, &sig_len, max_sig_len, - signature_algorithm, transcript_data, - transcript_len); - OPENSSL_free(transcript_data); - } else { - assert(hs->state == SSL3_ST_SW_KEY_EXCH_B); - sign_result = ssl_private_key_complete(ssl, ptr, &sig_len, max_sig_len); - } - - switch (sign_result) { + switch (ssl_private_key_sign(hs, ptr, &sig_len, max_sig_len, + signature_algorithm, hs->server_params, + hs->server_params_len)) { case ssl_private_key_success: if (!CBB_did_write(&child, sig_len)) { goto err; @@ -1191,7 +1167,6 @@ static int ssl3_send_server_key_exchange(SSL_HANDSHAKE *hs) { goto err; case ssl_private_key_retry: ssl->rwstate = SSL_PRIVATE_KEY_OPERATION; - hs->state = SSL3_ST_SW_KEY_EXCH_B; goto err; } } @@ -1345,32 +1320,26 @@ static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) { static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; CBS client_key_exchange; - uint32_t alg_k; - uint32_t alg_a; uint8_t *premaster_secret = NULL; size_t premaster_secret_len = 0; uint8_t *decrypt_buf = NULL; - unsigned psk_len = 0; - uint8_t psk[PSK_MAX_PSK_LEN]; - if (hs->state == SSL3_ST_SR_KEY_EXCH_A) { int ret = ssl->method->ssl_get_message(ssl); if (ret <= 0) { return ret; } + } - if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_KEY_EXCHANGE) || - !ssl_hash_current_message(hs)) { - return -1; - } + if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_KEY_EXCHANGE)) { + return -1; } CBS_init(&client_key_exchange, ssl->init_msg, ssl->init_num); - alg_k = hs->new_cipher->algorithm_mkey; - alg_a = hs->new_cipher->algorithm_auth; + uint32_t alg_k = hs->new_cipher->algorithm_mkey; + uint32_t alg_a = hs->new_cipher->algorithm_auth; - /* If using a PSK key exchange, prepare the pre-shared key. */ + /* If using a PSK key exchange, parse the PSK identity. */ if (alg_a & SSL_aPSK) { CBS psk_identity; @@ -1383,12 +1352,6 @@ static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) { goto err; } - if (ssl->psk_server_callback == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_NO_SERVER_CB); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); - goto err; - } - if (CBS_len(&psk_identity) > PSK_MAX_IDENTITY_LEN || CBS_contains_zero_byte(&psk_identity)) { OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG); @@ -1401,25 +1364,24 @@ static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); goto err; } - - /* Look up the key for the identity. */ - psk_len = ssl->psk_server_callback(ssl, hs->new_session->psk_identity, psk, - sizeof(psk)); - if (psk_len > PSK_MAX_PSK_LEN) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); - goto err; - } else if (psk_len == 0) { - /* PSK related to the given identity not found */ - OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNKNOWN_PSK_IDENTITY); - goto err; - } } /* Depending on the key exchange method, compute |premaster_secret| and * |premaster_secret_len|. */ if (alg_k & SSL_kRSA) { + CBS encrypted_premaster_secret; + if (ssl->version > SSL3_VERSION) { + if (!CBS_get_u16_length_prefixed(&client_key_exchange, + &encrypted_premaster_secret) || + CBS_len(&client_key_exchange) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + goto err; + } + } else { + encrypted_premaster_secret = client_key_exchange; + } + /* Allocate a buffer large enough for an RSA decryption. */ const size_t rsa_size = EVP_PKEY_size(hs->local_pubkey); decrypt_buf = OPENSSL_malloc(rsa_size); @@ -1428,43 +1390,12 @@ static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) { goto err; } - enum ssl_private_key_result_t decrypt_result; + /* Decrypt with no padding. PKCS#1 padding will be removed as part of the + * timing-sensitive code below. */ size_t decrypt_len; - if (hs->state == SSL3_ST_SR_KEY_EXCH_A) { - if (!ssl_has_private_key(ssl) || - EVP_PKEY_id(hs->local_pubkey) != EVP_PKEY_RSA) { - OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_RSA_CERTIFICATE); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); - goto err; - } - CBS encrypted_premaster_secret; - if (ssl->version > SSL3_VERSION) { - if (!CBS_get_u16_length_prefixed(&client_key_exchange, - &encrypted_premaster_secret) || - CBS_len(&client_key_exchange) != 0) { - OPENSSL_PUT_ERROR(SSL, - SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - goto err; - } - } else { - encrypted_premaster_secret = client_key_exchange; - } - - /* Decrypt with no padding. PKCS#1 padding will be removed as part of the - * timing-sensitive code below. */ - decrypt_result = ssl_private_key_decrypt( - ssl, decrypt_buf, &decrypt_len, rsa_size, - CBS_data(&encrypted_premaster_secret), - CBS_len(&encrypted_premaster_secret)); - } else { - assert(hs->state == SSL3_ST_SR_KEY_EXCH_B); - /* Complete async decrypt. */ - decrypt_result = - ssl_private_key_complete(ssl, decrypt_buf, &decrypt_len, rsa_size); - } - - switch (decrypt_result) { + switch (ssl_private_key_decrypt(hs, decrypt_buf, &decrypt_len, rsa_size, + CBS_data(&encrypted_premaster_secret), + CBS_len(&encrypted_premaster_secret))) { case ssl_private_key_success: break; case ssl_private_key_failure: @@ -1547,17 +1478,7 @@ static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) { /* The key exchange state may now be discarded. */ SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); - } else if (alg_k & SSL_kPSK) { - /* For plain PSK, other_secret is a block of 0s with the same length as the - * pre-shared key. */ - premaster_secret_len = psk_len; - premaster_secret = OPENSSL_malloc(premaster_secret_len); - if (premaster_secret == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - OPENSSL_memset(premaster_secret, 0, premaster_secret_len); - } else { + } else if (!(alg_k & SSL_kPSK)) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_TYPE); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); goto err; @@ -1566,10 +1487,42 @@ static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) { /* For a PSK cipher suite, the actual pre-master secret is combined with the * pre-shared key. */ if (alg_a & SSL_aPSK) { + if (ssl->psk_server_callback == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_NO_SERVER_CB); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + goto err; + } + + /* Look up the key for the identity. */ + uint8_t psk[PSK_MAX_PSK_LEN]; + unsigned psk_len = ssl->psk_server_callback( + ssl, hs->new_session->psk_identity, psk, sizeof(psk)); + if (psk_len > PSK_MAX_PSK_LEN) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + goto err; + } else if (psk_len == 0) { + /* PSK related to the given identity not found */ + OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNKNOWN_PSK_IDENTITY); + goto err; + } + + if (alg_k & SSL_kPSK) { + /* In plain PSK, other_secret is a block of 0s with the same length as the + * pre-shared key. */ + premaster_secret_len = psk_len; + premaster_secret = OPENSSL_malloc(premaster_secret_len); + if (premaster_secret == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + OPENSSL_memset(premaster_secret, 0, premaster_secret_len); + } + CBB new_premaster, child; uint8_t *new_data; size_t new_len; - CBB_zero(&new_premaster); if (!CBB_init(&new_premaster, 2 + psk_len + 2 + premaster_secret_len) || !CBB_add_u16_length_prefixed(&new_premaster, &child) || @@ -1588,6 +1541,10 @@ static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) { premaster_secret_len = new_len; } + if (!ssl_hash_current_message(hs)) { + goto err; + } + /* Compute the master secret */ hs->new_session->master_key_length = tls1_generate_master_secret( hs, hs->new_session->master_key, premaster_secret, premaster_secret_len); diff --git a/ssl/internal.h b/ssl/internal.h index 7843af54..8d1859b8 100644 --- a/ssl/internal.h +++ b/ssl/internal.h @@ -548,22 +548,20 @@ typedef struct ssl_handshake_st SSL_HANDSHAKE; * configured and zero otherwise. */ int ssl_has_private_key(const SSL *ssl); -/* ssl_private_key_* call the corresponding function on the - * |SSL_PRIVATE_KEY_METHOD| for |ssl|, if configured. Otherwise, they implement - * the operation with |EVP_PKEY|. */ +/* ssl_private_key_* perform the corresponding operation on + * |SSL_PRIVATE_KEY_METHOD|. If there is a custom private key configured, they + * call the corresponding function or |complete| depending on whether there is a + * pending operation. Otherwise, they implement the operation with + * |EVP_PKEY|. */ enum ssl_private_key_result_t ssl_private_key_sign( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, + SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, size_t max_out, uint16_t signature_algorithm, const uint8_t *in, size_t in_len); enum ssl_private_key_result_t ssl_private_key_decrypt( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, + SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, size_t max_out, const uint8_t *in, size_t in_len); -enum ssl_private_key_result_t ssl_private_key_complete(SSL *ssl, uint8_t *out, - size_t *out_len, - size_t max_out); - /* ssl_private_key_supports_signature_algorithm returns one if |hs|'s private * key supports |sigalg| and zero otherwise. */ int ssl_private_key_supports_signature_algorithm(SSL_HANDSHAKE *hs, @@ -1023,8 +1021,9 @@ struct ssl_handshake_st { uint8_t *peer_key; size_t peer_key_len; - /* server_params, in TLS 1.2, stores the ServerKeyExchange parameters to be - * signed while the signature is being computed. */ + /* server_params, in a TLS 1.2 server, stores the ServerKeyExchange + * parameters. It has client and server randoms prepended for signing + * convenience. */ uint8_t *server_params; size_t server_params_len; @@ -1128,6 +1127,10 @@ struct ssl_handshake_st { * negotiated in this handshake. */ unsigned extended_master_secret:1; + /* pending_private_key_op is one if there is a pending private key operation + * in progress. */ + unsigned pending_private_key_op:1; + /* client_version is the value sent or received in the ClientHello version. */ uint16_t client_version; @@ -1172,8 +1175,12 @@ int tls13_process_certificate_verify(SSL_HANDSHAKE *hs); int tls13_process_finished(SSL_HANDSHAKE *hs, int use_saved_value); int tls13_add_certificate(SSL_HANDSHAKE *hs); -enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs, - int is_first_run); + +/* tls13_add_certificate_verify adds a TLS 1.3 CertificateVerify message to the + * handshake. If it returns |ssl_private_key_retry|, it should be called again + * to retry when the signing operation is completed. */ +enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs); + int tls13_add_finished(SSL_HANDSHAKE *hs); int tls13_process_new_session_ticket(SSL *ssl); diff --git a/ssl/ssl_privkey.c b/ssl/ssl_privkey.c index 84927487..257d03e4 100644 --- a/ssl/ssl_privkey.c +++ b/ssl/ssl_privkey.c @@ -56,6 +56,7 @@ #include +#include #include #include @@ -406,33 +407,43 @@ static int legacy_sign_digest_supported(const SSL_SIGNATURE_ALGORITHM *alg) { !alg->is_rsa_pss; } +static enum ssl_private_key_result_t legacy_sign( + SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, uint16_t sigalg, + const uint8_t *in, size_t in_len) { + /* TODO(davidben): Remove support for |sign_digest|-only + * |SSL_PRIVATE_KEY_METHOD|s. */ + const SSL_SIGNATURE_ALGORITHM *alg = get_signature_algorithm(sigalg); + if (alg == NULL || !legacy_sign_digest_supported(alg)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY); + return ssl_private_key_failure; + } + + const EVP_MD *md = alg->digest_func(); + uint8_t hash[EVP_MAX_MD_SIZE]; + unsigned hash_len; + if (!EVP_Digest(in, in_len, hash, &hash_len, md, NULL)) { + return ssl_private_key_failure; + } + + return ssl->cert->key_method->sign_digest(ssl, out, out_len, max_out, md, + hash, hash_len); +} + enum ssl_private_key_result_t ssl_private_key_sign( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, + SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, size_t max_out, uint16_t sigalg, const uint8_t *in, size_t in_len) { + SSL *const ssl = hs->ssl; if (ssl->cert->key_method != NULL) { - if (ssl->cert->key_method->sign != NULL) { - return ssl->cert->key_method->sign(ssl, out, out_len, max_out, sigalg, in, - in_len); + enum ssl_private_key_result_t ret; + if (hs->pending_private_key_op) { + ret = ssl->cert->key_method->complete(ssl, out, out_len, max_out); + } else { + ret = (ssl->cert->key_method->sign != NULL + ? ssl->cert->key_method->sign + : legacy_sign)(ssl, out, out_len, max_out, sigalg, in, in_len); } - - /* TODO(davidben): Remove support for |sign_digest|-only - * |SSL_PRIVATE_KEY_METHOD|s. */ - const SSL_SIGNATURE_ALGORITHM *alg = get_signature_algorithm(sigalg); - if (alg == NULL || - !legacy_sign_digest_supported(alg)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY); - return ssl_private_key_failure; - } - - const EVP_MD *md = alg->digest_func(); - uint8_t hash[EVP_MAX_MD_SIZE]; - unsigned hash_len; - if (!EVP_Digest(in, in_len, hash, &hash_len, md, NULL)) { - return ssl_private_key_failure; - } - - return ssl->cert->key_method->sign_digest(ssl, out, out_len, max_out, md, - hash, hash_len); + hs->pending_private_key_op = ret == ssl_private_key_retry; + return ret; } *out_len = max_out; @@ -456,11 +467,19 @@ int ssl_public_key_verify(SSL *ssl, const uint8_t *signature, } enum ssl_private_key_result_t ssl_private_key_decrypt( - SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, + SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, size_t max_out, const uint8_t *in, size_t in_len) { + SSL *const ssl = hs->ssl; if (ssl->cert->key_method != NULL) { - return ssl->cert->key_method->decrypt(ssl, out, out_len, max_out, in, - in_len); + enum ssl_private_key_result_t ret; + if (hs->pending_private_key_op) { + ret = ssl->cert->key_method->complete(ssl, out, out_len, max_out); + } else { + ret = ssl->cert->key_method->decrypt(ssl, out, out_len, max_out, in, + in_len); + } + hs->pending_private_key_op = ret == ssl_private_key_retry; + return ret; } RSA *rsa = EVP_PKEY_get0_RSA(ssl->cert->privatekey); @@ -478,13 +497,6 @@ enum ssl_private_key_result_t ssl_private_key_decrypt( return ssl_private_key_success; } -enum ssl_private_key_result_t ssl_private_key_complete(SSL *ssl, uint8_t *out, - size_t *out_len, - size_t max_out) { - /* Only custom keys may be asynchronous. */ - return ssl->cert->key_method->complete(ssl, out, out_len, max_out); -} - int ssl_private_key_supports_signature_algorithm(SSL_HANDSHAKE *hs, uint16_t sigalg) { SSL *const ssl = hs->ssl; diff --git a/ssl/ssl_stat.c b/ssl/ssl_stat.c index 09f59e54..22149e25 100644 --- a/ssl/ssl_stat.c +++ b/ssl/ssl_stat.c @@ -142,9 +142,6 @@ const char *SSL_state_string_long(const SSL *ssl) { case SSL3_ST_CW_CERT_VRFY_A: return "SSLv3 write certificate verify A"; - case SSL3_ST_CW_CERT_VRFY_B: - return "SSLv3 write certificate verify B"; - case SSL3_ST_CW_CHANGE: return "SSLv3 write change cipher spec"; @@ -249,9 +246,6 @@ const char *SSL_state_string(const SSL *ssl) { case SSL3_ST_CW_CERT_VRFY_A: return "3WCV_A"; - case SSL3_ST_CW_CERT_VRFY_B: - return "3WCV_B"; - case SSL3_ST_CW_CHANGE: return "3WCCS_"; @@ -285,9 +279,6 @@ const char *SSL_state_string(const SSL *ssl) { case SSL3_ST_SW_KEY_EXCH_A: return "3WSKEA"; - case SSL3_ST_SW_KEY_EXCH_B: - return "3WSKEB"; - case SSL3_ST_SW_SRVR_DONE_A: return "3WSD_A"; diff --git a/ssl/tls13_both.c b/ssl/tls13_both.c index 32f937bd..6fdfb269 100644 --- a/ssl/tls13_both.c +++ b/ssl/tls13_both.c @@ -533,8 +533,7 @@ err: return 0; } -enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs, - int is_first_run) { +enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; enum ssl_private_key_result_t ret = ssl_private_key_failure; uint8_t *msg = NULL; @@ -564,20 +563,15 @@ enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs, goto err; } - enum ssl_private_key_result_t sign_result; - if (is_first_run) { - if (!tls13_get_cert_verify_signature_input( - hs, &msg, &msg_len, - ssl->server ? ssl_cert_verify_server : ssl_cert_verify_client)) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); - goto err; - } - sign_result = ssl_private_key_sign(ssl, sig, &sig_len, max_sig_len, - signature_algorithm, msg, msg_len); - } else { - sign_result = ssl_private_key_complete(ssl, sig, &sig_len, max_sig_len); + if (!tls13_get_cert_verify_signature_input( + hs, &msg, &msg_len, + ssl->server ? ssl_cert_verify_server : ssl_cert_verify_client)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + goto err; } + enum ssl_private_key_result_t sign_result = ssl_private_key_sign( + hs, sig, &sig_len, max_sig_len, signature_algorithm, msg, msg_len); if (sign_result != ssl_private_key_success) { ret = sign_result; goto err; diff --git a/ssl/tls13_client.c b/ssl/tls13_client.c index 6b39371b..92ea4f87 100644 --- a/ssl/tls13_client.c +++ b/ssl/tls13_client.c @@ -41,7 +41,6 @@ enum client_hs_state_t { state_send_end_of_early_data, state_send_client_certificate, state_send_client_certificate_verify, - state_complete_client_certificate_verify, state_complete_second_flight, state_done, }; @@ -543,8 +542,7 @@ static enum ssl_hs_wait_t do_send_client_certificate(SSL_HANDSHAKE *hs) { return ssl_hs_ok; } -static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL_HANDSHAKE *hs, - int is_first_run) { +static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; /* Don't send CertificateVerify if there is no certificate. */ if (!ssl_has_certificate(ssl)) { @@ -552,13 +550,13 @@ static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL_HANDSHAKE *hs, return ssl_hs_ok; } - switch (tls13_add_certificate_verify(hs, is_first_run)) { + switch (tls13_add_certificate_verify(hs)) { case ssl_private_key_success: hs->tls13_state = state_complete_second_flight; return ssl_hs_ok; case ssl_private_key_retry: - hs->tls13_state = state_complete_client_certificate_verify; + hs->tls13_state = state_send_client_certificate_verify; return ssl_hs_private_key_operation; case ssl_private_key_failure: @@ -649,10 +647,7 @@ enum ssl_hs_wait_t tls13_client_handshake(SSL_HANDSHAKE *hs) { ret = do_send_client_certificate(hs); break; case state_send_client_certificate_verify: - ret = do_send_client_certificate_verify(hs, 1 /* first run */); - break; - case state_complete_client_certificate_verify: - ret = do_send_client_certificate_verify(hs, 0 /* complete */); + ret = do_send_client_certificate_verify(hs); break; case state_complete_second_flight: ret = do_complete_second_flight(hs); diff --git a/ssl/tls13_server.c b/ssl/tls13_server.c index 162da225..0a5e1a2b 100644 --- a/ssl/tls13_server.c +++ b/ssl/tls13_server.c @@ -36,7 +36,6 @@ enum server_hs_state_t { state_process_second_client_hello, state_send_server_hello, state_send_server_certificate_verify, - state_complete_server_certificate_verify, state_send_server_finished, state_read_second_client_flight, state_process_end_of_early_data, @@ -583,15 +582,14 @@ err: return ssl_hs_error; } -static enum ssl_hs_wait_t do_send_server_certificate_verify(SSL_HANDSHAKE *hs, - int is_first_run) { - switch (tls13_add_certificate_verify(hs, is_first_run)) { +static enum ssl_hs_wait_t do_send_server_certificate_verify(SSL_HANDSHAKE *hs) { + switch (tls13_add_certificate_verify(hs)) { case ssl_private_key_success: hs->tls13_state = state_send_server_finished; return ssl_hs_ok; case ssl_private_key_retry: - hs->tls13_state = state_complete_server_certificate_verify; + hs->tls13_state = state_send_server_certificate_verify; return ssl_hs_private_key_operation; case ssl_private_key_failure: @@ -802,10 +800,7 @@ enum ssl_hs_wait_t tls13_server_handshake(SSL_HANDSHAKE *hs) { ret = do_send_server_hello(hs); break; case state_send_server_certificate_verify: - ret = do_send_server_certificate_verify(hs, 1 /* first run */); - break; - case state_complete_server_certificate_verify: - ret = do_send_server_certificate_verify(hs, 0 /* complete */); + ret = do_send_server_certificate_verify(hs); break; case state_send_server_finished: ret = do_send_server_finished(hs);