summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/rpki-client/crl.c17
-rw-r--r--usr.sbin/rpki-client/extern.h5
-rw-r--r--usr.sbin/rpki-client/parser.c111
3 files changed, 101 insertions, 32 deletions
diff --git a/usr.sbin/rpki-client/crl.c b/usr.sbin/rpki-client/crl.c
index 52324e03ac8..b50aff63ad0 100644
--- a/usr.sbin/rpki-client/crl.c
+++ b/usr.sbin/rpki-client/crl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: crl.c,v 1.12 2022/02/08 11:51:51 tb Exp $ */
+/* $OpenBSD: crl.c,v 1.13 2022/02/08 14:53:03 tb Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -33,7 +33,7 @@ crl_parse(const char *fn, const unsigned char *der, size_t len)
{
struct crl *crl;
const ASN1_TIME *at;
- struct tm expires_tm;
+ struct tm issued_tm, expires_tm;
int rc = 0;
/* just fail for empty buffers, the warning was printed elsewhere */
@@ -53,6 +53,19 @@ crl_parse(const char *fn, const unsigned char *der, size_t len)
goto out;
}
+ at = X509_CRL_get0_lastUpdate(crl->x509_crl);
+ if (at == NULL) {
+ warnx("%s: X509_CRL_get0_lastUpdate failed", fn);
+ goto out;
+ }
+ memset(&issued_tm, 0, sizeof(issued_tm));
+ if (ASN1_time_parse(at->data, at->length, &issued_tm, 0) == -1) {
+ warnx("%s: ASN1_time_parse failed", fn);
+ goto out;
+ }
+ if ((crl->issued = mktime(&issued_tm)) == -1)
+ errx(1, "%s: mktime failed", fn);
+
/* extract expire time for later use */
at = X509_CRL_get0_nextUpdate(crl->x509_crl);
if (at == NULL) {
diff --git a/usr.sbin/rpki-client/extern.h b/usr.sbin/rpki-client/extern.h
index 079c4e92336..a9b4429b83a 100644
--- a/usr.sbin/rpki-client/extern.h
+++ b/usr.sbin/rpki-client/extern.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: extern.h,v 1.117 2022/02/08 11:51:51 tb Exp $ */
+/* $OpenBSD: extern.h,v 1.118 2022/02/08 14:53:03 tb Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -280,7 +280,8 @@ struct crl {
RB_ENTRY(crl) entry;
char *aki;
X509_CRL *x509_crl;
- time_t expires; /* do not use after */
+ time_t issued; /* do not use before */
+ time_t expires; /* do not use after */
};
/*
* Tree of CRLs sorted by uri
diff --git a/usr.sbin/rpki-client/parser.c b/usr.sbin/rpki-client/parser.c
index ed8040716b4..f32a77dbb39 100644
--- a/usr.sbin/rpki-client/parser.c
+++ b/usr.sbin/rpki-client/parser.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: parser.c,v 1.62 2022/02/08 12:35:14 claudio Exp $ */
+/* $OpenBSD: parser.c,v 1.63 2022/02/08 14:53:03 tb Exp $ */
/*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -42,6 +42,7 @@
static void build_chain(const struct auth *, STACK_OF(X509) **);
static struct crl *get_crl(const struct auth *);
static void build_crls(const struct crl *, STACK_OF(X509_CRL) **);
+static struct crl *parse_load_crl_from_mft(struct entity *, const char *);
static X509_STORE_CTX *ctx;
static struct auth_tree auths = RB_INITIALIZER(&auths);
@@ -205,13 +206,13 @@ verify_cb(int ok, X509_STORE_CTX *store_ctx)
* Returns 1 for valid certificates, returns 0 if there is a verify error
*/
static int
-valid_x509(char *file, X509 *x509, struct auth *a, struct crl *crl,
- unsigned long flags, int nowarn)
+valid_x509(char *file, X509 *x509, struct auth *a, struct crl *crl, int nowarn)
{
X509_VERIFY_PARAM *params;
ASN1_OBJECT *cp_oid;
STACK_OF(X509) *chain;
STACK_OF(X509_CRL) *crls = NULL;
+ unsigned long flags;
int c;
build_chain(a, &chain);
@@ -231,6 +232,7 @@ valid_x509(char *file, X509 *x509, struct auth *a, struct crl *crl,
X509_STORE_CTX_set_verify_cb(ctx, verify_cb);
if (!X509_STORE_CTX_set_app_data(ctx, file))
cryptoerrx("X509_STORE_CTX_set_app_data");
+ flags = X509_V_FLAG_CRL_CHECK;
flags |= X509_V_FLAG_EXPLICIT_POLICY;
flags |= X509_V_FLAG_INHIBIT_MAP;
X509_STORE_CTX_set_flags(ctx, flags);
@@ -263,8 +265,8 @@ static struct roa *
proc_parser_roa(char *file, const unsigned char *der, size_t len)
{
struct roa *roa;
- struct crl *crl;
struct auth *a;
+ struct crl *crl;
X509 *x509;
if ((roa = roa_parse(&x509, file, der, len)) == NULL)
@@ -273,7 +275,7 @@ proc_parser_roa(char *file, const unsigned char *der, size_t len)
a = valid_ski_aki(file, &auths, roa->ski, roa->aki);
crl = get_crl(a);
- if (!valid_x509(file, x509, a, crl, X509_V_FLAG_CRL_CHECK, 0)) {
+ if (!valid_x509(file, x509, a, crl, 0)) {
X509_free(x509);
roa_free(roa);
return NULL;
@@ -354,32 +356,39 @@ proc_parser_mft_check(const char *fn, struct mft *p)
* Parse and validate a manifest file. Skip checking the fileandhash
* this is done in the post check. After this step we know the mft is
* valid and can be compared.
- * Here we *don't* validate against the list of CRLs, because the
- * certificate used to sign the manifest may specify a CRL that the root
- * certificate didn't, and we haven't scanned for it yet.
- * This chicken-and-egg isn't important, however, because we'll catch
- * the revocation list by the time we scan for any contained resources
- * (ROA, CER) and will see it then.
* Return the mft on success or NULL on failure.
*/
static struct mft *
-proc_parser_mft_pre(char *file, const unsigned char *der, size_t len)
+proc_parser_mft_pre(char *file, const unsigned char *der, size_t len,
+ struct entity *entp)
{
- struct mft *mft;
- X509 *x509;
- struct auth *a;
+ struct mft *mft;
+ X509 *x509;
+ struct crl *crl;
+ struct auth *a;
+ char *c, *crlfile;
if ((mft = mft_parse(&x509, file, der, len)) == NULL)
return NULL;
a = valid_ski_aki(file, &auths, mft->ski, mft->aki);
+ /* load CRL by hand, since it is referenced by the MFT itself */
+ c = x509_get_crl(x509, file);
+ crlfile = strrchr(c, '/');
+ if (crlfile != NULL)
+ crlfile++;
+ else
+ crlfile = c;
+ crl = parse_load_crl_from_mft(entp, crlfile);
+ free(c);
- /* CRL checks disabled here because CRL is referenced from mft */
- if (!valid_x509(file, x509, a, NULL, 0, 1)) {
+ if (!valid_x509(file, x509, a, crl, 1)) {
mft_free(mft);
+ crl_free(crl);
X509_free(x509);
return NULL;
}
+ crl_free(crl);
X509_free(x509);
return mft;
@@ -440,7 +449,7 @@ proc_parser_cert_validate(char *file, struct cert *cert)
a = valid_ski_aki(file, &auths, cert->ski, cert->aki);
crl = get_crl(a);
- if (!valid_x509(file, cert->x509, a, crl, X509_V_FLAG_CRL_CHECK, 0)) {
+ if (!valid_x509(file, cert->x509, a, crl, 0)) {
cert_free(cert);
return NULL;
}
@@ -550,8 +559,8 @@ proc_parser_gbr(char *file, const unsigned char *der, size_t len)
{
struct gbr *gbr;
X509 *x509;
- struct auth *a;
struct crl *crl;
+ struct auth *a;
if ((gbr = gbr_parse(&x509, file, der, len)) == NULL)
return;
@@ -560,7 +569,7 @@ proc_parser_gbr(char *file, const unsigned char *der, size_t len)
crl = get_crl(a);
/* return value can be ignored since nothing happens here */
- valid_x509(file, x509, a, crl, X509_V_FLAG_CRL_CHECK, 0);
+ valid_x509(file, x509, a, crl, 0);
X509_free(x509);
gbr_free(gbr);
@@ -598,7 +607,6 @@ get_crl(const struct auth *a)
if (a == NULL)
return NULL;
-
find.aki = a->cert->ski;
return RB_FIND(crl_tree, &crlt, &find);
}
@@ -614,10 +622,8 @@ build_crls(const struct crl *crl, STACK_OF(X509_CRL) **crls)
if (crl == NULL)
return;
-
if ((*crls = sk_X509_CRL_new_null()) == NULL)
errx(1, "sk_X509_CRL_new_null");
-
if (!sk_X509_CRL_push(*crls, crl->x509_crl))
err(1, "sk_X509_CRL_push");
}
@@ -642,6 +648,9 @@ parse_load_file(struct entity *entp, unsigned char **f, size_t *flen)
return file;
}
+/*
+ * Load the most recent MFT by opening both options and comparing the two.
+ */
static char *
parse_load_mft(struct entity *entp, struct mft **mft)
{
@@ -656,7 +665,7 @@ parse_load_mft(struct entity *entp, struct mft **mft)
f = load_file(file1, &flen);
if (f == NULL && errno != ENOENT)
warn("parse file %s", file1);
- mft1 = proc_parser_mft_pre(file1, f, flen);
+ mft1 = proc_parser_mft_pre(file1, f, flen, entp);
free(f);
}
@@ -664,7 +673,7 @@ parse_load_mft(struct entity *entp, struct mft **mft)
f = load_file(file2, &flen);
if (f == NULL && errno != ENOENT)
warn("parse file %s", file2);
- mft2 = proc_parser_mft_pre(file2, f, flen);
+ mft2 = proc_parser_mft_pre(file2, f, flen, entp);
free(f);
}
@@ -682,6 +691,54 @@ parse_load_mft(struct entity *entp, struct mft **mft)
}
/*
+ * Load the most recent CRL by opening both options and comparing the two.
+ */
+static struct crl *
+parse_load_crl_from_mft(struct entity *entp, const char *file)
+{
+ struct crl *crl1 = NULL, *crl2 = NULL;
+ char *file1, *file2;
+ unsigned char *f;
+ size_t flen;
+
+ if (file == NULL)
+ return NULL;
+
+ file1 = parse_filepath(entp->repoid, entp->path, file, DIR_VALID);
+ file2 = parse_filepath(entp->repoid, entp->path, file, DIR_TEMP);
+
+ if (file1 != NULL) {
+ f = load_file(file1, &flen);
+ if (f == NULL && errno != ENOENT)
+ warn("parse file %s", file1);
+ crl1 = crl_parse(file1, f, flen);
+ free(f);
+ }
+
+ if (file2 != NULL) {
+ f = load_file(file2, &flen);
+ if (f == NULL && errno != ENOENT)
+ warn("parse file %s", file2);
+ crl2 = crl_parse(file2, f, flen);
+ free(f);
+ }
+
+ free(file1);
+ free(file2);
+
+ if (crl1 == NULL || crl2 == NULL)
+ return crl2 == NULL ? crl1 : crl2;
+
+ if (crl1->issued >= crl2->issued) {
+ crl_free(crl2);
+ return crl1;
+ } else {
+ crl_free(crl1);
+ return crl2;
+ }
+}
+
+/*
* Process an entity and responing to parent process.
*/
static void
@@ -958,7 +1015,6 @@ proc_parser_file(char *file, unsigned char *buf, size_t len)
struct tal *tal = NULL;
enum rtype type;
char *aia = NULL, *aki = NULL;
- unsigned long verify_flags = X509_V_FLAG_CRL_CHECK;
if (num++ > 0)
printf("--\n");
@@ -995,7 +1051,6 @@ proc_parser_file(char *file, unsigned char *buf, size_t len)
mft_print(mft);
aia = mft->aia;
aki = mft->aki;
- verify_flags = 0;
break;
case RTYPE_ROA:
roa = roa_parse(&x509, file, buf, len);
@@ -1038,7 +1093,7 @@ proc_parser_file(char *file, unsigned char *buf, size_t len)
a = auth_find(&auths, aki);
crl = get_crl(a);
- if (valid_x509(file, x509, a, crl, verify_flags, 0))
+ if (valid_x509(file, x509, a, crl, 0))
printf("Validation: OK\n");
else
printf("Validation: Failed\n");