-/* $OpenBSD: cms.c,v 1.11 2021/10/26 10:52:49 claudio Exp $ */
+/* $OpenBSD: cms.c,v 1.12 2022/01/18 16:18:22 claudio Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
*/
unsigned char *
cms_parse_validate(X509 **xp, const char *fn, const unsigned char *der,
- size_t derlen, const ASN1_OBJECT *oid, size_t *rsz)
+ size_t derlen, const ASN1_OBJECT *oid, size_t *rsz, int nowarn)
{
const ASN1_OBJECT *obj;
ASN1_OCTET_STRING **os = NULL;
return NULL;
if ((cms = d2i_CMS_ContentInfo(NULL, &der, derlen)) == NULL) {
+ if (nowarn)
+ goto out;
cryptowarnx("%s: RFC 6488: failed CMS parse", fn);
goto out;
}
if (!CMS_verify(cms, NULL, NULL, NULL, NULL,
CMS_NO_SIGNER_CERT_VERIFY)) {
+ if (nowarn)
+ goto out;
cryptowarnx("%s: RFC 6488: CMS not self-signed", fn);
goto out;
}
if (OBJ_cmp(obj, oid) != 0) {
char buf[128], obuf[128];
+ if (nowarn)
+ goto out;
OBJ_obj2txt(buf, sizeof(buf), obj, 1);
OBJ_obj2txt(obuf, sizeof(obuf), oid, 1);
warnx("%s: RFC 6488 section 2.1.3.1: eContentType: "
certs = CMS_get0_signers(cms);
if (certs == NULL || sk_X509_num(certs) != 1) {
+ if (nowarn)
+ goto out;
warnx("%s: RFC 6488 section 2.1.4: eContent: "
"want 1 signer, have %d", fn, sk_X509_num(certs));
goto out;
/* Verify that we have eContent to disseminate. */
if ((os = CMS_get0_content(cms)) == NULL || *os == NULL) {
+ if (nowarn)
+ goto out;
warnx("%s: RFC 6488 section 2.1.4: "
"eContent: zero-length content", fn);
goto out;
-/* $OpenBSD: extern.h,v 1.105 2022/01/18 13:06:43 claudio Exp $ */
+/* $OpenBSD: extern.h,v 1.106 2022/01/18 16:18:22 claudio Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
void mft_free(struct mft *);
struct mft *mft_parse(X509 **, const char *, const unsigned char *,
size_t);
-int mft_check(const char *, struct mft *);
struct mft *mft_read(struct ibuf *);
+int mft_compare(const struct mft *, const struct mft *);
void roa_buffer(struct ibuf *, const struct roa *);
void roa_free(struct roa *);
/* Working with CMS. */
unsigned char *cms_parse_validate(X509 **, const char *,
const unsigned char *, size_t,
- const ASN1_OBJECT *, size_t *);
+ const ASN1_OBJECT *, size_t *, int);
int cms_econtent_version(const char *, const unsigned char **,
size_t, long *);
/* Helper for ASN1 parsing */
-/* $OpenBSD: gbr.c,v 1.12 2022/01/18 13:06:43 claudio Exp $ */
+/* $OpenBSD: gbr.c,v 1.13 2022/01/18 16:18:22 claudio Exp $ */
/*
* Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
*
memset(&p, 0, sizeof(struct parse));
p.fn = fn;
- cms = cms_parse_validate(x509, fn, der, len, gbr_oid, &cmsz);
+ cms = cms_parse_validate(x509, fn, der, len, gbr_oid, &cmsz, 0);
if (cms == NULL)
return NULL;
-/* $OpenBSD: mft.c,v 1.46 2022/01/18 13:06:43 claudio Exp $ */
+/* $OpenBSD: mft.c,v 1.47 2022/01/18 16:18:22 claudio Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
/*
* Parse the objects that have been published in the manifest.
* This conforms to RFC 6486.
- * Note that if the MFT is stale, all referenced objects are stripped
- * from the parsed content.
- * The MFT content is otherwise returned.
+ * On success the MFT content is returned. Stale MFTs only set
+ * the stale flag and returned like valid MFTs.
*/
struct mft *
mft_parse(X509 **x509, const char *fn, const unsigned char *der, size_t len)
memset(&p, 0, sizeof(struct parse));
p.fn = fn;
- cms = cms_parse_validate(x509, fn, der, len, mft_oid, &cmsz);
+ cms = cms_parse_validate(x509, fn, der, len, mft_oid, &cmsz, 0);
if (cms == NULL)
return NULL;
assert(*x509 != NULL);
return p;
}
+
+/*
+ * Compare two MFT files, returns 1 if first MFT is better and 0 if second
+ * should be used.
+ */
+int
+mft_compare(const struct mft *a, const struct mft *b)
+{
+ BIGNUM *abn = NULL, *bbn = NULL;
+ int r;
+
+ if (a == NULL)
+ return 0;
+ if (b == NULL)
+ return 1;
+
+warnx("%s: seq a %s, seq b %s", __func__, a->seqnum, b->seqnum);
+ BN_hex2bn(&abn, a->seqnum);
+ BN_hex2bn(&bbn, b->seqnum);
+
+ r = BN_cmp(abn, bbn);
+ BN_free(abn);
+ BN_free(bbn);
+
+ if (r <= 0)
+ return 0;
+
+warnx("%s: prefer b", __func__);
+ /*
+ * Equal sequence numbers should not happen for different content.
+ * In this case we prefer the newer MFT. It seems some CA update
+ * the EE cert and timestamps without issuing a new serial.
+ * This is bad bad bad bad bad.
+ */
+ return 1;
+}
-/* $OpenBSD: parser.c,v 1.39 2022/01/18 13:46:07 claudio Exp $ */
+/* $OpenBSD: parser.c,v 1.40 2022/01/18 16:18:22 claudio Exp $ */
/*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
* Check all files and their hashes in a MFT structure.
* Return zero on failure, non-zero on success.
*/
-int
+static int
mft_check(const char *fn, struct mft *p)
{
size_t i;
struct entity *entp;
struct tal *tal;
struct cert *cert;
- struct mft *mft;
+ struct mft *mft, *mft2;
struct roa *roa;
struct ibuf *b;
unsigned char *f;
size_t flen;
- char *file;
+ char *file, *nfile;
int c;
while ((entp = TAILQ_FIRST(q)) != NULL) {
/* 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);
+ if (entp->type != RTYPE_MFT) /* MFT handled specially */
+ io_str_buffer(b, file);
switch (entp->type) {
case RTYPE_TAL:
case RTYPE_MFT:
mft = proc_parser_mft(file, f, flen,
entp->path, entp->repoid);
+
+ /* need to check alternate mft and compare serial */
+ nfile = parse_filepath(entp->repoid, entp->path,
+ entp->file, 1);
+ if (nfile != NULL && strcmp(nfile, file) != 0) {
+ free(f);
+ f = load_file(nfile, &flen);
+ mft2 = proc_parser_mft(nfile, f, flen,
+ entp->path, entp->repoid);
+ if (mft_compare(mft2, mft)) {
+ /* swap MFT */
+warnx("using old valid MFT %s", nfile);
+ mft_free(mft);
+ mft = mft2;
+ mft2 = NULL;
+ free(file);
+ file = nfile;
+ nfile = NULL;
+ }
+ mft_free(mft2);
+ }
+ free(nfile);
+
c = (mft != NULL);
+ io_str_buffer(b, file);
io_simple_buffer(b, &c, sizeof(int));
if (mft != NULL)
mft_buffer(b, mft);
-/* $OpenBSD: roa.c,v 1.35 2022/01/18 13:06:43 claudio Exp $ */
+/* $OpenBSD: roa.c,v 1.36 2022/01/18 16:18:22 claudio Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
memset(&p, 0, sizeof(struct parse));
p.fn = fn;
- cms = cms_parse_validate(x509, fn, der, len, roa_oid, &cmsz);
+ cms = cms_parse_validate(x509, fn, der, len, roa_oid, &cmsz, 0);
if (cms == NULL)
return NULL;
-/* $OpenBSD: x509.c,v 1.31 2022/01/18 16:09:51 tb Exp $ */
+/* $OpenBSD: x509.c,v 1.32 2022/01/18 16:18:22 claudio Exp $ */
/*
* Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
ASN1_OBJECT *gbr_oid; /* id-ct-rpkiGhostbusters CMS content type */
ASN1_OBJECT *bgpsec_oid; /* id-kp-bgpsec-router Key Purpose */
-
void
x509_init_oid(void)
{