in ssl/tls13_both.cc [97:313]
bool tls13_process_certificate(SSL_HANDSHAKE *hs, const SSLMessage &msg,
bool allow_anonymous) {
SSL *const ssl = hs->ssl;
CBS body = msg.body;
bssl::UniquePtr<CRYPTO_BUFFER> decompressed;
if (msg.type == SSL3_MT_COMPRESSED_CERTIFICATE) {
CBS compressed;
uint16_t alg_id;
uint32_t uncompressed_len;
if (!CBS_get_u16(&body, &alg_id) ||
!CBS_get_u24(&body, &uncompressed_len) ||
!CBS_get_u24_length_prefixed(&body, &compressed) ||
CBS_len(&body) != 0) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
return false;
}
if (uncompressed_len > ssl->max_cert_list) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
OPENSSL_PUT_ERROR(SSL, SSL_R_UNCOMPRESSED_CERT_TOO_LARGE);
ERR_add_error_dataf("requested=%u",
static_cast<unsigned>(uncompressed_len));
return false;
}
ssl_cert_decompression_func_t decompress = nullptr;
for (const auto &alg : ssl->ctx->cert_compression_algs) {
if (alg.alg_id == alg_id) {
decompress = alg.decompress;
break;
}
}
if (decompress == nullptr) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERT_COMPRESSION_ALG);
ERR_add_error_dataf("alg=%d", static_cast<int>(alg_id));
return false;
}
CRYPTO_BUFFER *decompressed_ptr = nullptr;
if (!decompress(ssl, &decompressed_ptr, uncompressed_len,
CBS_data(&compressed), CBS_len(&compressed))) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_DECOMPRESSION_FAILED);
ERR_add_error_dataf("alg=%d", static_cast<int>(alg_id));
return false;
}
decompressed.reset(decompressed_ptr);
if (CRYPTO_BUFFER_len(decompressed_ptr) != uncompressed_len) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_DECOMPRESSION_FAILED);
ERR_add_error_dataf(
"alg=%d got=%u expected=%u", static_cast<int>(alg_id),
static_cast<unsigned>(CRYPTO_BUFFER_len(decompressed_ptr)),
static_cast<unsigned>(uncompressed_len));
return false;
}
CBS_init(&body, CRYPTO_BUFFER_data(decompressed_ptr),
CRYPTO_BUFFER_len(decompressed_ptr));
} else {
assert(msg.type == SSL3_MT_CERTIFICATE);
}
CBS context, certificate_list;
if (!CBS_get_u8_length_prefixed(&body, &context) ||
CBS_len(&context) != 0 ||
!CBS_get_u24_length_prefixed(&body, &certificate_list) ||
CBS_len(&body) != 0) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
return false;
}
UniquePtr<STACK_OF(CRYPTO_BUFFER)> certs(sk_CRYPTO_BUFFER_new_null());
if (!certs) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return false;
}
const bool retain_sha256 =
ssl->server && hs->config->retain_only_sha256_of_client_certs;
UniquePtr<EVP_PKEY> pkey;
while (CBS_len(&certificate_list) > 0) {
CBS certificate, extensions;
if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) ||
!CBS_get_u16_length_prefixed(&certificate_list, &extensions) ||
CBS_len(&certificate) == 0) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
return false;
}
if (sk_CRYPTO_BUFFER_num(certs.get()) == 0) {
pkey = ssl_cert_parse_pubkey(&certificate);
if (!pkey) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
return false;
}
// TLS 1.3 always uses certificate keys for signing thus the correct
// keyUsage is enforced.
if (!ssl_cert_check_key_usage(&certificate,
key_usage_digital_signature)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return false;
}
if (retain_sha256) {
// Retain the hash of the leaf certificate if requested.
SHA256(CBS_data(&certificate), CBS_len(&certificate),
hs->new_session->peer_sha256);
}
}
UniquePtr<CRYPTO_BUFFER> buf(
CRYPTO_BUFFER_new_from_CBS(&certificate, ssl->ctx->pool));
if (!buf ||
!PushToStack(certs.get(), std::move(buf))) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return false;
}
// Parse out the extensions.
SSLExtension status_request(
TLSEXT_TYPE_status_request,
!ssl->server && hs->config->ocsp_stapling_enabled);
SSLExtension sct(
TLSEXT_TYPE_certificate_timestamp,
!ssl->server && hs->config->signed_cert_timestamps_enabled);
uint8_t alert = SSL_AD_DECODE_ERROR;
if (!ssl_parse_extensions(&extensions, &alert, {&status_request, &sct},
/*ignore_unknown=*/false)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return false;
}
// All Certificate extensions are parsed, but only the leaf extensions are
// stored.
if (status_request.present) {
uint8_t status_type;
CBS ocsp_response;
if (!CBS_get_u8(&status_request.data, &status_type) ||
status_type != TLSEXT_STATUSTYPE_ocsp ||
!CBS_get_u24_length_prefixed(&status_request.data, &ocsp_response) ||
CBS_len(&ocsp_response) == 0 ||
CBS_len(&status_request.data) != 0) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return false;
}
if (sk_CRYPTO_BUFFER_num(certs.get()) == 1) {
hs->new_session->ocsp_response.reset(
CRYPTO_BUFFER_new_from_CBS(&ocsp_response, ssl->ctx->pool));
if (hs->new_session->ocsp_response == nullptr) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return false;
}
}
}
if (sct.present) {
if (!ssl_is_sct_list_valid(&sct.data)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return false;
}
if (sk_CRYPTO_BUFFER_num(certs.get()) == 1) {
hs->new_session->signed_cert_timestamp_list.reset(
CRYPTO_BUFFER_new_from_CBS(&sct.data, ssl->ctx->pool));
if (hs->new_session->signed_cert_timestamp_list == nullptr) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return false;
}
}
}
}
// Store a null certificate list rather than an empty one if the peer didn't
// send certificates.
if (sk_CRYPTO_BUFFER_num(certs.get()) == 0) {
certs.reset();
}
hs->peer_pubkey = std::move(pkey);
hs->new_session->certs = std::move(certs);
if (!ssl->ctx->x509_method->session_cache_objects(hs->new_session.get())) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return false;
}
if (sk_CRYPTO_BUFFER_num(hs->new_session->certs.get()) == 0) {
if (!allow_anonymous) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_CERTIFICATE_REQUIRED);
return false;
}
// OpenSSL returns X509_V_OK when no certificates are requested. This is
// classed by them as a bug, but it's assumed by at least NGINX.
hs->new_session->verify_result = X509_V_OK;
// No certificate, so nothing more to do.
return true;
}
hs->new_session->peer_sha256_valid = retain_sha256;
return true;
}