static int cert_set_chain_and_key( CERT *cert, CRYPTO_BUFFER *const *certs, size_t num_certs, EVP_PKEY *privkey, const SSL_PRIVATE_KEY_METHOD *privkey_method) { if (num_certs == 0 || (privkey == NULL && privkey_method == NULL)) { OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); return 0; } if (privkey != NULL && privkey_method != NULL) { OPENSSL_PUT_ERROR(SSL, SSL_R_CANNOT_HAVE_BOTH_PRIVKEY_AND_METHOD); return 0; } switch (check_leaf_cert_and_privkey(certs[0], privkey)) { case leaf_cert_and_privkey_error: return 0; case leaf_cert_and_privkey_mismatch: OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_AND_PRIVATE_KEY_MISMATCH); return 0; case leaf_cert_and_privkey_ok: break; } STACK_OF(CRYPTO_BUFFER) *certs_sk = sk_CRYPTO_BUFFER_new_null(); if (certs_sk == NULL) { return 0; } for (size_t i = 0; i < num_certs; i++) { if (!sk_CRYPTO_BUFFER_push(certs_sk, certs[i])) { sk_CRYPTO_BUFFER_pop_free(certs_sk, CRYPTO_BUFFER_free); return 0; } CRYPTO_BUFFER_up_ref(certs[i]); } EVP_PKEY_free(cert->privatekey); cert->privatekey = privkey; if (privkey != NULL) { EVP_PKEY_up_ref(privkey); } cert->key_method = privkey_method; sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free); cert->chain = certs_sk; return 1; }
/* Free up and clear all certificates and chains */ void ssl_cert_clear_certs(CERT *cert) { if (cert == NULL) { return; } cert->x509_method->cert_clear(cert); sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free); cert->chain = NULL; EVP_PKEY_free(cert->privatekey); cert->privatekey = NULL; cert->key_method = NULL; }
STACK_OF(CRYPTO_BUFFER) * ssl_parse_client_CA_list(SSL *ssl, uint8_t *out_alert, CBS *cbs) { CRYPTO_BUFFER_POOL *const pool = ssl->ctx->pool; STACK_OF(CRYPTO_BUFFER) *ret = sk_CRYPTO_BUFFER_new_null(); if (ret == NULL) { *out_alert = SSL_AD_INTERNAL_ERROR; OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); return NULL; } CBS child; if (!CBS_get_u16_length_prefixed(cbs, &child)) { *out_alert = SSL_AD_DECODE_ERROR; OPENSSL_PUT_ERROR(SSL, SSL_R_LENGTH_MISMATCH); goto err; } while (CBS_len(&child) > 0) { CBS distinguished_name; if (!CBS_get_u16_length_prefixed(&child, &distinguished_name)) { *out_alert = SSL_AD_DECODE_ERROR; OPENSSL_PUT_ERROR(SSL, SSL_R_CA_DN_TOO_LONG); goto err; } CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&distinguished_name, pool); if (buffer == NULL || !sk_CRYPTO_BUFFER_push(ret, buffer)) { CRYPTO_BUFFER_free(buffer); *out_alert = SSL_AD_INTERNAL_ERROR; OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); goto err; } } if (!ssl->ctx->x509_method->check_client_CA_list(ret)) { *out_alert = SSL_AD_INTERNAL_ERROR; OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); goto err; } return ret; err: sk_CRYPTO_BUFFER_pop_free(ret, CRYPTO_BUFFER_free); return NULL; }
void SSL_SESSION_free(SSL_SESSION *session) { if (session == NULL || !CRYPTO_refcount_dec_and_test_zero(&session->references)) { return; } CRYPTO_free_ex_data(&g_ex_data_class, session, &session->ex_data); OPENSSL_cleanse(session->master_key, sizeof(session->master_key)); OPENSSL_cleanse(session->session_id, sizeof(session->session_id)); sk_CRYPTO_BUFFER_pop_free(session->certs, CRYPTO_BUFFER_free); session->x509_method->session_clear(session); OPENSSL_free(session->tlsext_hostname); OPENSSL_free(session->tlsext_tick); OPENSSL_free(session->tlsext_signed_cert_timestamp_list); OPENSSL_free(session->ocsp_response); OPENSSL_free(session->psk_identity); OPENSSL_free(session->early_alpn); OPENSSL_cleanse(session, sizeof(*session)); OPENSSL_free(session); }
STACK_OF(CRYPTO_BUFFER) *ssl_parse_cert_chain(uint8_t *out_alert, EVP_PKEY **out_pubkey, uint8_t *out_leaf_sha256, CBS *cbs, CRYPTO_BUFFER_POOL *pool) { *out_pubkey = NULL; STACK_OF(CRYPTO_BUFFER) *ret = sk_CRYPTO_BUFFER_new_null(); if (ret == NULL) { *out_alert = SSL_AD_INTERNAL_ERROR; OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); return NULL; } CBS certificate_list; if (!CBS_get_u24_length_prefixed(cbs, &certificate_list)) { *out_alert = SSL_AD_DECODE_ERROR; OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); goto err; } while (CBS_len(&certificate_list) > 0) { CBS certificate; if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) || CBS_len(&certificate) == 0) { *out_alert = SSL_AD_DECODE_ERROR; OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH); goto err; } if (sk_CRYPTO_BUFFER_num(ret) == 0) { *out_pubkey = ssl_cert_parse_pubkey(&certificate); if (*out_pubkey == NULL) { *out_alert = SSL_AD_DECODE_ERROR; goto err; } /* Retain the hash of the leaf certificate if requested. */ if (out_leaf_sha256 != NULL) { SHA256(CBS_data(&certificate), CBS_len(&certificate), out_leaf_sha256); } } CRYPTO_BUFFER *buf = CRYPTO_BUFFER_new_from_CBS(&certificate, pool); if (buf == NULL) { *out_alert = SSL_AD_DECODE_ERROR; goto err; } if (!sk_CRYPTO_BUFFER_push(ret, buf)) { *out_alert = SSL_AD_INTERNAL_ERROR; CRYPTO_BUFFER_free(buf); OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); goto err; } } return ret; err: EVP_PKEY_free(*out_pubkey); *out_pubkey = NULL; sk_CRYPTO_BUFFER_pop_free(ret, CRYPTO_BUFFER_free); return NULL; }
int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) { SSL *const ssl = hs->ssl; CBS cbs, context, certificate_list; CBS_init(&cbs, ssl->init_msg, ssl->init_num); if (!CBS_get_u8_length_prefixed(&cbs, &context) || CBS_len(&context) != 0) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); return 0; } const int retain_sha256 = ssl->server && ssl->retain_only_sha256_of_client_certs; int ret = 0; EVP_PKEY *pkey = NULL; STACK_OF(CRYPTO_BUFFER) *certs = sk_CRYPTO_BUFFER_new_null(); if (certs == NULL) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); goto err; } if (!CBS_get_u24_length_prefixed(&cbs, &certificate_list)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); goto err; } 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) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH); goto err; } if (sk_CRYPTO_BUFFER_num(certs) == 0) { pkey = ssl_cert_parse_pubkey(&certificate); if (pkey == NULL) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); goto err; } /* TLS 1.3 always uses certificate keys for signing thus the correct * keyUsage is enforced. */ if (!ssl_cert_check_digital_signature_key_usage(&certificate)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); goto err; } if (retain_sha256) { /* Retain the hash of the leaf certificate if requested. */ SHA256(CBS_data(&certificate), CBS_len(&certificate), ssl->s3->new_session->peer_sha256); } } CRYPTO_BUFFER *buf = CRYPTO_BUFFER_new_from_CBS(&certificate, ssl->ctx->pool); if (buf == NULL || !sk_CRYPTO_BUFFER_push(certs, buf)) { CRYPTO_BUFFER_free(buf); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); goto err; } /* Parse out the extensions. */ int have_status_request = 0, have_sct = 0; CBS status_request, sct; const SSL_EXTENSION_TYPE ext_types[] = { {TLSEXT_TYPE_status_request, &have_status_request, &status_request}, {TLSEXT_TYPE_certificate_timestamp, &have_sct, &sct}, }; uint8_t alert; if (!ssl_parse_extensions(&extensions, &alert, ext_types, OPENSSL_ARRAY_SIZE(ext_types), 0 /* reject unknown */)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); goto err; } /* All Certificate extensions are parsed, but only the leaf extensions are * stored. */ if (have_status_request) { if (ssl->server || !ssl->ocsp_stapling_enabled) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION); goto err; } uint8_t status_type; CBS ocsp_response; if (!CBS_get_u8(&status_request, &status_type) || status_type != TLSEXT_STATUSTYPE_ocsp || !CBS_get_u24_length_prefixed(&status_request, &ocsp_response) || CBS_len(&ocsp_response) == 0 || CBS_len(&status_request) != 0) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); goto err; } if (sk_CRYPTO_BUFFER_num(certs) == 1 && !CBS_stow(&ocsp_response, &ssl->s3->new_session->ocsp_response, &ssl->s3->new_session->ocsp_response_length)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); goto err; } } if (have_sct) { if (ssl->server || !ssl->signed_cert_timestamps_enabled) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION); goto err; } if (!ssl_is_sct_list_valid(&sct)) { OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); goto err; } if (sk_CRYPTO_BUFFER_num(certs) == 1 && !CBS_stow(&sct, &ssl->s3->new_session->tlsext_signed_cert_timestamp_list, &ssl->s3->new_session ->tlsext_signed_cert_timestamp_list_length)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); goto err; } } } if (CBS_len(&cbs) != 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); goto err; } EVP_PKEY_free(hs->peer_pubkey); hs->peer_pubkey = pkey; pkey = NULL; sk_CRYPTO_BUFFER_pop_free(ssl->s3->new_session->certs, CRYPTO_BUFFER_free); ssl->s3->new_session->certs = certs; certs = NULL; if (!ssl_session_x509_cache_objects(ssl->s3->new_session)) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); goto err; } if (sk_CRYPTO_BUFFER_num(ssl->s3->new_session->certs) == 0) { if (!allow_anonymous) { OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_CERTIFICATE_REQUIRED); goto err; } /* 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. */ ssl->s3->new_session->verify_result = X509_V_OK; /* No certificate, so nothing more to do. */ ret = 1; goto err; } ssl->s3->new_session->peer_sha256_valid = retain_sha256; if (!ssl_verify_cert_chain(ssl, &ssl->s3->new_session->verify_result, ssl->s3->new_session->x509_chain)) { goto err; } ret = 1; err: sk_CRYPTO_BUFFER_pop_free(certs, CRYPTO_BUFFER_free); EVP_PKEY_free(pkey); return ret; }