diff --git a/CMakeLists.txt b/CMakeLists.txt index b5058f56..7fd519ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -820,7 +820,7 @@ endif() # set(CPACK_PACKAGE_NAME "GmSSL") set(CPACK_PACKAGE_VENDOR "GmSSL develop team") -set(CPACK_PACKAGE_VERSION "3.2.0-dev.1102") +set(CPACK_PACKAGE_VERSION "3.2.0-dev.1103") set(CPACK_PACKAGE_DESCRIPTION_FILE ${PROJECT_SOURCE_DIR}/README.md) set(CPACK_NSIS_MODIFY_PATH ON) include(CPack) diff --git a/include/gmssl/ocsp.h b/include/gmssl/ocsp.h index a2586e14..5baf41e5 100644 --- a/include/gmssl/ocsp.h +++ b/include/gmssl/ocsp.h @@ -313,6 +313,9 @@ int ocsp_verify(OCSP_SIGN_CTX *ctx, const uint8_t *signer_cert, size_t signer_cert_len, const char *signer_id, size_t signer_id_len, int *reason); +int ocsp_response_get_signer_cert(const uint8_t *resp, size_t resplen, + const uint8_t *certs, size_t certs_len, + const uint8_t **signer_cert, size_t *signer_cert_len); #ifdef __cplusplus diff --git a/include/gmssl/version.h b/include/gmssl/version.h index 39bc7c57..81dec00a 100644 --- a/include/gmssl/version.h +++ b/include/gmssl/version.h @@ -18,7 +18,7 @@ extern "C" { #define GMSSL_VERSION_NUM 30200 -#define GMSSL_VERSION_STR "GmSSL 3.2.0-dev.1102" +#define GMSSL_VERSION_STR "GmSSL 3.2.0-dev.1103" int gmssl_version_num(void); const char *gmssl_version_str(void); diff --git a/include/gmssl/x509_cer.h b/include/gmssl/x509_cer.h index fff9cad2..8b02ecfa 100644 --- a/include/gmssl/x509_cer.h +++ b/include/gmssl/x509_cer.h @@ -329,6 +329,7 @@ typedef enum { X509_cert_ca, X509_cert_root_ca, X509_cert_crl_sign, + X509_cert_ocsp_signing, } X509_CERT_TYPE; int x509_cert_check(const uint8_t *cert, size_t certlen, int cert_type); @@ -338,6 +339,9 @@ int x509_cert_check_name_constraints(const uint8_t *cert, size_t certlen, int x509_cert_is_self_issued(const uint8_t *cert, size_t certlen); int x509_tlcp_cert_pair_entity_match(const uint8_t *sign_cert, size_t sign_certlen, const uint8_t *kenc_cert, size_t kenc_certlen); +int x509_cert_verify_by_ocsp_response(const uint8_t *cert, size_t certlen, + const uint8_t *issuer_cert, size_t issuer_certlen, + const uint8_t *ocsp, size_t ocsp_len); /* IssuerAndSerialNumber ::= SEQUENCE { @@ -382,10 +386,12 @@ typedef enum { int x509_certs_verify(const uint8_t *certs, size_t certslen, int certs_type, const uint8_t *rootcerts, size_t rootcertslen, const uint8_t *crl, size_t crl_len, + const uint8_t *ocsp, size_t ocsp_len, int depth, int *verify_result); int x509_certs_verify_tlcp(const uint8_t *certs, size_t certslen, int certs_type, const uint8_t *rootcerts, size_t rootcertslen, const uint8_t *crl, size_t crl_len, + const uint8_t *ocsp, size_t ocsp_len, int depth, int *verify_result); int x509_certs_check_name_constraints(const uint8_t *cert_chain, size_t cert_chain_len, const uint8_t *rootcacert, size_t rootcacertlen); diff --git a/src/ocsp.c b/src/ocsp.c index b07e26e8..3b265492 100644 --- a/src/ocsp.c +++ b/src/ocsp.c @@ -2549,3 +2549,123 @@ int ocsp_verify(OCSP_SIGN_CTX *ctx, return -1; } } + +static int ocsp_response_find_signer_cert_in_certs(int responder_id_type, + const uint8_t *responder_id, size_t responder_id_len, + const uint8_t *certs, size_t certs_len, + const uint8_t **signer_cert, size_t *signer_cert_len) +{ + const uint8_t *cert; + size_t cert_len; + int ret; + + if (!responder_id || !responder_id_len || !signer_cert || !signer_cert_len + || (!certs && certs_len)) { + error_print(); + return -1; + } + while (certs_len) { + if (x509_cert_from_der(&cert, &cert_len, &certs, &certs_len) != 1) { + error_print(); + return -1; + } + if ((ret = ocsp_verify_responder_id(responder_id_type, + responder_id, responder_id_len, cert, cert_len)) < 0) { + error_print(); + return -1; + } + if (ret == 1) { + *signer_cert = cert; + *signer_cert_len = cert_len; + return 1; + } + } + *signer_cert = NULL; + *signer_cert_len = 0; + return 0; +} + +int ocsp_response_get_signer_cert(const uint8_t *resp, size_t resplen, + const uint8_t *certs, size_t certs_len, + const uint8_t **signer_cert, size_t *signer_cert_len) +{ + const uint8_t *p; + size_t len; + int response_status; + const uint8_t *basic_response; + size_t basic_response_len; + const uint8_t *response_data; + size_t response_data_len; + int signature_algor; + const uint8_t *signature; + size_t signature_len; + const uint8_t *embedded_certs; + size_t embedded_certs_len; + int responder_id_type; + const uint8_t *responder_id; + size_t responder_id_len; + time_t produced_at; + const uint8_t *single_response_first; + size_t single_response_first_len; + const uint8_t *single_response_others; + size_t single_response_others_len; + const uint8_t *response_exts; + size_t response_exts_len; + int ret; + + if (!resp || !resplen || (!certs && certs_len) || !signer_cert || !signer_cert_len) { + error_print(); + return -1; + } + *signer_cert = NULL; + *signer_cert_len = 0; + + p = resp; + len = resplen; + if (ocsp_response_from_der(&response_status, &basic_response, &basic_response_len, + &p, &len) != 1 + || asn1_length_is_zero(len) != 1) { + error_print(); + return -1; + } + if (response_status != OCSP_response_status_successful) { + return 0; + } + p = basic_response; + len = basic_response_len; + if (ocsp_basic_response_from_der(&response_data, &response_data_len, + &signature_algor, &signature, &signature_len, + &embedded_certs, &embedded_certs_len, &p, &len) != 1 + || asn1_length_is_zero(len) != 1) { + error_print(); + return -1; + } + p = response_data; + len = response_data_len; + if (ocsp_response_data_from_der(&responder_id_type, + &responder_id, &responder_id_len, + &produced_at, + &single_response_first, &single_response_first_len, + &single_response_others, &single_response_others_len, + &response_exts, &response_exts_len, + &p, &len) != 1 + || asn1_length_is_zero(len) != 1) { + error_print(); + return -1; + } + if (certs_len) { + if ((ret = ocsp_response_find_signer_cert_in_certs(responder_id_type, + responder_id, responder_id_len, + certs, certs_len, + signer_cert, signer_cert_len)) != 0) { + return ret; + } + } + if (embedded_certs_len) { + return ocsp_response_find_signer_cert_in_certs(responder_id_type, + responder_id, responder_id_len, + embedded_certs, embedded_certs_len, + signer_cert, signer_cert_len); + } + return 0; +} diff --git a/src/tlcp.c b/src/tlcp.c index b9172d97..5df11fed 100644 --- a/src/tlcp.c +++ b/src/tlcp.c @@ -809,6 +809,7 @@ int tlcp_recv_server_certificate(TLS_CONNECT *conn) if (conn->ctx->cacertslen) { if (x509_certs_verify_tlcp(conn->peer_cert_chain, conn->peer_cert_chain_len, X509_cert_chain_server, conn->ctx->cacerts, conn->ctx->cacertslen, NULL, 0, + NULL, 0, conn->ctx->verify_depth, &verify_result) != 1) { error_print(); tls_send_alert(conn, TLS_alert_bad_certificate); diff --git a/src/tls12.c b/src/tls12.c index 6f03f3a7..a468b7d7 100644 --- a/src/tls12.c +++ b/src/tls12.c @@ -1286,6 +1286,7 @@ int tls_recv_server_certificate(TLS_CONNECT *conn) if (conn->ctx->cacertslen) { if (x509_certs_verify(conn->peer_cert_chain, conn->peer_cert_chain_len, X509_cert_chain_server, conn->ctx->cacerts, conn->ctx->cacertslen, NULL, 0, + NULL, 0, conn->ctx->verify_depth, &verify_result) != 1) { error_print(); conn->verify_result = verify_result; @@ -2586,6 +2587,7 @@ int tls_recv_client_certificate(TLS_CONNECT *conn) } if (x509_certs_verify(conn->client_certs, conn->client_certs_len, X509_cert_chain_client, conn->ctx->cacerts, conn->ctx->cacertslen, NULL, 0, + NULL, 0, verify_depth, &verify_result) != 1) { error_print(); tls_send_alert(conn, TLS_alert_bad_certificate); diff --git a/src/tls13.c b/src/tls13.c index 0f0a8a29..66d0fed1 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -6158,8 +6158,8 @@ int tls13_recv_server_certificate(TLS_CONNECT *conn) int ret; const uint8_t *request_context; size_t request_context_len; - const uint8_t *leaf_status_request_ocsp_response; - size_t leaf_status_request_ocsp_response_len; + const uint8_t *leaf_status_request_ocsp_response = NULL; + size_t leaf_status_request_ocsp_response_len = 0; const uint8_t *leaf_signed_certificate_timestamp; size_t leaf_signed_certificate_timestamp_len; const uint8_t *cert; @@ -6258,25 +6258,21 @@ int tls13_recv_server_certificate(TLS_CONNECT *conn) // 验证一个证书链之前,应该首先判断一下这个证书链对应的根证书是否存在 // 如果我们没有根证书,那么就根本不能验证 // 把查找根证书和验证证书链的函数分开 - if (x509_certs_verify( + ret = x509_certs_verify( conn->peer_cert_chain, conn->peer_cert_chain_len, X509_cert_chain_server, conn->ctx->cacerts, conn->ctx->cacertslen, NULL, 0, - conn->ctx->verify_depth, &verify_result) != 1) { + leaf_status_request_ocsp_response, leaf_status_request_ocsp_response_len, + conn->ctx->verify_depth, &verify_result); + if (ret < 0) { error_print(); tls13_send_alert(conn, TLS_alert_bad_certificate); return -1; } - // status_request - if (leaf_status_request_ocsp_response) { - if (ocsp_response_verify( - leaf_status_request_ocsp_response, - leaf_status_request_ocsp_response_len, - conn->ctx->cacerts, conn->ctx->cacertslen) != 1) { - error_print(); - tls13_send_alert(conn, TLS_alert_certificate_revoked); - return -1; - } + if (ret == 0) { + error_print(); + tls13_send_alert(conn, TLS_alert_certificate_revoked); + return -1; } // signed_certificate_timestamp if (leaf_signed_certificate_timestamp) { @@ -8514,7 +8510,7 @@ int tls13_recv_client_certificate(TLS_CONNECT *conn) const uint8_t *request_context; size_t request_context_len; const uint8_t *status_request_ocsp_response = NULL; - size_t status_request_ocsp_response_len; + size_t status_request_ocsp_response_len = 0; const uint8_t *signed_certificate_timestamp = NULL; size_t signed_certificate_timestamp_len; const uint8_t *cert; @@ -8618,23 +8614,20 @@ int tls13_recv_client_certificate(TLS_CONNECT *conn) } // verify client cert_chain - if (x509_certs_verify(conn->peer_cert_chain, conn->peer_cert_chain_len, X509_cert_chain_client, + ret = x509_certs_verify(conn->peer_cert_chain, conn->peer_cert_chain_len, X509_cert_chain_client, conn->ctx->cacerts, conn->ctx->cacertslen, NULL, 0, - conn->ctx->verify_depth, &verify_result) != 1) { + status_request_ocsp_response, status_request_ocsp_response_len, + conn->ctx->verify_depth, &verify_result); + if (ret < 0) { error_print(); tls13_send_alert(conn, TLS_alert_bad_certificate); return -1; } - // status_request - if (status_request_ocsp_response) { - if (ocsp_response_verify( - status_request_ocsp_response, status_request_ocsp_response_len, - conn->ctx->cacerts, conn->ctx->cacertslen) != 1) { - error_print(); - tls13_send_alert(conn, TLS_alert_certificate_revoked); - return -1; - } + if (ret == 0) { + error_print(); + tls13_send_alert(conn, TLS_alert_certificate_revoked); + return -1; } // signed_certificate_timestamp if (signed_certificate_timestamp) { diff --git a/src/x509_cer.c b/src/x509_cer.c index 6d91db3b..cd4771e1 100644 --- a/src/x509_cer.c +++ b/src/x509_cer.c @@ -1928,10 +1928,32 @@ static int x509_cert_check_optional_crl(const uint8_t *cert, size_t certlen, } return ret; } + +static int x509_cert_check_optional_ocsp(const uint8_t *cert, size_t certlen, + const uint8_t *issuer_cert, size_t issuer_certlen, + const uint8_t *ocsp, size_t ocsp_len) +{ + int ret; + + if (!ocsp && ocsp_len == 0) { + return 1; + } + if (!cert || !certlen || !issuer_cert || !issuer_certlen || !ocsp || !ocsp_len) { + error_print(); + return -1; + } + if ((ret = x509_cert_verify_by_ocsp_response(cert, certlen, + issuer_cert, issuer_certlen, ocsp, ocsp_len)) < 0) { + error_print(); + return -1; + } + return ret; +} int x509_certs_verify(const uint8_t *certs, size_t certslen, int certs_type, const uint8_t *rootcerts, size_t rootcertslen, const uint8_t *crl, size_t crl_len, + const uint8_t *ocsp, size_t ocsp_len, int depth, int *verify_result) { int entity_cert_type; @@ -2007,6 +2029,17 @@ int x509_certs_verify(const uint8_t *certs, size_t certslen, int certs_type, error_print(); return -1; } + if (path_len == 0) { + if ((ret = x509_cert_check_optional_ocsp(cert, certlen, + cacert, cacertlen, ocsp, ocsp_len)) < 0) { + error_print(); + return -1; + } + if (ret == 0) { + error_print(); + return 0; + } + } cert = cacert; certlen = cacertlen; @@ -2031,6 +2064,17 @@ int x509_certs_verify(const uint8_t *certs, size_t certslen, int certs_type, error_print(); return -1; } + if (path_len == 0) { + if ((ret = x509_cert_check_optional_ocsp(cert, certlen, + cacert, cacertlen, ocsp, ocsp_len)) < 0) { + error_print(); + return -1; + } + if (ret == 0) { + error_print(); + return 0; + } + } if (x509_certs_check_basic_constraints(cert_chain, cert_chain_len, cacert, cacertlen) != 1) { @@ -2053,6 +2097,7 @@ int x509_certs_verify(const uint8_t *certs, size_t certslen, int certs_type, int x509_certs_verify_tlcp(const uint8_t *certs, size_t certslen, int certs_type, const uint8_t *rootcerts, size_t rootcertslen, const uint8_t *crl, size_t crl_len, + const uint8_t *ocsp, size_t ocsp_len, int depth, int *verify_result) { int sign_cert_type; @@ -2164,6 +2209,26 @@ int x509_certs_verify_tlcp(const uint8_t *certs, size_t certslen, int certs_type error_print(); return -1; } + if (path_len == 0) { + if ((ret = x509_cert_check_optional_ocsp(cert, certlen, + cacert, cacertlen, ocsp, ocsp_len)) < 0) { + error_print(); + return -1; + } + if (ret == 0) { + error_print(); + return 0; + } + if ((ret = x509_cert_check_optional_ocsp(kenc_cert, kenc_certlen, + cacert, cacertlen, ocsp, ocsp_len)) < 0) { + error_print(); + return -1; + } + if (ret == 0) { + error_print(); + return 0; + } + } cert = cacert; certlen = cacertlen; @@ -2196,6 +2261,24 @@ int x509_certs_verify_tlcp(const uint8_t *certs, size_t certslen, int certs_type error_print(); return -1; } + if ((ret = x509_cert_check_optional_ocsp(cert, certlen, + cacert, cacertlen, ocsp, ocsp_len)) < 0) { + error_print(); + return -1; + } + if (ret == 0) { + error_print(); + return 0; + } + if ((ret = x509_cert_check_optional_ocsp(kenc_cert, kenc_certlen, + cacert, cacertlen, ocsp, ocsp_len)) < 0) { + error_print(); + return -1; + } + if (ret == 0) { + error_print(); + return 0; + } } if (x509_certs_check_basic_constraints_tlcp(cert_chain, cert_chain_len, diff --git a/src/x509_ext.c b/src/x509_ext.c index c5125341..940194da 100644 --- a/src/x509_ext.c +++ b/src/x509_ext.c @@ -1381,6 +1381,7 @@ int x509_key_usage_check(int bits, int cert_type) break; case X509_cert_server_auth: case X509_cert_client_auth: + case X509_cert_ocsp_signing: if (!(bits & X509_KU_DIGITAL_SIGNATURE)) { error_print(); return -1; @@ -2170,6 +2171,7 @@ int x509_basic_constraints_check(int ca, int path_len_constraint, int cert_type) case X509_cert_client_auth: case X509_cert_server_key_encipher: case X509_cert_client_key_encipher: + case X509_cert_ocsp_signing: if (ca > 0 || path_len_constraint != -1) { error_print(); return -1; @@ -2613,6 +2615,11 @@ int x509_ext_key_usage_check(const int *oids, size_t oids_cnt, int cert_type) return 1; } break; + case X509_cert_ocsp_signing: + if (oids[i] == OID_kp_ocsp_signing) { + return 1; + } + break; default: error_print(); diff --git a/src/x509_vrf.c b/src/x509_vrf.c index b472bccc..8e46dd7e 100644 --- a/src/x509_vrf.c +++ b/src/x509_vrf.c @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -418,6 +419,7 @@ int x509_cert_check_subject(const uint8_t *cert, size_t certlen, int cert_type) case X509_cert_client_auth: case X509_cert_server_key_encipher: case X509_cert_client_key_encipher: + case X509_cert_ocsp_signing: is_cacert = 0; break; case X509_cert_ca: @@ -2003,6 +2005,7 @@ static int x509_cert_check_basic_constraints_by_type(const uint8_t *cert, size_t case X509_cert_client_auth: case X509_cert_server_key_encipher: case X509_cert_client_key_encipher: + case X509_cert_ocsp_signing: is_ca = 0; break; case X509_cert_ca: @@ -2615,3 +2618,59 @@ int x509_cert_is_revoked_by_crl(const uint8_t *cert, size_t certlen, } return ret; } + +int x509_cert_verify_by_ocsp_response(const uint8_t *cert, size_t certlen, + const uint8_t *issuer_cert, size_t issuer_certlen, + const uint8_t *ocsp, size_t ocsp_len) +{ + uint8_t req[OCSP_MAX_REQUEST_SIZE]; + size_t reqlen; + OCSP_SIGN_CTX ctx; + const uint8_t *signer_cert; + size_t signer_certlen; + int signer_is_issuer; + int reason; + int ret; + + if (!cert || !certlen || !issuer_cert || !issuer_certlen || !ocsp || !ocsp_len) { + error_print(); + return -1; + } + if (ocsp_request_generate(req, &reqlen, sizeof(req), + cert, certlen, issuer_cert, issuer_certlen, DIGEST_sm3()) != 1 + || ocsp_verify_init(&ctx, req, reqlen, issuer_cert, issuer_certlen) != 1) { + error_print(); + return -1; + } + if ((ret = ocsp_response_get_signer_cert(ocsp, ocsp_len, + issuer_cert, issuer_certlen, &signer_cert, &signer_certlen)) < 0) { + error_print(); + return 0; + } + if (ret == 0) { + return 0; + } + + signer_is_issuer = (signer_certlen == issuer_certlen + && memcmp(signer_cert, issuer_cert, issuer_certlen) == 0); + if (!signer_is_issuer) { + if (x509_cert_verify_by_ca_cert(signer_cert, signer_certlen, + issuer_cert, issuer_certlen, + SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1) { + error_print(); + return 0; + } + if (x509_cert_check(signer_cert, signer_certlen, X509_cert_ocsp_signing) != 1) { + error_print(); + return 0; + } + } + + ret = ocsp_verify(&ctx, ocsp, ocsp_len, + signer_cert, signer_certlen, + NULL, 0, &reason); + if (ret != 1) { + return 0; + } + return 1; +}