in tls/s2n_x509_validator.c [651:731]
static S2N_RESULT s2n_x509_validator_verify_cert_chain(struct s2n_x509_validator *validator, struct s2n_connection *conn)
{
RESULT_ENSURE(validator->state == READY_TO_VERIFY, S2N_ERR_INVALID_CERT_STATE);
X509_VERIFY_PARAM *param = X509_STORE_CTX_get0_param(validator->store_ctx);
X509_VERIFY_PARAM_set_depth(param, validator->max_chain_depth);
DEFER_CLEANUP(STACK_OF(X509_CRL) *crl_stack = NULL, sk_X509_CRL_free_pointer);
if (conn->config->crl_lookup_cb) {
X509_STORE_CTX_set_verify_cb(validator->store_ctx, s2n_crl_ossl_verify_callback);
crl_stack = sk_X509_CRL_new_null();
RESULT_GUARD(s2n_crl_get_crls_from_lookup_list(validator, crl_stack));
/* Set the CRL list that the libcrypto will use to validate certificates with */
X509_STORE_CTX_set0_crls(validator->store_ctx, crl_stack);
/* Enable CRL validation for certificates in X509_verify_cert */
RESULT_GUARD_OSSL(X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK),
S2N_ERR_INTERNAL_LIBCRYPTO_ERROR);
/* Enable CRL validation for all certificates, not just the leaf */
RESULT_GUARD_OSSL(X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK_ALL),
S2N_ERR_INTERNAL_LIBCRYPTO_ERROR);
}
/* Disabling time validation may set a NO_CHECK_TIME flag on the X509_STORE_CTX. Calling
* X509_STORE_CTX_set_time will override this flag. To prevent this, X509_STORE_CTX_set_time is
* only called if time validation is enabled.
*/
if (conn->config->disable_x509_time_validation) {
RESULT_GUARD(s2n_x509_validator_disable_time_validation(conn, validator));
} else {
uint64_t current_sys_time = 0;
RESULT_GUARD(s2n_config_wall_clock(conn->config, ¤t_sys_time));
if (sizeof(time_t) == 4) {
/* cast value to uint64_t to prevent overflow errors */
RESULT_ENSURE_LTE(current_sys_time, (uint64_t) MAX_32_TIMESTAMP_NANOS);
}
/* this wants seconds not nanoseconds */
time_t current_time = (time_t) (current_sys_time / ONE_SEC_IN_NANOS);
X509_STORE_CTX_set_time(validator->store_ctx, 0, current_time);
}
/* It's assumed that if a valid certificate chain is received with an issuer that's present in
* the trust store, the certificate chain should be trusted. This should be the case even if
* the issuer in the trust store isn't a root certificate. Setting the PARTIAL_CHAIN flag
* allows the libcrypto to trust certificates in the trust store that aren't root certificates.
*/
X509_STORE_CTX_set_flags(validator->store_ctx, X509_V_FLAG_PARTIAL_CHAIN);
int verify_ret = X509_verify_cert(validator->store_ctx);
if (verify_ret <= 0) {
int ossl_error = X509_STORE_CTX_get_error(validator->store_ctx);
switch (ossl_error) {
case X509_V_ERR_CERT_NOT_YET_VALID:
RESULT_BAIL(S2N_ERR_CERT_NOT_YET_VALID);
case X509_V_ERR_CERT_HAS_EXPIRED:
RESULT_BAIL(S2N_ERR_CERT_EXPIRED);
case X509_V_ERR_CERT_REVOKED:
RESULT_BAIL(S2N_ERR_CERT_REVOKED);
case X509_V_ERR_UNABLE_TO_GET_CRL:
case X509_V_ERR_DIFFERENT_CRL_SCOPE:
RESULT_BAIL(S2N_ERR_CRL_LOOKUP_FAILED);
case X509_V_ERR_CRL_SIGNATURE_FAILURE:
RESULT_BAIL(S2N_ERR_CRL_SIGNATURE);
case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
RESULT_BAIL(S2N_ERR_CRL_ISSUER);
case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION:
RESULT_BAIL(S2N_ERR_CRL_UNHANDLED_CRITICAL_EXTENSION);
default:
RESULT_BAIL(S2N_ERR_CERT_UNTRUSTED);
}
}
validator->state = VALIDATED;
return S2N_RESULT_OK;
}