From fb58da67e854f4d7adcfe4989bb43cc1b2354ded Mon Sep 17 00:00:00 2001 From: Zhi Guan Date: Sun, 7 Jun 2026 00:00:53 +0800 Subject: [PATCH] Add OCSP --- CMakeLists.txt | 2 + include/gmssl/ocsp.h | 171 ++++++++++++++++++++ include/gmssl/x509_key.h | 2 + src/ocsp.c | 339 +++++++++++++++++++++++++++++++++++++++ src/x509_alg.c | 13 +- src/x509_key.c | 25 ++- tests/ocsptest.c | 248 ++++++++++++++++++++++++++++ 7 files changed, 792 insertions(+), 8 deletions(-) create mode 100644 include/gmssl/ocsp.h create mode 100644 src/ocsp.c create mode 100644 tests/ocsptest.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c98271e..d57378cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,6 +118,7 @@ set(src src/x509_req.c src/x509_crl.c src/x509_new.c + src/ocsp.c src/x509_key.c src/rsa.c src/file.c @@ -184,6 +185,7 @@ set(tests x509_req x509_crl x509_key + ocsp ) diff --git a/include/gmssl/ocsp.h b/include/gmssl/ocsp.h new file mode 100644 index 00000000..bc2d86c0 --- /dev/null +++ b/include/gmssl/ocsp.h @@ -0,0 +1,171 @@ +/* + * Copyright 2014-2026 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. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + +#ifndef GMSSL_OCSP_H +#define GMSSL_OCSP_H + + +#include +#include +#include +#include +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +CertID ::= SEQUENCE { + hashAlgorithm AlgorithmIdentifier, + issuerNameHash OCTET STRING, + issuerKeyHash OCTET STRING, + serialNumber CertificateSerialNumber } + +Request ::= SEQUENCE { + reqCert CertID, + singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL } +*/ +int ocsp_request_item_to_der(int hash_algor, + const uint8_t *issuer_name_hash, size_t issuer_name_hash_len, + const uint8_t *issuer_key_hash, size_t issuer_key_hash_len, + const uint8_t *serial_number, size_t serial_number_len, + const uint8_t *single_request_exts, size_t single_request_exts_len, + uint8_t **out, size_t *outlen); +int ocsp_request_item_from_der(int *hash_algor, + const uint8_t **issuer_name_hash, size_t *issuer_name_hash_len, + const uint8_t **issuer_key_hash, size_t *issuer_key_hash_len, + const uint8_t **serial_number, size_t *serial_number_len, + const uint8_t **single_request_exts, size_t *single_request_exts_len, + const uint8_t **in, size_t *inlen); +int ocsp_request_item_print(FILE *fp, int fmt, int ind, const char *label, + const uint8_t *d, size_t dlen); + +/* +TBSRequest ::= SEQUENCE { + version [0] EXPLICIT Version DEFAULT v1, + requestorName [1] EXPLICIT GeneralName OPTIONAL, + requestList SEQUENCE OF Request, + requestExtensions [2] EXPLICIT Extensions OPTIONAL } + +Signature ::= SEQUENCE { + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING, + certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + +OCSPRequest ::= SEQUENCE { + tbsRequest TBSRequest, + optionalSignature [0] EXPLICIT Signature OPTIONAL } +*/ +int ocsp_request_to_der(int version, + const uint8_t *requestor_name, size_t requestor_name_len, + const uint8_t *request_list, size_t request_list_len, + const uint8_t *request_exts, size_t request_exts_len, + const uint8_t *optional_signature, size_t optional_signature_len, + uint8_t **out, size_t *outlen); +int ocsp_request_from_der(int *version, + const uint8_t **requestor_name, size_t *requestor_name_len, + const uint8_t **request_list, size_t *request_list_len, + const uint8_t **request_exts, size_t *request_exts_len, + const uint8_t **optional_signature, size_t *optional_signature_len, + const uint8_t **in, size_t *inlen); +int ocsp_request_print(FILE *fp, int fmt, int ind, const char *label, + const uint8_t *d, size_t dlen); +int ocsp_request_generate(uint8_t *req, size_t *reqlen, size_t maxlen, + const uint8_t *cert, size_t certlen, + const uint8_t *issuer_cert, size_t issuer_certlen, + const DIGEST *digest); + +/* + +OCSPResponse ::= SEQUENCE { + responseStatus OCSPResponseStatus, + responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } + +OCSPResponseStatus ::= ENUMERATED { + successful (0), + malformedRequest (1), + internalError (2), + tryLater (3), + sigRequired (5), + unauthorized (6) } + +ResponseBytes ::= SEQUENCE { + responseType OBJECT IDENTIFIER, + response OCTET STRING } + +id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-ad-ocsp 1 } + +BasicOCSPResponse ::= SEQUENCE { + tbsResponseData ResponseData, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING, + certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } + +ResponseData ::= SEQUENCE { + version [0] EXPLICIT Version DEFAULT v1, + responderID ResponderID, + producedAt GeneralizedTime, + responses SEQUENCE OF SingleResponse, + responseExtensions [1] EXPLICIT Extensions OPTIONAL } + +ResponderID ::= CHOICE { + byName [1] Name, + byKey [2] KeyHash } + +KeyHash ::= OCTET STRING + +SingleResponse ::= SEQUENCE { + certID CertID, + certStatus CertStatus, + thisUpdate GeneralizedTime, + nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, + singleExtensions [1] EXPLICIT Extensions OPTIONAL } + +CertStatus ::= CHOICE { + good [0] IMPLICIT NULL, + revoked [1] IMPLICIT RevokedInfo, + unknown [2] IMPLICIT UnknownInfo } + +RevokedInfo ::= SEQUENCE { + revocationTime GeneralizedTime, + revocationReason [0] EXPLICIT CRLReason OPTIONAL } + +UnknownInfo ::= NULL + +ArchiveCutoff ::= GeneralizedTime + +AcceptableResponses ::= SEQUENCE OF OBJECT IDENTIFIER + +ServiceLocator ::= SEQUENCE { + issuer Name, + locator AuthorityInfoAccessSyntax OPTIONAL } + +CrlID ::= SEQUENCE { + crlUrl [0] EXPLICIT IA5String OPTIONAL, + crlNum [1] EXPLICIT INTEGER OPTIONAL, + crlTime [2] EXPLICIT GeneralizedTime OPTIONAL } + +PreferredSignatureAlgorithms ::= SEQUENCE OF PreferredSignatureAlgorithm + +PreferredSignatureAlgorithm ::= SEQUENCE { + sigIdentifier AlgorithmIdentifier, + certIdentifier AlgorithmIdentifier OPTIONAL } +*/ + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/x509_key.h b/include/gmssl/x509_key.h index dc0e16ea..0032e810 100644 --- a/include/gmssl/x509_key.h +++ b/include/gmssl/x509_key.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #ifdef ENABLE_SM9 #include @@ -123,6 +124,7 @@ void x509_key_cleanup(X509_KEY *key); #define X509_PUBLIC_KEY_MAX_SIZE 1184 int x509_public_key_to_bytes(const X509_KEY *key, uint8_t **out, size_t *outlen); int x509_public_key_from_bytes(X509_KEY *key, int algor, int algor_param, const uint8_t **in, size_t *inlen); +int x509_public_key_digest_ex(const X509_KEY *key, const DIGEST *digest_algor, uint8_t *dgst, size_t *dgstlen); int x509_public_key_digest(const X509_KEY *key, uint8_t dgst[32]); int x509_public_key_equ(const X509_KEY *key, const X509_KEY *pub); int x509_public_key_print(FILE *fp, int fmt, int ind, const char *label, const X509_KEY *key); diff --git a/src/ocsp.c b/src/ocsp.c new file mode 100644 index 00000000..3f2851d2 --- /dev/null +++ b/src/ocsp.c @@ -0,0 +1,339 @@ +/* + * Copyright 2014-2026 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. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + + +int ocsp_request_item_to_der(int hash_algor, + const uint8_t *issuer_name_hash, size_t issuer_name_hash_len, + const uint8_t *issuer_key_hash, size_t issuer_key_hash_len, + const uint8_t *serial_number, size_t serial_number_len, + const uint8_t *single_request_exts, size_t single_request_exts_len, + uint8_t **out, size_t *outlen) +{ + size_t cert_id_len = 0; + size_t len = 0; + + if (!issuer_name_hash || !issuer_name_hash_len + || !issuer_key_hash || !issuer_key_hash_len + || !serial_number || !serial_number_len) { + error_print(); + return -1; + } + if (x509_digest_algor_to_der(hash_algor, NULL, &cert_id_len) != 1 + || asn1_octet_string_to_der(issuer_name_hash, issuer_name_hash_len, NULL, &cert_id_len) != 1 + || asn1_octet_string_to_der(issuer_key_hash, issuer_key_hash_len, NULL, &cert_id_len) != 1 + || asn1_integer_to_der(serial_number, serial_number_len, NULL, &cert_id_len) != 1) { + error_print(); + return -1; + } + len = cert_id_len; + if (asn1_sequence_header_to_der(cert_id_len, NULL, &len) != 1 + || x509_explicit_exts_to_der(0, single_request_exts, single_request_exts_len, NULL, &len) < 0 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_sequence_header_to_der(cert_id_len, out, outlen) != 1 + || x509_digest_algor_to_der(hash_algor, out, outlen) != 1 + || asn1_octet_string_to_der(issuer_name_hash, issuer_name_hash_len, out, outlen) != 1 + || asn1_octet_string_to_der(issuer_key_hash, issuer_key_hash_len, out, outlen) != 1 + || asn1_integer_to_der(serial_number, serial_number_len, out, outlen) != 1 + || x509_explicit_exts_to_der(0, single_request_exts, single_request_exts_len, out, outlen) < 0) { + error_print(); + return -1; + } + return 1; +} + +int ocsp_request_item_from_der(int *hash_algor, + const uint8_t **issuer_name_hash, size_t *issuer_name_hash_len, + const uint8_t **issuer_key_hash, size_t *issuer_key_hash_len, + const uint8_t **serial_number, size_t *serial_number_len, + const uint8_t **single_request_exts, size_t *single_request_exts_len, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + size_t dlen; + const uint8_t *cert_id; + size_t cert_id_len; + + if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_sequence_from_der(&cert_id, &cert_id_len, &d, &dlen) != 1 + || x509_digest_algor_from_der(hash_algor, &cert_id, &cert_id_len) != 1 + || asn1_octet_string_from_der(issuer_name_hash, issuer_name_hash_len, &cert_id, &cert_id_len) != 1 + || asn1_octet_string_from_der(issuer_key_hash, issuer_key_hash_len, &cert_id, &cert_id_len) != 1 + || asn1_integer_from_der(serial_number, serial_number_len, &cert_id, &cert_id_len) != 1 + || asn1_length_is_zero(cert_id_len) != 1 + || x509_explicit_exts_from_der(0, single_request_exts, single_request_exts_len, &d, &dlen) < 0 + || asn1_length_is_zero(dlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int ocsp_request_item_print(FILE *fp, int fmt, int ind, const char *label, + const uint8_t *d, size_t dlen) +{ + const uint8_t *seq; + size_t seq_len; + const uint8_t *p; + size_t len; + const uint8_t *cert_id; + size_t cert_id_len; + int hash_algor; + const uint8_t *issuer_name_hash; + size_t issuer_name_hash_len; + const uint8_t *issuer_key_hash; + size_t issuer_key_hash_len; + const uint8_t *serial; + size_t serial_len; + + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + + if (asn1_sequence_from_der(&seq, &seq_len, &d, &dlen) != 1) goto err; + format_print(fp, fmt, ind, "reqCert\n"); + if (asn1_sequence_from_der(&cert_id, &cert_id_len, &seq, &seq_len) != 1) goto err; + if (x509_digest_algor_from_der(&hash_algor, &cert_id, &cert_id_len) != 1) goto err; + if (asn1_octet_string_from_der(&issuer_name_hash, &issuer_name_hash_len, &cert_id, &cert_id_len) != 1) goto err; + if (asn1_octet_string_from_der(&issuer_key_hash, &issuer_key_hash_len, &cert_id, &cert_id_len) != 1) goto err; + if (asn1_integer_from_der(&serial, &serial_len, &cert_id, &cert_id_len) != 1) goto err; + format_print(fp, fmt, ind + 4, "hashAlgorithm: %s\n", x509_digest_algor_name(hash_algor)); + format_bytes(fp, fmt, ind + 4, "issuerNameHash", issuer_name_hash, issuer_name_hash_len); + format_bytes(fp, fmt, ind + 4, "issuerKeyHash", issuer_key_hash, issuer_key_hash_len); + format_bytes(fp, fmt, ind + 4, "serialNumber", serial, serial_len); + if (asn1_length_is_zero(cert_id_len) != 1) goto err; + if (x509_explicit_exts_from_der(0, &p, &len, &seq, &seq_len) < 0) goto err; + if (p) x509_exts_print(fp, fmt, ind, "singleRequestExtensions", p, len); + if (asn1_length_is_zero(seq_len) != 1) goto err; + if (asn1_length_is_zero(dlen) != 1) goto err; + return 1; +err: + error_print(); + return -1; +} + +int ocsp_request_to_der(int version, + const uint8_t *requestor_name, size_t requestor_name_len, + const uint8_t *request_list, size_t request_list_len, + const uint8_t *request_exts, size_t request_exts_len, + const uint8_t *optional_signature, size_t optional_signature_len, + uint8_t **out, size_t *outlen) +{ + size_t tbs_request_len = 0; + size_t len = 0; + + if (!request_list || !request_list_len) { + error_print(); + return -1; + } + if ((version >= 0 && x509_explicit_version_to_der(0, version, NULL, &tbs_request_len) != 1) + || asn1_explicit_to_der(1, requestor_name, requestor_name_len, NULL, &tbs_request_len) < 0 + || asn1_sequence_to_der(request_list, request_list_len, NULL, &tbs_request_len) != 1 + || x509_explicit_exts_to_der(2, request_exts, request_exts_len, NULL, &tbs_request_len) < 0) { + error_print(); + return -1; + } + len = tbs_request_len; + if (asn1_sequence_header_to_der(tbs_request_len, NULL, &len) != 1 + || asn1_explicit_to_der(0, optional_signature, optional_signature_len, NULL, &len) < 0 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_sequence_header_to_der(tbs_request_len, out, outlen) != 1 + || (version >= 0 && x509_explicit_version_to_der(0, version, out, outlen) != 1) + || asn1_explicit_to_der(1, requestor_name, requestor_name_len, out, outlen) < 0 + || asn1_sequence_to_der(request_list, request_list_len, out, outlen) != 1 + || x509_explicit_exts_to_der(2, request_exts, request_exts_len, out, outlen) < 0 + || asn1_explicit_to_der(0, optional_signature, optional_signature_len, out, outlen) < 0) { + error_print(); + return -1; + } + return 1; +} + +int ocsp_request_from_der(int *version, + const uint8_t **requestor_name, size_t *requestor_name_len, + const uint8_t **request_list, size_t *request_list_len, + const uint8_t **request_exts, size_t *request_exts_len, + const uint8_t **optional_signature, size_t *optional_signature_len, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + size_t dlen; + const uint8_t *tbs_request; + size_t tbs_request_len; + + if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + *version = X509_version_v1; + if (asn1_sequence_from_der(&tbs_request, &tbs_request_len, &d, &dlen) != 1 + || x509_explicit_version_from_der(0, version, &tbs_request, &tbs_request_len) < 0 + || asn1_explicit_from_der(1, requestor_name, requestor_name_len, &tbs_request, &tbs_request_len) < 0 + || asn1_sequence_from_der(request_list, request_list_len, &tbs_request, &tbs_request_len) != 1 + || x509_explicit_exts_from_der(2, request_exts, request_exts_len, &tbs_request, &tbs_request_len) < 0 + || asn1_length_is_zero(tbs_request_len) != 1 + || asn1_explicit_from_der(0, optional_signature, optional_signature_len, &d, &dlen) < 0 + || asn1_length_is_zero(dlen) != 1) { + error_print(); + return -1; + } + if (*version == -1) { + *version = X509_version_v1; + } + if (*version != X509_version_v1) { + error_print(); + return -1; + } + return 1; +} + +int ocsp_request_print(FILE *fp, int fmt, int ind, const char *label, + const uint8_t *d, size_t dlen) +{ + const uint8_t *seq; + size_t seq_len; + const uint8_t *p; + size_t len; + const uint8_t *tbs_request; + size_t tbs_request_len; + const uint8_t *request_list; + size_t request_list_len; + int ret; + int version = X509_version_v1; + + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + + if (asn1_sequence_from_der(&seq, &seq_len, &d, &dlen) != 1) goto err; + if (asn1_sequence_from_der(&tbs_request, &tbs_request_len, &seq, &seq_len) != 1) goto err; + format_print(fp, fmt, ind, "tbsRequest\n"); + ind += 4; + if ((ret = x509_explicit_version_from_der(0, &version, &tbs_request, &tbs_request_len)) < 0) goto err; + if (version == -1) version = X509_version_v1; + if (ret) format_print(fp, fmt, ind, "version: v1 (%d)\n", version); + if (version != X509_version_v1) goto err; + if ((ret = asn1_explicit_from_der(1, &p, &len, &tbs_request, &tbs_request_len)) < 0) goto err; + if (ret) format_bytes(fp, fmt, ind, "requestorName", p, len); + if (asn1_sequence_from_der(&request_list, &request_list_len, &tbs_request, &tbs_request_len) != 1) goto err; + format_print(fp, fmt, ind, "requestList\n"); + while (request_list_len) { + const uint8_t *request; + size_t request_len; + if (asn1_any_from_der(&request, &request_len, &request_list, &request_list_len) != 1) goto err; + if (ocsp_request_item_print(fp, fmt, ind + 4, "Request", request, request_len) != 1) goto err; + } + if (x509_explicit_exts_from_der(2, &p, &len, &tbs_request, &tbs_request_len) < 0) goto err; + if (p) x509_exts_print(fp, fmt, ind, "requestExtensions", p, len); + if (asn1_length_is_zero(tbs_request_len) != 1) goto err; + ind -= 4; + if (asn1_explicit_from_der(0, &p, &len, &seq, &seq_len) < 0) goto err; + if (p) format_bytes(fp, fmt, ind, "optionalSignature", p, len); + if (asn1_length_is_zero(seq_len) != 1) goto err; + if (asn1_length_is_zero(dlen) != 1) goto err; + return 1; +err: + error_print(); + return -1; +} + +int ocsp_request_generate(uint8_t *req, size_t *reqlen, size_t maxlen, + const uint8_t *cert, size_t certlen, + const uint8_t *issuer_cert, size_t issuer_certlen, + const DIGEST *digest_algor) +{ + const uint8_t *issuer; + size_t issuer_len; + const uint8_t *issuer_subject; + size_t issuer_subject_len; + const uint8_t *serial; + size_t serial_len; + X509_KEY issuer_public_key; + uint8_t issuer_name[512]; + uint8_t *issuer_name_ptr = issuer_name; + size_t issuer_name_len = 0; + uint8_t issuer_name_hash[DIGEST_MAX_SIZE]; + size_t issuer_name_hash_len; + uint8_t issuer_key_hash[DIGEST_MAX_SIZE]; + size_t issuer_key_hash_len; + uint8_t request_list[256]; + uint8_t *request_list_ptr = request_list; + size_t request_list_len = 0; + uint8_t *out; + size_t outlen = 0; + size_t len = 0; + + if (!req || !reqlen || !digest_algor + || !cert || !certlen || !issuer_cert || !issuer_certlen) { + error_print(); + return -1; + } + out = req; + + if (x509_cert_get_issuer_and_serial_number(cert, certlen, &issuer, &issuer_len, &serial, &serial_len) != 1 + || x509_cert_get_subject(issuer_cert, issuer_certlen, &issuer_subject, &issuer_subject_len) != 1 + || x509_cert_get_subject_public_key(issuer_cert, issuer_certlen, &issuer_public_key) != 1 + || x509_name_equ(issuer, issuer_len, issuer_subject, issuer_subject_len) != 1) { + error_print(); + return -1; + } + + // issuer_name_hash + if (asn1_sequence_to_der(issuer_subject, issuer_subject_len, NULL, &len) != 1 + || asn1_length_le(len, sizeof(issuer_name)) != 1 + || asn1_sequence_to_der(issuer_subject, issuer_subject_len, &issuer_name_ptr, &issuer_name_len) != 1 + || digest(digest_algor, issuer_name, issuer_name_len, issuer_name_hash, &issuer_name_hash_len) != 1) { + error_print(); + return -1; + } + len = 0; + + // issuer_key_hash + if (x509_public_key_digest_ex(&issuer_public_key, digest_algor, issuer_key_hash, &issuer_key_hash_len) != 1) { + error_print(); + return -1; + } + + // request_list + if (ocsp_request_item_to_der(digest_algor->oid, + issuer_name_hash, issuer_name_hash_len, + issuer_key_hash, issuer_key_hash_len, + serial, serial_len, NULL, 0, NULL, &len) != 1 + || asn1_length_le(len, sizeof(request_list)) != 1 + || ocsp_request_item_to_der(digest_algor->oid, + issuer_name_hash, issuer_name_hash_len, + issuer_key_hash, issuer_key_hash_len, + serial, serial_len, NULL, 0, &request_list_ptr, &request_list_len) != 1) { + error_print(); + return -1; + } + len = 0; + + if (ocsp_request_to_der(-1, NULL, 0, request_list, request_list_len, NULL, 0, NULL, 0, NULL, &len) != 1 + || asn1_length_le(len, maxlen) != 1 + || ocsp_request_to_der(-1, NULL, 0, request_list, request_list_len, NULL, 0, NULL, 0, &out, &outlen) != 1) { + error_print(); + return -1; + } + + *reqlen = outlen; + return 1; +} diff --git a/src/x509_alg.c b/src/x509_alg.c index 06fbae67..c8145fbc 100644 --- a/src/x509_alg.c +++ b/src/x509_alg.c @@ -114,11 +114,20 @@ int x509_digest_algor_from_der(int *oid, const uint8_t **in, size_t *inlen) if (ret < 0) error_print(); return ret; } - if ((ret = asn1_oid_info_from_der(&info, x509_digest_algors, x509_digest_algors_count, &p, &len)) != 1 - || asn1_length_is_zero(len) != 1) { + if ((ret = asn1_oid_info_from_der(&info, x509_digest_algors, x509_digest_algors_count, &p, &len)) != 1) { error_print(); return ret; } + if (len) { + if (asn1_null_from_der(&p, &len) != 1) { + error_print(); + return -1; + } + if (asn1_length_is_zero(len) != 1) { + error_print(); + return -1; + } + } *oid = info->oid; return 1; } diff --git a/src/x509_key.c b/src/x509_key.c index 139ad15a..ad4e76e9 100644 --- a/src/x509_key.c +++ b/src/x509_key.c @@ -593,20 +593,33 @@ int x509_public_key_from_bytes(X509_KEY *key, int algor, int algor_param, const return 1; } -int x509_public_key_digest(const X509_KEY *key, uint8_t dgst[32]) +int x509_public_key_digest_ex(const X509_KEY *key, const DIGEST *digest_algor, uint8_t *dgst, size_t *dgstlen) { - SM3_CTX ctx; uint8_t bits[X509_PUBLIC_KEY_MAX_SIZE]; uint8_t *p = bits; size_t len = 0; - if (x509_public_key_to_bytes(key, &p, &len) != 1) { + if (!digest_algor || !dgst || !dgstlen) { + error_print(); + return -1; + } + if (x509_public_key_to_bytes(key, &p, &len) != 1 + || digest(digest_algor, bits, len, dgst, dgstlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_public_key_digest(const X509_KEY *key, uint8_t dgst[32]) +{ + size_t dgstlen; + + if (x509_public_key_digest_ex(key, DIGEST_sm3(), dgst, &dgstlen) != 1 + || dgstlen != 32) { error_print(); return -1; } - sm3_init(&ctx); - sm3_update(&ctx, bits, len); - sm3_finish(&ctx, dgst); return 1; } diff --git a/tests/ocsptest.c b/tests/ocsptest.c new file mode 100644 index 00000000..000f400a --- /dev/null +++ b/tests/ocsptest.c @@ -0,0 +1,248 @@ +/* + * Copyright 2014-2026 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. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + +#include +#include +#include +#include +#include +#include +#include + + +static uint8_t issuer_name_hash[32] = { + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, + 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, + 0x00, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, + 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, +}; + +static uint8_t issuer_key_hash[32] = { + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe, + 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01, +}; + +static uint8_t serial_number[] = { 0x05 }; + +static int test_ocsp_request_item(void) +{ + uint8_t buf[128]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + int hash_algor; + const uint8_t *name_hash; + size_t name_hash_len; + const uint8_t *key_hash; + size_t key_hash_len; + const uint8_t *serial; + size_t serial_len; + const uint8_t *single_request_exts; + size_t single_request_exts_len; + + if (ocsp_request_item_to_der(OID_sm3, + issuer_name_hash, sizeof(issuer_name_hash), + issuer_key_hash, sizeof(issuer_key_hash), + serial_number, sizeof(serial_number), NULL, 0, &p, &len) != 1) { + error_print(); + return -1; + } + ocsp_request_item_print(stderr, 0, 0, "Request", buf, len); + + if (ocsp_request_item_from_der(&hash_algor, + &name_hash, &name_hash_len, + &key_hash, &key_hash_len, + &serial, &serial_len, + &single_request_exts, &single_request_exts_len, &cp, &len) != 1 + || asn1_length_is_zero(len) != 1 + || hash_algor != OID_sm3 + || name_hash_len != sizeof(issuer_name_hash) + || memcmp(name_hash, issuer_name_hash, sizeof(issuer_name_hash)) != 0 + || key_hash_len != sizeof(issuer_key_hash) + || memcmp(key_hash, issuer_key_hash, sizeof(issuer_key_hash)) != 0 + || serial_len != sizeof(serial_number) + || memcmp(serial, serial_number, sizeof(serial_number)) != 0 + || single_request_exts != NULL + || single_request_exts_len != 0) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_ocsp_request(void) +{ + uint8_t request_item[128]; + uint8_t *p = request_item; + size_t request_item_len = 0; + uint8_t req[256]; + const uint8_t *cp = req; + size_t reqlen = 0; + int version; + const uint8_t *requestor_name; + size_t requestor_name_len; + const uint8_t *request_list; + size_t request_list_len; + const uint8_t *request_exts; + size_t request_exts_len; + const uint8_t *optional_signature; + size_t optional_signature_len; + const uint8_t *request; + size_t request_len; + int hash_algor; + const uint8_t *name_hash; + size_t name_hash_len; + const uint8_t *key_hash; + size_t key_hash_len; + const uint8_t *serial; + size_t serial_len; + const uint8_t *single_request_exts; + size_t single_request_exts_len; + + if (ocsp_request_item_to_der(OID_sm3, + issuer_name_hash, sizeof(issuer_name_hash), + issuer_key_hash, sizeof(issuer_key_hash), + serial_number, sizeof(serial_number), NULL, 0, + &p, &request_item_len) != 1) { + error_print(); + return -1; + } + p = req; + if (ocsp_request_to_der(-1, NULL, 0, request_item, request_item_len, + NULL, 0, NULL, 0, &p, &reqlen) != 1) { + error_print(); + return -1; + } + ocsp_request_print(stderr, 0, 0, "OCSPRequest", req, reqlen); + + if (ocsp_request_from_der(&version, + &requestor_name, &requestor_name_len, + &request_list, &request_list_len, + &request_exts, &request_exts_len, + &optional_signature, &optional_signature_len, + &cp, &reqlen) != 1 + || asn1_length_is_zero(reqlen) != 1 + || version != X509_version_v1 + || requestor_name != NULL + || requestor_name_len != 0 + || request_exts != NULL + || request_exts_len != 0 + || optional_signature != NULL + || optional_signature_len != 0) { + error_print(); + return -1; + } + cp = request_list; + reqlen = request_list_len; + if (asn1_any_from_der(&request, &request_len, &cp, &reqlen) != 1 + || asn1_length_is_zero(reqlen) != 1) { + error_print(); + return -1; + } + cp = request; + reqlen = request_len; + if (ocsp_request_item_from_der(&hash_algor, + &name_hash, &name_hash_len, + &key_hash, &key_hash_len, + &serial, &serial_len, + &single_request_exts, &single_request_exts_len, &cp, &reqlen) != 1 + || asn1_length_is_zero(reqlen) != 1 + || hash_algor != OID_sm3 + || name_hash_len != sizeof(issuer_name_hash) + || memcmp(name_hash, issuer_name_hash, sizeof(issuer_name_hash)) != 0 + || key_hash_len != sizeof(issuer_key_hash) + || memcmp(key_hash, issuer_key_hash, sizeof(issuer_key_hash)) != 0 + || serial_len != sizeof(serial_number) + || memcmp(serial, serial_number, sizeof(serial_number)) != 0 + || single_request_exts != NULL + || single_request_exts_len != 0) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +#ifdef ENABLE_SHA1 +/* + * Extracted from BoringSSL pki/testdata/ocsp_unittest/good_response_sha256.pem, + * the embedded "OCSP REQUEST" block. + */ +static uint8_t ocsp_request_der[] = { + 0x30, 0x42, 0x30, 0x40, 0x30, 0x3e, 0x30, 0x3c, + 0x30, 0x3a, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, + 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x44, + 0x9b, 0x1c, 0x5b, 0x31, 0xc6, 0xe9, 0x99, 0x09, + 0x66, 0x52, 0x3e, 0x49, 0xc3, 0xf7, 0x73, 0xc0, + 0x24, 0x19, 0x0a, 0x04, 0x14, 0x34, 0x5c, 0xb2, + 0x8b, 0x1d, 0x8c, 0xdd, 0x6c, 0xbf, 0xf8, 0xf5, + 0xcc, 0xf4, 0x65, 0x21, 0xe8, 0x7a, 0x8d, 0xf3, + 0x91, 0x02, 0x01, 0x05, +}; + +static int test_ocsp_request_vector(void) +{ + const uint8_t *cp = ocsp_request_der; + size_t len = sizeof(ocsp_request_der); + int version; + const uint8_t *requestor_name; + size_t requestor_name_len; + const uint8_t *request_list; + size_t request_list_len; + const uint8_t *request_exts; + size_t request_exts_len; + const uint8_t *optional_signature; + size_t optional_signature_len; + + ocsp_request_print(stderr, 0, 0, "OCSPRequest", ocsp_request_der, sizeof(ocsp_request_der)); + + if (ocsp_request_from_der(&version, + &requestor_name, &requestor_name_len, + &request_list, &request_list_len, + &request_exts, &request_exts_len, + &optional_signature, &optional_signature_len, + &cp, &len) != 1 + || asn1_length_is_zero(len) != 1 + || version != X509_version_v1 + || requestor_name != NULL + || requestor_name_len != 0 + || request_list == NULL + || request_list_len == 0 + || request_exts != NULL + || request_exts_len != 0 + || optional_signature != NULL + || optional_signature_len != 0) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} +#endif + +int main(void) +{ + if (test_ocsp_request_item() != 1) goto err; + if (test_ocsp_request() != 1) goto err; +#ifdef ENABLE_SHA1 + if (test_ocsp_request_vector() != 1) goto err; +#endif + printf("%s all tests passed\n", __FILE__); + return 0; +err: + error_print(); + return -1; +}