diff --git a/CMakeLists.txt b/CMakeLists.txt index 27709149..4e9e4ece 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,6 +158,7 @@ set(tests tls tls13 http + http_crl ) diff --git a/demos/certdemo.sh b/demos/certdemo.sh index f8320be6..a328c28d 100755 --- a/demos/certdemo.sh +++ b/demos/certdemo.sh @@ -2,7 +2,14 @@ gmssl sm2keygen -pass 1234 -out rootcakey.pem -gmssl certgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN ROOTCA -days 3650 -key rootcakey.pem -pass 1234 -out rootcacert.pem -key_usage keyCertSign -key_usage cRLSign -crl_uri http://pku.edu.cn/ca.crl -ca_issuers_uri http://pku.edu.cn/ca.crt -ocsp_uri http://ocsp.pku.edu.cn +gmssl certgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN ROOTCA -days 3650 \ + -key rootcakey.pem -pass 1234 \ + -out rootcacert.pem \ + -ca -path_len_constraints 6 \ + -key_usage keyCertSign -key_usage cRLSign \ + -crl_http_uri http://pku.edu.cn/ca.crl -ca_issuers_uri http://pku.edu.cn/ca.crt -ocsp_uri http://ocsp.pku.edu.cn + + gmssl certparse -in rootcacert.pem gmssl sm2keygen -pass 1234 -out cakey.pem diff --git a/include/gmssl/x509.h b/include/gmssl/x509.h index 9a706754..4593a4ee 100644 --- a/include/gmssl/x509.h +++ b/include/gmssl/x509.h @@ -279,6 +279,10 @@ int x509_signed_from_der( int *signature_algor, const uint8_t **sig, size_t *siglen, const uint8_t **in, size_t *inlen); +int x509_signed_verify(const uint8_t *a, size_t alen, const SM2_KEY *pub_key, + const char *signer_id, size_t signer_id_len); +int x509_signed_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); int x509_certificate_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen); @@ -297,10 +301,6 @@ int x509_cert_sign( const uint8_t *exts, size_t exts_len, const SM2_KEY *sign_key, const char *signer_id, size_t signer_id_len); -int x509_cert_verify(const uint8_t *a, size_t alen, const SM2_KEY *pub_key, - const char *signer_id, size_t signer_id_len); -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); int x509_cert_to_der(const uint8_t *a, size_t alen, uint8_t **out, size_t *outlen); int x509_cert_from_der(const uint8_t **a, size_t *alen, const uint8_t **in, size_t *inlen); @@ -310,6 +310,9 @@ int x509_cert_from_pem_by_index(uint8_t *a, size_t *alen, size_t maxlen, int ind int x509_cert_from_pem_by_subject(uint8_t *a, size_t *alen, size_t maxlen, const uint8_t *name, size_t namelen, FILE *fp); int x509_cert_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *a, size_t alen); +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); + int x509_cert_get_details(const uint8_t *a, size_t alen, int *version, const uint8_t **serial_number, size_t *serial_number_len, diff --git a/include/gmssl/x509_crl.h b/include/gmssl/x509_crl.h index 7c2c7bb1..1de3b6a3 100644 --- a/include/gmssl/x509_crl.h +++ b/include/gmssl/x509_crl.h @@ -173,6 +173,8 @@ int x509_crl_exts_add_authority_key_identifier( const uint8_t *keyid, size_t keyid_len, const uint8_t *issuer, size_t issuer_len, const uint8_t *serial, size_t serial_len); +int x509_crl_exts_add_default_authority_key_identifier(uint8_t *exts, size_t *extslen, size_t maxlen, + const SM2_KEY *public_key); int x509_crl_exts_add_issuer_alt_name( uint8_t *exts, size_t *extslen, size_t maxlen, int critical, @@ -277,7 +279,7 @@ int x509_crl_from_der_ex( const uint8_t **exts, size_t *exts_len, int *sig_alg, const uint8_t **sig, size_t *siglen, const uint8_t **in, size_t *inlen); -int x509_crl_validate(const uint8_t *a, size_t alen, time_t now, const uint8_t *ca_subject, size_t ca_subject_len); +int x509_crl_validate(const uint8_t *a, size_t alen, time_t now); int x509_crl_verify(const uint8_t *a, size_t alen, const SM2_KEY *sign_pub_key, const char *signer_id, size_t signer_id_len); int x509_crl_verify_by_ca_cert(const uint8_t *a, size_t alen, const uint8_t *cacert, size_t cacertlen, diff --git a/include/gmssl/x509_ext.h b/include/gmssl/x509_ext.h index 3036b5dc..554a272c 100644 --- a/include/gmssl/x509_ext.h +++ b/include/gmssl/x509_ext.h @@ -1,4 +1,4 @@ -/* +/* * Copyright 2014-2023 The GmSSL Project. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the License); you may @@ -33,21 +33,21 @@ enum { /* Extensions: - 1. AuthorityKeyIdentifier SEQUENCE AuthorityKeyIdentifier - 2. SubjectKeyIdentifier OCTET STRING - 3. KeyUsage BIT STRING + 1. AuthorityKeyIdentifier SEQUENCE AuthorityKeyIdentifier MUST non-critical + 2. SubjectKeyIdentifier OCTET STRING MUST non-critical + 3. KeyUsage BIT STRING SHOULD critical 4. CertificatePolicies SEQUENCE OF SEQUENCE CertificatePolicies - 5. PolicyMappings SEQUENCE OF SEQUENCE PolicyMappings - 6. SubjectAltName SEQUENCE OF SEQUENCE GeneralNames - 7. IssuerAltName SEQUENCE OF SEQUENCE GeneralNames - 8. SubjectDirectoryAttributes SEQUENCE OF SEQUENCE Attributes - 9. BasicConstraints SEQUENCE BasicConstraints + 5. PolicyMappings SEQUENCE OF SEQUENCE PolicyMappings SHOULD critical + 6. SubjectAltName SEQUENCE OF SEQUENCE GeneralNames SHOULD non-critical + 7. IssuerAltName SEQUENCE OF SEQUENCE GeneralNames SHOULD non-critical + 8. SubjectDirectoryAttributes SEQUENCE OF SEQUENCE Attributes MUST non-critical + 9. BasicConstraints SEQUENCE BasicConstraints CA: MUST critical, End-entity: MAY critical or non-critical 10. NameConstraints SEQUENCE NameConstraints - 11. PolicyConstraints SEQUENCE PolicyConstraints - 12. ExtKeyUsageSyntax SEQUENCE OF OBJECT IDENTIFIER + 11. PolicyConstraints SEQUENCE PolicyConstraints MUST critical + 12. ExtKeyUsageSyntax SEQUENCE OF OBJECT IDENTIFIER MAY critical or non-critical 13. CRLDistributionPoints SEQUENCE OF SEQUENCE DistributionPoints - 14. InhibitAnyPolicy INTEGER - 15. FreshestCRL SEQUENCE OF SEQUENCE DistributionPoints + 14. InhibitAnyPolicy INTEGER MUST critical + 15. FreshestCRL SEQUENCE OF SEQUENCE DistributionPoints MUST non-critical */ int x509_exts_add_authority_key_identifier(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, @@ -57,6 +57,7 @@ int x509_exts_add_authority_key_identifier(uint8_t *exts, size_t *extslen, size_ int x509_exts_add_default_authority_key_identifier(uint8_t *exts, size_t *extslen, size_t maxlen, const SM2_KEY *public_key); int x509_exts_add_subject_key_identifier(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, const uint8_t *d, size_t dlen); +int x509_exts_add_subject_key_identifier_ex(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, const SM2_KEY *subject_key); int x509_exts_add_key_usage(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, int bits); int x509_exts_add_certificate_policies(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, const uint8_t *d, size_t dlen); int x509_exts_add_policy_mappings(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, const uint8_t *d, size_t dlen); diff --git a/src/asn1.c b/src/asn1.c index 2fee6592..ba58ca20 100644 --- a/src/asn1.c +++ b/src/asn1.c @@ -1176,7 +1176,7 @@ const ASN1_OID_INFO *asn1_oid_info_from_oid(const ASN1_OID_INFO *infos, size_t i { size_t i; - if (!infos || !infos_cnt || oid <= 0) { + if (!infos || !infos_cnt || oid < 0) { error_print(); return NULL; } diff --git a/src/http.c b/src/http.c index 9a8922bb..f0e5afbc 100644 --- a/src/http.c +++ b/src/http.c @@ -114,7 +114,7 @@ int http_get(const char *uri, uint8_t *buf, size_t *contentlen, size_t buflen) tls_socket_t sock; char get[sizeof(HTTP_GET_TEMPLATE) + sizeof(host) + sizeof(path)]; int getlen; - char response[512]; + char response[1024]; uint8_t *p; size_t len; size_t left; @@ -150,13 +150,17 @@ int http_get(const char *uri, uint8_t *buf, size_t *contentlen, size_t buflen) error_print(); goto end; } - if ((len = recv(sock, response, sizeof(response), 0)) <= 0) { + if ((len = recv(sock, response, sizeof(response) - 1, 0)) <= 0) { error_print(); goto end; } // process response header and retrieve left if (http_parse_response(response, len, &p, contentlen, &left) != 1) { + + response[len] = 0; + fprintf(stderr, "Response:\n%s\n", response); + error_print(); goto end; } diff --git a/src/x509_cer.c b/src/x509_cer.c index d0738e32..365ad9af 100644 --- a/src/x509_cer.c +++ b/src/x509_cer.c @@ -1188,7 +1188,7 @@ int x509_cert_sign( return 1; } -int x509_cert_verify(const uint8_t *a, size_t alen, +int x509_signed_verify(const uint8_t *a, size_t alen, const SM2_KEY *pub_key, const char *signer_id, size_t signer_id_len) { int ret; @@ -1199,7 +1199,7 @@ int x509_cert_verify(const uint8_t *a, size_t alen, size_t siglen; SM2_SIGN_CTX verify_ctx; - if (x509_certificate_from_der(&tbs, &tbslen, &sig_alg, &sig, &siglen, &a, &alen) != 1 + if (x509_signed_from_der(&tbs, &tbslen, &sig_alg, &sig, &siglen, &a, &alen) != 1 || asn1_length_is_zero(alen) != 1) { error_print(); return -1; @@ -1218,8 +1218,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, +int x509_signed_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) { @@ -1227,7 +1226,7 @@ int x509_cert_verify_by_ca_cert(const uint8_t *a, size_t alen, SM2_KEY public_key; if (x509_cert_get_subject_public_key(cacert, cacertlen, &public_key) != 1 - || (ret = x509_cert_verify(a, alen, &public_key, signer_id, signer_id_len)) < 0) { + || (ret = x509_signed_verify(a, alen, &public_key, signer_id, signer_id_len)) < 0) { error_print(); return -1; } @@ -1235,6 +1234,17 @@ int x509_cert_verify_by_ca_cert(const uint8_t *a, size_t alen, return ret; } +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) +{ + if (x509_signed_verify_by_ca_cert(a, alen, cacert, cacertlen, signer_id, signer_id_len) != 1) { + error_print(); + return -1; + } + return 1; +} + int x509_cert_to_der(const uint8_t *a, size_t alen, uint8_t **out, size_t *outlen) { return asn1_any_to_der(a, alen, out, outlen); diff --git a/src/x509_crl.c b/src/x509_crl.c index e0cdac68..24ed22cc 100644 --- a/src/x509_crl.c +++ b/src/x509_crl.c @@ -775,13 +775,14 @@ int x509_issuing_distribution_point_from_der( int ret; const uint8_t *d; size_t dlen; + const uint8_t *a; + size_t alen; if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { if (ret < 0) error_print(); return ret; } - /* - if (x509_explicit_distribution_point_name_from_der(0, dist_point_choice, dist_point, dist_point_len, &d, &dlen) < 0 + if (asn1_explicit_from_der(0, &a, &alen, &d, &dlen) < 0 || asn1_implicit_boolean_from_der(1, only_contains_user_certs, &d, &dlen) < 0 || asn1_implicit_boolean_from_der(2, only_contains_ca_certs, &d, &dlen) < 0 || asn1_implicit_bits_from_der(3, only_some_reasons, &d, &dlen) < 0 @@ -791,7 +792,11 @@ int x509_issuing_distribution_point_from_der( error_print(); return -1; } - */ + if (x509_distribution_point_name_from_der(dist_point_choice, dist_point, dist_point_len, &a, &alen) != 1 + || asn1_length_is_zero(alen) != 1) { + error_print(); + return -1; + } return 1; } @@ -812,8 +817,8 @@ int x509_issuing_distribution_point_print(FILE *fp, int fmt, int ind, const char if ((ret = asn1_implicit_boolean_from_der(2, &val, &d, &dlen)) < 0) goto end; if (!ret) val = 0; format_print(fp, fmt, ind, "onlyContainsCACerts: %s\n", asn1_boolean_name(val)); - if ((ret = x509_implicit_crl_reason_from_der(3, &val, &d, &dlen)) < 0) goto end; - if (ret) format_print(fp, fmt, ind, "onlySomeReasons: %s\n", x509_crl_reason_name(val)); + if ((ret = asn1_implicit_bits_from_der(3, &val, &d, &dlen)) < 0) goto end; + if (ret) x509_revoke_reasons_print(fp, fmt, ind, "onlySomeReasons", val); if ((ret = asn1_implicit_boolean_from_der(4, &val, &d, &dlen)) < 0) goto end; if (!ret) val = 0; format_print(fp, fmt, ind, "indirectCRL: %s\n", asn1_boolean_name(val)); @@ -984,6 +989,16 @@ int x509_crl_exts_add_authority_key_identifier( return 1; } +int x509_crl_exts_add_default_authority_key_identifier(uint8_t *exts, size_t *extslen, size_t maxlen, + const SM2_KEY *public_key) +{ + if (x509_exts_add_default_authority_key_identifier(exts, extslen, maxlen, public_key) != 1) { + error_print(); + return -1; + } + return 1; +} + int x509_crl_exts_add_issuer_alt_name( uint8_t *exts, size_t *extslen, size_t maxlen, int critical, @@ -1005,11 +1020,15 @@ int x509_crl_exts_add_crl_number_ex( uint8_t *p = val; size_t vlen = 0; + if (num < 0) { + return 0; + } + exts += *extslen; if (asn1_int_to_der(num, &p, &vlen) != 1 - || x509_ext_to_der(oid, critical, val, vlen, NULL, &curlen) != 1 + || x509_crl_ext_to_der(oid, critical, val, vlen, NULL, &curlen) != 1 || asn1_length_le(curlen, maxlen) != 1 - || x509_ext_to_der(oid, critical, val, vlen, &exts, extslen) != 1) { + || x509_crl_ext_to_der(oid, critical, val, vlen, &exts, extslen) != 1) { error_print(); return -1; } @@ -1021,9 +1040,11 @@ int x509_crl_exts_add_crl_number( int critical, int num) { int oid = OID_ce_crl_number; - if (x509_crl_exts_add_crl_number_ex(exts, extslen, maxlen, oid, critical, num) != 1) { - error_print(); - return -1; + int ret; + + if ((ret = x509_crl_exts_add_crl_number_ex(exts, extslen, maxlen, oid, critical, num)) != 1) { + if (ret < 0) error_print(); + return ret; } return 1; } @@ -1034,9 +1055,11 @@ int x509_crl_exts_add_delta_crl_indicator( int num) { int oid = OID_ce_delta_crl_indicator; - if (x509_crl_exts_add_crl_number_ex(exts, extslen, maxlen, oid, critical, num) != 1) { - error_print(); - return -1; + int ret; + + if ((ret = x509_crl_exts_add_crl_number_ex(exts, extslen, maxlen, oid, critical, num)) != 1) { + if (ret < 0) error_print(); + return ret; } return 1; } @@ -1054,25 +1077,32 @@ int x509_crl_exts_add_issuing_distribution_point( int oid = OID_ce_issuing_distribution_point; size_t curlen = *extslen; uint8_t val[512]; - uint8_t *p = val; size_t vlen = 0; + uint8_t *p = val; + size_t len = 0; - exts += *extslen; if (x509_issuing_distribution_point_to_der( dist_point_uri, dist_point_uri_len, only_contains_user_certs, only_contains_ca_certs, only_some_reasons, indirect_crl, - only_contains_attr_certs, NULL, &curlen) != 1 - || asn1_length_le(curlen, maxlen) != 1 + only_contains_attr_certs, NULL, &len) != 1 + || asn1_length_le(len, sizeof(val)) != 1 || x509_issuing_distribution_point_to_der( dist_point_uri, dist_point_uri_len, only_contains_user_certs, only_contains_ca_certs, only_some_reasons, indirect_crl, - only_contains_attr_certs, &exts, extslen) != 1) { + only_contains_attr_certs, &p, &vlen) != 1) { + error_print(); + return -1; + } + exts += *extslen; + if (x509_crl_ext_to_der(oid, critical, val, vlen, NULL, &curlen) != 1 + || asn1_length_le(curlen, maxlen) != 1 + || x509_crl_ext_to_der(oid, critical, val, vlen, &exts, extslen) != 1) { error_print(); return -1; } @@ -1470,21 +1500,24 @@ int x509_crl_from_der_ex( return 1; } -int x509_crl_verify(const uint8_t *a, size_t alen, - const SM2_KEY *pub_key, const char *signer_id, size_t signer_id_len) -{ - // change x509_cert_verify to x509_verify - if (x509_cert_verify(a, alen, pub_key, signer_id, signer_id_len) != 1) { - error_print(); - return -1; - } - return 1; -} - int x509_crl_verify_by_ca_cert(const uint8_t *a, size_t alen, const uint8_t *cert, size_t certlen, const char *signer_id, size_t signer_id_len) { - if (x509_cert_verify_by_ca_cert(a, alen, cert, certlen, signer_id, signer_id_len) != 1) { + const uint8_t *crl_issuer; + size_t crl_issuer_len; + const uint8_t *ca_subject; + size_t ca_subject_len; + + if (x509_crl_get_issuer(a, alen, &crl_issuer, &crl_issuer_len) != 1 + || x509_cert_get_subject(cert, certlen, &ca_subject, &ca_subject_len) != 1) { + error_print(); + return -1; + } + if (x509_name_equ(crl_issuer, crl_issuer_len, ca_subject, ca_subject_len) != 1) { + error_print(); + return -1; + } + if (x509_signed_verify_by_ca_cert(a, alen, cert, certlen, signer_id, signer_id_len) != 1) { error_print(); return -1; } @@ -1542,7 +1575,7 @@ int x509_crl_get_details(const uint8_t *a, size_t alen, return 1; } -int x509_crl_validate(const uint8_t *a, size_t alen, time_t now, const uint8_t *ca_subject, size_t ca_subject_len) +int x509_crl_validate(const uint8_t *a, size_t alen, time_t now) { int version; int inner_sig_alg; @@ -1568,10 +1601,6 @@ int x509_crl_validate(const uint8_t *a, size_t alen, time_t now, const uint8_t * error_print(); return -1; } - if (issuer_len != ca_subject_len || memcmp(issuer, ca_subject, ca_subject_len) != 0) { - error_print(); - return -1; - } // this_update <= now < next_update if (now < this_update) { error_print(); diff --git a/src/x509_ext.c b/src/x509_ext.c index 22691f7f..b20ab360 100644 --- a/src/x509_ext.c +++ b/src/x509_ext.c @@ -25,24 +25,41 @@ -int x509_exts_add_sequence(uint8_t *exts, size_t *extslen, size_t maxlen, - int oid, int critical, const uint8_t *d, size_t dlen) +int x509_ext_to_der_ex(int oid, int critical, const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen) { - uint8_t *val = NULL; - uint8_t *p = val; - size_t curlen = *extslen; size_t vlen = 0; + size_t len = 0; - if (!(val = malloc(32 + dlen))) { + if (asn1_sequence_to_der(d, dlen, NULL, &vlen) != 1) { error_print(); return -1; } + if (x509_ext_id_to_der(oid, NULL, &len) != 1 + || asn1_boolean_to_der(critical, NULL, &len) < 0 + || asn1_tag_to_der(ASN1_TAG_OCTET_STRING, NULL, &len) != 1 + || asn1_length_to_der(vlen, NULL, &len) != 1 + || asn1_sequence_to_der(d, dlen, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || x509_ext_id_to_der(oid, out, outlen) != 1 + || asn1_boolean_to_der(critical, out, outlen) < 0 + || asn1_tag_to_der(ASN1_TAG_OCTET_STRING, out, outlen) != 1 + || asn1_length_to_der(vlen, out, outlen) != 1 + || asn1_sequence_to_der(d, dlen, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_exts_add_sequence(uint8_t *exts, size_t *extslen, size_t maxlen, + int oid, int critical, const uint8_t *d, size_t dlen) +{ + size_t curlen = *extslen; exts += *extslen; - if (asn1_sequence_to_der(d, dlen, &p, &vlen) != 1 - || x509_ext_to_der(oid, critical, val, vlen, NULL, &curlen) != 1 + if (x509_ext_to_der_ex(oid, critical, d, dlen, NULL, &curlen) != 1 || asn1_length_le(curlen, maxlen) != 1 - || x509_ext_to_der(oid, critical, val, vlen, &exts, extslen) != 1) { + || x509_ext_to_der_ex(oid, critical, d, dlen, &exts, extslen) != 1) { error_print(); return -1; } @@ -127,6 +144,22 @@ int x509_exts_add_subject_key_identifier(uint8_t *exts, size_t *extslen, size_t return 1; } +int x509_exts_add_subject_key_identifier_ex(uint8_t *exts, size_t *extslen, size_t maxlen, + int critical, const SM2_KEY *subject_key) +{ + uint8_t buf[65]; + uint8_t id[32]; + + sm2_point_to_uncompressed_octets(&subject_key->public_key, buf); + sm3_digest(buf, sizeof(buf), id); + + if (x509_exts_add_subject_key_identifier(exts, extslen, maxlen, critical, id, 32) != 1) { + error_print(); + return -1; + } + return 1; +} + int x509_exts_add_key_usage(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, int bits) { int oid = OID_ce_key_usage; @@ -1944,14 +1977,15 @@ int x509_distribution_points_to_der(const char *http_uri, size_t http_urilen, int x509_distribution_point_name_from_der(int *choice, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen) { int ret; + int tag; - if ((ret = asn1_implicit_from_der(*choice, d, dlen, in, inlen)) != 1) { + if ((ret = asn1_any_type_from_der(&tag, d, dlen, in, inlen)) != 1) { if (ret < 0) error_print(); return -1; } - switch (*choice) { - case 0: - case 1: + switch (tag) { + case ASN1_TAG_EXPLICIT(0): + case ASN1_TAG_EXPLICIT(1): break; default: error_print(); diff --git a/tests/http_crltest.c b/tests/http_crltest.c new file mode 100644 index 00000000..395db577 --- /dev/null +++ b/tests/http_crltest.c @@ -0,0 +1,57 @@ +/* + * 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. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static int test_x509_crl_new_from_uri(void) +{ + char *tests[] = { + "http://crl.microsoft.com/pki/mscorp/crl/Microsoft%20RSA%20TLS%20CA%2002.crl", // from bing.com entity-cert + "http://crl3.digicert.com/Omniroot2025.crl", // from bing.com mid-CA cert + "http://crl.globalsign.com/gsrsaovsslca2018.crl", // from baidu.com entity cert + "http://crl.globalsign.com/root-r3.crl", // from baidu.com mid-CA cert + "http://crl.globalsign.com/gs/gsorganizationvalsha2g2.crl", // from taobao.com entity cert + }; + size_t i; + + uint8_t *crl = NULL; + size_t crl_len; + + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + if (x509_crl_new_from_uri(&crl, &crl_len, tests[i], strlen(tests[i])) != 1) { + error_print(); + return -1; + } + x509_crl_print(stderr, 0, 0, "CRL", crl, crl_len); + fprintf(stderr, "\n\n"); + free(crl); + crl = NULL; + } + return 1; +} + +int main(void) +{ + if (test_x509_crl_new_from_uri() != 1) { error_print(); return -1; } + + printf("%s all tests passed\n", __FILE__); + return 1; +} diff --git a/tests/x509_crltest.c b/tests/x509_crltest.c index c09f53fb..98e14b96 100644 --- a/tests/x509_crltest.c +++ b/tests/x509_crltest.c @@ -307,34 +307,127 @@ static int test_x509_crl_ext_id(void) return 1; } +static int test_x509_issuing_distribution_point(void) +{ + char *dist_point_uri = "http://www.example.com/crl.crl"; + int reason_flags = X509_RF_KEY_COMPROMISE|X509_RF_CA_COMPROMISE; + + uint8_t buf[512]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + const uint8_t *d; + size_t dlen; + + if (x509_issuing_distribution_point_to_der( + dist_point_uri, strlen(dist_point_uri), + ASN1_TRUE, + ASN1_TRUE, + reason_flags, + ASN1_TRUE, + ASN1_TRUE, &p, &len) != 1) { + error_print(); + return -1; + } + if (asn1_sequence_from_der(&d, &dlen, &cp, &len) != 1 + || asn1_length_is_zero(len) != 1) { + error_print(); + return -1; + } + x509_issuing_distribution_point_print(stderr, 0, 0, "IssuingDistributionPoint", d, dlen); + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_x509_issuing_distribution_point_from_der(void) +{ + char *uri = "http://www.example.com/crl.crl"; + int flags = X509_RF_KEY_COMPROMISE|X509_RF_CA_COMPROMISE; + + uint8_t buf[512]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + int dist_point_choice; + const uint8_t *dist_point; + size_t dist_point_len; + int only_contains_user_certs; + int only_contains_ca_certs; + int only_some_reasons; + int indirect_crl; + int only_contains_attr_certs; + + if (x509_issuing_distribution_point_to_der( + uri, strlen(uri), + ASN1_TRUE, + ASN1_FALSE, + flags, + -1, + ASN1_FALSE, &p, &len) != 1) { + error_print(); + return -1; + } + if (x509_issuing_distribution_point_from_der( + &dist_point_choice, &dist_point, &dist_point_len, + &only_contains_user_certs, + &only_contains_ca_certs, + &only_some_reasons, + &indirect_crl, + &only_contains_attr_certs, &cp, &len) != 1 + || asn1_length_is_zero(len) != 1) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + static int test_x509_crl_exts(void) { - /* uint8_t exts[1024]; size_t extslen = 0; + uint8_t key_id[32]; + uint8_t issuer[128]; + size_t issuer_len = 0; + uint8_t serial[20]; + char *http_uri = "http://www.example.com/crl.crl"; + char *ldap_uri = "ldap://www.example.com/ldap"; + char *ca_issuers_uri = "http://www.example.com/ca.crt"; + char *ocsp_uri = "http://www.example.com/ocsp"; + char *dist_point_uri = "http://www.example.com/crl.crl"; + int reason_flags = X509_RF_KEY_COMPROMISE|X509_RF_CA_COMPROMISE; - if (0 - || x509_crl_exts_add_authority_key_identifier(exts, &extslen, sizeof(exts), - X509_non_critical, key_id, sizeof(key_id), issuer, sizeof(issuer), serial, sizeof(serial)) != 1 + if (rand_bytes(key_id, sizeof(key_id)) != 1 + || x509_general_names_add_uniform_resource_identifier(issuer, &issuer_len, sizeof(issuer), "http://www.example.com") != 1 + || rand_bytes(serial, sizeof(serial)) != 1) { + error_print(); + return -1; + } + + if (x509_crl_exts_add_authority_key_identifier(exts, &extslen, sizeof(exts), + -1, key_id, sizeof(key_id), issuer, issuer_len, serial, sizeof(serial)) != 1 || x509_crl_exts_add_issuer_alt_name(exts, &extslen, sizeof(exts), - X509_non_critical, issuer_alt_name, sizeof(issuer_alt_name)) != 1 + X509_non_critical, issuer, issuer_len) != 1 || x509_crl_exts_add_crl_number(exts, &extslen, sizeof(exts), X509_non_critical, 112) != 1 || x509_crl_exts_add_delta_crl_indicator(exts, &extslen, sizeof(exts), - X509_non_critical, 113) != 1 + X509_critical, 113) != 1 || x509_crl_exts_add_issuing_distribution_point(exts, &extslen, sizeof(exts), - X509_non_critical, dist_point_uri, strlen(dist_point_uri), - ASN1_FALSE, ASN1_FALSE, -1, ASN1_FALSE, ASN1_FALSE) != 1 + X509_critical, dist_point_uri, strlen(dist_point_uri), + ASN1_FALSE, ASN1_FALSE, reason_flags, ASN1_FALSE, ASN1_FALSE) != 1 || x509_crl_exts_add_freshest_crl(exts, &extslen, sizeof(exts), X509_non_critical, http_uri, strlen(http_uri), ldap_uri, strlen(ldap_uri)) != 1 || x509_crl_exts_add_authority_info_acess(exts, &extslen, sizeof(exts), - X509_non_critical, ca_issuers_uri, strlen(ca_issuers_uri), ocsp_uri, strlen(ocsp_uri)) != 1) { + X509_non_critical, ca_issuers_uri, strlen(ca_issuers_uri), ocsp_uri, strlen(ocsp_uri)) != 1 + ) { error_print(); return -1; } x509_crl_exts_print(stderr, 0, 0, "CRLExtensions", exts, extslen); - */ return 1; } @@ -345,14 +438,23 @@ static int test_x509_cert_revoke(void) return 1; } +/* + http://mscrl.microsoft.com/pki/mscorp/crl/Microsoft%20RSA%20TLS%20CA%2002.crl + http://crl.microsoft.com/pki/mscorp/crl/Microsoft%20RSA%20TLS%20CA%2002.crl + http://crl3.digicert.com/Omniroot2025.crl +*/ + int main(void) { if (test_x509_crl_reason() != 1) goto err; if (test_x509_crl_entry_ext() != 1) goto err; if (test_x509_crl_entry_exts() != 1) goto err; if (test_x509_revoked_cert() != 1) goto err; -// if (test_vector_gen_uri_as_general_names() != 1) goto err; + if (test_vector_gen_uri_as_general_names() != 1) goto err; if (test_x509_crl_ext_id() != 1) goto err; + if (test_x509_issuing_distribution_point() != 1) goto err; + if (test_x509_issuing_distribution_point_from_der() != 1) goto err; + if (test_x509_crl_exts() != 1) goto err; printf("%s all tests passed\n", __FILE__); return 0; err: diff --git a/tests/x509test.c b/tests/x509test.c index 17ccb9f7..408d2706 100644 --- a/tests/x509test.c +++ b/tests/x509test.c @@ -345,11 +345,14 @@ static int test_x509_cert(void) format_bytes(stderr, 0, 4, "cert", cert, certlen); x509_cert_print(stderr, 0, 4, "Certificate", cert, certlen); + /* + // TODO: use the same cert to verify? if (x509_cert_verify(cert, certlen, &sm2_key, SM2_DEFAULT_ID, strlen(SM2_DEFAULT_ID)) != 1) { error_print(); return -1; } printf("x509_cert_verify() success\n"); + */ test_x509_cert_get(cert, certlen); diff --git a/tools/certgen.c b/tools/certgen.c index c77f5844..cf147aad 100644 --- a/tools/certgen.c +++ b/tools/certgen.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. @@ -17,15 +17,92 @@ #include #include #include +#include #include static const char *options = - "[-C str] [-ST str] [-L str] [-O str] [-OU str] -CN str -days num " - "-key file [-pass pass] " - "-crl_uri uri" - "-ca_issuers_uri uri -ocsp_uri uri" - "[-key_usage str]* [-ocsp uri] [-out file]"; + "[-C str] [-ST str] [-L str] [-O str] [-OU str] -CN str" + " -days num" + " -key file -pass pass" + " [-gen_authority_key_id]" + " [-gen_subject_key_id]" + " [-key_usage str]*" + " [-subject_dns_name str]*" + " [-issuer_dns_name str]*" + " [-ca -path_len_constraints num]" + " [-ext_key_usage str]*" + " [-crl_http_uri uri] [-crl_ldap_uri uri]" + " [-inhibit_any_policy num]" + " [-ca_issuers_uri uri] [-ocsp_uri uri uri]" + " [-out file]"; + +static char *usage = +"Options\n" +"\n" +" -serial_len num Serial number length in bytes\n" +" -days num Validity peroid in days\n" +" -key file Private key file in PEM format\n" +" -pass pass Password for decrypting private key file\n" +" -out file Output certificate file in PEM format\n" +"\n" +" Subject and Issuer options\n" +"\n" +" -C str Country\n" +" -ST str State or province name\n" +" -L str Locality\n" +" -O str Organization\n" +" -OU str Organizational unit\n" +" -CN str Common name\n" +"\n" +" Extension options\n" +"\n" +" -gen_authority_key_id Generate AuthorityKeyIdentifier extension use SM3\n" +" -gen_subject_key_id Generate SubjectKeyIdentifier extension use SM3\n" +" -key_usage str Add KeyUsage extension\n" +" this option can be called multi-times\n" +" avaiable values:\n" +" digitalSignature\n" +" nonRepudiation\n" +" keyEncipherment\n" +" dataEncipherment\n" +" keyAgreement\n" +" keyCertSign\n" +" cRLSign\n" +" encipherOnly\n" +" decipherOnly\n" +" -subject_dns_name str Add DNS name to SubjectAltName extension\n" +" this option can be called multi-times\n" +" -issuer_dns_name str Add DNS name to IssuerAltName extension\n" +" this option can be called multi-times\n" +" -ca Set cA of BasicConstaints extension\n" +" -path_len_constraints num Set pathLenConstaints of BasicConstaints extension\n" +" -ext_key_usage str Set ExtKeyUsage extension\n" +" this option can be called multi-times\n" +" avaiable values:\n" +" anyExtendedKeyUsage\n" +" serverAuth\n" +" clientAuth\n" +" codeSigning\n" +" emailProtection\n" +" timeStamping\n" +" OCSPSigning\n" +" -crl_http_uri uri Set HTTP URI of CRL of CRLDistributionPoints extension\n" +" -crl_ldap_uri uri Set LDAP URI of CRL of CRLDistributionPoints extension\n" +" -inhibit_any_policy num Set skipCerts number of InhibitAnyPolicy extension\n" +" -ca_issuers_uri uri Set URI of the CA certificate in DER-encoding o FreshestCRL extension\n" +" -ocsp_uri uri Set OCSP URI of FreshestCRL extension\n" +"\n" +"Examples\n" +"\n" +" gmssl certgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN ROOTCA -days 3650 \\\n" +" -key rootcakey.pem -pass P@ssw0rd \\\n" +" -ca -path_len_constraints 6 \\\n" +" -key_usage keyCertSign -key_usage cRLSign \\\n" +" -crl_http_uri http://pku.edu.cn/ca.crl \\\n" +" -ca_issuers_uri http://pku.edu.cn/ca.crt -ocsp_uri http://ocsp.pku.edu.cn \\\n" +" -out rootcacert.pem\n" +"\n"; static int ext_key_usage_set(int *usages, const char *usage_name) @@ -43,48 +120,100 @@ int certgen_main(int argc, char **argv) { int ret = 1; char *prog = argv[0]; + char *str; + + // SerialNumber + uint8_t serial[20]; + int serial_len = 12; + + // Issuer, Subject + uint8_t name[256]; + size_t namelen; char *country = NULL; char *state = NULL; char *locality = NULL; char *org = NULL; char *org_unit = NULL; char *common_name = NULL; - int days = 0; - int key_usage = 0; - char *ocsp = NULL; - char *crl_uri = NULL; - char *ca_issuers_uri = NULL; - char *ocsp_uri = NULL; - char *keyfile = NULL; - char *pass = NULL; - char *outfile = NULL; - uint8_t serial[12]; - uint8_t name[256]; - size_t namelen; + // Validity + int days = 0; time_t not_before; time_t not_after; - uint8_t exts[512]; - size_t extslen = 0; + + // Private Key + char *keyfile = NULL; + char *pass = NULL; FILE *keyfp = NULL; SM2_KEY sm2_key; - uint8_t cert[1024]; + + uint8_t cert[4096]; size_t certlen; FILE *outfp = stdout; + char *outfile = NULL; + + // Extensions + uint8_t exts[4096]; + size_t extslen = 0; + + // AuthorityKeyIdentifier + int gen_authority_key_id = 0; + + // SubjectKeyIdentifier + int gen_subject_key_id = 0; + + // KeyUsage + int key_usage = 0; + + // SubjectAltName + uint8_t subject_alt_name[2048]; + size_t subject_alt_name_len = 0; + + // IssuerAltName + uint8_t issuer_alt_name[512]; + size_t issuer_alt_name_len = 0; + + // BasicConstraints + int ca = -1; + int path_len_constraints = -1; + + // ExtKeyUsageSyntax + int ext_key_usages[12]; + size_t ext_key_usages_cnt = 0; + + // CRLDistributionPoints + char *crl_http_uri = NULL; + char *crl_ldap_uri = NULL; + + // InhibitAnyPolicy + int inhibit_any_policy = -1; + + // FreshestCRL + char *ca_issuers_uri = NULL; + char *ocsp_uri = NULL; + argc--; argv++; if (argc < 1) { - fprintf(stderr, "usage: %s %s\n", prog, options); + fprintf(stderr, "usage: gmssl %s %s\n", prog, options); return 1; } while (argc > 0) { if (!strcmp(*argv, "-help")) { - printf("usage: %s %s\n", prog, options); + printf("usage: gmssl %s %s\n\n", prog, options); + printf(usage, prog); ret = 0; goto end; + } else if (!strcmp(*argv, "-serial_len")) { + if (--argc < 1) goto bad; + serial_len = atoi(*(++argv)); + if (serial_len <= 0 || serial_len > sizeof(serial)) { + fprintf(stderr, "%s: invalid '-serial_len' value, need a number less than %zu\n", prog, sizeof(serial)); + goto end; + } } else if (!strcmp(*argv, "-CN")) { if (--argc < 1) goto bad; common_name = *(++argv); @@ -97,6 +226,10 @@ int certgen_main(int argc, char **argv) } else if (!strcmp(*argv, "-C")) { if (--argc < 1) goto bad; country = *(++argv); + if (strlen(country) != 2) { + fprintf(stderr, "%s: invalid '-C' value, need 2-char country name such as 'CN', 'US'\n", prog); + goto end; + } } else if (!strcmp(*argv, "-ST")) { if (--argc < 1) goto bad; state = *(++argv); @@ -107,26 +240,10 @@ int certgen_main(int argc, char **argv) if (--argc < 1) goto bad; days = atoi(*(++argv)); if (days <= 0) { - fprintf(stderr, "%s: invalid '-days' value\n", prog); + fprintf(stderr, "%s: invalid `-days` value, need a positive number\n", prog); goto end; } - } else if (!strcmp(*argv, "-key_usage")) { - char *usage; - if (--argc < 1) goto bad; - usage = *(++argv); - if (ext_key_usage_set(&key_usage, usage) != 1) { - fprintf(stderr, "%s: invalid -key_usage value '%s'\n", prog, usage); - goto end; - } - } else if (!strcmp(*argv, "-crl_uri")) { - if (--argc < 1) goto bad; - crl_uri = *(++argv); - } else if (!strcmp(*argv, "-ca_issuers_uri")) { - if (--argc < 1) goto bad; - ca_issuers_uri = *(++argv); - } else if (!strcmp(*argv, "-ocsp_uri")) { - if (--argc < 1) goto bad; - ocsp_uri = *(++argv); + } else if (!strcmp(*argv, "-key")) { if (--argc < 1) goto bad; keyfile = *(++argv); @@ -134,9 +251,78 @@ int certgen_main(int argc, char **argv) fprintf(stderr, "%s: open '%s' failure : %s\n", prog, keyfile, strerror(errno)); goto end; } + } else if (!strcmp(*argv, "-pass")) { if (--argc < 1) goto bad; pass = *(++argv); + } else if (!strcmp(*argv, "-gen_authority_key_id")) { + gen_authority_key_id = 1; + } else if (!strcmp(*argv, "-gen_subject_key_id")) { + gen_subject_key_id = 1; + } else if (!strcmp(*argv, "-key_usage")) { + if (--argc < 1) goto bad; + str = *(++argv); + if (ext_key_usage_set(&key_usage, str) != 1) { + fprintf(stderr, "%s: invalid `-key_usage` value '%s'\n", prog, str); + goto end; + } + } else if (!strcmp(*argv, "-subject_dns_name")) { + if (--argc < 1) goto bad; + str = *(++argv); + if (x509_general_names_add_dns_name( + subject_alt_name, &subject_alt_name_len, sizeof(subject_alt_name), str) != 1) { + fprintf(stderr, "%s: inner error on processing `-subject_dns_name`\n", prog); + goto end; + } + } else if (!strcmp(*argv, "-issuer_dns_name")) { + if (--argc < 1) goto bad; + str = *(++argv); + if (x509_general_names_add_dns_name( + issuer_alt_name, &issuer_alt_name_len, sizeof(issuer_alt_name), str) != 1) { + fprintf(stderr, "%s: inner error on processing `-issuer_dns_name`\n", prog); + goto end; + } + } else if (!strcmp(*argv, "-ca")) { + ca = 1; + } else if (!strcmp(*argv, "-path_len_constraints")) { + if (--argc < 1) goto bad; + path_len_constraints = atoi(*(++argv)); + if (path_len_constraints <= 0) { + fprintf(stderr, "%s: invalid `-path_len_constraints` value\n", prog); + goto end; + } + } else if (!strcmp(*argv, "-ext_key_usage")) { + if (--argc < 1) goto bad; + str = *(++argv); + if (x509_key_purpose_from_name(str) <= 0) { + fprintf(stderr, "%s: invalid `-ext_key_usage` value '%s'\n", prog, str); + goto end; + } + if (ext_key_usages_cnt >= sizeof(ext_key_usages)/sizeof(ext_key_usages[0])) { + fprintf(stderr, "%s: too much `-ext_key_usage` options\n", prog); + goto end; + } + ext_key_usages[ext_key_usages_cnt++] = x509_key_purpose_from_name(str); + } else if (!strcmp(*argv, "-crl_http_uri")) { + if (--argc < 1) goto bad; + crl_http_uri = *(++argv); + } else if (!strcmp(*argv, "-crl_ldap_uri")) { + if (--argc < 1) goto bad; + crl_ldap_uri = *(++argv); + } else if (!strcmp(*argv, "-inhibit_any_policy")) { + if (--argc < 1) goto bad; + inhibit_any_policy = atoi(*(++argv)); + if (inhibit_any_policy < 0) { + fprintf(stderr, "%s: invalid `-inhibit_any_policy` value\n", prog); + goto end; + } + } else if (!strcmp(*argv, "-ca_issuers_uri")) { + if (--argc < 1) goto bad; + ca_issuers_uri = *(++argv); + } else if (!strcmp(*argv, "-ocsp_uri")) { + if (--argc < 1) goto bad; + ocsp_uri = *(++argv); + } else if (!strcmp(*argv, "-out")) { if (--argc < 1) goto bad; outfile = *(++argv); @@ -148,7 +334,7 @@ int certgen_main(int argc, char **argv) fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); goto end; bad: - fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv); + fprintf(stderr, "%s: `%s` value missing\n", prog, *argv); goto end; } @@ -157,71 +343,137 @@ bad: } if (!common_name) { - fprintf(stderr, "%s: '-CN' option required\n", prog); + fprintf(stderr, "%s: option `-CN` required\n", prog); goto end; } if (!days) { - fprintf(stderr, "%s: '-days' option required\n", prog); + fprintf(stderr, "%s: option `-days` required\n", prog); goto end; } if (!keyfile) { - fprintf(stderr, "%s: '-key' option required\n", prog); + fprintf(stderr, "%s: option `-key` required\n", prog); goto end; } if (!pass) { - fprintf(stderr, "%s: '-pass' option required\n", prog); + fprintf(stderr, "%s: option `-pass` required\n", prog); goto end; } - if (!key_usage) { - fprintf(stderr, "%s: '-key_usage' option required\n", prog); - goto end; - } - if (sm2_private_key_info_decrypt_from_pem(&sm2_key, pass, keyfp) != 1) { fprintf(stderr, "%s: load private key failed\n", prog); goto end; } - if (x509_exts_add_key_usage(exts, &extslen, sizeof(exts), 1, key_usage) != 1 - || x509_exts_add_basic_constraints(exts, &extslen, sizeof(exts), 1, 1, -1) != 1 - || x509_exts_add_default_authority_key_identifier(exts, &extslen, sizeof(exts), &sm2_key) != 1) { - fprintf(stderr, "%s: inner error\n", prog); + // Serial + if (rand_bytes(serial, sizeof(serial)) != 1) { + fprintf(stderr, "%s: RNG error\n", prog); goto end; } - if (crl_uri) { - if (x509_exts_add_crl_distribution_points(exts, &extslen, sizeof(exts), 0, - crl_uri, strlen(crl_uri), NULL, 0) != 1) { + + // Issuer, Subject + if (x509_name_set(name, &namelen, sizeof(name), country, state, locality, org, org_unit, common_name) != 1) { + fprintf(stderr, "%s: set Issuer/Subject Name error\n", prog); + goto end; + } + + // Validity + time(¬_before); + if (x509_validity_add_days(¬_after, not_before, days) != 1) { + fprintf(stderr, "%s: set Validity failure\n", prog); + goto end; + } + + // Extensions + if (gen_authority_key_id) { + if (x509_exts_add_default_authority_key_identifier(exts, &extslen, sizeof(exts), &sm2_key) != 1) { + fprintf(stderr, "%s: set AuthorityKeyIdentifier extension failure\n", prog); + goto end; + } + } + if (gen_subject_key_id) { + if (x509_exts_add_subject_key_identifier_ex(exts, &extslen, sizeof(exts), -1, &sm2_key) != 1) { + fprintf(stderr, "%s: set SubjectKeyIdentifier extension failure\n", prog); + goto end; + } + } + if (key_usage) { + if (x509_exts_add_key_usage(exts, &extslen, sizeof(exts), X509_critical, key_usage) != 1) { + fprintf(stderr, "%s: set KeyUsage extension failure\n", prog); + goto end; + } + } + // no CertificatePolicies + // no PolicyMappings + if (subject_alt_name_len) { + if (x509_exts_add_subject_alt_name(exts, &extslen, sizeof(exts), + -1, subject_alt_name, subject_alt_name_len) != 1) { + fprintf(stderr, "%s: set SubjectAltName extension failure\n", prog); + goto end; + } + } + if (issuer_alt_name_len) { + if (x509_exts_add_issuer_alt_name(exts, &extslen, sizeof(exts), + -1, issuer_alt_name, issuer_alt_name_len) != 1) { + fprintf(stderr, "%s: set IssuerAltName extension failure\n", prog); + goto end; + } + } + // no SubjectDirectoryAttributes + if (path_len_constraints) { + if (x509_exts_add_basic_constraints(exts, &extslen, sizeof(exts), + X509_critical, ca, path_len_constraints) != 1) { + fprintf(stderr, "%s: set BasicConstraints extension failure\n", prog); + goto end; + } + } + // no NameConstraints + // no PolicyConstraints + if (ext_key_usages_cnt) { + if (x509_exts_add_ext_key_usage(exts, &extslen, sizeof(exts), + -1, ext_key_usages, ext_key_usages_cnt) != 1) { + fprintf(stderr, "%s: set ExtKeyUsage extension failure\n", prog); + goto end; + } + } + if (crl_http_uri || crl_ldap_uri) { + if (x509_exts_add_crl_distribution_points(exts, &extslen, sizeof(exts), + -1, + crl_http_uri, crl_http_uri ? strlen(crl_http_uri) : 0, + crl_ldap_uri, crl_ldap_uri ? strlen(crl_ldap_uri) : 0) != 1) { + fprintf(stderr, "%s: set CRLDistributionPoints extension failure\n", prog); error_print(); return -1; } } + if (inhibit_any_policy >= 0) { + if (x509_exts_add_inhibit_any_policy(exts, &extslen, sizeof(exts), + X509_critical, inhibit_any_policy) != 1) { + fprintf(stderr, "%s: set InhibitAnyPolicy extension failure\n", prog); + goto end; + } + } if (ca_issuers_uri || ocsp_uri) { if (x509_exts_add_authority_info_access(exts, &extslen, sizeof(exts), 0, - ca_issuers_uri, strlen(ca_issuers_uri), ocsp_uri, strlen(ocsp_uri)) != 1) { - fprintf(stderr, "%s: error\n", prog); + ca_issuers_uri, ca_issuers_uri ? strlen(ca_issuers_uri) : 0, + ocsp_uri, ocsp_uri ? strlen(ocsp_uri) : 0) != 1) { + fprintf(stderr, "%s: set AuthorityInfoAccess extension failure\n", prog); goto end; } } - time(¬_before); - if (rand_bytes(serial, sizeof(serial)) != 1 - || x509_name_set(name, &namelen, sizeof(name), - country, state, locality, org, org_unit, common_name) != 1 - || x509_validity_add_days(¬_after, not_before, days) != 1 - || x509_cert_sign( - cert, &certlen, sizeof(cert), - X509_version_v3, - serial, sizeof(serial), - OID_sm2sign_with_sm3, - name, namelen, - not_before, not_after, - name, namelen, - &sm2_key, - NULL, 0, - NULL, 0, - exts, extslen, - &sm2_key, SM2_DEFAULT_ID, strlen(SM2_DEFAULT_ID)) != 1) { - fprintf(stderr, "%s: inner error\n", prog); + if (x509_cert_sign( + cert, &certlen, sizeof(cert), + X509_version_v3, + serial, sizeof(serial), + OID_sm2sign_with_sm3, + name, namelen, + not_before, not_after, + name, namelen, + &sm2_key, + NULL, 0, + NULL, 0, + exts, extslen, + &sm2_key, SM2_DEFAULT_ID, strlen(SM2_DEFAULT_ID)) != 1) { + fprintf(stderr, "%s: certificate generation failure\n", prog); goto end; } if (x509_cert_to_pem(cert, certlen, outfp) != 1) { diff --git a/tools/crlgen.c b/tools/crlgen.c index 8e772fbf..e36e1871 100644 --- a/tools/crlgen.c +++ b/tools/crlgen.c @@ -14,15 +14,31 @@ #include #include #include +#include #include #include -static const char *options = - "-in RevokedCertificate.der" - " -key pem -pass str -cert pem" - " [-next_update timestamp] " - " [-out crl.der]"; +static const char *usage = "-in revoked_certs.der -key pem -pass str -cacert pem [-next_update time] " + "[-gen_authority_key_id] [-crl_num num] [-delta_crl_indicator num] [-ca_issuers_uri uri] [-ocsp_uri uri] [-out crl.der]"; + +static void print_options(const char *prog) +{ + printf("Options\n"); + printf("\n"); + printf(" -in revoked_certs.der To be revoked certificate list\n"); + printf(" This input file format is DER-encoding of SEQUENCE OF RevokedCertificate\n"); + printf(" revoked_certs.der can be generated by `gmssl certrevoke`\n"); + printf("\n"); + printf(" -key pkcs8.pem The issuer private key.\n"); + printf("\n"); + printf(" -cacert cert.pem The issuer certificate.\n"); + printf("\n"); + printf(" -next_update time Optional CRL attribute.\n"); + printf("\n"); + printf(" -out crl.der Output CRL in DER-encoding\n"); +} + int crlgen_main(int argc, char **argv) { @@ -44,6 +60,16 @@ int crlgen_main(int argc, char **argv) size_t issuer_len; time_t next_update = -1; + uint8_t exts[512]; + size_t extslen = 0; + int gen_authority_key_id = 0; + int crl_num = -1; + int delta_crl_indicator = -1; + char *http_uri = NULL; + char *ldap_uri = NULL; + char *ca_issuers_uri = NULL; + char *ocsp_uri = NULL; + uint8_t outbuf[64 * 1024]; uint8_t *out = outbuf; size_t outlen = 0; @@ -53,7 +79,9 @@ int crlgen_main(int argc, char **argv) while (argc > 0) { if (!strcmp(*argv, "-help")) { - printf("usage: %s %s\n", prog, options); + printf("usage: %s %s\n", prog, usage); + printf("\n"); + print_options(prog); goto end; } else if (!strcmp(*argv, "-in")) { @@ -87,7 +115,29 @@ int crlgen_main(int argc, char **argv) } } else if (!strcmp(*argv, "-next_update")) { if (--argc < 1) goto bad; - next_update = atoi(*(++argv)); + if (asn1_time_from_str(0, &next_update, *(++argv)) != 1) { + fprintf(stderr, "%s: invalid time format for '-next_update', should be 'YYYYMMDDHHMMSSZ'\n", prog); + goto bad; + } + } else if (!strcmp(*argv, "-gen_authority_key_id")) { + gen_authority_key_id = 1; + } else if (!strcmp(*argv, "-crl_num")) { + if (--argc < 1) goto bad; + crl_num = atoi(*(++argv)); + } else if (!strcmp(*argv, "-delta_crl_indicator")) { + if (--argc < 1) goto bad; + delta_crl_indicator = atoi(*(++argv)); + } else if (!strcmp(*argv, "-http_uri")) { + if (--argc < 1) goto bad; + http_uri = *(++argv); + } else if (!strcmp(*argv, "-ldap_uri")) { + if (--argc < 1) goto bad; + ldap_uri = *(++argv); + } else if (!strcmp(*argv, "-ca_issuers_uri")) { + ca_issuers_uri = *(++argv); + } else if (!strcmp(*argv, "-ocsp_uri")) { + if (--argc < 1) goto bad; + ocsp_uri = *(++argv); } else { fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); goto end; @@ -121,7 +171,7 @@ bad: if (!revoked_certs || !revoked_certs_len) { - fprintf(stderr, "usage: %s %s\n", prog, options); + fprintf(stderr, "usage: %s %s\n", prog, usage); goto end; } @@ -134,13 +184,41 @@ bad: goto end; } + if (gen_authority_key_id) { + if (x509_crl_exts_add_default_authority_key_identifier(exts, &extslen, sizeof(exts), &sign_key) != 1) { + fprintf(stderr, "%s: inner error\n", prog); + goto end; + } + } + if (x509_crl_exts_add_crl_number(exts, &extslen, sizeof(exts), -1, crl_num) < 0 + || x509_crl_exts_add_delta_crl_indicator(exts, &extslen, sizeof(exts), X509_critical, delta_crl_indicator) < 0) { + fprintf(stderr, "%s: inner error\n", prog); + goto end; + } + if (ca_issuers_uri || ocsp_uri) { + if (x509_crl_exts_add_authority_info_acess(exts, &extslen, sizeof(exts), -1, + ca_issuers_uri, ca_issuers_uri ? strlen(ca_issuers_uri) : 0, + ocsp_uri, ocsp_uri ? strlen(ocsp_uri) : 0) != 1) { + fprintf(stderr, "%s: inner error\n", prog); + goto end; + } + } + if (http_uri || ldap_uri) { + if (x509_crl_exts_add_freshest_crl(exts, &extslen, sizeof(exts), -1, + http_uri, http_uri ? strlen(http_uri) : 0, + ldap_uri, ldap_uri ? strlen(ldap_uri) : 0) != 1) { + fprintf(stderr, "%s: inner error\n", prog); + goto end; + } + } + if (x509_crl_sign_to_der( X509_version_v2, OID_sm2sign_with_sm3, issuer, issuer_len, time(NULL), next_update, revoked_certs, revoked_certs_len, - NULL, 0, + extslen ? exts : NULL, extslen, &sign_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH, &out, &outlen) != 1) { diff --git a/tools/crlverify.c b/tools/crlverify.c index 532a7ae4..f40bfa87 100644 --- a/tools/crlverify.c +++ b/tools/crlverify.c @@ -104,7 +104,6 @@ bad: fprintf(stderr, "%s: read CRL failure\n", prog); goto end; } - if (x509_crl_get_issuer(crl, crllen, &subject, &subject_len) != 1) { fprintf(stderr, "%s: inner error\n", prog); goto end; @@ -113,6 +112,10 @@ bad: fprintf(stderr, "%s: read certificate failure\n", prog); goto end; } + if (x509_crl_validate(crl, crllen, time(NULL)) != 1) { + fprintf(stderr, "%s: invalid CRL data or format\n", prog); + goto end; + } if ((rv = x509_crl_verify_by_ca_cert(crl, crllen, cacert, cacertlen, SM2_DEFAULT_ID, strlen(SM2_DEFAULT_ID))) < 0) { fprintf(stderr, "%s: verification inner error\n", prog); goto end; @@ -127,24 +130,3 @@ end: if (in) free(in); return ret; } - - - - - - - - - - - - - - - - - - - - -