-/* $OpenBSD: rsc.c,v 1.4 2022/05/15 16:43:35 tb Exp $ */
+/* $OpenBSD: rsc.c,v 1.5 2022/05/31 18:40:15 tb Exp $ */
/*
* Copyright (c) 2022 Job Snijders <job@fastly.com>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <assert.h>
#include <err.h>
-#include <stdarg.h>
-#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/safestack.h>
+#include <openssl/stack.h>
#include <openssl/x509.h>
+#include <openssl/x509v3.h>
#include "extern.h"
extern ASN1_OBJECT *rsc_oid;
/*
- * Append an AS identifier structure to our list of results.
- * Return zero on failure.
- * XXX: merge with append_as() in cert.c
+ * Types and templates for RSC eContent - draft-ietf-sidrops-rpki-rsc-08
*/
-static int
-append_as(struct parse *p, const struct cert_as *as)
-{
- if (!as_check_overlap(as, p->fn, p->res->as, p->res->asz))
- return 0;
- if (p->res->asz >= MAX_AS_SIZE)
- return 0;
- p->res->as = reallocarray(p->res->as, p->res->asz + 1,
- sizeof(struct cert_as));
- if (p->res->as == NULL)
- err(1, NULL);
- p->res->as[p->res->asz++] = *as;
- return 1;
-}
-/*
- * Append an IP address structure to our list of results.
- * return zero on failure.
- * XXX: merge with append_ip() in cert.c
- */
-static int
-append_ip(struct parse *p, const struct cert_ip *ip)
-{
- struct rsc *res = p->res;
-
- if (!ip_addr_check_overlap(ip, p->fn, p->res->ips, p->res->ipsz))
- return 0;
- if (res->ipsz >= MAX_IP_SIZE)
- return 0;
-
- res->ips = reallocarray(res->ips, res->ipsz + 1,
- sizeof(struct cert_ip));
- if (res->ips == NULL)
- err(1, NULL);
-
- res->ips[res->ipsz++] = *ip;
- return 1;
-}
+typedef struct {
+ ASIdOrRanges *asnum;
+} ConstrainedASIdentifiers;
+
+ASN1_SEQUENCE(ConstrainedASIdentifiers) = {
+ ASN1_EXP_SEQUENCE_OF(ConstrainedASIdentifiers, asnum, ASIdOrRange, 0),
+} ASN1_SEQUENCE_END(ConstrainedASIdentifiers);
+
+typedef struct {
+ ASN1_OCTET_STRING *addressFamily;
+ STACK_OF(IPAddressOrRange) *addressesOrRanges;
+} ConstrainedIPAddressFamily;
+
+ASN1_SEQUENCE(ConstrainedIPAddressFamily) = {
+ ASN1_SIMPLE(ConstrainedIPAddressFamily, addressFamily,
+ ASN1_OCTET_STRING),
+ ASN1_SEQUENCE_OF(ConstrainedIPAddressFamily, addressesOrRanges,
+ IPAddressOrRange),
+} ASN1_SEQUENCE_END(ConstrainedIPAddressFamily);
+
+typedef STACK_OF(ConstrainedIPAddressFamily) ConstrainedIPAddrBlocks;
+DECLARE_STACK_OF(ConstrainedIPAddressFamily);
+
+ASN1_ITEM_TEMPLATE(ConstrainedIPAddrBlocks) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, ConstrainedIPAddrBlocks,
+ ConstrainedIPAddressFamily)
+ASN1_ITEM_TEMPLATE_END(ConstrainedIPAddrBlocks);
+
+typedef struct {
+ ConstrainedASIdentifiers *asID;
+ ConstrainedIPAddrBlocks *ipAddrBlocks;
+} ResourceBlock;
+
+ASN1_SEQUENCE(ResourceBlock) = {
+ ASN1_EXP_OPT(ResourceBlock, asID, ConstrainedASIdentifiers, 0),
+ ASN1_EXP_SEQUENCE_OF_OPT(ResourceBlock, ipAddrBlocks,
+ ConstrainedIPAddressFamily, 1)
+} ASN1_SEQUENCE_END(ResourceBlock);
+
+typedef struct {
+ ASN1_IA5STRING *fileName;
+ ASN1_OCTET_STRING *hash;
+} FileNameAndHash;
+
+DECLARE_STACK_OF(FileNameAndHash);
+
+#ifndef DEFINE_STACK_OF
+#define sk_ConstrainedIPAddressFamily_num(sk) \
+ SKM_sk_num(ConstrainedIPAddressFamily, (sk))
+#define sk_ConstrainedIPAddressFamily_value(sk, i) \
+ SKM_sk_value(ConstrainedIPAddressFamily, (sk), (i))
+
+#define sk_FileNameAndHash_num(sk) SKM_sk_num(FileNameAndHash, (sk))
+#define sk_FileNameAndHash_value(sk, i) SKM_sk_value(FileNameAndHash, (sk), (i))
+#endif
+
+ASN1_SEQUENCE(FileNameAndHash) = {
+ ASN1_OPT(FileNameAndHash, fileName, ASN1_IA5STRING),
+ ASN1_SIMPLE(FileNameAndHash, hash, ASN1_OCTET_STRING),
+} ASN1_SEQUENCE_END(FileNameAndHash);
+
+typedef struct {
+ ASN1_INTEGER *version;
+ ResourceBlock *resources;
+ X509_ALGOR *digestAlgorithm;
+ STACK_OF(FileNameAndHash) *checkList;
+} RpkiSignedChecklist;
+
+ASN1_SEQUENCE(RpkiSignedChecklist) = {
+ ASN1_IMP_OPT(RpkiSignedChecklist, version, ASN1_INTEGER, 0),
+ ASN1_SIMPLE(RpkiSignedChecklist, resources, ResourceBlock),
+ ASN1_SIMPLE(RpkiSignedChecklist, digestAlgorithm, X509_ALGOR),
+ ASN1_SEQUENCE_OF(RpkiSignedChecklist, checkList, FileNameAndHash),
+} ASN1_SEQUENCE_END(RpkiSignedChecklist);
+
+DECLARE_ASN1_FUNCTIONS(RpkiSignedChecklist);
+IMPLEMENT_ASN1_FUNCTIONS(RpkiSignedChecklist);
static int
-rsc_check_digesttype(struct parse *p, const unsigned char *d, size_t dsz)
+rsc_check_digesttype(struct parse *p, const X509_ALGOR *alg)
{
- X509_ALGOR *alg;
const ASN1_OBJECT *obj;
int type, nid;
- int rc = 0;
-
- if ((alg = d2i_X509_ALGOR(NULL, &d, dsz)) == NULL) {
- cryptowarnx("%s: RSC DigestAlgorithmIdentifier faild to parse",
- p->fn);
- goto out;
- }
X509_ALGOR_get0(&obj, &type, NULL, alg);
if (type != V_ASN1_UNDEF) {
warnx("%s: RSC DigestAlgorithmIdentifier unexpected parameters:"
" %d", p->fn, type);
- goto out;
+ return 0;
}
if ((nid = OBJ_obj2nid(obj)) != NID_sha256) {
warnx("%s: RSC DigestAlgorithmIdentifier: want SHA256, have %s"
" (NID %d)", p->fn, ASN1_tag2str(nid), nid);
- goto out;
+ return 0;
}
- rc = 1;
- out:
- X509_ALGOR_free(alg);
- return rc;
+ return 1;
}
/*
- * Parse and individual "FileNameAndHash", draft-ietf-sidrops-rpki-rsc
- * section 4.1.
+ * Parse the FileNameAndHash sequence, draft-ietf-sidrops-rpki-rsc, section 4.4.
* Return zero on failure, non-zero on success.
*/
static int
-rsc_parse_filenamehash(struct parse *p, const ASN1_OCTET_STRING *os)
+rsc_parse_checklist(struct parse *p, const STACK_OF(FileNameAndHash) *checkList)
{
- ASN1_SEQUENCE_ANY *seq;
- const ASN1_TYPE *file, *hash;
- char *fn = NULL;
- const unsigned char *d = os->data;
- size_t dsz = os->length;
- int i = 0, rc = 0, elemsz;
- struct rscfile *rent;
-
- if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
- cryptowarnx("%s: RSC FileNameAndHash: failed ASN.1 sequence "
- "parse", p->fn);
- goto out;
- }
+ FileNameAndHash *fh;
+ ASN1_IA5STRING *fn;
+ struct rscfile *file;
+ size_t sz, i;
- elemsz = sk_ASN1_TYPE_num(seq);
- if (elemsz != 1 && elemsz != 2) {
- warnx("%s: RSC FileNameAndHash: want 1 or 2 elements, have %d",
- p->fn, elemsz);
- goto out;
- }
-
- if (elemsz == 2) {
- ASN1_IA5STRING *filename;
-
- file = sk_ASN1_TYPE_value(seq, i++);
- if (file->type != V_ASN1_IA5STRING) {
- warnx("%s: RSC FileNameAndHash: want ASN.1 IA5 string,"
- " have %s (NID %d)", p->fn,
- ASN1_tag2str(file->type), file->type);
- goto out;
- }
-
- filename = file->value.ia5string;
-
- if (!valid_filename(filename->data, filename->length)) {
- warnx("%s: RSC FileNameAndHash: bad filename", p->fn);
- goto out;
- }
-
- fn = strndup(filename->data, filename->length);
- if (fn == NULL)
- err(1, NULL);
- }
-
- /* Now hash value. */
-
- hash = sk_ASN1_TYPE_value(seq, i);
- if (hash->type != V_ASN1_OCTET_STRING) {
- warnx("%s: RSC FileNameAndHash: want ASN.1 OCTET string, have "
- "%s (NID %d)", p->fn, ASN1_tag2str(hash->type), hash->type);
- goto out;
- }
-
- if (hash->value.octet_string->length != SHA256_DIGEST_LENGTH) {
- warnx("%s: RSC Digest: invalid SHA256 length, have %d",
- p->fn, hash->value.octet_string->length);
- goto out;
+ if ((sz = sk_FileNameAndHash_num(checkList)) == 0) {
+ warnx("%s: RSC checkList needs at least one entry", p->fn);
+ return 0;
}
- p->res->files = recallocarray(p->res->files, p->res->filesz,
- p->res->filesz + 1, sizeof(struct rscfile));
+ p->res->files = calloc(sz, sizeof(struct rscfile));
if (p->res->files == NULL)
err(1, NULL);
+ p->res->filesz = sz;
- rent = &p->res->files[p->res->filesz++];
- rent->filename = fn;
- fn = NULL;
- memcpy(rent->hash, hash->value.octet_string->data,
- SHA256_DIGEST_LENGTH);
-
- rc = 1;
- out:
- free(fn);
- sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
- return rc;
-}
+ for (i = 0; i < sz; i++) {
+ fh = sk_FileNameAndHash_value(checkList, i);
-/*
- * Parse the FileNameAndHash sequence, draft-ietf-sidrops-rpki-rsc
- * section 4.1
- * Return zero on failure, non-zero on success.
- */
-static int
-rsc_parse_checklist(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: RSC checkList: failed ASN.1 sequence parse",
- p->fn);
- goto out;
- }
+ file = &p->res->files[i];
- 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: RSC checkList: want ASN.1 sequence, have %s"
- " (NID %d)", p->fn, ASN1_tag2str(t->type), t->type);
- goto out;
+ if (fh->hash->length != SHA256_DIGEST_LENGTH) {
+ warnx("%s: RSC Digest: invalid SHA256 length", p->fn);
+ return 0;
}
- if (!rsc_parse_filenamehash(p, t->value.octet_string))
- goto out;
- }
+ memcpy(file->hash, fh->hash->data, SHA256_DIGEST_LENGTH);
- rc = 1;
- out:
- sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
- return rc;
-}
-
-/*
- * Convert ASN1 INTEGER and add it to parse results
- * Return zero on failure.
- * XXX: merge with sbgp_asid() in cert.c
- */
-static int
-rsc_parse_asid(struct parse *p, const ASN1_INTEGER *i)
-{
- struct cert_as as;
+ if ((fn = fh->fileName) == NULL)
+ continue;
- memset(&as, 0, sizeof(struct cert_as));
- as.type = CERT_AS_ID;
+ if (!valid_filename(fn->data, fn->length)) {
+ warnx("%s: RSC FileNameAndHash: bad filename", p->fn);
+ return 0;
+ }
- if (!as_id_parse(i, &as.id)) {
- warnx("%s: RSC malformed AS identifier", p->fn);
- return 0;
- }
- if (as.id == 0) {
- warnx("%s: RSC AS identifier zero is reserved", p->fn);
- return 0;
+ file->filename = strndup(fn->data, fn->length);
+ if (file->filename == NULL)
+ err(1, NULL);
}
- return append_as(p, &as);
+ return 1;
}
/*
- * Parse AS Range and add it to parse result
- * Return zero on failure.
- * XXX: merge with sbgp_asrange() in cert.c
+ * Parse asID (inside ResourceBlock)
+ * Return 0 on failure.
*/
static int
-rsc_parse_asrange(struct parse *p, const unsigned char *d, size_t dsz)
+rsc_parse_aslist(struct parse *p, const ConstrainedASIdentifiers *asids)
{
- struct cert_as as;
- ASN1_SEQUENCE_ANY *seq;
- const ASN1_TYPE *t;
- int rc = 0;
-
- if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
- cryptowarnx("%s: ASRange failed ASN.1 seq parse", p->fn);
- goto out;
- }
+ int i, asz;
- if (sk_ASN1_TYPE_num(seq) != 2) {
- warnx("%s: expected 2 elements in RSC ASRange, have %d",
- p->fn, sk_ASN1_TYPE_num(seq));
- goto out;
- }
+ if (asids == NULL)
+ return 1;
- memset(&as, 0, sizeof(struct cert_as));
- as.type = CERT_AS_RANGE;
-
- t = sk_ASN1_TYPE_value(seq, 0);
- if (t->type != V_ASN1_INTEGER) {
- warnx("%s: RSC ASRange: 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, &as.range.min)) {
- warnx("%s: RSC malformed AS identifier", p->fn);
- goto out;
- }
-
- t = sk_ASN1_TYPE_value(seq, 1);
- if (t->type != V_ASN1_INTEGER) {
- warnx("%s: RSC ASRange: 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, &as.range.max)) {
- warnx("%s: RSC malformed AS identifier", p->fn);
- goto out;
+ if ((asz = sk_ASIdOrRange_num(asids->asnum)) == 0) {
+ warnx("%s: RSC asID empty", p->fn);
+ return 0;
}
- if (as.range.max == as.range.min) {
- warnx("%s: RSC ASRange error: range is singular", p->fn);
- goto out;
- }
- if (as.range.max < as.range.min) {
- warnx("%s: RSC ASRange: range is out of order", p->fn);
- goto out;
+ if (asz >= MAX_AS_SIZE) {
+ warnx("%s: too many AS number entries: limit %d",
+ p->fn, MAX_AS_SIZE);
+ return 0;
}
- if (!append_as(p, &as))
- goto out;
-
- rc = 1;
- out:
- sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
- return rc;
-}
+ p->res->as = calloc(asz, sizeof(struct cert_as));
+ if (p->res->as == NULL)
+ err(1, NULL);
-/*
- * parse AsList (inside ResourceBlock)
- * Return 0 on failure.
- */
-static int
-rsc_parse_aslist(struct parse *p, const unsigned char *d, size_t dsz)
-{
- ASN1_SEQUENCE_ANY *seq;
- const ASN1_TYPE *t;
- int i, rc = 0;
+ for (i = 0; i < asz; i++) {
+ const ASIdOrRange *aor;
- if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
- cryptowarnx("%s: RSC AsList: failed ASN.1 sequence parse",
- p->fn);
- goto out;
- }
+ aor = sk_ASIdOrRange_value(asids->asnum, i);
- for (i = 0; i < sk_ASN1_TYPE_num(seq); i++) {
- t = sk_ASN1_TYPE_value(seq, i);
- switch (t->type) {
- case V_ASN1_INTEGER:
- if (!rsc_parse_asid(p, t->value.integer))
- goto out;
+ switch (aor->type) {
+ case ASIdOrRange_id:
+ if (!sbgp_as_id(p->fn, p->res->as, &p->res->asz,
+ aor->u.id))
+ return 0;
break;
- case V_ASN1_SEQUENCE:
- d = t->value.asn1_string->data;
- dsz = t->value.asn1_string->length;
- if (!rsc_parse_asrange(p, d, dsz))
- goto out;
+ case ASIdOrRange_range:
+ if (!sbgp_as_range(p->fn, p->res->as, &p->res->asz,
+ aor->u.range))
+ return 0;
break;
default:
- warnx("%s: RSC AsList expected INTEGER or SEQUENCE, "
- "have %s (NID %d)", p->fn, ASN1_tag2str(t->type),
- t->type);
- goto out;
+ warnx("%s: RSC AsList: unknown type %d", p->fn,
+ aor->type);
+ return 0;
}
}
- rc = 1;
- out:
- sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
- return rc;
+ return 1;
}
-/*
- * parse IPAddressFamilyItem (inside IPList, inside ResourceBlock)
- * Return 0 on failure.
- */
static int
-rsc_parse_ipaddrfamitem(struct parse *p, const ASN1_OCTET_STRING *os)
+rsc_parse_iplist(struct parse *p, const ConstrainedIPAddrBlocks *ipAddrBlocks)
{
- ASN1_OCTET_STRING *aos = NULL;
- IPAddressOrRange *aor = NULL;
- int tag;
- const unsigned char *cnt = os->data;
- long cntsz;
- const unsigned char *d;
- struct cert_ip ip;
- int rc = 0;
-
- memset(&ip, 0, sizeof(struct cert_ip));
-
- /*
- * IPAddressFamilyItem is a sequence containing an addressFamily and
- * an IPAddressOrRange.
- */
- if (!ASN1_frame(p->fn, os->length, &cnt, &cntsz, &tag)) {
- cryptowarnx("%s: ASN1_frame failed", p->fn);
- goto out;
- }
- if (tag != V_ASN1_SEQUENCE) {
- warnx("expected ASN.1 sequence, got %d", tag);
- goto out;
- }
-
- d = cnt;
-
- if ((aos = d2i_ASN1_OCTET_STRING(NULL, &cnt, cntsz)) == NULL) {
- cryptowarnx("%s: d2i_ASN1_OCTET_STRING failed", p->fn);
- goto out;
- }
-
- cntsz -= cnt - d;
- assert(cntsz >= 0);
-
- if (!ip_addr_afi_parse(p->fn, aos, &ip.afi)) {
- warnx("%s: RSC invalid addressFamily", p->fn);
- goto out;
- }
-
- d = cnt;
-
- if ((aor = d2i_IPAddressOrRange(NULL, &cnt, cntsz)) == NULL) {
- warnx("%s: d2i_IPAddressOrRange failed", p->fn);
- goto out;
- }
-
- cntsz -= cnt - d;
- assert(cntsz >= 0);
-
- if (cntsz > 0) {
- warnx("%s: trailing garbage in RSC IPAddressFamilyItem", p->fn);
- goto out;
- }
-
- switch (aor->type) {
- case IPAddressOrRange_addressPrefix:
- ip.type = CERT_IP_ADDR;
- if (!ip_addr_parse(aor->u.addressPrefix, ip.afi, p->fn, &ip.ip))
- goto out;
- break;
- case IPAddressOrRange_addressRange:
- ip.type = CERT_IP_RANGE;
- if (!ip_addr_parse(aor->u.addressRange->min, ip.afi, p->fn,
- &ip.range.min))
- goto out;
- if (!ip_addr_parse(aor->u.addressRange->max, ip.afi, p->fn,
- &ip.range.max))
- goto out;
- break;
- default:
- warnx("%s: unknown addressOrRange type %d\n", p->fn, aor->type);
- goto out;
- }
-
- if (!ip_cert_compose_ranges(&ip)) {
- warnx("%s: RSC IP address range reversed", p->fn);
- goto out;
+ const ConstrainedIPAddressFamily *af;
+ const IPAddressOrRanges *aors;
+ const IPAddressOrRange *aor;
+ size_t ipsz;
+ enum afi afi;
+ int i, j;
+
+ if (ipAddrBlocks == NULL)
+ return 1;
+
+ if (sk_ConstrainedIPAddressFamily_num(ipAddrBlocks) == 0) {
+ warnx("%s: RSC ipAddrBlocks empty", p->fn);
+ return 0;
}
- if (!append_ip(p, &ip))
- goto out;
+ for (i = 0; i < sk_ConstrainedIPAddressFamily_num(ipAddrBlocks); i++) {
+ af = sk_ConstrainedIPAddressFamily_value(ipAddrBlocks, i);
+ aors = af->addressesOrRanges;
- rc = 1;
- out:
- ASN1_OCTET_STRING_free(aos);
- IPAddressOrRange_free(aor);
- return rc;
-}
-
-static int
-rsc_parse_iplist(struct parse *p, const unsigned char *d, size_t dsz)
-{
- ASN1_SEQUENCE_ANY *seq;
- const ASN1_TYPE *t;
- int i, rc = 0;
-
- if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
- cryptowarnx("%s: RSC IPList: failed ASN.1 sequence parse",
- p->fn);
- goto out;
- }
-
- 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: RSC IPList: want ASN.1 sequence, have %s"
- " (NID %d)", p->fn, ASN1_tag2str(t->type), t->type);
- goto out;
+ ipsz = p->res->ipsz + sk_IPAddressOrRange_num(aors);
+ if (ipsz >= MAX_IP_SIZE) {
+ warnx("%s: too many IP address entries: limit %d",
+ p->fn, MAX_IP_SIZE);
+ return 0;
}
- if (!rsc_parse_ipaddrfamitem(p, t->value.octet_string))
- goto out;
- }
- rc = 1;
- out:
- sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
- return rc;
-}
-
-/*
- * Parse a ResourceBlock, draft-ietf-sidrops-rpki-rsc section 4
- * Returns zero on failure, non-zero on success.
- */
-static int
-rsc_parse_resourceblock(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, ptag, rc = 0;
- const ASN1_TYPE *t;
- long plen;
-
- if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
- cryptowarnx("%s: RSC: ResourceBlock: failed ASN.1 sequence "
- "parse", p->fn);
- goto out;
- }
-
- if (sk_ASN1_TYPE_num(seq) == 0) {
- warnx("%s: ResourceBlock, there must be at least one of asID "
- "or ipAddrBlocks", p->fn);
- goto out;
- }
+ p->res->ips = recallocarray(p->res->ips, p->res->ipsz, ipsz,
+ sizeof(struct cert_ip));
+ if (p->res->ips == NULL)
+ err(1, NULL);
- for (i = 0; i < sk_ASN1_TYPE_num(seq); i++) {
- t = sk_ASN1_TYPE_value(seq, i);
+ if (!ip_addr_afi_parse(p->fn, af->addressFamily, &afi)) {
+ warnx("%s: RSC: invalid AFI", p->fn);
+ return 0;
+ }
- d = t->value.asn1_string->data;
- dsz = t->value.asn1_string->length;
- if (!ASN1_frame(p->fn, dsz, &d, &plen, &ptag))
- goto out;
- switch (ptag) {
- case RSRCBLK_TYPE_ASID:
- if (!rsc_parse_aslist(p, d, plen))
- goto out;
- break;
- case RSRCBLK_TYPE_IPADDRBLK:
- if (!rsc_parse_iplist(p, d, plen))
- goto out;
- break;
- default:
- warnx("%s: want ASN.1 context specific id, have %s"
- " (NID %d)", p->fn, ASN1_tag2str(ptag), ptag);
- goto out;
+ for (j = 0; j < sk_IPAddressOrRange_num(aors); j++) {
+ aor = sk_IPAddressOrRange_value(aors, j);
+ switch (aor->type) {
+ case IPAddressOrRange_addressPrefix:
+ if (!sbgp_addr(p->fn, p->res->ips,
+ &p->res->ipsz, afi, aor->u.addressPrefix))
+ return 0;
+ break;
+ case IPAddressOrRange_addressRange:
+ if (!sbgp_addr_range(p->fn, p->res->ips,
+ &p->res->ipsz, afi, aor->u.addressRange))
+ return 0;
+ break;
+ default:
+ warnx("%s: RFC 3779: IPAddressOrRange: "
+ "unknown type %d", p->fn, aor->type);
+ return 0;
+ }
}
}
- rc = 1;
- out:
- sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
- return rc;
+ return 1;
}
/*
- * Parses the eContent segment of a RSC file
+ * Parses the eContent segment of an RSC file
* draft-ietf-sidrops-rpki-rsc, section 4
* Returns zero on failure, non-zero on success.
*/
static int
rsc_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p)
{
- ASN1_SEQUENCE_ANY *seq;
- const ASN1_TYPE *t;
- int i = 0, rc = 0, sz;
+ RpkiSignedChecklist *rsc;
+ ResourceBlock *resources;
long rsc_version;
+ int rc = 0;
/*
* draft-ietf-sidrops-rpki-rsc section 4
*/
- if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
- cryptowarnx("%s: RSC: RpkiSignedChecklist: failed ASN.1 "
- "sequence parse", p->fn);
+ if ((rsc = d2i_RpkiSignedChecklist(NULL, &d, dsz)) == NULL) {
+ cryptowarnx("%s: RSC: failed ASN.1 decode", p->fn);
goto out;
}
- if ((sz = sk_ASN1_TYPE_num(seq)) != 3 && sz != 4) {
- warnx("%s: RSC RpkiSignedChecklist: want 3 or 4 elements, have"
- "%d", p->fn, sk_ASN1_TYPE_num(seq));
- goto out;
- }
-
- /*
- * if there are 4 elements, a version should be present: check it.
- */
- if (sz == 4) {
- 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, &rsc_version) == -1)
+ /* Validate the optional version field */
+ if (rsc->version != NULL) {
+ rsc_version = ASN1_INTEGER_get(rsc->version);
+ if (rsc_version < 0) {
+ cryptowarnx("%s: RSC: ASN1_INTEGER_get failed", p->fn);
goto out;
+ }
- switch (rsc_version) {
+ switch(rsc_version) {
case 0:
- warnx("%s: invalid encoding for version 0", p->fn);
+ warnx("%s: RSC: incorrect version encoding", p->fn);
goto out;
default:
- warnx("%s: version %ld not supported (yet)", p->fn,
+ warnx("%s: RSC: version %ld not supported (yet)", p->fn,
rsc_version);
goto out;
}
}
- /*
- * The RSC's eContent ResourceBlock indicates which Internet Number
- * Resources are associated with the signature over the checkList.
- */
- t = sk_ASN1_TYPE_value(seq, i++);
- if (t->type != V_ASN1_SEQUENCE) {
- warnx("%s: RSC ResourceBlock: want ASN.1 sequence, have %s"
- "(NID %d)", p->fn, ASN1_tag2str(t->type), t->type);
+ resources = rsc->resources;
+ if (resources->asID == NULL && resources->ipAddrBlocks == NULL) {
+ warnx("%s: RSC: one of asID or ipAddrBlocks must be present",
+ p->fn);
goto out;
}
- if (!rsc_parse_resourceblock(t->value.octet_string, p))
- goto out;
- /* digestAlgorithm */
- t = sk_ASN1_TYPE_value(seq, i++);
- if (t->type != V_ASN1_SEQUENCE) {
- warnx("%s: RSC DigestAlgorithmIdentifier: want ASN.1 sequence,"
- " have %s (NID %d)", p->fn, ASN1_tag2str(t->type), t->type);
+ if (!rsc_parse_aslist(p, resources->asID))
goto out;
- }
- if (!rsc_check_digesttype(p, t->value.asn1_string->data,
- t->value.asn1_string->length))
+
+ if (!rsc_parse_iplist(p, resources->ipAddrBlocks))
goto out;
- /*
- * Now a sequence of FileNameAndHash
- */
- t = sk_ASN1_TYPE_value(seq, i++);
- if (t->type != V_ASN1_SEQUENCE) {
- warnx("%s: RSC checkList: want ASN.1 sequence, have %s "
- "(NID %d)", p->fn, ASN1_tag2str(t->type), t->type);
+ if (!rsc_check_digesttype(p, rsc->digestAlgorithm))
goto out;
- }
- if (!rsc_parse_checklist(p, t->value.octet_string))
+
+ if (!rsc_parse_checklist(p, rsc->checkList))
goto out;
rc = 1;
out:
- sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
+ RpkiSignedChecklist_free(rsc);
return rc;
}
rsc_parse(X509 **x509, const char *fn, const unsigned char *der, size_t len)
{
struct parse p;
- size_t cmsz;
unsigned char *cms;
- int rc = 0;
+ size_t cmsz;
const ASN1_TIME *at;
+ int rc = 0;
memset(&p, 0, sizeof(struct parse));
p.fn = fn;