X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fstatem%2Fstatem_srvr.c;h=81c8ee4f21eb519cad1df50655d50a92cc2e9eb1;hp=6168b98ede6e2527121cf6010412360609888878;hb=f1b97da1fd90cf3935eafedc8df0d0165cb75f2f;hpb=72ceb6a6923456d9ff036cd81014024cf54280c4 diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 6168b98ede..81c8ee4f21 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -48,15 +48,14 @@ static int ossl_statem_server13_read_transition(SSL *s, int mt) default: break; - case TLS_ST_SW_HELLO_RETRY_REQUEST: - if (mt == SSL3_MT_CLIENT_HELLO) { - st->hand_state = TLS_ST_SR_CLNT_HELLO; - return 1; - } - break; - case TLS_ST_EARLY_DATA: - if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) { + if (s->hello_retry_request) { + if (mt == SSL3_MT_CLIENT_HELLO) { + st->hand_state = TLS_ST_SR_CLNT_HELLO; + return 1; + } + break; + } else if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) { if (mt == SSL3_MT_END_OF_EARLY_DATA) { st->hand_state = TLS_ST_SR_END_OF_EARLY_DATA; return 1; @@ -397,7 +396,8 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s) return WRITE_TRAN_CONTINUE; case TLS_ST_SW_HELLO_RETRY_REQUEST: - return WRITE_TRAN_FINISHED; + st->hand_state = TLS_ST_EARLY_DATA; + return WRITE_TRAN_CONTINUE; case TLS_ST_SW_SRVR_HELLO: st->hand_state = TLS_ST_SW_ENCRYPTED_EXTENSIONS; @@ -1353,7 +1353,7 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) */ if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) { if (clienthello->dtls_cookie_len == 0) - return 1; + return MSG_PROCESS_FINISHED_READING; } } @@ -1430,16 +1430,18 @@ static int tls_early_post_process_client_hello(SSL *s, int *pal) DOWNGRADE dgrd = DOWNGRADE_NONE; /* Finished parsing the ClientHello, now we can start processing it */ - /* Give the early callback a crack at things */ - if (s->ctx->early_cb != NULL) { - int code; - /* A failure in the early callback terminates the connection. */ - code = s->ctx->early_cb(s, &al, s->ctx->early_cb_arg); - if (code == 0) + /* Give the ClientHello callback a crack at things */ + if (s->ctx->client_hello_cb != NULL) { + /* A failure in the ClientHello callback terminates the connection. */ + switch (s->ctx->client_hello_cb(s, &al, s->ctx->client_hello_cb_arg)) { + case SSL_CLIENT_HELLO_SUCCESS: + break; + case SSL_CLIENT_HELLO_RETRY: + s->rwstate = SSL_CLIENT_HELLO_CB; + return -1; + case SSL_CLIENT_HELLO_ERROR: + default: goto err; - if (code < 0) { - s->rwstate = SSL_EARLY_WORK; - return code; } } @@ -1934,6 +1936,74 @@ static int tls_handle_status_request(SSL *s, int *al) return 1; } +/* + * Call the alpn_select callback if needed. Upon success, returns 1. + * Upon failure, returns 0 and sets |*al| to the appropriate fatal alert. + */ +int tls_handle_alpn(SSL *s, int *al) +{ + const unsigned char *selected = NULL; + unsigned char selected_len = 0; + + if (s->ctx->ext.alpn_select_cb != NULL && s->s3->alpn_proposed != NULL) { + int r = s->ctx->ext.alpn_select_cb(s, &selected, &selected_len, + s->s3->alpn_proposed, + (unsigned int)s->s3->alpn_proposed_len, + s->ctx->ext.alpn_select_cb_arg); + + if (r == SSL_TLSEXT_ERR_OK) { + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = OPENSSL_memdup(selected, selected_len); + if (s->s3->alpn_selected == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + s->s3->alpn_selected_len = selected_len; +#ifndef OPENSSL_NO_NEXTPROTONEG + /* ALPN takes precedence over NPN. */ + s->s3->npn_seen = 0; +#endif + + /* Check ALPN is consistent with session */ + if (s->session->ext.alpn_selected == NULL + || selected_len != s->session->ext.alpn_selected_len + || memcmp(selected, s->session->ext.alpn_selected, + selected_len) != 0) { + /* Not consistent so can't be used for early_data */ + s->ext.early_data_ok = 0; + + if (!s->hit) { + /* If a new session update it with the new ALPN value */ + s->session->ext.alpn_selected = OPENSSL_memdup(selected, + selected_len); + if (s->session->ext.alpn_selected == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + s->session->ext.alpn_selected_len = selected_len; + } + } + + return 1; + } else if (r != SSL_TLSEXT_ERR_NOACK) { + *al = SSL_AD_NO_APPLICATION_PROTOCOL; + return 0; + } + /* + * If r == SSL_TLSEXT_ERR_NOACK then behave as if no callback was + * present. + */ + } + + /* Check ALPN is consistent with session */ + if (s->session->ext.alpn_selected != NULL) { + /* Not consistent so can't be used for early_data */ + s->ext.early_data_ok = 0; + } + + return 1; +} + WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst) { int al = SSL_AD_HANDSHAKE_FAILURE; @@ -2018,6 +2088,17 @@ WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst) SSL_R_CLIENTHELLO_TLSEXT); goto f_err; } + /* + * Call alpn_select callback if needed. Has to be done after SNI and + * cipher negotiation (HTTP/2 restricts permitted ciphers). In TLSv1.3 + * we already did this because cipher negotiation happens earlier, and + * we must handle ALPN before we decide whether to accept early_data. + */ + if (!SSL_IS_TLS13(s) && !tls_handle_alpn(s, &al)) { + SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, + SSL_R_CLIENTHELLO_TLSEXT); + goto f_err; + } wst = WORK_MORE_C; } @@ -2415,7 +2496,7 @@ int tls_construct_server_key_exchange(SSL *s, WPACKET *pkt) size_t siglen, tbslen; int rv; - if (pkey == NULL || md == NULL) { + if (pkey == NULL || !tls1_lookup_md(lu, &md)) { /* Should never happen */ al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, @@ -2671,7 +2752,7 @@ static int tls_process_cke_rsa(SSL *s, PACKET *pkt, int *al) * fails. See https://tools.ietf.org/html/rfc5246#section-7.4.7.1 */ - if (RAND_bytes(rand_premaster_secret, sizeof(rand_premaster_secret)) <= 0) + if (ssl_randbytes(s, rand_premaster_secret, sizeof(rand_premaster_secret)) <= 0) goto err; /* @@ -3172,7 +3253,8 @@ WORK_STATE tls_post_process_client_key_exchange(SSL *s, WORK_STATE wst) MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt) { - int i, al = SSL_AD_INTERNAL_ERROR, ret = MSG_PROCESS_ERROR; + int i, al = SSL_AD_INTERNAL_ERROR; + MSG_PROCESS_RETURN ret = MSG_PROCESS_ERROR; X509 *x = NULL; unsigned long l, llen; const unsigned char *certstart, *certbytes; @@ -3378,9 +3460,22 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt) } age_add_u; if (SSL_IS_TLS13(s)) { - if (RAND_bytes(age_add_u.age_add_c, sizeof(age_add_u)) <= 0) + if (ssl_randbytes(s, age_add_u.age_add_c, sizeof(age_add_u)) <= 0) goto err; s->session->ext.tick_age_add = age_add_u.age_add; + /* + * ticket_nonce is set to a single 0 byte because we only ever send a + * single ticket per connection. IMPORTANT: If we ever support multiple + * tickets per connection then this will need to be changed. + */ + OPENSSL_free(s->session->ext.tick_nonce); + s->session->ext.tick_nonce = OPENSSL_zalloc(sizeof(char)); + if (s->session->ext.tick_nonce == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, + ERR_R_MALLOC_FAILURE); + goto err; + } + s->session->ext.tick_nonce_len = 1; s->session->time = (long)time(NULL); if (s->s3->alpn_selected != NULL) { OPENSSL_free(s->session->ext.alpn_selected); @@ -3474,7 +3569,7 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt) const EVP_CIPHER *cipher = EVP_aes_256_cbc(); iv_len = EVP_CIPHER_iv_length(cipher); - if (RAND_bytes(iv, iv_len) <= 0) + if (ssl_randbytes(s, iv, iv_len) <= 0) goto err; if (!EVP_EncryptInit_ex(ctx, cipher, NULL, tctx->ext.tick_aes_key, iv)) @@ -3497,7 +3592,9 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt) (s->hit && !SSL_IS_TLS13(s)) ? 0 : s->session->timeout) || (SSL_IS_TLS13(s) - && !WPACKET_put_bytes_u32(pkt, age_add_u.age_add)) + && (!WPACKET_put_bytes_u32(pkt, age_add_u.age_add) + || !WPACKET_sub_memcpy_u8(pkt, s->session->ext.tick_nonce, + s->session->ext.tick_nonce_len))) /* Now the actual ticket data */ || !WPACKET_start_sub_packet_u16(pkt) || !WPACKET_get_total_written(pkt, &macoffset)