diff --git a/lib/hx509/hxtool-commands.in b/lib/hx509/hxtool-commands.in index 5df67f874..64ca23f78 100644 --- a/lib/hx509/hxtool-commands.in +++ b/lib/hx509/hxtool-commands.in @@ -408,6 +408,17 @@ command = { argument="ocsp-response-file ..." help = "Print the OCSP responses" } +command = { + name = "revoke-print" + option = { + long = "verbose" + type = "flag" + help = "verbose" + } + min_args="1" + argument="ocsp/crl files" + help = "Print the OCSP/CRL files" +} command = { name = "request-create" option = { diff --git a/lib/hx509/hxtool.c b/lib/hx509/hxtool.c index ef95af2f9..f4720f63f 100644 --- a/lib/hx509/hxtool.c +++ b/lib/hx509/hxtool.c @@ -1135,6 +1135,45 @@ ocsp_print(struct ocsp_print_options *opt, int argc, char **argv) return 0; } +int +revoke_print(struct revoke_print_options *opt, int argc, char **argv) +{ + hx509_revoke_ctx revoke_ctx; + int ret; + + ret = hx509_revoke_init(context, &revoke_ctx); + if (ret) + errx(1, "hx509_revoke_init: %d", ret); + + while(argc--) { + char *s = *argv++; + + if (strncmp(s, "crl:", 4) == 0) { + s += 4; + + ret = hx509_revoke_add_crl(context, revoke_ctx, s); + if (ret) + errx(1, "hx509_revoke_add_crl: %s: %d", s, ret); + + } else if (strncmp(s, "ocsp:", 4) == 0) { + s += 5; + + ret = hx509_revoke_add_ocsp(context, revoke_ctx, s); + if (ret) + errx(1, "hx509_revoke_add_ocsp: %s: %d", s, ret); + + } else { + errx(1, "unknown option to verify: `%s'\n", s); + } + } + + ret = hx509_revoke_print(context, revoke_ctx, stdout); + if (ret) + warnx("hx509_revoke_print: %d", ret); + + return ret; +} + /* * */ diff --git a/lib/hx509/revoke.c b/lib/hx509/revoke.c index af10bce1c..019e6bb76 100644 --- a/lib/hx509/revoke.c +++ b/lib/hx509/revoke.c @@ -561,27 +561,18 @@ out: } static int -load_crl(const char *path, time_t *t, CRLCertificateList *crl) +crl_parser(hx509_context context, const char *type, + const hx509_pem_header *header, + const void *data, size_t len, void *ctx) { - size_t length, size; - struct stat sb; - void *data; + CRLCertificateList *crl = (CRLCertificateList *)ctx; + size_t size; int ret; - memset(crl, 0, sizeof(*crl)); + if (strcasecmp("X509 CRL", type) != 0) + return HX509_CRYPTO_SIG_INVALID_FORMAT; - ret = rk_undumpdata(path, &data, &length); - if (ret) - return ret; - - ret = stat(path, &sb); - if (ret) - return errno; - - *t = sb.st_mtime; - - ret = decode_CRLCertificateList(data, length, crl, &size); - rk_xfree(data); + ret = decode_CRLCertificateList(data, len, crl, &size); if (ret) return ret; @@ -590,9 +581,47 @@ load_crl(const char *path, time_t *t, CRLCertificateList *crl) free_CRLCertificateList(crl); return HX509_CRYPTO_SIG_INVALID_FORMAT; } + return 0; } +static int +load_crl(hx509_context context, const char *path, time_t *t, CRLCertificateList *crl) +{ + struct stat sb; + size_t length; + void *data; + FILE *f; + int ret; + + memset(crl, 0, sizeof(*crl)); + + ret = stat(path, &sb); + if (ret) + return errno; + + *t = sb.st_mtime; + + if ((f = fopen(path, "r")) == NULL) + return errno; + + rk_cloexec_file(f); + + ret = hx509_pem_read(context, f, crl_parser, crl); + fclose(f); + + if (ret == HX509_PARSING_KEY_FAILED) { + + ret = rk_undumpdata(path, &data, &length); + if (ret) + return ret; + + ret = crl_parser(context, "X509 CRL", NULL, data, length, crl); + rk_xfree(data); + } + return ret; +} + /** * Add a CRL file to the revokation context. * @@ -644,7 +673,8 @@ hx509_revoke_add_crl(hx509_context context, return ENOMEM; } - ret = load_crl(path, + ret = load_crl(context, + path, &ctx->crls.val[ctx->crls.len].last_modfied, &ctx->crls.val[ctx->crls.len].crl); if (ret) { @@ -674,7 +704,6 @@ hx509_revoke_add_crl(hx509_context context, * @ingroup hx509_revoke */ - int hx509_revoke_verify(hx509_context context, hx509_revoke_ctx ctx, @@ -781,7 +810,7 @@ hx509_revoke_verify(hx509_context context, if (ret == 0 && crl->last_modfied != sb.st_mtime) { CRLCertificateList cl; - ret = load_crl(crl->path, &crl->last_modfied, &cl); + ret = load_crl(context, crl->path, &crl->last_modfied, &cl); if (ret == 0) { free_CRLCertificateList(&crl->crl); crl->crl = cl; @@ -1064,6 +1093,140 @@ printable_time(time_t t) return s; } +/* + * + */ + +static int +print_ocsp(hx509_context context, struct revoke_ocsp *ocsp, FILE *out) +{ + int ret = 0; + size_t i; + + fprintf(out, "signer: "); + + switch(ocsp->ocsp.tbsResponseData.responderID.element) { + case choice_OCSPResponderID_byName: { + hx509_name n; + char *s; + _hx509_name_from_Name(&ocsp->ocsp.tbsResponseData.responderID.u.byName, &n); + hx509_name_to_string(n, &s); + hx509_name_free(&n); + fprintf(out, " byName: %s\n", s); + free(s); + break; + } + case choice_OCSPResponderID_byKey: { + char *s; + hex_encode(ocsp->ocsp.tbsResponseData.responderID.u.byKey.data, + ocsp->ocsp.tbsResponseData.responderID.u.byKey.length, + &s); + fprintf(out, " byKey: %s\n", s); + free(s); + break; + } + default: + _hx509_abort("choice_OCSPResponderID unknown"); + break; + } + + fprintf(out, "producedAt: %s\n", + printable_time(ocsp->ocsp.tbsResponseData.producedAt)); + + fprintf(out, "replies: %d\n", ocsp->ocsp.tbsResponseData.responses.len); + + for (i = 0; i < ocsp->ocsp.tbsResponseData.responses.len; i++) { + const char *status; + switch (ocsp->ocsp.tbsResponseData.responses.val[i].certStatus.element) { + case choice_OCSPCertStatus_good: + status = "good"; + break; + case choice_OCSPCertStatus_revoked: + status = "revoked"; + break; + case choice_OCSPCertStatus_unknown: + status = "unknown"; + break; + default: + status = "element unknown"; + } + + fprintf(out, "\t%zu. status: %s\n", i, status); + + fprintf(out, "\tthisUpdate: %s\n", + printable_time(ocsp->ocsp.tbsResponseData.responses.val[i].thisUpdate)); + if (ocsp->ocsp.tbsResponseData.responses.val[i].nextUpdate) + fprintf(out, "\tproducedAt: %s\n", + printable_time(ocsp->ocsp.tbsResponseData.responses.val[i].thisUpdate)); + + } + + fprintf(out, "appended certs:\n"); + if (ocsp->certs) + ret = hx509_certs_iter_f(context, ocsp->certs, hx509_ci_print_names, out); + + return ret; +} + +static int +print_crl(hx509_context context, struct revoke_crl *crl, FILE *out) +{ + { + hx509_name n; + char *s; + _hx509_name_from_Name(&crl->crl.tbsCertList.issuer, &n); + hx509_name_to_string(n, &s); + hx509_name_free(&n); + fprintf(out, " issuer: %s\n", s); + free(s); + } + + fprintf(out, " thisUpdate: %s\n", + printable_time(_hx509_Time2time_t(&crl->crl.tbsCertList.thisUpdate))); + + return 0; +} + + +/* + * + */ + +int +hx509_revoke_print(hx509_context context, + hx509_revoke_ctx ctx, + FILE *out) +{ + int saved_ret = 0, ret; + size_t n; + + for (n = 0; n < ctx->ocsps.len; n++) { + struct revoke_ocsp *ocsp = &ctx->ocsps.val[n]; + + fprintf(out, "OCSP %s\n", ocsp->path); + + ret = print_ocsp(context, ocsp, out); + if (ret) { + fprintf(out, "failure printing OCSP: %d\n", ret); + saved_ret = ret; + } + } + + for (n = 0; n < ctx->crls.len; n++) { + struct revoke_crl *crl = &ctx->crls.val[n]; + + fprintf(out, "CRL %s\n", crl->path); + + ret = print_crl(context, crl, out); + if (ret) { + fprintf(out, "failure printing CRL: %d\n", ret); + saved_ret = ret; + } + } + return saved_ret; + +} + /** * Print the OCSP reply stored in a file. * @@ -1081,7 +1244,6 @@ hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out) { struct revoke_ocsp ocsp; int ret; - size_t i; if (out == NULL) out = stdout; @@ -1098,67 +1260,7 @@ hx509_revoke_ocsp_print(hx509_context context, const char *path, FILE *out) return ret; } - fprintf(out, "signer: "); - - switch(ocsp.ocsp.tbsResponseData.responderID.element) { - case choice_OCSPResponderID_byName: { - hx509_name n; - char *s; - _hx509_name_from_Name(&ocsp.ocsp.tbsResponseData.responderID.u.byName, &n); - hx509_name_to_string(n, &s); - hx509_name_free(&n); - fprintf(out, " byName: %s\n", s); - free(s); - break; - } - case choice_OCSPResponderID_byKey: { - char *s; - hex_encode(ocsp.ocsp.tbsResponseData.responderID.u.byKey.data, - ocsp.ocsp.tbsResponseData.responderID.u.byKey.length, - &s); - fprintf(out, " byKey: %s\n", s); - free(s); - break; - } - default: - _hx509_abort("choice_OCSPResponderID unknown"); - break; - } - - fprintf(out, "producedAt: %s\n", - printable_time(ocsp.ocsp.tbsResponseData.producedAt)); - - fprintf(out, "replies: %d\n", ocsp.ocsp.tbsResponseData.responses.len); - - for (i = 0; i < ocsp.ocsp.tbsResponseData.responses.len; i++) { - const char *status; - switch (ocsp.ocsp.tbsResponseData.responses.val[i].certStatus.element) { - case choice_OCSPCertStatus_good: - status = "good"; - break; - case choice_OCSPCertStatus_revoked: - status = "revoked"; - break; - case choice_OCSPCertStatus_unknown: - status = "unknown"; - break; - default: - status = "element unknown"; - } - - fprintf(out, "\t%zu. status: %s\n", i, status); - - fprintf(out, "\tthisUpdate: %s\n", - printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate)); - if (ocsp.ocsp.tbsResponseData.responses.val[i].nextUpdate) - fprintf(out, "\tproducedAt: %s\n", - printable_time(ocsp.ocsp.tbsResponseData.responses.val[i].thisUpdate)); - - } - - fprintf(out, "appended certs:\n"); - if (ocsp.certs) - ret = hx509_certs_iter_f(context, ocsp.certs, hx509_ci_print_names, out); + ret = print_ocsp(context, &ocsp, out); free_ocsp(&ocsp); return ret;