From b5df2121d3a8bffd51745f67fee4ccb5f872d034 Mon Sep 17 00:00:00 2001 From: Zhi Guan Date: Tue, 31 Jan 2023 19:18:46 +0800 Subject: [PATCH] Add crlget tool --- CMakeLists.txt | 1 + src/x509_cer.c | 15 ++++- src/x509_ext.c | 143 ++++++++++++++++++++++++++++++------------- tests/x509_exttest.c | 21 +++++++ tools/crlget.c | 90 ++++++++++++++++++++++----- tools/gmssl.c | 4 ++ 6 files changed, 212 insertions(+), 62 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e9e4ece..4760453d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,6 +104,7 @@ set(tools tools/reqparse.c tools/reqsign.c tools/crlgen.c + tools/crlget.c tools/crlparse.c tools/crlverify.c tools/cmssign.c diff --git a/src/x509_cer.c b/src/x509_cer.c index 38e04aba..f884339e 100644 --- a/src/x509_cer.c +++ b/src/x509_cer.c @@ -889,7 +889,20 @@ int x509_exts_get_ext_by_index(const uint8_t *d, size_t dlen, int index, int x509_exts_get_ext_by_oid(const uint8_t *d, size_t dlen, int oid, int *critical, const uint8_t **val, size_t *vlen) { - return -1; + int ext_id; + uint32_t nodes[32]; + size_t nodes_cnt; + + while (dlen) { + if (x509_ext_from_der(&ext_id, nodes, &nodes_cnt, critical, val, vlen, &d, &dlen) != 1) { + error_print(); + return -1; + } + if (ext_id == oid) { + return 1; + } + } + return 0; } int x509_exts_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen) diff --git a/src/x509_ext.c b/src/x509_ext.c index aa696f4d..511870ad 100644 --- a/src/x509_ext.c +++ b/src/x509_ext.c @@ -679,47 +679,18 @@ int x509_general_names_add_registered_id(uint8_t *gns, size_t *gnslen, size_t ma return 1; } -int x509_uri_as_general_names_to_der_ex(int tag, const char *uri, size_t urilen, - uint8_t **out, size_t *outlen) -{ - int choice = X509_gn_uniform_resource_identifier; - size_t len = 0; - - if (!uri || !urilen) { - return 0; - } - if (x509_general_name_to_der(choice, (uint8_t *)uri, urilen, NULL, &len) != 1 - || asn1_sequence_header_to_der_ex(tag, len, out, outlen) != 1 - || x509_general_name_to_der(choice, (uint8_t *)uri, urilen, out, outlen) != 1) { - error_print(); - return -1; - } - return 1; -} - -/* -int x509_uri_as_general_names_from_der_ex(int tag, const uint8_t **uri, size_t *urilen, - const uint8_t **in, size_t *inlen) -{ - int choice = X509_gn_uniform_resource_identifier; - int ret; - const uint8_t *d; - size_t dlen; - - if ((ret = asn1_sequence_from_der_ex(tag, &d, &dlen, in, inlen)) != 1) { - if (ret < 0) error_print(); - return ret; - } - if (x509_general_names_get_first(d, dlen, NULL, choice, uri, urilen) < 0) { - error_print(); - return -1; - } - return 1; -} -*/ - int x509_general_names_get_next(const uint8_t *gns, size_t gns_len, const uint8_t **ptr, int choice, const uint8_t **d, size_t *dlen) { + + if (!gns || !gns_len) { + error_print(); + return -1; + } + if (!ptr || !d || !dlen) { + error_print(); + return -1; + } + if (*ptr > gns + gns_len) { error_print(); return -1; @@ -742,14 +713,69 @@ int x509_general_names_get_next(const uint8_t *gns, size_t gns_len, const uint8_ int x509_general_names_get_first(const uint8_t *gns, size_t gns_len, const uint8_t **ptr, int choice, const uint8_t **d, size_t *dlen) { int ret; - *ptr = gns; - if ((ret = x509_general_names_get_next(gns, gns_len, ptr, choice, d, dlen)) < 0) { + const uint8_t *p; + p = gns; + + if ((ret = x509_general_names_get_next(gns, gns_len, &p, choice, d, dlen)) < 0) { error_print(); return - 1; } + + if (ptr) { + *ptr = p; + } + return ret; } + + +/* +DistributionPointName ::= CHOICE { + fullName [0] GeneralNames, + nameRelativeToCRLIssuer [1] RelativeDistinguishedName } + +本来GeneralNames是一个SEQUENCE OF,本来这个类型编码的时候应该是80开头的 + + +*/ +int x509_uri_as_general_names_to_der_ex(int tag, const char *uri, size_t urilen, + uint8_t **out, size_t *outlen) +{ + int choice = X509_gn_uniform_resource_identifier; + size_t len = 0; + + if (!uri || !urilen) { + return 0; + } + if (x509_general_name_to_der(choice, (uint8_t *)uri, urilen, NULL, &len) != 1 + || asn1_sequence_header_to_der_ex(tag, len, out, outlen) != 1 + || x509_general_name_to_der(choice, (uint8_t *)uri, urilen, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_uri_as_general_names_from_der_ex(int tag, const uint8_t **uri, size_t *urilen, + const uint8_t **in, size_t *inlen) +{ + int choice = X509_gn_uniform_resource_identifier; + int ret; + const uint8_t *d; + size_t dlen; + + if ((ret = asn1_type_from_der(tag, &d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_general_names_get_first(d, dlen, NULL, choice, uri, urilen) < 0) { + error_print(); + return -1; + } + return 1; +} + int x509_general_names_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen) { int choice; @@ -2009,6 +2035,7 @@ int x509_distribution_point_name_from_der(int *choice, const uint8_t **d, size_t switch (tag) { case ASN1_TAG_EXPLICIT(0): *choice = 0; + // 此时返回的值是GeneralNames的d,dlen,因此这个返回值不能用general_names_from来解析 break; case ASN1_TAG_EXPLICIT(1): *choice = 1; @@ -2033,8 +2060,10 @@ int x509_uri_as_distribution_point_name_from_der(const char **uri, size_t *urile return ret; } if (choice == 0) { - *uri = (char *)d; - *urilen = dlen; + if (x509_general_names_get_first(d, dlen, NULL, choice, (const uint8_t **)uri, urilen) < 0) { + error_print(); + return -1; + } } return 1; } @@ -2187,6 +2216,32 @@ int x509_uri_as_distribution_points_to_der(const char *uri, size_t urilen, return 1; } + +/* + +DistributionPoints :== SEQUENCE OF DistributionPoint + + + 80 Len -- DistributionPoints header + + 80 Len DistributionPoint 1 header + + 80 EXPLICIT(0) + DistributionPointName + 80 len d,dln GeneralNames + 06 len URI + + 01 len d,dlen ReasonFlags + 82 len, d,dlen GeneralNames + + 80 Len DistributionPoint 2 header + + + + 80 Len DistributionPoint 3 header + +*/ + int x509_uri_as_distribution_points_from_der(const char **uri, size_t *urilen, int *reasons, const uint8_t **crl_issuer, size_t *crl_issuer_len, const uint8_t **in, size_t *inlen) @@ -2213,7 +2268,6 @@ int x509_uri_as_distribution_points_from_der(const char **uri, size_t *urilen, } } return 1; - } int x509_distribution_points_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen) @@ -2688,3 +2742,4 @@ int x509_exts_add_authority_info_access(uint8_t *exts, size_t *extslen, size_t m } + diff --git a/tests/x509_exttest.c b/tests/x509_exttest.c index 345abc2a..0af731bf 100644 --- a/tests/x509_exttest.c +++ b/tests/x509_exttest.c @@ -833,6 +833,25 @@ static int test_x509_cert_with_exts(void) return 1; } +static int test_x509_distribution_point_name(void) +{ + uint8_t buf[512]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + + x509_general_name_to_der(X509_gn_uniform_resource_identifier, (uint8_t *)"http://", 7, &p, &len); + +// x509_uri_as_general_names_to_der_ex(0x80, "http://", 7, &p, &len); + + format_bytes(stderr, 0, 0, "GeneralNames", buf, len); + + return 1; +} + + + int main(int argc, char **argv) { if (test_x509_other_name() != 1) goto err; @@ -851,6 +870,8 @@ int main(int argc, char **argv) if (test_x509_revoke_reasons() != 1) goto err; if (test_x509_exts() != 1) goto err; if (test_x509_cert_with_exts() != 1) goto err; + if (test_x509_distribution_point_name() != 1) goto err; + printf("%s all tests passed!\n", __FILE__); return 0; err: diff --git a/tools/crlget.c b/tools/crlget.c index a5dc5375..655f045a 100644 --- a/tools/crlget.c +++ b/tools/crlget.c @@ -14,46 +14,51 @@ #include #include #include +#include #include +#include -static const char *usage = "[-in pem] [-out file]\n"; +static const char *usage = "-cert pem [-out file]\n"; static const char *options = "Options\n" "\n" -" -in pem | stdin Input certificates in PEM format.\n" +" -cert pem Input certificates in PEM format.\n" " -out der | stdout Output CRL file in DER-encoding\n" "\n" "Examples\n" "\n" -" gmssl crlget -in cert.pem -out crl.der\n" +" gmssl crlget -cert cert.pem -out crl.der\n" "\n"; -int certparse_main(int argc, char **argv) +int crlget_main(int argc, char **argv) { int ret = 1; char *prog = argv[0]; - char *infile = NULL; + char *str; + + uint8_t *cert = NULL; + size_t certlen = 0; char *outfile = NULL; - FILE *infp = stdin; FILE *outfp = stdout; - uint8_t cert[18192]; - size_t certlen; + + const uint8_t *exts; + size_t extslen; argc--; argv++; while (argc > 0) { if (!strcmp(*argv, "-help")) { - printf("usage: gmssl %s %s\n\n", prog, options); - printf("%s\n", usage); + printf("usage: gmssl %s %s\n\n", prog, usage); + printf("%s\n", options); goto end; - } else if (!strcmp(*argv, "-in")) { + } else if (!strcmp(*argv, "-cert")) { if (--argc < 1) goto bad; - infile = *(++argv); - if (!(infp = fopen(infile, "rb"))) { - fprintf(stderr, "%s: open '%s' failure : %s\n", prog, infile, strerror(errno)); + str = *(++argv); + if (x509_cert_new_from_file(&cert, &certlen, str) != 1) { + fprintf(stderr, "%s: load ca certificate '%s' failure\n", prog, str); goto end; } } else if (!strcmp(*argv, "-out")) { @@ -75,17 +80,68 @@ bad: argv++; } - if (x509_cert_from_pem(cert, &certlen, sizeof(cert), infp) != 1) { + if (!cert) { + fprintf(stderr, "%s: `-cert` option required\n", prog); + printf("usage: gmssl %s %s\n\n", prog, options); goto end; } + if (x509_cert_get_exts(cert, certlen, &exts, &extslen) != 1) { + error_print(); + goto end; + } + if (!exts) { + goto end; + } + + int critical; + const uint8_t *val; + size_t vlen; + + if ((ret = x509_exts_get_ext_by_oid(exts, extslen, OID_ce_crl_distribution_points, &critical, &val, &vlen)) < 0) { + error_print(); goto end; } - if (x509_exts_get_ext_by_oid(exts, extslen, OID_ce_crl_ + char *uristr; + const char *uri; + size_t urilen; + int reason; + const uint8_t *crl_issuer; + size_t crl_issuer_len; + + if (x509_uri_as_distribution_points_from_der(&uri, &urilen, &reason, &crl_issuer, &crl_issuer_len, &val, &vlen) != 1) { + error_print(); + goto end; + } + if (!(uristr = strndup(uri, urilen))) { + error_print(); + goto end; + } + + uint8_t *crl = NULL; + size_t crl_len = 0; + + if (http_get(uristr, NULL, &crl_len, 0) < 0) { + error_print(); + goto end; + } + if (!(crl = malloc(crl_len))) { + error_print(); + goto end; + } + if (http_get(uristr, crl, &crl_len, crl_len) != 1) { + error_print(); + goto end; + } + + fwrite(crl, crl_len, 1, outfp); + + + ret = 0; end: - if (infile && infp) fclose(infp); + if (cert) free(cert); if (outfile && outfp) fclose(outfp); return ret; } diff --git a/tools/gmssl.c b/tools/gmssl.c index c9040fd8..7da74f1b 100644 --- a/tools/gmssl.c +++ b/tools/gmssl.c @@ -19,6 +19,7 @@ extern int certgen_main(int argc, char **argv); extern int certparse_main(int argc, char **argv); extern int certverify_main(int argc, char **argv); extern int certrevoke_main(int argc, char **argv); +extern int crlget_main(int argc, char **argv); extern int crlgen_main(int argc, char **argv); extern int crlparse_main(int argc, char **argv); extern int crlverify_main(int argc, char **argv); @@ -82,6 +83,7 @@ static const char *options = " reqgen Generate certificate signing request (CSR)\n" " reqsign Generate certificate from CSR\n" " reqparse Parse and print a CSR\n" + " crlget Download the CRL of given certificate\n" " crlgen Sign a CRL with CA certificate and private key\n" " crlparse Verify a CRL with certificate\n" " crlverify Parse and print CRL\n" @@ -134,6 +136,8 @@ int main(int argc, char **argv) return certverify_main(argc, argv); } else if (!strcmp(*argv, "certrevoke")) { return certrevoke_main(argc, argv); + } else if (!strcmp(*argv, "crlget")) { + return crlget_main(argc, argv); } else if (!strcmp(*argv, "crlgen")) { return crlgen_main(argc, argv); } else if (!strcmp(*argv, "crlparse")) {