diff --git a/include/gmssl/x509.h b/include/gmssl/x509.h index 0e1021e6..3dba6c7a 100644 --- a/include/gmssl/x509.h +++ b/include/gmssl/x509.h @@ -345,10 +345,14 @@ typedef enum { X509_verify_err_cert_chain_too_long = -5, } X509_VERIFY_ERR; -int x509_certs_verify(const uint8_t *certs, size_t certslen, - int server, +typedef enum { + X509_cert_chain_server, + X509_cert_chain_client, +} X509_CERT_CHAIN_TYPE; + +int x509_certs_verify(const uint8_t *certs, size_t certslen, int certs_type, const uint8_t *rootcerts, size_t rootcertslen, int depth, int *verify_result); -int x509_certs_verify_tlcp(const uint8_t *certs, size_t certslen, +int x509_certs_verify_tlcp(const uint8_t *certs, size_t certslen, int certs_type, const uint8_t *rootcerts, size_t rootcertslen, int depth, int *verify_result); int x509_certs_get_subjects(const uint8_t *certs, size_t certslen, uint8_t *names, size_t *nameslen); int x509_certs_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen); diff --git a/src/tlcp.c b/src/tlcp.c index 2da93033..c2cc321a 100644 --- a/src/tlcp.c +++ b/src/tlcp.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2022 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2023 The GmSSL Project. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. @@ -257,7 +257,7 @@ int tlcp_do_connect(TLS_CONNECT *conn) if (conn->ca_certs_len) { // 只有提供了CA证书才验证服务器证书链 // FIXME: 逻辑需要再检查 - if (x509_certs_verify_tlcp(conn->server_certs, conn->server_certs_len, + if (x509_certs_verify_tlcp(conn->server_certs, conn->server_certs_len, X509_cert_chain_server, conn->ca_certs, conn->ca_certs_len, depth, &verify_result) != 1) { error_print(); tls_send_alert(conn, alert); @@ -791,8 +791,7 @@ int tlcp_do_accept(TLS_CONNECT *conn) tls_send_alert(conn, TLS_alert_unexpected_message); goto end; } - if (x509_certs_verify(conn->client_certs, conn->client_certs_len, - 0, // client + if (x509_certs_verify(conn->client_certs, conn->client_certs_len, X509_cert_chain_client, conn->ca_certs, conn->ca_certs_len, 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 4b3e5252..ed5d586a 100644 --- a/src/tls12.c +++ b/src/tls12.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2022 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2023 The GmSSL Project. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. @@ -344,8 +344,7 @@ int tls12_do_connect(TLS_CONNECT *conn) sm2_sign_update(&sign_ctx, record + 5, recordlen - 5); // verify ServerCertificate - if (x509_certs_verify(conn->server_certs, conn->server_certs_len, - 1, // server + if (x509_certs_verify(conn->server_certs, conn->server_certs_len, X509_cert_chain_server, conn->ca_certs, conn->ca_certs_len, depth, &verify_result) != 1) { error_print(); tls_send_alert(conn, alert); @@ -883,8 +882,7 @@ int tls12_do_accept(TLS_CONNECT *conn) tls_send_alert(conn, TLS_alert_unexpected_message); goto end; } - if (x509_certs_verify(conn->client_certs, conn->client_certs_len, - 0, // client + if (x509_certs_verify(conn->client_certs, conn->client_certs_len, X509_cert_chain_client, conn->ca_certs, conn->ca_certs_len, verify_depth, &verify_result) != 1) { error_print(); tls_send_alert(conn, TLS_alert_bad_certificate); diff --git a/src/x509_cer.c b/src/x509_cer.c index e26c1441..2079118d 100644 --- a/src/x509_cer.c +++ b/src/x509_cer.c @@ -1087,6 +1087,7 @@ int x509_cert_verify(const uint8_t *a, size_t alen, return ret; } +// TODO: return an extra error code int x509_cert_verify_by_ca_cert(const uint8_t *a, size_t alen, const uint8_t *cacert, size_t cacertlen, const char *signer_id, size_t signer_id_len) @@ -1565,10 +1566,10 @@ int x509_cert_validate(const uint8_t *cert, size_t certlen, int cert_type, return 1; } -int x509_certs_verify(const uint8_t *certs, size_t certslen, - int server, +int x509_certs_verify(const uint8_t *certs, size_t certslen, int certs_type, const uint8_t *rootcerts, size_t rootcertslen, int depth, int *verify_result) { + int entity_cert_type; const uint8_t *cert; size_t certlen; const uint8_t *cacert; @@ -1577,37 +1578,66 @@ int x509_certs_verify(const uint8_t *certs, size_t certslen, size_t namelen; *verify_result = -1; - int cert_type = server ? X509_cert_server_auth : X509_cert_client_auth; + int path_len = 0; int path_len_constraints; + switch (certs_type) { + case X509_cert_chain_server: + entity_cert_type = X509_cert_server_auth; + break; + case X509_cert_chain_client: + entity_cert_type = X509_cert_client_auth; + break; + default: + error_print(); + return -1; + } + + // entity cert if (x509_cert_from_der(&cert, &certlen, &certs, &certslen) != 1) { error_print(); return -1; } + if ((*verify_result = x509_cert_validate(cert, certlen, entity_cert_type, + &path_len_constraints)) < 0) { + error_print(); + return -1; + } + while (certslen) { - if ((*verify_result = x509_cert_validate(cert, certlen, cert_type, &path_len_constraints)) < 0) { - error_print(); - return -1; - } - - cert_type = X509_cert_ca; - - // FIXME: check path_len_constraints - if (x509_cert_from_der(&cacert, &cacertlen, &certs, &certslen) != 1) { error_print(); return -1; } - // 这里应该检查证书是否有效啊, 这个函数应该返回进一步的错误信息 + if ((*verify_result = x509_cert_validate(cert, certlen, X509_cert_ca, + &path_len_constraints)) < 0) { + error_print(); + return -1; + } + + if (path_len == 0) { + if (path_len_constraints != 0) { + error_print(); + return -1; + } + } + if (path_len > path_len_constraints || path_len > depth) { + error_print(); + return -1; + } + if (x509_cert_verify_by_ca_cert(cert, certlen, cacert, cacertlen, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1) { error_print(); return -1; } + cert = cacert; certlen = cacertlen; + path_len++; } + if (x509_cert_get_issuer(cert, certlen, &name, &namelen) != 1) { error_print(); return -1; @@ -1626,72 +1656,119 @@ int x509_certs_verify(const uint8_t *certs, size_t certslen, return 1; } -int x509_certs_verify_tlcp(const uint8_t *certs, size_t certslen, +int x509_certs_verify_tlcp(const uint8_t *certs, size_t certslen, int certs_type, const uint8_t *rootcerts, size_t rootcertslen, int depth, int *verify_result) { - const uint8_t *signcert; - size_t signcertlen; - int signcert_verified = 0; + int sign_cert_type; + int kenc_cert_type; const uint8_t *cert; size_t certlen; + const uint8_t *kenc_cert; + size_t kenc_certlen; const uint8_t *cacert; size_t cacertlen; const uint8_t *name; size_t namelen; - *verify_result = -1; - if (x509_cert_from_der(&signcert, &signcertlen, &certs, &certslen) != 1) { + int path_len = 0; + int path_len_constraints; + + switch (certs_type) { + case X509_cert_chain_server: + sign_cert_type = X509_cert_server_auth; + kenc_cert_type = X509_cert_server_key_encipher; + break; + case X509_cert_chain_client: + sign_cert_type = X509_cert_server_auth; + kenc_cert_type = X509_cert_server_key_encipher; + break; + default: error_print(); return -1; } + if (x509_cert_from_der(&cert, &certlen, &certs, &certslen) != 1) { error_print(); return -1; } - // 要检查这两个证书的类型是否分别为签名和加密证书 - // FIXME: 检查depth + if ((*verify_result = x509_cert_validate(cert, certlen, sign_cert_type, + &path_len_constraints)) < 0) { + error_print(); + return -1; + } + + // entity key encipherment cert + if (x509_cert_from_der(&kenc_cert, &kenc_certlen, &certs, &certslen) != 1) { + error_print(); + return -1; + } + if ((*verify_result = x509_cert_validate(kenc_cert, kenc_certlen, kenc_cert_type, + &path_len_constraints)) < 0) { + error_print(); + return -1; + } + while (certslen) { - if ((*verify_result = x509_cert_check(cert, certlen)) < 0) { - error_print(); - return -1; - } + if (x509_cert_from_der(&cacert, &cacertlen, &certs, &certslen) != 1) { error_print(); return -1; } - if (!signcert_verified) { - if (x509_cert_verify_by_ca_cert(cert, certlen, cacert, cacertlen, + if ((*verify_result = x509_cert_validate(cacert, cacertlen, X509_cert_ca, + &path_len_constraints)) < 0) { + error_print(); + return -1; + } + + if (path_len == 0) { + if (path_len_constraints != 0) { + error_print(); + return -1; + } + + // verify entity key encipherment cert + if (x509_cert_verify_by_ca_cert(kenc_cert, kenc_certlen, cacert, cacertlen, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1) { error_print(); return -1; } - signcert_verified = 1; } + if (path_len > path_len_constraints || path_len > depth) { + error_print(); + return -1; + } + if (x509_cert_verify_by_ca_cert(cert, certlen, cacert, cacertlen, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1) { error_print(); return -1; } + cert = cacert; certlen = cacertlen; + path_len++; } + + if (x509_cert_get_issuer(cert, certlen, &name, &namelen) != 1) { error_print(); return -1; } if (x509_certs_get_cert_by_subject(rootcerts, rootcertslen, name, namelen, &cacert, &cacertlen) != 1) { - // 当前证书链和提供的CA证书不匹配 error_print(); return -1; } - if (!signcert_verified) { - if (x509_cert_verify_by_ca_cert(cert, certlen, cacert, cacertlen, + + // when no mid CA certs + if (path_len == 0) { + if (x509_cert_verify_by_ca_cert(kenc_cert, kenc_certlen, cacert, cacertlen, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1) { error_print(); return -1; } } + if (x509_cert_verify_by_ca_cert(cert, certlen, cacert, cacertlen, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1) { error_print(); @@ -1700,7 +1777,6 @@ int x509_certs_verify_tlcp(const uint8_t *certs, size_t certslen, return 1; } - int x509_certs_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen) { const uint8_t *p;