in ssl/handshake_server.cc [1100:1221]
static enum ssl_hs_wait_t do_send_server_certificate(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
ScopedCBB cbb;
if (ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
if (!ssl_has_certificate(hs)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET);
return ssl_hs_error;
}
if (!ssl_output_cert_chain(hs)) {
return ssl_hs_error;
}
if (hs->certificate_status_expected) {
CBB body, ocsp_response;
if (!ssl->method->init_message(ssl, cbb.get(), &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(hs->config->cert->ocsp_response.get()),
CRYPTO_BUFFER_len(hs->config->cert->ocsp_response.get())) ||
!ssl_add_message_cbb(ssl, cbb.get())) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return ssl_hs_error;
}
}
}
// 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) && hs->config->psk_identity_hint)) {
// 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.get(), SSL3_RANDOM_SIZE * 2 + 128) ||
!CBB_add_bytes(cbb.get(), ssl->s3->client_random, SSL3_RANDOM_SIZE) ||
!CBB_add_bytes(cbb.get(), ssl->s3->server_random, SSL3_RANDOM_SIZE)) {
return ssl_hs_error;
}
// PSK ciphers begin with an identity hint.
if (alg_a & SSL_aPSK) {
size_t len = hs->config->psk_identity_hint == nullptr
? 0
: strlen(hs->config->psk_identity_hint.get());
if (!CBB_add_u16_length_prefixed(cbb.get(), &child) ||
!CBB_add_bytes(&child,
(const uint8_t *)hs->config->psk_identity_hint.get(),
len)) {
return ssl_hs_error;
}
}
if (alg_k & SSL_kECDHE) {
// Determine the group to use.
uint16_t group_id;
if (!tls1_get_shared_group(hs, &group_id)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
return ssl_hs_error;
}
hs->new_session->group_id = group_id;
hs->key_shares[0] = SSLKeyShare::Create(group_id);
if (!hs->key_shares[0] ||
!CBB_add_u8(cbb.get(), NAMED_CURVE_TYPE) ||
!CBB_add_u16(cbb.get(), group_id) ||
!CBB_add_u8_length_prefixed(cbb.get(), &child)) {
return ssl_hs_error;
}
SSL_HANDSHAKE_HINTS *const hints = hs->hints.get();
bool hint_ok = false;
if (hints && !hs->hints_requested &&
hints->ecdhe_group_id == group_id &&
!hints->ecdhe_public_key.empty() &&
!hints->ecdhe_private_key.empty()) {
CBS cbs = MakeConstSpan(hints->ecdhe_private_key);
hint_ok = hs->key_shares[0]->DeserializePrivateKey(&cbs);
}
if (hint_ok) {
// Reuse the ECDH key from handshake hints.
if (!CBB_add_bytes(&child, hints->ecdhe_public_key.data(),
hints->ecdhe_public_key.size())) {
return ssl_hs_error;
}
} else {
// Generate a key, and emit the public half.
if (!hs->key_shares[0]->Offer(&child)) {
return ssl_hs_error;
}
// If generating hints, save the ECDHE key.
if (hints && hs->hints_requested) {
bssl::ScopedCBB private_key_cbb;
if (!hints->ecdhe_public_key.CopyFrom(
MakeConstSpan(CBB_data(&child), CBB_len(&child))) ||
!CBB_init(private_key_cbb.get(), 32) ||
!hs->key_shares[0]->SerializePrivateKey(private_key_cbb.get()) ||
!CBBFinishArray(private_key_cbb.get(),
&hints->ecdhe_private_key)) {
return ssl_hs_error;
}
hints->ecdhe_group_id = group_id;
}
}
} else {
assert(alg_k & SSL_kPSK);
}
if (!CBBFinishArray(cbb.get(), &hs->server_params)) {
return ssl_hs_error;
}
}
hs->state = state12_send_server_key_exchange;
return ssl_hs_ok;
}