static S2N_RESULT s2n_x509_validator_verify_cert_chain()

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, &current_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;
}