-/* $OpenBSD: main.c,v 1.193 2022/04/11 18:59:23 claudio Exp $ */
+/* $OpenBSD: main.c,v 1.194 2022/04/19 09:52:29 claudio Exp $ */
/*
* Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
* These are always relative to the directory in which "mft" sits.
*/
static void
-queue_add_from_mft(const char *path, const struct mftfile *file,
- struct repo *rp)
-{
- char *nfile, *npath = NULL;
-
- if (path != NULL)
- if ((npath = strdup(path)) == NULL)
- err(1, NULL);
- if ((nfile = strdup(file->file)) == NULL)
- err(1, NULL);
-
- entityq_add(npath, nfile, file->type, file->location, rp, NULL, 0, -1);
-}
-
-/*
- * Loops over queue_add_from_mft() for all files.
- * The order here is important: we want to parse the revocation
- * list *before* we parse anything else.
- */
-static void
-queue_add_from_mft_set(const struct mft *mft, const char *name, struct repo *rp)
+queue_add_from_mft(const struct mft *mft, struct repo *rp)
{
size_t i;
const struct mftfile *f;
+ char *nfile, *npath = NULL;
for (i = 0; i < mft->filesz; i++) {
f = &mft->files[i];
- if (f->type != RTYPE_CRL)
- continue;
- queue_add_from_mft(mft->path, f, rp);
- }
-
- for (i = 0; i < mft->filesz; i++) {
- f = &mft->files[i];
- switch (f->type) {
- case RTYPE_CER:
- case RTYPE_ROA:
- case RTYPE_GBR:
- queue_add_from_mft(mft->path, f, rp);
- break;
- case RTYPE_CRL:
- continue;
- default:
- warnx("%s: unsupported file: %s", name, f->file);
- }
+ if (mft->path != NULL)
+ if ((npath = strdup(mft->path)) == NULL)
+ err(1, NULL);
+ if ((nfile = strdup(f->file)) == NULL)
+ err(1, NULL);
+ entityq_add(npath, nfile, f->type, f->location, rp, NULL, 0,
+ -1);
}
}
}
mft = mft_read(b);
if (!mft->stale)
- queue_add_from_mft_set(mft, file,
- repo_byid(mft->repoid));
+ queue_add_from_mft(mft, repo_byid(mft->repoid));
else
st->mfts_stale++;
mft_free(mft);
-/* $OpenBSD: mft.c,v 1.57 2022/04/11 10:03:12 claudio Exp $ */
+/* $OpenBSD: mft.c,v 1.58 2022/04/19 09:52:29 claudio Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
struct parse {
const char *fn; /* manifest file name */
struct mft *res; /* result object */
+ int found_crl;
};
extern ASN1_OBJECT *mft_oid;
size_t dsz = os->length;
int rc = 0;
struct mftfile *fent;
+ enum rtype type;
if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
cryptowarnx("%s: RFC 6486 section 4.2.1: FileAndHash: "
goto out;
}
+ type = rtype_from_mftfile(fn);
+ /* remember the filehash for the CRL in struct mft */
+ if (type == RTYPE_CRL && strcmp(fn, p->res->crl) == 0) {
+ memcpy(p->res->crlhash, hash->value.bit_string->data,
+ SHA256_DIGEST_LENGTH);
+ p->found_crl = 1;
+ }
+
/* Insert the filename and hash value. */
fent = &p->res->files[p->res->filesz++];
-
- fent->type = rtype_from_mftfile(fn);
+ fent->type = type;
fent->file = fn;
fn = NULL;
memcpy(fent->hash, hash->value.bit_string->data, SHA256_DIGEST_LENGTH);
goto out;
}
+ if (!p->found_crl) {
+ warnx("%s: CRL not part of MFT fileList", p->fn);
+ goto out;
+ }
+
rc = 1;
out:
sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
int rc = 0;
size_t cmsz;
unsigned char *cms;
+ char *crldp, *crlfile;
memset(&p, 0, sizeof(struct parse));
p.fn = fn;
goto out;
}
+ /* get CRL info for later */
+ if (!x509_get_crl(*x509, fn, &crldp))
+ goto out;
+ if (crldp == NULL) {
+ warnx("%s: RFC 6487 section 4.8.6: CRL: "
+ "missing CRL distribution point extension", fn);
+ goto out;
+ }
+ if ((crlfile = strrchr(crldp, '/')) == NULL ||
+ !valid_filename(crlfile + 1, strlen(crlfile + 1)) ||
+ rtype_from_file_extension(crlfile + 1) != RTYPE_CRL) {
+ warnx("%s: RFC 6487 section 4.8.6: CRL: "
+ "bad CRL distribution point extension", fn);
+ goto out;
+ }
+ if ((p.res->crl = strdup(crlfile + 1)) == NULL)
+ err(1, NULL);
+ free(crldp);
+
if (mft_parse_econtent(cms, cmsz, &p) == 0)
goto out;
-/* $OpenBSD: parser.c,v 1.67 2022/04/11 18:59:23 claudio Exp $ */
+/* $OpenBSD: parser.c,v 1.68 2022/04/19 09:52:29 claudio Exp $ */
/*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
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);
return rc;
}
+/*
+ * Load the correct CRL using the info from the MFT.
+ */
+static struct crl *
+parse_load_crl_from_mft(struct entity *entp, struct mft *mft, enum location loc)
+{
+ struct crl *crl = NULL;
+ unsigned char *f = NULL;
+ char *fn = NULL;
+ size_t flen;
+
+ while (1) {
+ fn = parse_filepath(entp->repoid, entp->path, mft->crl, loc);
+ if (fn == NULL)
+ goto next;
+
+ f = load_file(fn, &flen);
+ if (f == NULL && errno != ENOENT)
+ warn("parse file %s", fn);
+ if (f == NULL)
+ goto next;
+ if (!valid_hash(f, flen, mft->crlhash, sizeof(mft->crlhash)))
+ goto next;
+ crl = crl_parse(fn, f, flen);
+next:
+ free(f);
+ free(fn);
+ f = NULL;
+ fn = NULL;
+
+ if (crl != NULL)
+ return crl;
+ if (loc == DIR_TEMP)
+ loc = DIR_VALID;
+ else
+ return NULL;
+ }
+}
+
/*
* 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
*/
static struct mft *
proc_parser_mft_pre(char *file, const unsigned char *der, size_t len,
- struct entity *entp)
+ struct entity *entp, enum location loc, struct crl **crl)
{
struct mft *mft;
X509 *x509;
- struct crl *crl;
struct auth *a;
- char *c, *crlfile;
+ *crl = NULL;
if ((mft = mft_parse(&x509, file, der, len)) == NULL)
return NULL;
+ *crl = parse_load_crl_from_mft(entp, mft, loc);
a = valid_ski_aki(file, &auths, mft->ski, mft->aki);
- /* load CRL by hand, since it is referenced by the MFT itself */
- if (!x509_get_crl(x509, file, &c) || c == NULL) {
- if (c == NULL)
- warnx("%s: RFC 6487 section 4.8.6: CRL: "
- "no CRL distribution point extension", file);
- mft_free(mft);
+ if (!valid_x509(file, x509, a, *crl, 1)) {
X509_free(x509);
- return NULL;
- }
- crlfile = strrchr(c, '/');
- if (crlfile != NULL)
- crlfile++;
- else
- crlfile = c;
- crl = parse_load_crl_from_mft(entp, crlfile);
- free(c);
-
- if (!valid_x509(file, x509, a, crl, 1)) {
mft_free(mft);
- crl_free(crl);
- X509_free(x509);
+ crl_free(*crl);
+ *crl = NULL;
return NULL;
}
- crl_free(crl);
X509_free(x509);
+ mft->repoid = entp->repoid;
return mft;
}
* Return the mft on success or NULL on failure.
*/
static struct mft *
-proc_parser_mft_post(char *file, struct mft *mft, const char *path,
- unsigned int repoid)
+proc_parser_mft_post(char *file, struct mft *mft, const char *path)
{
/* check that now is not before from */
time_t now = time(NULL);
mft->stale = 1;
}
- mft->repoid = repoid;
if (path != NULL)
if ((mft->path = strdup(path)) == NULL)
err(1, NULL);
return mft;
}
+/*
+ * Load the most recent MFT by opening both options and comparing the two.
+ */
+static char *
+proc_parser_mft(struct entity *entp, struct mft **mp)
+{
+ struct mft *mft1 = NULL, *mft2 = NULL;
+ struct crl *crl, *crl1 = NULL, *crl2 = NULL;
+ char *f, *file, *file1, *file2;
+ size_t flen;
+
+ *mp = NULL;
+ file1 = parse_filepath(entp->repoid, entp->path, entp->file, DIR_VALID);
+ file2 = parse_filepath(entp->repoid, entp->path, entp->file, DIR_TEMP);
+
+ if (file1 != NULL) {
+ f = load_file(file1, &flen);
+ if (f == NULL && errno != ENOENT)
+ warn("parse file %s", file1);
+ mft1 = proc_parser_mft_pre(file1, f, flen, entp, DIR_VALID,
+ &crl1);
+ free(f);
+ }
+ if (file2 != NULL) {
+ f = load_file(file2, &flen);
+ if (f == NULL && errno != ENOENT)
+ warn("parse file %s", file2);
+ mft2 = proc_parser_mft_pre(file2, f, flen, entp, DIR_TEMP,
+ &crl2);
+ free(f);
+ }
+
+ if (mft_compare(mft1, mft2) == 1) {
+ mft_free(mft2);
+ crl_free(crl2);
+ free(file2);
+ *mp = proc_parser_mft_post(file1, mft1, entp->path);
+ crl = crl1;
+ file = file1;
+ } else {
+ mft_free(mft1);
+ crl_free(crl1);
+ free(file1);
+ *mp = proc_parser_mft_post(file2, mft2, entp->path);
+ crl = crl2;
+ file = file2;
+ }
+
+ if (*mp != NULL) {
+ if (RB_INSERT(crl_tree, &crlt, crl) != NULL) {
+ warnx("%s: duplicate AKI %s", file, crl->aki);
+ crl_free(crl);
+ }
+ } else {
+ crl_free(crl);
+ }
+ return file;
+}
+
/*
* Validate a certificate, if invalid free the resouces and return NULL.
*/
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)
-{
- struct mft *mft1 = NULL, *mft2 = NULL;
- char *f, *file1, *file2;
- size_t flen;
-
- file1 = parse_filepath(entp->repoid, entp->path, entp->file, DIR_VALID);
- file2 = parse_filepath(entp->repoid, entp->path, entp->file, DIR_TEMP);
-
- if (file1 != NULL) {
- f = load_file(file1, &flen);
- if (f == NULL && errno != ENOENT)
- warn("parse file %s", file1);
- mft1 = proc_parser_mft_pre(file1, f, flen, entp);
- free(f);
- }
-
- if (file2 != NULL) {
- f = load_file(file2, &flen);
- if (f == NULL && errno != ENOENT)
- warn("parse file %s", file2);
- mft2 = proc_parser_mft_pre(file2, f, flen, entp);
- free(f);
- }
-
- if (mft_compare(mft1, mft2) == 1) {
- mft_free(mft2);
- free(file2);
- *mft = mft1;
- return file1;
- } else {
- mft_free(mft1);
- free(file1);
- *mft = mft2;
- return file2;
- }
-}
-
-/*
- * 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.
*/
*/
break;
case RTYPE_CRL:
- file = parse_load_file(entp, &f, &flen);
+ /*
+ * CRLs are already loaded with the MFT so nothing
+ * really needs to be done here.
+ */
+ file = parse_filepath(entp->repoid, entp->path,
+ entp->file, entp->location);
io_str_buffer(b, file);
- proc_parser_crl(file, f, flen);
break;
case RTYPE_MFT:
- file = parse_load_mft(entp, &mft);
-
- mft = proc_parser_mft_post(file, mft,
- entp->path, entp->repoid);
-
+ file = proc_parser_mft(entp, &mft);
io_str_buffer(b, file);
c = (mft != NULL);
io_simple_buffer(b, &c, sizeof(int));