static enum ssl_hs_wait_t do_send_hello_retry_request(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; CBB cbb, body, extensions; uint16_t group_id; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_HELLO_RETRY_REQUEST) || !CBB_add_u16(&body, ssl->version) || !tls1_get_shared_group(hs, &group_id) || !CBB_add_u16_length_prefixed(&body, &extensions) || !CBB_add_u16(&extensions, TLSEXT_TYPE_key_share) || !CBB_add_u16(&extensions, 2 /* length */) || !CBB_add_u16(&extensions, group_id) || !ssl_add_message_cbb(ssl, &cbb)) { CBB_cleanup(&cbb); return ssl_hs_error; } hs->tls13_state = state_process_second_client_hello; return ssl_hs_flush_and_read_message; }
static enum ssl_hs_wait_t do_send_new_session_ticket(SSL_HANDSHAKE *hs) { /* TLS 1.3 recommends single-use tickets, so issue multiple tickets in case the * client makes several connections before getting a renewal. */ static const int kNumTickets = 2; SSL *const ssl = hs->ssl; /* If the client doesn't accept resumption with PSK_DHE_KE, don't send a * session ticket. */ if (!hs->accept_psk_mode) { hs->tls13_state = state_done; return ssl_hs_ok; } SSL_SESSION *session = ssl->s3->new_session; CBB cbb; CBB_zero(&cbb); for (int i = 0; i < kNumTickets; i++) { if (!RAND_bytes((uint8_t *)&session->ticket_age_add, 4)) { goto err; } CBB body, ticket, extensions; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_NEW_SESSION_TICKET) || !CBB_add_u32(&body, session->timeout) || !CBB_add_u32(&body, session->ticket_age_add) || !CBB_add_u16_length_prefixed(&body, &ticket) || !ssl_encrypt_ticket(ssl, &ticket, session) || !CBB_add_u16_length_prefixed(&body, &extensions)) { goto err; } if (ssl->ctx->enable_early_data) { session->ticket_max_early_data = kMaxEarlyDataAccepted; CBB early_data_info; if (!CBB_add_u16(&extensions, TLSEXT_TYPE_ticket_early_data_info) || !CBB_add_u16_length_prefixed(&extensions, &early_data_info) || !CBB_add_u32(&early_data_info, session->ticket_max_early_data) || !CBB_flush(&extensions)) { goto err; } } /* Add a fake extension. See draft-davidben-tls-grease-01. */ if (!CBB_add_u16(&extensions, ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) || !CBB_add_u16(&extensions, 0 /* empty */)) { goto err; } if (!ssl_add_message_cbb(ssl, &cbb)) { goto err; } } hs->session_tickets_sent++; hs->tls13_state = state_done; return ssl_hs_flush; err: CBB_cleanup(&cbb); return ssl_hs_error; }
static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; /* Send a ServerHello. */ CBB cbb, body, extensions; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_HELLO) || !CBB_add_u16(&body, ssl->version) || !RAND_bytes(ssl->s3->server_random, sizeof(ssl->s3->server_random)) || !CBB_add_bytes(&body, ssl->s3->server_random, SSL3_RANDOM_SIZE) || !CBB_add_u16(&body, ssl_cipher_get_value(ssl->s3->tmp.new_cipher)) || !CBB_add_u16_length_prefixed(&body, &extensions) || !ssl_ext_pre_shared_key_add_serverhello(hs, &extensions) || !ssl_ext_key_share_add_serverhello(hs, &extensions)) { goto err; } if (ssl->s3->short_header) { if (!CBB_add_u16(&extensions, TLSEXT_TYPE_short_header) || !CBB_add_u16(&extensions, 0 /* empty extension */)) { goto err; } } if (!ssl_add_message_cbb(ssl, &cbb)) { goto err; } /* Derive and enable the handshake traffic secrets. */ if (!tls13_derive_handshake_secrets(hs) || !tls13_set_traffic_key(ssl, evp_aead_open, hs->client_handshake_secret, hs->hash_len) || !tls13_set_traffic_key(ssl, evp_aead_seal, hs->server_handshake_secret, hs->hash_len)) { goto err; } /* Send EncryptedExtensions. */ if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_ENCRYPTED_EXTENSIONS) || !ssl_add_serverhello_tlsext(hs, &body) || !ssl_add_message_cbb(ssl, &cbb)) { goto err; } /* Determine whether to request a client certificate. */ hs->cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER); /* CertificateRequest may only be sent in non-resumption handshakes. */ if (ssl->s3->session_reused) { hs->cert_request = 0; } /* Send a CertificateRequest, if necessary. */ if (hs->cert_request) { CBB sigalgs_cbb; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CERTIFICATE_REQUEST) || !CBB_add_u8(&body, 0 /* no certificate_request_context. */)) { goto err; } const uint16_t *sigalgs; size_t num_sigalgs = tls12_get_verify_sigalgs(ssl, &sigalgs); if (!CBB_add_u16_length_prefixed(&body, &sigalgs_cbb)) { goto err; } for (size_t i = 0; i < num_sigalgs; i++) { if (!CBB_add_u16(&sigalgs_cbb, sigalgs[i])) { goto err; } } if (!ssl_add_client_CA_list(ssl, &body) || !CBB_add_u16(&body, 0 /* empty certificate_extensions. */) || !ssl_add_message_cbb(ssl, &cbb)) { goto err; } } /* Send the server Certificate message, if necessary. */ if (!ssl->s3->session_reused) { if (!ssl_has_certificate(ssl)) { OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET); goto err; } if (!tls13_add_certificate(hs)) { goto err; } hs->tls13_state = state_send_server_certificate_verify; return ssl_hs_ok; } hs->tls13_state = state_send_server_finished; return ssl_hs_ok; err: CBB_cleanup(&cbb); return ssl_hs_error; }
static int add_new_session_tickets(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; /* TLS 1.3 recommends single-use tickets, so issue multiple tickets in case * the client makes several connections before getting a renewal. */ static const int kNumTickets = 2; SSL_SESSION *session = hs->new_session; CBB cbb; CBB_zero(&cbb); /* Rebase the session timestamp so that it is measured from ticket * issuance. */ ssl_session_rebase_time(ssl, session); for (int i = 0; i < kNumTickets; i++) { if (!RAND_bytes((uint8_t *)&session->ticket_age_add, 4)) { goto err; } session->ticket_age_add_valid = 1; CBB body, ticket, extensions; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_NEW_SESSION_TICKET) || !CBB_add_u32(&body, session->timeout) || !CBB_add_u32(&body, session->ticket_age_add) || !CBB_add_u16_length_prefixed(&body, &ticket) || !ssl_encrypt_ticket(ssl, &ticket, session) || !CBB_add_u16_length_prefixed(&body, &extensions)) { goto err; } if (ssl->cert->enable_early_data) { session->ticket_max_early_data = kMaxEarlyDataAccepted; CBB early_data_info; if (!CBB_add_u16(&extensions, TLSEXT_TYPE_ticket_early_data_info) || !CBB_add_u16_length_prefixed(&extensions, &early_data_info) || !CBB_add_u32(&early_data_info, session->ticket_max_early_data) || !CBB_flush(&extensions)) { goto err; } } /* Add a fake extension. See draft-davidben-tls-grease-01. */ if (!CBB_add_u16(&extensions, ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) || !CBB_add_u16(&extensions, 0 /* empty */)) { goto err; } if (!ssl_add_message_cbb(ssl, &cbb)) { goto err; } } return 1; err: CBB_cleanup(&cbb); return 0; }