-/* $OpenBSD: parser.c,v 1.41 2022/01/18 16:24:55 claudio Exp $ */
+/* $OpenBSD: parser.c,v 1.42 2022/01/18 16:29:06 claudio Exp $ */
/*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
struct parse_repo {
RB_ENTRY(parse_repo) entry;
char *path;
+ char *validpath;
unsigned int id;
};
}
static void
-repo_add(unsigned int id, char *path)
+repo_add(unsigned int id, char *path, char *validpath)
{
struct parse_repo *rp;
- if ((rp = malloc(sizeof(*rp))) == NULL)
+ if ((rp = calloc(1, sizeof(*rp))) == NULL)
err(1, NULL);
rp->id = id;
- if ((rp->path = strdup(path)) == NULL)
- err(1, NULL);
+ if (path != NULL)
+ if ((rp->path = strdup(path)) == NULL)
+ err(1, NULL);
+ if (validpath != NULL)
+ if ((rp->validpath = strdup(validpath)) == NULL)
+ err(1, NULL);
if (RB_INSERT(repo_tree, &repos, rp) != NULL)
errx(1, "repository already added: id %d, %s", id, path);
}
+/*
+ * Build access path to file based on repoid, path and file values.
+ * If wantalt == 1 the function can return NULL, if wantalt == 0 it
+ * can not fail.
+ */
+static char *
+parse_filepath(unsigned int repoid, const char *path, const char *file,
+ int wantalt)
+{
+ struct parse_repo *rp;
+ char *fn, *repopath;
+
+ /* build file path based on repoid, entity path and filename */
+ rp = repo_get(repoid);
+ if (rp == NULL) {
+ /* no repo so no alternative path. */
+ if (wantalt)
+ return NULL;
+
+ if (path == NULL) {
+ if ((fn = strdup(file)) == NULL)
+ err(1, NULL);
+ } else {
+ if (asprintf(&fn, "%s/%s", path, file) == -1)
+ err(1, NULL);
+ }
+ } else {
+ if (wantalt || rp->path == NULL)
+ repopath = rp->validpath;
+ else
+ repopath = rp->path;
+
+ if (repopath == NULL)
+ return NULL;
+
+ if (path == NULL) {
+ if (asprintf(&fn, "%s/%s", repopath, file) == -1)
+ err(1, NULL);
+ } else {
+ if (asprintf(&fn, "%s/%s/%s", repopath, path,
+ file) == -1)
+ err(1, NULL);
+ }
+ }
+ return fn;
+}
+
+/*
+ * Callback for X509_verify_cert() to handle critical extensions in old
+ * LibreSSL libraries or OpenSSL libs without RFC3779 support.
+ */
static int
verify_cb(int ok, X509_STORE_CTX *store_ctx)
{
}
/*
- * Parse and validate a ROA.
- * This is standard stuff.
- * Returns the roa on success, NULL on failure.
+ * Validate the X509 certificate. If crl is NULL don't check CRL.
+ * Returns 1 for valid certificates, returns 0 if there is a verify error
*/
-static struct roa *
-proc_parser_roa(char *file, const unsigned char *der, size_t len)
+static int
+valid_x509(char *file, X509 *x509, struct auth *a, struct crl *crl)
{
- struct roa *roa;
- X509 *x509;
- int c;
- struct auth *a;
STACK_OF(X509) *chain;
- STACK_OF(X509_CRL) *crls;
- struct crl *crl;
-
- if ((roa = roa_parse(&x509, file, der, len)) == NULL)
- return NULL;
+ STACK_OF(X509_CRL) *crls = NULL;
+ int c;
- a = valid_ski_aki(file, &auths, roa->ski, roa->aki);
build_chain(a, &chain);
- crl = get_crl(a);
- build_crls(crl, &crls);
+ if (crl != NULL)
+ build_crls(crl, &crls);
assert(x509 != NULL);
if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL))
cryptoerrx("X509_STORE_CTX_init");
+
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");
- X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_CRL_CHECK);
+ if (crl != NULL)
+ X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_CRL_CHECK);
X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH);
X509_STORE_CTX_set0_trusted_stack(ctx, chain);
- X509_STORE_CTX_set0_crls(ctx, crls);
+ if (crl != NULL)
+ X509_STORE_CTX_set0_crls(ctx, crls);
if (X509_verify_cert(ctx) <= 0) {
c = X509_STORE_CTX_get_error(ctx);
+ warnx("%s: %s", file, X509_verify_cert_error_string(c));
X509_STORE_CTX_cleanup(ctx);
- if (verbose > 0 || c != X509_V_ERR_UNABLE_TO_GET_CRL)
- warnx("%s: %s", file, X509_verify_cert_error_string(c));
- X509_free(x509);
- roa_free(roa);
sk_X509_free(chain);
sk_X509_CRL_free(crls);
- return NULL;
+ return 0;
}
+
X509_STORE_CTX_cleanup(ctx);
+ sk_X509_free(chain);
+ sk_X509_CRL_free(crls);
+ return 1;
+}
+
+/*
+ * Parse and validate a ROA.
+ * This is standard stuff.
+ * Returns the roa on success, NULL on failure.
+ */
+static struct roa *
+proc_parser_roa(char *file, const unsigned char *der, size_t len)
+{
+ struct roa *roa;
+ struct crl *crl;
+ struct auth *a;
+ X509 *x509;
+
+ if ((roa = roa_parse(&x509, file, der, len)) == NULL)
+ return NULL;
+
+ a = valid_ski_aki(file, &auths, roa->ski, roa->aki);
+ crl = get_crl(a);
+
+ if (!valid_x509(file, x509, a, crl)) {
+ X509_free(x509);
+ roa_free(roa);
+ return NULL;
+ }
+ X509_free(x509);
/*
* Check CRL to figure out the soonest transitive expiry moment
if (valid_roa(file, &auths, roa))
roa->valid = 1;
- sk_X509_free(chain);
- sk_X509_CRL_free(crls);
- X509_free(x509);
-
return roa;
}
mft_check(const char *fn, struct mft *p)
{
size_t i;
- int fd, rc = 1;
- char *cp, *h, *path = NULL;
-
- /* Check hash of file now, but first build path for it */
- cp = strrchr(fn, '/');
- assert(cp != NULL);
- assert(cp - fn < INT_MAX);
+ int fd, try, rc = 1;
+ char *h, *path;
for (i = 0; i < p->filesz; i++) {
const struct mftfile *m = &p->files[i];
free(h);
continue;
}
- if (asprintf(&path, "%.*s/%s", (int)(cp - fn), fn,
- m->file) == -1)
- err(1, NULL);
- fd = open(path, O_RDONLY);
+
+ fd = -1;
+ try = 0;
+ path = NULL;
+ do {
+ free(path);
+ if ((path = parse_filepath(p->repoid, p->path, m->file,
+ try++)) == NULL)
+ break;
+ fd = open(path, O_RDONLY);
+ } while (fd == -1 && try < 2);
+
+ free(path);
+
if (!valid_filehash(fd, m->hash, sizeof(m->hash))) {
warnx("%s: bad message digest for %s", fn, m->file);
rc = 0;
}
- free(path);
}
return rc;
{
struct mft *mft;
X509 *x509;
- int c;
struct auth *a;
- STACK_OF(X509) *chain;
if ((mft = mft_parse(&x509, file, der, len)) == NULL)
return NULL;
a = valid_ski_aki(file, &auths, mft->ski, mft->aki);
- build_chain(a, &chain);
-
- if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL))
- cryptoerrx("X509_STORE_CTX_init");
-
- /* CRL checks disabled here because CRL is referenced from mft */
- 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");
- X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH);
- X509_STORE_CTX_set0_trusted_stack(ctx, chain);
- if (X509_verify_cert(ctx) <= 0) {
- c = X509_STORE_CTX_get_error(ctx);
- X509_STORE_CTX_cleanup(ctx);
- warnx("%s: %s", file, X509_verify_cert_error_string(c));
+ if (!valid_x509(file, x509, a, NULL)) {
mft_free(mft);
X509_free(x509);
- sk_X509_free(chain);
return NULL;
}
-
- X509_STORE_CTX_cleanup(ctx);
- sk_X509_free(chain);
X509_free(x509);
- if (!mft_check(file, mft)) {
- mft_free(mft);
- return NULL;
- }
-
+ mft->repoid = repoid;
if (path != NULL)
if ((mft->path = strdup(path)) == NULL)
err(1, NULL);
- mft->repoid = repoid;
+
+ if (!mft->stale)
+ if (!mft_check(file, mft)) {
+ mft_free(mft);
+ return NULL;
+ }
+
return mft;
}
{
struct cert *cert;
X509 *x509;
- int c;
- struct auth *a = NULL;
- STACK_OF(X509) *chain;
- STACK_OF(X509_CRL) *crls;
+ struct auth *a;
+ struct crl *crl;
/* Extract certificate data and X509. */
return NULL;
a = valid_ski_aki(file, &auths, cert->ski, cert->aki);
- build_chain(a, &chain);
- build_crls(get_crl(a), &crls);
-
- assert(x509 != NULL);
- if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL))
- cryptoerrx("X509_STORE_CTX_init");
-
- 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");
- X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_CRL_CHECK);
- X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH);
- X509_STORE_CTX_set0_trusted_stack(ctx, chain);
- X509_STORE_CTX_set0_crls(ctx, crls);
+ crl = get_crl(a);
- if (X509_verify_cert(ctx) <= 0) {
- c = X509_STORE_CTX_get_error(ctx);
- warnx("%s: %s", file, X509_verify_cert_error_string(c));
- X509_STORE_CTX_cleanup(ctx);
+ if (!valid_x509(file, x509, a, crl)) {
cert_free(cert);
- sk_X509_free(chain);
- sk_X509_CRL_free(crls);
X509_free(x509);
return NULL;
}
-
- X509_STORE_CTX_cleanup(ctx);
- sk_X509_free(chain);
- sk_X509_CRL_free(crls);
X509_free(x509);
cert->talid = a->cert->talid;
{
struct gbr *gbr;
X509 *x509;
- int c;
struct auth *a;
- STACK_OF(X509) *chain;
- STACK_OF(X509_CRL) *crls;
+ struct crl *crl;
if ((gbr = gbr_parse(&x509, file, der, len)) == NULL)
return;
a = valid_ski_aki(file, &auths, gbr->ski, gbr->aki);
+ crl = get_crl(a);
- build_chain(a, &chain);
- build_crls(get_crl(a), &crls);
-
- assert(x509 != NULL);
- if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL))
- cryptoerrx("X509_STORE_CTX_init");
- 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");
- X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_CRL_CHECK);
- X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH);
- X509_STORE_CTX_set0_trusted_stack(ctx, chain);
- X509_STORE_CTX_set0_crls(ctx, crls);
-
- if (X509_verify_cert(ctx) <= 0) {
- c = X509_STORE_CTX_get_error(ctx);
- if (verbose > 0 || c != X509_V_ERR_UNABLE_TO_GET_CRL)
- warnx("%s: %s", file, X509_verify_cert_error_string(c));
- }
+ /* return value can be ignored since nothing happens here */
+ valid_x509(file, x509, a, crl);
- X509_STORE_CTX_cleanup(ctx);
- sk_X509_free(chain);
- sk_X509_CRL_free(crls);
X509_free(x509);
gbr_free(gbr);
}
}
static char *
-parse_filepath(struct entity *entp)
+parse_load_file(struct entity *entp, unsigned char **f, size_t *flen)
{
- struct parse_repo *rp;
- char *file;
+ char *file, *nfile;
- /* build file path based on repoid, entity path and filename */
- rp = repo_get(entp->repoid);
- if (rp == NULL) {
- if (entp->path == NULL) {
- if ((file = strdup(entp->file)) == NULL)
- err(1, NULL);
- } else {
- if (asprintf(&file, "%s/%s", entp->path,
- entp->file) == -1)
- err(1, NULL);
- }
- } else {
- if (entp->path == NULL) {
- if (asprintf(&file, "%s/%s", rp->path,
- entp->file) == -1)
- err(1, NULL);
- } else {
- if (asprintf(&file, "%s/%s/%s", rp->path,
- entp->path, entp->file) == -1)
- err(1, NULL);
- }
+ file = parse_filepath(entp->repoid, entp->path, entp->file, 0);
+
+ /* TAL files include the data already */
+ if (entp->type == RTYPE_TAL) {
+ *f = NULL;
+ *flen = 0;
+ return file;
}
+
+ *f = load_file(file, flen);
+ if (*f != NULL)
+ return file;
+
+ if (errno != ENOENT)
+ goto fail;
+
+ /* try alternate file location */
+ nfile = parse_filepath(entp->repoid, entp->path, entp->file, 1);
+ if (nfile == NULL)
+ goto fail;
+
+ free(file);
+ file = nfile;
+
+ *f = load_file(file, flen);
+ if (*f != NULL)
+ return file;
+
+fail:
+ warn("parse file %s", file);
return file;
}
/* handle RTYPE_REPO first */
if (entp->type == RTYPE_REPO) {
- repo_add(entp->repoid, entp->path);
+ repo_add(entp->repoid, entp->path, entp->file);
entity_free(entp);
continue;
}
- f = NULL;
- file = parse_filepath(entp);
- if (entp->type != RTYPE_TAL) {
- f = load_file(file, &flen);
- if (f == NULL)
- warn("%s", file);
- }
+ file = parse_load_file(entp, &f, &flen);
- /* pass back at least type and filename */
+ /* pass back at least type, repoid and filename */
b = io_new_buffer();
io_simple_buffer(b, &entp->type, sizeof(entp->type));
io_str_buffer(b, file);
ERR_load_crypto_strings();
OpenSSL_add_all_ciphers();
OpenSSL_add_all_digests();
+ x509_init_oid();
if ((ctx = X509_STORE_CTX_new()) == NULL)
cryptoerrx("X509_STORE_CTX_new");