diff --git a/src/tls/xqc_tls.c b/src/tls/xqc_tls.c index 8f9a971a0..d1de6d995 100644 --- a/src/tls/xqc_tls.c +++ b/src/tls/xqc_tls.c @@ -1018,6 +1018,25 @@ xqc_ssl_new_session_cb(SSL *ssl, SSL_SESSION *session) } +xqc_bool_t +xqc_cert_verify_err_tolerable(int err_code, uint8_t cert_verify_flag) +{ + if (err_code == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY + || err_code == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) + { + return XQC_TRUE; + } + + if ((cert_verify_flag & XQC_TLS_CERT_FLAG_ALLOW_SELF_SIGNED) != 0 + && XQC_TLS_SELF_SIGNED_CERT(err_code)) + { + return XQC_TRUE; + } + + return XQC_FALSE; +} + + int xqc_ssl_cert_verify_cb(int ok, X509_STORE_CTX *store_ctx) { @@ -1041,10 +1060,8 @@ xqc_ssl_cert_verify_cb(int ok, X509_STORE_CTX *store_ctx) } int err_code = X509_STORE_CTX_get_error(store_ctx); - if (err_code != X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY - && err_code != X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY - && !((tls->cert_verify_flag & XQC_TLS_CERT_FLAG_ALLOW_SELF_SIGNED) != 0 - && XQC_TLS_SELF_SIGNED_CERT(err_code))) + if (!xqc_cert_verify_err_tolerable(err_code, + tls->cert_verify_flag)) { xqc_log(tls->log, XQC_LOG_ERROR, "|certificate verify failed with err_code:%d|", err_code); if (tls->cbs->error_cb) { diff --git a/src/tls/xqc_tls.h b/src/tls/xqc_tls.h index 3ddf2c8ca..cc4917706 100644 --- a/src/tls/xqc_tls.h +++ b/src/tls/xqc_tls.h @@ -222,5 +222,14 @@ xqc_int_t xqc_tls_update_tp(xqc_tls_t *tls, uint8_t *tp_buf, size_t tp_len); */ void *xqc_tls_get_ssl(xqc_tls_t *tls); +/** + * @brief check if a cert verification error is tolerable + * + * tolerable errors include missing issuer cert (local or chain) + * and self-signed cert when allowed by cert_verify_flag. + */ +xqc_bool_t xqc_cert_verify_err_tolerable(int err_code, + uint8_t cert_verify_flag); + #endif diff --git a/tests/unittest/xqc_tls_test.c b/tests/unittest/xqc_tls_test.c index 304970e0a..d6b5c2560 100644 --- a/tests/unittest/xqc_tls_test.c +++ b/tests/unittest/xqc_tls_test.c @@ -881,6 +881,65 @@ void xqc_test_destroy_tls_ctx() xqc_tls_ctx_destroy(ctx_svr); } +void +xqc_test_cert_verify_err_tolerable() +{ + /* + * error 20: issuer cert not found in local store + * should be tolerated regardless of flags + */ + CU_ASSERT(xqc_cert_verify_err_tolerable( + X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, 0) == XQC_TRUE); + + /* + * error 2: issuer cert of untrusted cert not found + * should also be tolerated (this was the bug in #693) + */ + CU_ASSERT(xqc_cert_verify_err_tolerable( + X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT, 0) == XQC_TRUE); + + /* + * error 18: self-signed leaf cert, allowed when flag is set + */ + CU_ASSERT(xqc_cert_verify_err_tolerable( + X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, + XQC_TLS_CERT_FLAG_ALLOW_SELF_SIGNED) == XQC_TRUE); + + /* + * error 19: self-signed cert in chain, allowed when flag is set + */ + CU_ASSERT(xqc_cert_verify_err_tolerable( + X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN, + XQC_TLS_CERT_FLAG_ALLOW_SELF_SIGNED) == XQC_TRUE); + + /* + * error 18: self-signed leaf cert, rejected without flag + */ + CU_ASSERT(xqc_cert_verify_err_tolerable( + X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, 0) == XQC_FALSE); + + /* + * error 19: self-signed in chain, rejected without flag + */ + CU_ASSERT(xqc_cert_verify_err_tolerable( + X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN, 0) == XQC_FALSE); + + /* + * error 10: expired cert, should always be rejected + */ + CU_ASSERT(xqc_cert_verify_err_tolerable( + X509_V_ERR_CERT_HAS_EXPIRED, 0) == XQC_FALSE); + CU_ASSERT(xqc_cert_verify_err_tolerable( + X509_V_ERR_CERT_HAS_EXPIRED, + XQC_TLS_CERT_FLAG_ALLOW_SELF_SIGNED) == XQC_FALSE); + + /* + * error 23: revoked cert, should always be rejected + */ + CU_ASSERT(xqc_cert_verify_err_tolerable( + X509_V_ERR_CERT_REVOKED, 0) == XQC_FALSE); +} + void xqc_test_tls() { @@ -892,6 +951,7 @@ xqc_test_tls() xqc_test_tls_ctx_register_alpn(); xqc_test_tls_reset_initial(); + xqc_test_cert_verify_err_tolerable(); xqc_test_tls_multiple_crypto_data(); xqc_test_tls_generic(); xqc_test_tls_process_truncated_crypto_handshake();