Hi all,
Thanks for taking the time to review & suggest improvements. I amended
the changeset based on your feedback.
To summarize the changes:
* to address sloppiness in command line option handling, make pemmode
mutually exclusive with filemode and specifying outformats
* rename PEM printing function to pem_print()
* don't limit printing PEM to just one file, allow multiple arguments
like filemode also does
* visually align variables inside pem_print()
* avoid the ASN1_item_d2i gotcha of der_in being advanced past the
parsed data
* free buf unconditionally
OK?
Kind regards,
Job
Index: extern.h
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.150
diff -u -p -r1.150 extern.h
--- extern.h 19 Aug 2022 12:45:53 -0000 1.150
+++ extern.h 25 Aug 2022 13:00:26 -0000
@@ -664,6 +664,7 @@ void mft_print(const X509 *, const str
void roa_print(const X509 *, const struct roa *);
void gbr_print(const X509 *, const struct gbr *);
void rsc_print(const X509 *, const struct rsc *);
+int print_pem(const char *);
/* Output! */
Index: main.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v
retrieving revision 1.209
diff -u -p -r1.209 main.c
--- main.c 4 Aug 2022 13:44:07 -0000 1.209
+++ main.c 25 Aug 2022 13:00:27 -0000
@@ -64,6 +64,7 @@ const char *bird_tablename = "ROAS";
int verbose;
int noop;
int filemode;
+int pemmode;
int rrdpon = 1;
int repo_timeout;
@@ -819,7 +820,7 @@ main(int argc, char *argv[])
"proc exec unveil", NULL) == -1)
err(1, "pledge");
- while ((c = getopt(argc, argv, "b:Bcd:e:fjnorRs:S:t:T:vV")) != -1)
+ while ((c = getopt(argc, argv, "b:Bcd:e:fjnoprRs:S:t:T:vV")) != -1)
switch (c) {
case 'b':
bind_addr = optarg;
@@ -849,6 +850,9 @@ main(int argc, char *argv[])
case 'o':
outformats |= FORMAT_OPENBGPD;
break;
+ case 'p':
+ pemmode = 1;
+ break;
case 'R':
rrdpon = 0;
break;
@@ -888,6 +892,20 @@ main(int argc, char *argv[])
argv += optind;
argc -= optind;
+ if (pemmode && (filemode || outformats))
+ goto usage;
+
+ if (pemmode) {
+ if (pledge("stdio rpath", NULL) == -1)
+ err(1, "pledge");
+
+ for (; *argv != NULL; argv++) {
+ if ((rc = print_pem(*argv)) != 0)
+ return rc;
+ }
+ return rc;
+ }
+
if (!filemode) {
if (argc == 1)
outputdir = argv[0];
@@ -1278,6 +1296,7 @@ usage:
" [-e rsync_prog]\n"
" [-S skiplist] [-s timeout] [-T table] [-t tal]"
" [outputdir]\n"
- " rpki-client [-Vv] [-d cachedir] [-t tal] -f file ...\n");
+ " rpki-client [-Vv] [-d cachedir] [-t tal] -f file ...\n"
+ " rpki-client -p file ...\n");
return 1;
}
Index: print.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/print.c,v
retrieving revision 1.14
diff -u -p -r1.14 print.c
--- print.c 14 Jul 2022 13:24:56 -0000 1.14
+++ print.c 25 Aug 2022 13:00:27 -0000
@@ -1,5 +1,6 @@
/* $OpenBSD: print.c,v 1.14 2022/07/14 13:24:56 job Exp $ */
/*
+ * Copyright (c) 2022 Job Snijders <[email protected]>
* Copyright (c) 2021 Claudio Jeker <[email protected]>
* Copyright (c) 2019 Kristaps Dzonsons <[email protected]>
*
@@ -26,6 +27,8 @@
#include <time.h>
#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
#include "extern.h"
@@ -567,4 +570,99 @@ rsc_print(const X509 *x, const struct rs
if (outformats & FORMAT_JSON)
printf("\t],\n");
+}
+
+/*
+ * Read a file, extract the encapsulated X509 cert and print in PEM format.
+ * Return zero on success, non-zero on failure.
+ */
+int
+print_pem(const char *fn)
+{
+ BIO *bio_out = NULL;
+ X509 *x = NULL;
+ X509_CRL *c = NULL;
+ struct gbr *gbr = NULL;
+ struct mft *mft = NULL;
+ struct roa *roa = NULL;
+ struct rsc *rsc = NULL;
+ unsigned char *buf = NULL;
+ const unsigned char *der;
+ size_t len;
+ enum rtype type;
+ int rc = 1;
+
+ x509_init_oid();
+
+ type = rtype_from_file_extension(fn);
+ if (type == RTYPE_INVALID) {
+ warnx("%s: unsupported file type", fn);
+ goto out;
+ }
+
+ if ((buf = load_file(fn, &len)) == NULL) {
+ warnx("load_file failed");
+ goto out;
+ }
+
+ if ((bio_out = BIO_new_fp(stdout, BIO_NOCLOSE)) == NULL)
+ errx(1, "BIO_new_fp");
+
+ switch (type) {
+ case RTYPE_CER:
+ der = buf;
+ if ((x = d2i_X509(NULL, &der, len)) == NULL) {
+ warnx("d2i_X509 failed");
+ goto out;
+ }
+ break;
+ case RTYPE_CRL:
+ der = buf;
+ if ((c = d2i_X509_CRL(NULL, &der, len)) == NULL) {
+ warnx("d2i_X509_CRL failed");
+ goto out;
+ }
+ if (!X509_CRL_print(bio_out, c))
+ errx(1, "X509_CRL_print");
+ if (!PEM_write_bio_X509_CRL(bio_out, c))
+ errx(1, "PEM_write_bio_X509_CRL");
+ rc = 0;
+ goto out;
+ case RTYPE_GBR:
+ if ((gbr = gbr_parse(&x, fn, buf, len)) == NULL)
+ goto out;
+ break;
+ case RTYPE_MFT:
+ if ((mft = mft_parse(&x, fn, buf, len)) == NULL)
+ goto out;
+ break;
+ case RTYPE_ROA:
+ if ((roa = roa_parse(&x, fn, buf, len)) == NULL)
+ goto out;
+ break;
+ case RTYPE_RSC:
+ if ((rsc = rsc_parse(&x, fn, buf, len)) == NULL)
+ goto out;
+ break;
+ default:
+ errx(1, "%s: unhandled", fn);
+ }
+
+ if (!X509_print(bio_out, x))
+ errx(1, "X509_print");
+
+ if (!PEM_write_bio_X509(bio_out, x))
+ errx(1, "PEM_write_bio_X509");
+
+ rc = 0;
+ out:
+ BIO_free(bio_out);
+ free(buf);
+ X509_free(x);
+ X509_CRL_free(c);
+ gbr_free(gbr);
+ mft_free(mft);
+ roa_free(roa);
+ rsc_free(rsc);
+ return rc;
}
Index: rpki-client.8
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/rpki-client.8,v
retrieving revision 1.68
diff -u -p -r1.68 rpki-client.8
--- rpki-client.8 30 Jun 2022 10:27:52 -0000 1.68
+++ rpki-client.8 25 Aug 2022 13:00:27 -0000
@@ -37,6 +37,9 @@
.Op Fl t Ar tal
.Fl f
.Ar
+.Nm
+.Fl p
+.Ar
.Sh DESCRIPTION
The
.Nm
@@ -144,6 +147,12 @@ If the
and
.Fl j
options are not specified this is the default.
+.It Fl p Ar
+Print the encapsulated DER encoded X.509 certificate or CRL in
+.Ar file
+in both human-readable and
+.Em PEM
+format.
.It Fl R
Synchronize via RSYNC only.
.It Fl r