in src/ssl/tls13_both.cc [399:560]
bool tls13_add_certificate(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
CERT *const cert = hs->config->cert.get();
DC *const dc = cert->dc.get();
ScopedCBB cbb;
CBB *body, body_storage, certificate_list;
if (hs->cert_compression_negotiated) {
if (!CBB_init(cbb.get(), 1024)) {
return false;
}
body = cbb.get();
} else {
body = &body_storage;
if (!ssl->method->init_message(ssl, cbb.get(), body, SSL3_MT_CERTIFICATE)) {
return false;
}
}
if (// The request context is always empty in the handshake.
!CBB_add_u8(body, 0) ||
!CBB_add_u24_length_prefixed(body, &certificate_list)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
}
if (!ssl_has_certificate(hs)) {
return ssl_add_message_cbb(ssl, cbb.get());
}
CRYPTO_BUFFER *leaf_buf = sk_CRYPTO_BUFFER_value(cert->chain.get(), 0);
CBB leaf, extensions;
if (!CBB_add_u24_length_prefixed(&certificate_list, &leaf) ||
!CBB_add_bytes(&leaf, CRYPTO_BUFFER_data(leaf_buf),
CRYPTO_BUFFER_len(leaf_buf)) ||
!CBB_add_u16_length_prefixed(&certificate_list, &extensions)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
}
if (hs->scts_requested && cert->signed_cert_timestamp_list != nullptr) {
CBB contents;
if (!CBB_add_u16(&extensions, TLSEXT_TYPE_certificate_timestamp) ||
!CBB_add_u16_length_prefixed(&extensions, &contents) ||
!CBB_add_bytes(
&contents,
CRYPTO_BUFFER_data(cert->signed_cert_timestamp_list.get()),
CRYPTO_BUFFER_len(cert->signed_cert_timestamp_list.get())) ||
!CBB_flush(&extensions)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
}
}
if (hs->ocsp_stapling_requested && cert->ocsp_response != NULL) {
CBB contents, ocsp_response;
if (!CBB_add_u16(&extensions, TLSEXT_TYPE_status_request) ||
!CBB_add_u16_length_prefixed(&extensions, &contents) ||
!CBB_add_u8(&contents, TLSEXT_STATUSTYPE_ocsp) ||
!CBB_add_u24_length_prefixed(&contents, &ocsp_response) ||
!CBB_add_bytes(&ocsp_response,
CRYPTO_BUFFER_data(cert->ocsp_response.get()),
CRYPTO_BUFFER_len(cert->ocsp_response.get())) ||
!CBB_flush(&extensions)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
}
}
if (ssl_signing_with_dc(hs)) {
const CRYPTO_BUFFER *raw = dc->raw.get();
CBB child;
if (!CBB_add_u16(&extensions, TLSEXT_TYPE_delegated_credential) ||
!CBB_add_u16_length_prefixed(&extensions, &child) ||
!CBB_add_bytes(&child, CRYPTO_BUFFER_data(raw),
CRYPTO_BUFFER_len(raw)) ||
!CBB_flush(&extensions)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
ssl->s3->delegated_credential_used = true;
}
for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(cert->chain.get()); i++) {
CRYPTO_BUFFER *cert_buf = sk_CRYPTO_BUFFER_value(cert->chain.get(), i);
CBB child;
if (!CBB_add_u24_length_prefixed(&certificate_list, &child) ||
!CBB_add_bytes(&child, CRYPTO_BUFFER_data(cert_buf),
CRYPTO_BUFFER_len(cert_buf)) ||
!CBB_add_u16(&certificate_list, 0 /* no extensions */)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
}
}
if (!hs->cert_compression_negotiated) {
return ssl_add_message_cbb(ssl, cbb.get());
}
Array<uint8_t> msg;
if (!CBBFinishArray(cbb.get(), &msg)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
}
const CertCompressionAlg *alg = nullptr;
for (const auto &candidate : ssl->ctx->cert_compression_algs) {
if (candidate.alg_id == hs->cert_compression_alg_id) {
alg = &candidate;
break;
}
}
if (alg == nullptr || alg->compress == nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
}
CBB compressed;
body = &body_storage;
if (!ssl->method->init_message(ssl, cbb.get(), body,
SSL3_MT_COMPRESSED_CERTIFICATE) ||
!CBB_add_u16(body, hs->cert_compression_alg_id) ||
!CBB_add_u24(body, msg.size()) ||
!CBB_add_u24_length_prefixed(body, &compressed)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
}
SSL_HANDSHAKE_HINTS *const hints = hs->hints.get();
if (hints && !hs->hints_requested &&
hints->cert_compression_alg_id == hs->cert_compression_alg_id &&
hints->cert_compression_input == MakeConstSpan(msg) &&
!hints->cert_compression_output.empty()) {
if (!CBB_add_bytes(&compressed, hints->cert_compression_output.data(),
hints->cert_compression_output.size())) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
}
} else {
if (!alg->compress(ssl, &compressed, msg.data(), msg.size())) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
}
if (hints && hs->hints_requested) {
hints->cert_compression_alg_id = hs->cert_compression_alg_id;
if (!hints->cert_compression_input.CopyFrom(msg) ||
!hints->cert_compression_output.CopyFrom(
MakeConstSpan(CBB_data(&compressed), CBB_len(&compressed)))) {
return false;
}
}
}
if (!ssl_add_message_cbb(ssl, cbb.get())) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return false;
}
return true;
}