summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorTheo Buehler <tb@cvs.openbsd.org>2022-05-19 06:37:52 +0000
committerTheo Buehler <tb@cvs.openbsd.org>2022-05-19 06:37:52 +0000
commit40403dafb8be53c282c0e3ddc971a0dce2eb9497 (patch)
treeeddf79beccae36d25b8531bb96a091baa878ad1c /usr.sbin
parent1d32d08dd8b528aa0dc2cb88d2f84aa8279c782b (diff)
Rewrite mft.c and roa.c with ASN.1 templates
The ASN.1 templates are a rather direct translation of the ASN.1 in the relevant RFCs and they allow deserializing the Manifest and ROA eContent in a single step instead of numerous opaque d2i_ASN1_SEQUENCE_ANY() calls. Once the eContent is deserialized, we can walk the structs, validate it as before and populate the internal data structures. Positive feedback job ok claudio
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/rpki-client/mft.c251
-rw-r--r--usr.sbin/rpki-client/roa.c368
2 files changed, 210 insertions, 409 deletions
diff --git a/usr.sbin/rpki-client/mft.c b/usr.sbin/rpki-client/mft.c
index eb8e4691776..cf7ab80188a 100644
--- a/usr.sbin/rpki-client/mft.c
+++ b/usr.sbin/rpki-client/mft.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mft.c,v 1.65 2022/05/15 15:00:53 deraadt Exp $ */
+/* $OpenBSD: mft.c,v 1.66 2022/05/19 06:37:51 tb Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -27,7 +27,10 @@
#include <openssl/bn.h>
#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/safestack.h>
#include <openssl/sha.h>
+#include <openssl/stack.h>
#include <openssl/x509.h>
#include "extern.h"
@@ -44,6 +47,48 @@ struct parse {
extern ASN1_OBJECT *mft_oid;
/*
+ * Types and templates for the Manifest eContent, RFC 6486, section 4.2.
+ */
+
+typedef struct {
+ ASN1_IA5STRING *file;
+ ASN1_BIT_STRING *hash;
+} FileAndHash;
+
+DECLARE_STACK_OF(FileAndHash);
+
+#if defined(LIBRESSL_VERSION_NUMBER)
+#define sk_FileAndHash_num(sk) SKM_sk_num(FileAndHash, (sk))
+#define sk_FileAndHash_value(sk, i) SKM_sk_value(FileAndHash, (sk), (i))
+#endif
+
+typedef struct {
+ ASN1_INTEGER *version;
+ ASN1_INTEGER *manifestNumber;
+ ASN1_GENERALIZEDTIME *thisUpdate;
+ ASN1_GENERALIZEDTIME *nextUpdate;
+ ASN1_OBJECT *fileHashAlg;
+ STACK_OF(FileAndHash) *fileList;
+} Manifest;
+
+ASN1_SEQUENCE(FileAndHash) = {
+ ASN1_SIMPLE(FileAndHash, file, ASN1_IA5STRING),
+ ASN1_SIMPLE(FileAndHash, hash, ASN1_BIT_STRING),
+} ASN1_SEQUENCE_END(FileAndHash);
+
+ASN1_SEQUENCE(Manifest) = {
+ ASN1_IMP_OPT(Manifest, version, ASN1_INTEGER, 0),
+ ASN1_SIMPLE(Manifest, manifestNumber, ASN1_INTEGER),
+ ASN1_SIMPLE(Manifest, thisUpdate, ASN1_GENERALIZEDTIME),
+ ASN1_SIMPLE(Manifest, nextUpdate, ASN1_GENERALIZEDTIME),
+ ASN1_SIMPLE(Manifest, fileHashAlg, ASN1_OBJECT),
+ ASN1_SEQUENCE_OF(Manifest, fileList, FileAndHash),
+} ASN1_SEQUENCE_END(Manifest);
+
+DECLARE_ASN1_FUNCTIONS(Manifest);
+IMPLEMENT_ASN1_FUNCTIONS(Manifest);
+
+/*
* Convert an ASN1_GENERALIZEDTIME to a struct tm.
* Returns 1 on success, 0 on failure.
*/
@@ -173,70 +218,36 @@ rtype_from_mftfile(const char *fn)
* Return zero on failure, non-zero on success.
*/
static int
-mft_parse_filehash(struct parse *p, const ASN1_OCTET_STRING *os)
+mft_parse_filehash(struct parse *p, const FileAndHash *fh)
{
- ASN1_SEQUENCE_ANY *seq;
- const ASN1_TYPE *file, *hash;
char *fn = NULL;
- const unsigned char *d = os->data;
- 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: "
- "failed ASN.1 sequence parse", p->fn);
- goto out;
- }
- if (sk_ASN1_TYPE_num(seq) != 2) {
- warnx("%s: RFC 6486 section 4.2.1: FileAndHash: "
- "want 2 elements, have %d", p->fn,
- sk_ASN1_TYPE_num(seq));
- goto out;
- }
-
/* First is the filename itself. */
- file = sk_ASN1_TYPE_value(seq, 0);
- if (file->type != V_ASN1_IA5STRING) {
- warnx("%s: RFC 6486 section 4.2.1: FileAndHash: "
- "want ASN.1 IA5 string, have %s (NID %d)",
- p->fn, ASN1_tag2str(file->type), file->type);
- goto out;
- }
- if (!valid_mft_filename(file->value.ia5string->data,
- file->value.ia5string->length)) {
+ if (!valid_mft_filename(fh->file->data, fh->file->length)) {
warnx("%s: RFC 6486 section 4.2.2: bad filename", p->fn);
goto out;
}
- fn = strndup((const char *)file->value.ia5string->data,
- file->value.ia5string->length);
+ fn = strndup(fh->file->data, fh->file->length);
if (fn == NULL)
err(1, NULL);
/* Now hash value. */
- hash = sk_ASN1_TYPE_value(seq, 1);
- if (hash->type != V_ASN1_BIT_STRING) {
- warnx("%s: RFC 6486 section 4.2.1: FileAndHash: "
- "want ASN.1 bit string, have %s (NID %d)",
- p->fn, ASN1_tag2str(hash->type), hash->type);
- goto out;
- }
-
- if (hash->value.bit_string->length != SHA256_DIGEST_LENGTH) {
+ if (fh->hash->length != SHA256_DIGEST_LENGTH) {
warnx("%s: RFC 6486 section 4.2.1: hash: "
"invalid SHA256 length, have %d",
- p->fn, hash->value.bit_string->length);
+ p->fn, fh->hash->length);
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);
+ memcpy(p->res->crlhash, fh->hash->data, SHA256_DIGEST_LENGTH);
p->found_crl = 1;
}
@@ -245,64 +256,11 @@ mft_parse_filehash(struct parse *p, const ASN1_OCTET_STRING *os)
fent->type = type;
fent->file = fn;
fn = NULL;
- memcpy(fent->hash, hash->value.bit_string->data, SHA256_DIGEST_LENGTH);
-
- rc = 1;
-out:
- free(fn);
- sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
- return rc;
-}
-
-/*
- * Parse the "FileAndHash" sequence, RFC 6486, sec. 4.2.
- * Return zero on failure, non-zero on success.
- */
-static int
-mft_parse_flist(struct parse *p, const ASN1_OCTET_STRING *os)
-{
- ASN1_SEQUENCE_ANY *seq;
- const ASN1_TYPE *t;
- const unsigned char *d = os->data;
- size_t dsz = os->length;
- int i, rc = 0;
-
- if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
- cryptowarnx("%s: RFC 6486 section 4.2: fileList: "
- "failed ASN.1 sequence parse", p->fn);
- goto out;
- }
-
- if (sk_ASN1_TYPE_num(seq) > MAX_MANIFEST_ENTRIES) {
- warnx("%s: %d exceeds manifest entry limit (%d)", p->fn,
- sk_ASN1_TYPE_num(seq), MAX_MANIFEST_ENTRIES);
- goto out;
- }
-
- p->res->files = calloc(sk_ASN1_TYPE_num(seq), sizeof(struct mftfile));
- if (p->res->files == NULL)
- err(1, NULL);
-
- for (i = 0; i < sk_ASN1_TYPE_num(seq); i++) {
- t = sk_ASN1_TYPE_value(seq, i);
- if (t->type != V_ASN1_SEQUENCE) {
- warnx("%s: RFC 6486 section 4.2: fileList: "
- "want ASN.1 sequence, have %s (NID %d)",
- p->fn, ASN1_tag2str(t->type), t->type);
- goto out;
- }
- if (!mft_parse_filehash(p, t->value.octet_string))
- goto out;
- }
-
- if (!p->found_crl) {
- warnx("%s: CRL not part of MFT fileList", p->fn);
- goto out;
- }
+ memcpy(fent->hash, fh->hash->data, SHA256_DIGEST_LENGTH);
rc = 1;
out:
- sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
+ free(fn);
return rc;
}
@@ -313,35 +271,24 @@ mft_parse_flist(struct parse *p, const ASN1_OCTET_STRING *os)
static int
mft_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p)
{
- ASN1_SEQUENCE_ANY *seq;
- const ASN1_TYPE *t;
- const ASN1_GENERALIZEDTIME *from, *until;
+ Manifest *mft;
+ FileAndHash *fh;
long mft_version;
- int i = 0, rc = 0;
+ int i, rc = 0;
- if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
+ if ((mft = d2i_Manifest(NULL, &d, dsz)) == NULL) {
cryptowarnx("%s: RFC 6486 section 4.2: Manifest: "
"failed ASN.1 sequence parse", p->fn);
goto out;
}
- /* Test if the optional profile version field is present. */
- if (sk_ASN1_TYPE_num(seq) != 5 &&
- sk_ASN1_TYPE_num(seq) != 6) {
- warnx("%s: RFC 6486 section 4.2: Manifest: "
- "want 5 or 6 elements, have %d", p->fn,
- sk_ASN1_TYPE_num(seq));
- goto out;
- }
-
/* Parse the optional version field */
- if (sk_ASN1_TYPE_num(seq) == 6) {
- t = sk_ASN1_TYPE_value(seq, i++);
- d = t->value.asn1_string->data;
- dsz = t->value.asn1_string->length;
-
- if (cms_econtent_version(p->fn, &d, dsz, &mft_version) == -1)
+ if (mft->version != NULL) {
+ mft_version = ASN1_INTEGER_get(mft->version);
+ if (mft_version < 0) {
+ cryptowarnx("%s: ASN1_INTEGER_get failed", p->fn);
goto out;
+ }
switch (mft_version) {
case 0:
@@ -354,17 +301,7 @@ mft_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p)
}
}
- /* Now the manifest sequence number. */
-
- t = sk_ASN1_TYPE_value(seq, i++);
- if (t->type != V_ASN1_INTEGER) {
- warnx("%s: RFC 6486 section 4.2.1: manifestNumber: "
- "want ASN.1 integer, have %s (NID %d)",
- p->fn, ASN1_tag2str(t->type), t->type);
- goto out;
- }
-
- p->res->seqnum = x509_convert_seqnum(p->fn, t->value.integer);
+ p->res->seqnum = x509_convert_seqnum(p->fn, mft->manifestNumber);
if (p->res->seqnum == NULL)
goto out;
@@ -378,60 +315,46 @@ mft_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p)
* compare against the current time trivially.
*/
- t = sk_ASN1_TYPE_value(seq, i++);
- if (t->type != V_ASN1_GENERALIZEDTIME) {
- warnx("%s: RFC 6486 section 4.2.1: thisUpdate: "
- "want ASN.1 generalised time, have %s (NID %d)",
- p->fn, ASN1_tag2str(t->type), t->type);
- goto out;
- }
- from = t->value.generalizedtime;
-
- t = sk_ASN1_TYPE_value(seq, i++);
- if (t->type != V_ASN1_GENERALIZEDTIME) {
- warnx("%s: RFC 6486 section 4.2.1: nextUpdate: "
- "want ASN.1 generalised time, have %s (NID %d)",
- p->fn, ASN1_tag2str(t->type), t->type);
- goto out;
- }
- until = t->value.generalizedtime;
-
- if (!mft_parse_time(from, until, p))
+ if (!mft_parse_time(mft->thisUpdate, mft->nextUpdate, p))
goto out;
/* File list algorithm. */
- t = sk_ASN1_TYPE_value(seq, i++);
- if (t->type != V_ASN1_OBJECT) {
- warnx("%s: RFC 6486 section 4.2.1: fileHashAlg: "
- "want ASN.1 object, have %s (NID %d)",
- p->fn, ASN1_tag2str(t->type), t->type);
- goto out;
- }
- if (OBJ_obj2nid(t->value.object) != NID_sha256) {
+ if (OBJ_obj2nid(mft->fileHashAlg) != NID_sha256) {
warnx("%s: RFC 6486 section 4.2.1: fileHashAlg: "
"want SHA256 object, have %s (NID %d)", p->fn,
- ASN1_tag2str(OBJ_obj2nid(t->value.object)),
- OBJ_obj2nid(t->value.object));
+ ASN1_tag2str(OBJ_obj2nid(mft->fileHashAlg)),
+ OBJ_obj2nid(mft->fileHashAlg));
goto out;
}
/* Now the sequence. */
- t = sk_ASN1_TYPE_value(seq, i++);
- if (t->type != V_ASN1_SEQUENCE) {
- warnx("%s: RFC 6486 section 4.2.1: fileList: "
- "want ASN.1 sequence, have %s (NID %d)",
- p->fn, ASN1_tag2str(t->type), t->type);
+ if (sk_FileAndHash_num(mft->fileList) > MAX_MANIFEST_ENTRIES) {
+ warnx("%s: %d exceeds manifest entry limit (%d)", p->fn,
+ sk_FileAndHash_num(mft->fileList), MAX_MANIFEST_ENTRIES);
goto out;
}
- if (!mft_parse_flist(p, t->value.octet_string))
+ p->res->files = calloc(sk_FileAndHash_num(mft->fileList),
+ sizeof(struct mftfile));
+ if (p->res->files == NULL)
+ err(1, NULL);
+
+ for (i = 0; i < sk_FileAndHash_num(mft->fileList); i++) {
+ fh = sk_FileAndHash_value(mft->fileList, i);
+ if (!mft_parse_filehash(p, fh))
+ 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);
+ out:
+ Manifest_free(mft);
return rc;
}
diff --git a/usr.sbin/rpki-client/roa.c b/usr.sbin/rpki-client/roa.c
index a03efc6086f..56360efd37d 100644
--- a/usr.sbin/rpki-client/roa.c
+++ b/usr.sbin/rpki-client/roa.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: roa.c,v 1.42 2022/05/15 16:43:35 tb Exp $ */
+/* $OpenBSD: roa.c,v 1.43 2022/05/19 06:37:51 tb Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -24,6 +24,9 @@
#include <unistd.h>
#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/stack.h>
+#include <openssl/safestack.h>
#include <openssl/x509.h>
#include "extern.h"
@@ -39,214 +42,57 @@ struct parse {
extern ASN1_OBJECT *roa_oid;
/*
- * Parse IP address (ROAIPAddress), RFC 6482, section 3.3.
- * Returns zero on failure, non-zero on success.
+ * Types and templates for the ROA eContent, RFC 6482, section 3.
*/
-static int
-roa_parse_addr(const ASN1_OCTET_STRING *os, enum afi afi, struct parse *p)
-{
- ASN1_SEQUENCE_ANY *seq;
- const unsigned char *d = os->data;
- size_t dsz = os->length;
- int rc = 0;
- const ASN1_TYPE *t;
- const ASN1_INTEGER *maxlength;
- long maxlen;
- struct ip_addr addr;
- struct roa_ip *res;
-
- if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
- cryptowarnx("%s: RFC 6482 section 3.3: address: "
- "failed ASN.1 sequence parse", p->fn);
- goto out;
- }
-
- /* ROAIPAddress has the address and optional maxlength. */
-
- if (sk_ASN1_TYPE_num(seq) != 1 &&
- sk_ASN1_TYPE_num(seq) != 2) {
- warnx("%s: RFC 6482 section 3.3: address: "
- "want 1 or 2 elements, have %d",
- p->fn, sk_ASN1_TYPE_num(seq));
- goto out;
- }
-
- t = sk_ASN1_TYPE_value(seq, 0);
- if (t->type != V_ASN1_BIT_STRING) {
- warnx("%s: RFC 6482 section 3.3: address: "
- "want ASN.1 bit string, have %s (NID %d)",
- p->fn, ASN1_tag2str(t->type), t->type);
- goto out;
- }
- if (!ip_addr_parse(t->value.bit_string, afi, p->fn, &addr)) {
- warnx("%s: RFC 6482 section 3.3: address: "
- "invalid IP address", p->fn);
- goto out;
- }
- maxlen = addr.prefixlen;
-
- if (sk_ASN1_TYPE_num(seq) == 2) {
- t = sk_ASN1_TYPE_value(seq, 1);
- if (t->type != V_ASN1_INTEGER) {
- warnx("%s: RFC 6482 section 3.1: maxLength: "
- "want ASN.1 integer, have %s (NID %d)",
- p->fn, ASN1_tag2str(t->type), t->type);
- goto out;
- }
-
- maxlength = t->value.integer;
- maxlen = ASN1_INTEGER_get(maxlength);
- if (maxlen < 0) {
- warnx("%s: RFC 6482 section 3.2: maxLength: "
- "want positive integer, have %ld", p->fn, maxlen);
- goto out;
- }
- if (addr.prefixlen > maxlen) {
- warnx("%s: prefixlen (%d) larger than maxLength (%ld)",
- p->fn, addr.prefixlen, maxlen);
- goto out;
- }
- if (maxlen > ((afi == AFI_IPV4) ? 32 : 128)) {
- warnx("%s: maxLength (%ld) too large", p->fn, maxlen);
- goto out;
- }
- }
-
- res = &p->res->ips[p->res->ipsz++];
- res->addr = addr;
- res->afi = afi;
- res->maxlength = maxlen;
- ip_roa_compose_ranges(res);
+typedef struct {
+ ASN1_BIT_STRING *address;
+ ASN1_INTEGER *maxLength;
+} ROAIPAddress;
- rc = 1;
-out:
- sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
- return rc;
-}
+DECLARE_STACK_OF(ROAIPAddress);
-/*
- * Parse IP address family, RFC 6482, section 3.3.
- * Returns zero on failure, non-zero on success.
- */
-static int
-roa_parse_ipfam(const ASN1_OCTET_STRING *os, struct parse *p)
-{
- ASN1_SEQUENCE_ANY *seq, *sseq = NULL;
- const unsigned char *d = os->data;
- size_t dsz = os->length;
- int i, rc = 0;
- const ASN1_TYPE *t;
- enum afi afi;
-
- if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
- cryptowarnx("%s: RFC 6482 section 3.3: ROAIPAddressFamily: "
- "failed ASN.1 sequence parse", p->fn);
- goto out;
- }
- if (sk_ASN1_TYPE_num(seq) != 2) {
- warnx("%s: RFC 6482 section 3.3: ROAIPAddressFamily: "
- "want 2 elements, have %d",
- p->fn, sk_ASN1_TYPE_num(seq));
- goto out;
- }
+typedef struct {
+ ASN1_OCTET_STRING *addressFamily;
+ STACK_OF(ROAIPAddress) *addresses;
+} ROAIPAddressFamily;
- t = sk_ASN1_TYPE_value(seq, 0);
- if (t->type != V_ASN1_OCTET_STRING) {
- warnx("%s: RFC 6482 section 3.3: addressFamily: "
- "want ASN.1 octet string, have %s (NID %d)",
- p->fn, ASN1_tag2str(t->type), t->type);
- goto out;
- }
- if (!ip_addr_afi_parse(p->fn, t->value.octet_string, &afi)) {
- warnx("%s: RFC 6482 section 3.3: addressFamily: "
- "invalid", p->fn);
- goto out;
- }
-
- t = sk_ASN1_TYPE_value(seq, 1);
- if (t->type != V_ASN1_SEQUENCE) {
- warnx("%s: RFC 6482 section 3.3: addresses: "
- "want ASN.1 sequence, have %s (NID %d)",
- p->fn, ASN1_tag2str(t->type), t->type);
- goto out;
- }
-
- d = t->value.octet_string->data;
- dsz = t->value.octet_string->length;
+DECLARE_STACK_OF(ROAIPAddressFamily);
- if ((sseq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
- cryptowarnx("%s: RFC 6482 section 3.3: addresses: "
- "failed ASN.1 sequence parse", p->fn);
- goto out;
- }
+#if defined(LIBRESSL_VERSION_NUMBER)
+#define sk_ROAIPAddress_num(st) SKM_sk_num(ROAIPAddress, (st))
+#define sk_ROAIPAddress_value(st, i) SKM_sk_value(ROAIPAddress, (st), (i))
- /* will be called multiple times so use recallocarray */
- if (p->res->ipsz + sk_ASN1_TYPE_num(sseq) >= MAX_IP_SIZE) {
- warnx("%s: too many IPAddress entries: limit %d",
- p->fn, MAX_IP_SIZE);
- goto out;
- }
- p->res->ips = recallocarray(p->res->ips, p->res->ipsz,
- p->res->ipsz + sk_ASN1_TYPE_num(sseq), sizeof(struct roa_ip));
- if (p->res->ips == NULL)
- err(1, NULL);
+#define sk_ROAIPAddressFamily_num(st) SKM_sk_num(ROAIPAddressFamily, (st))
+#define sk_ROAIPAddressFamily_value(st, i) \
+ SKM_sk_value(ROAIPAddressFamily, (st), (i))
+#endif
- for (i = 0; i < sk_ASN1_TYPE_num(sseq); i++) {
- t = sk_ASN1_TYPE_value(sseq, i);
- if (t->type != V_ASN1_SEQUENCE) {
- warnx("%s: RFC 6482 section 3.3: ROAIPAddress: "
- "want ASN.1 sequence, have %s (NID %d)",
- p->fn, ASN1_tag2str(t->type), t->type);
- goto out;
- }
- if (!roa_parse_addr(t->value.octet_string, afi, p))
- goto out;
- }
+typedef struct {
+ ASN1_INTEGER *version;
+ ASN1_INTEGER *asid;
+ STACK_OF(ROAIPAddressFamily) *ipAddrBlocks;
+} RouteOriginAttestation;
- rc = 1;
-out:
- sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
- sk_ASN1_TYPE_pop_free(sseq, ASN1_TYPE_free);
- return rc;
-}
+ASN1_SEQUENCE(ROAIPAddress) = {
+ ASN1_SIMPLE(ROAIPAddress, address, ASN1_BIT_STRING),
+ ASN1_OPT(ROAIPAddress, maxLength, ASN1_INTEGER),
+} ASN1_SEQUENCE_END(ROAIPAddress);
-/*
- * Parse IP blocks, RFC 6482, section 3.3.
- * Returns zero on failure, non-zero on success.
- */
-static int
-roa_parse_ipblocks(const ASN1_OCTET_STRING *os, struct parse *p)
-{
- ASN1_SEQUENCE_ANY *seq;
- const unsigned char *d = os->data;
- size_t dsz = os->length;
- int i, rc = 0;
- const ASN1_TYPE *t;
-
- if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
- cryptowarnx("%s: RFC 6482 section 3.3: ipAddrBlocks: "
- "failed ASN.1 sequence parse", p->fn);
- goto out;
- }
+ASN1_SEQUENCE(ROAIPAddressFamily) = {
+ ASN1_SIMPLE(ROAIPAddressFamily, addressFamily, ASN1_OCTET_STRING),
+ ASN1_SEQUENCE_OF(ROAIPAddressFamily, addresses, ROAIPAddress),
+} ASN1_SEQUENCE_END(ROAIPAddressFamily);
- for (i = 0; i < sk_ASN1_TYPE_num(seq); i++) {
- t = sk_ASN1_TYPE_value(seq, i);
- if (t->type != V_ASN1_SEQUENCE) {
- warnx("%s: RFC 6482 section 3.3: ROAIPAddressFamily: "
- "want ASN.1 sequence, have %s (NID %d)",
- p->fn, ASN1_tag2str(t->type), t->type);
- goto out;
- }
- if (!roa_parse_ipfam(t->value.octet_string, p))
- goto out;
- }
+ASN1_SEQUENCE(RouteOriginAttestation) = {
+ ASN1_IMP_OPT(RouteOriginAttestation, version, ASN1_INTEGER, 0),
+ ASN1_SIMPLE(RouteOriginAttestation, asid, ASN1_INTEGER),
+ ASN1_SEQUENCE_OF(RouteOriginAttestation, ipAddrBlocks,
+ ROAIPAddressFamily),
+} ASN1_SEQUENCE_END(RouteOriginAttestation);
- rc = 1;
-out:
- sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
- return rc;
-}
+DECLARE_ASN1_FUNCTIONS(RouteOriginAttestation);
+IMPLEMENT_ASN1_FUNCTIONS(RouteOriginAttestation);
/*
* Parses the eContent section of an ROA file, RFC 6482, section 3.
@@ -255,34 +101,31 @@ out:
static int
roa_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p)
{
- ASN1_SEQUENCE_ANY *seq;
- int i = 0, rc = 0, sz;
- const ASN1_TYPE *t;
- long roa_version;
-
- /* RFC 6482, section 3. */
-
- if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
- cryptowarnx("%s: RFC 6482 section 3: RouteOriginAttestation: "
- "failed ASN.1 sequence parse", p->fn);
- goto out;
- }
-
- if ((sz = sk_ASN1_TYPE_num(seq)) != 2 && sz != 3) {
- warnx("%s: RFC 6482 section 3: RouteOriginAttestation: "
- "want 2 or 3 elements, have %d",
- p->fn, sk_ASN1_TYPE_num(seq));
+ RouteOriginAttestation *roa;
+ long roa_version;
+ const ROAIPAddressFamily *addrfam;
+ const STACK_OF(ROAIPAddress) *addrs;
+ int addrsz;
+ enum afi afi;
+ const ROAIPAddress *addr;
+ long maxlen;
+ struct ip_addr ipaddr;
+ struct roa_ip *res;
+ int i, j, rc = 0;
+
+ if ((roa = d2i_RouteOriginAttestation(NULL, &d, dsz)) == NULL) {
+ cryptowarnx("%s: RFC 6482 section 3: failed to parse "
+ "RouteOriginAttestation", p->fn);
goto out;
}
/* Parse the optional version field */
- if (sz == 3) {
- t = sk_ASN1_TYPE_value(seq, i++);
- d = t->value.asn1_string->data;
- dsz = t->value.asn1_string->length;
-
- if (cms_econtent_version(p->fn, &d, dsz, &roa_version) == -1)
+ if (roa->version != NULL) {
+ roa_version = ASN1_INTEGER_get(roa->version);
+ if (roa_version < 0) {
+ warnx("%s: ASN1_INTEGER_get failed", p->fn);
goto out;
+ }
switch (roa_version) {
case 0:
@@ -295,40 +138,75 @@ roa_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p)
}
}
- /*
- * RFC 6482, section 3.2.
- * It doesn't ever actually state that AS numbers can't be
- * negative, but...?
- */
-
- t = sk_ASN1_TYPE_value(seq, i++);
- if (t->type != V_ASN1_INTEGER) {
- warnx("%s: RFC 6482 section 3.2: asID: "
- "want ASN.1 integer, have %s (NID %d)",
- p->fn, ASN1_tag2str(t->type), t->type);
- goto out;
- }
- if (!as_id_parse(t->value.integer, &p->res->asid)) {
+ if (!as_id_parse(roa->asid, &p->res->asid)) {
warnx("%s: RFC 6482 section 3.2: asID: "
"malformed AS identifier", p->fn);
goto out;
}
- /* RFC 6482, section 3.3. */
+ for (i = 0; i < sk_ROAIPAddressFamily_num(roa->ipAddrBlocks); i++) {
+ addrfam = sk_ROAIPAddressFamily_value(roa->ipAddrBlocks, i);
+ addrs = addrfam->addresses;
+ addrsz = sk_ROAIPAddress_num(addrs);
- t = sk_ASN1_TYPE_value(seq, i++);
- if (t->type != V_ASN1_SEQUENCE) {
- warnx("%s: RFC 6482 section 3.3: ipAddrBlocks: "
- "want ASN.1 sequence, have %s (NID %d)",
- p->fn, ASN1_tag2str(t->type), t->type);
- goto out;
+ if (!ip_addr_afi_parse(p->fn, addrfam->addressFamily, &afi)) {
+ warnx("%s: RFC 6482 section 3.3: addressFamily: "
+ "invalid", p->fn);
+ goto out;
+ }
+
+ if (p->res->ipsz + addrsz >= MAX_IP_SIZE) {
+ warnx("%s: too many IPAddress entries: limit %d",
+ p->fn, MAX_IP_SIZE);
+ goto out;
+ }
+ p->res->ips = recallocarray(p->res->ips, p->res->ipsz,
+ p->res->ipsz + addrsz, sizeof(struct roa_ip));
+ if (p->res->ips == NULL)
+ err(1, NULL);
+
+ for (j = 0; j < addrsz; j++) {
+ addr = sk_ROAIPAddress_value(addrs, j);
+
+ if (!ip_addr_parse(addr->address, afi, p->fn,
+ &ipaddr)) {
+ warnx("%s: RFC 6482 section 3.3: address: "
+ "invalid IP address", p->fn);
+ goto out;
+ }
+ maxlen = ipaddr.prefixlen;
+
+ if (addr->maxLength != NULL) {
+ maxlen = ASN1_INTEGER_get(addr->maxLength);
+ if (maxlen < 0) {
+ warnx("%s: RFC 6482 section 3.2: "
+ "ASN1_INTEGER_get failed", p->fn);
+ goto out;
+ }
+ if (ipaddr.prefixlen > maxlen) {
+ warnx("%s: prefixlen (%d) larger than "
+ "maxLength (%ld)", p->fn,
+ ipaddr.prefixlen, maxlen);
+ goto out;
+ }
+ if (maxlen > ((afi == AFI_IPV4) ? 32 : 128)) {
+ warnx("%s: maxLength (%ld) too large",
+ p->fn, maxlen);
+ goto out;
+ }
+ }
+
+ res = &p->res->ips[p->res->ipsz++];
+ res->addr = ipaddr;
+ res->afi = afi;
+ res->maxlength = maxlen;
+ ip_roa_compose_ranges(res);
+ }
}
- if (!roa_parse_ipblocks(t->value.octet_string, p))
- goto out;
rc = 1;
-out:
- sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
+ out:
+ RouteOriginAttestation_free(roa);
return rc;
}