On Tue, May 31, 2022 at 01:16:19PM +0200, Theo Buehler wrote:
> I chose to implement the constrained versions of the RFC 3779 types from
> the draft because the OpenSSL RFC 3779 code has static IPAddrBlocks_it,
> so we have to work around that anyway. This isn't quite minimal, but it
> avoids asymmetry between ASIdentifiers and IPAddrBlocks and it's cleaner
> than reusing as many of the available RFC 3779 types as possible (which
> also means additional checks either when walking the structs or after).
>
> The diff has three parts that build on top of each other. There is no
> overlap outside of extern.h, so it should not make the review harder.
>
> The mechanical cert.c diff adjusts some sbgp_addr_*() and sbgp_as_*() to
> remove the struct parse argument so that we can use them from rsc.c.
>
> The rsc.c diff is the tricky part: it switches to templates and uses the
> cert.c functions. rsc_parse_aslist() and rsc_parse_iplist() are similar
> to sbgp_assysnum() and sbgp_ipaddrblk(), but somewhat easier. We get
> rid of the copy-paste XXXs and the last bit of low level ASN.1 fiddling.
>
> Remove the unused ASN1_frame() and cms_econtent_version() from cms.c.
I checked the changes outside of rsc.c and am OK with those.
I also looked at the new version of rsc.c and think it is much nicer code.
I did not test the rsc.c changes with an RSC file though.
OK claudio@
> Index: cert.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
> retrieving revision 1.82
> diff -u -p -r1.82 cert.c
> --- cert.c 15 May 2022 15:00:53 -0000 1.82
> +++ cert.c 31 May 2022 10:46:00 -0000
> @@ -58,11 +58,12 @@ extern ASN1_OBJECT *notify_oid; /* 1.3.6
> * Returns zero on failure (IP overlap) non-zero on success.
> */
> static int
> -append_ip(struct parse *p, const struct cert_ip *ip)
> +append_ip(const char *fn, struct cert_ip *ips, size_t *ipsz,
> + const struct cert_ip *ip)
> {
> - if (!ip_addr_check_overlap(ip, p->fn, p->res->ips, p->res->ipsz))
> + if (!ip_addr_check_overlap(ip, fn, ips, *ipsz))
> return 0;
> - p->res->ips[p->res->ipsz++] = *ip;
> + ips[(*ipsz)++] = *ip;
> return 1;
> }
>
> @@ -72,11 +73,12 @@ append_ip(struct parse *p, const struct
> * as defined by RFC 3779 section 3.3.
> */
> static int
> -append_as(struct parse *p, const struct cert_as *as)
> +append_as(const char *fn, struct cert_as *ases, size_t *asz,
> + const struct cert_as *as)
> {
> - if (!as_check_overlap(as, p->fn, p->res->as, p->res->asz))
> + if (!as_check_overlap(as, fn, ases, *asz))
> return 0;
> - p->res->as[p->res->asz++] = *as;
> + ases[(*asz)++] = *as;
> return 1;
> }
>
> @@ -84,8 +86,9 @@ append_as(struct parse *p, const struct
> * Parse a range of AS identifiers as in 3.2.3.8.
> * Returns zero on failure, non-zero on success.
> */
> -static int
> -sbgp_asrange(struct parse *p, const ASRange *range)
> +int
> +sbgp_as_range(const char *fn, struct cert_as *ases, size_t *asz,
> + const ASRange *range)
> {
> struct cert_as as;
>
> @@ -94,34 +97,35 @@ sbgp_asrange(struct parse *p, const ASRa
>
> if (!as_id_parse(range->min, &as.range.min)) {
> warnx("%s: RFC 3779 section 3.2.3.8 (via RFC 1930): "
> - "malformed AS identifier", p->fn);
> + "malformed AS identifier", fn);
> return 0;
> }
>
> if (!as_id_parse(range->max, &as.range.max)) {
> warnx("%s: RFC 3779 section 3.2.3.8 (via RFC 1930): "
> - "malformed AS identifier", p->fn);
> + "malformed AS identifier", fn);
> return 0;
> }
>
> if (as.range.max == as.range.min) {
> warnx("%s: RFC 3379 section 3.2.3.8: ASRange: "
> - "range is singular", p->fn);
> + "range is singular", fn);
> return 0;
> } else if (as.range.max < as.range.min) {
> warnx("%s: RFC 3379 section 3.2.3.8: ASRange: "
> - "range is out of order", p->fn);
> + "range is out of order", fn);
> return 0;
> }
>
> - return append_as(p, &as);
> + return append_as(fn, ases, asz, &as);
> }
>
> /*
> * Parse an entire 3.2.3.10 integer type.
> */
> -static int
> -sbgp_asid(struct parse *p, const ASN1_INTEGER *i)
> +int
> +sbgp_as_id(const char *fn, struct cert_as *ases, size_t *asz,
> + const ASN1_INTEGER *i)
> {
> struct cert_as as;
>
> @@ -130,27 +134,27 @@ sbgp_asid(struct parse *p, const ASN1_IN
>
> if (!as_id_parse(i, &as.id)) {
> warnx("%s: RFC 3779 section 3.2.3.10 (via RFC 1930): "
> - "malformed AS identifier", p->fn);
> + "malformed AS identifier", fn);
> return 0;
> }
> if (as.id == 0) {
> warnx("%s: RFC 3779 section 3.2.3.10 (via RFC 1930): "
> - "AS identifier zero is reserved", p->fn);
> + "AS identifier zero is reserved", fn);
> return 0;
> }
>
> - return append_as(p, &as);
> + return append_as(fn, ases, asz, &as);
> }
>
> static int
> -sbgp_asinherit(struct parse *p)
> +sbgp_as_inherit(const char *fn, struct cert_as *ases, size_t *asz)
> {
> struct cert_as as;
>
> memset(&as, 0, sizeof(struct cert_as));
> as.type = CERT_AS_INHERIT;
>
> - return append_as(p, &as);
> + return append_as(fn, ases, asz, &as);
> }
>
> /*
> @@ -214,7 +218,7 @@ sbgp_assysnum(struct parse *p, X509_EXTE
> err(1, NULL);
>
> if (aors == NULL) {
> - if (!sbgp_asinherit(p))
> + if (!sbgp_as_inherit(p->fn, p->res->as, &p->res->asz))
> goto out;
> }
>
> @@ -224,11 +228,13 @@ sbgp_assysnum(struct parse *p, X509_EXTE
> aor = sk_ASIdOrRange_value(aors, i);
> switch (aor->type) {
> case ASIdOrRange_id:
> - if (!sbgp_asid(p, aor->u.id))
> + if (!sbgp_as_id(p->fn, p->res->as, &p->res->asz,
> + aor->u.id))
> goto out;
> break;
> case ASIdOrRange_range:
> - if (!sbgp_asrange(p, aor->u.range))
> + if (!sbgp_as_range(p->fn, p->res->as, &p->res->asz,
> + aor->u.range))
> goto out;
> break;
> default:
> @@ -248,8 +254,9 @@ sbgp_assysnum(struct parse *p, X509_EXTE
> * Construct a RFC 3779 2.2.3.8 range from its bit string.
> * Returns zero on failure, non-zero on success.
> */
> -static int
> -sbgp_addr(struct parse *p, enum afi afi, const ASN1_BIT_STRING *bs)
> +int
> +sbgp_addr(const char *fn, struct cert_ip *ips, size_t *ipsz, enum afi afi,
> + const ASN1_BIT_STRING *bs)
> {
> struct cert_ip ip;
>
> @@ -258,27 +265,28 @@ sbgp_addr(struct parse *p, enum afi afi,
> ip.afi = afi;
> ip.type = CERT_IP_ADDR;
>
> - if (!ip_addr_parse(bs, afi, p->fn, &ip.ip)) {
> + if (!ip_addr_parse(bs, afi, fn, &ip.ip)) {
> warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: "
> - "invalid IP address", p->fn);
> + "invalid IP address", fn);
> return 0;
> }
>
> if (!ip_cert_compose_ranges(&ip)) {
> warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: "
> - "IP address range reversed", p->fn);
> + "IP address range reversed", fn);
> return 0;
> }
>
> - return append_ip(p, &ip);
> + return append_ip(fn, ips, ipsz, &ip);
> }
>
> /*
> * Parse RFC 3779 2.2.3.9 range of addresses.
> * Returns zero on failure, non-zero on success.
> */
> -static int
> -sbgp_addr_range(struct parse *p, enum afi afi, const IPAddressRange *range)
> +int
> +sbgp_addr_range(const char *fn, struct cert_ip *ips, size_t *ipsz,
> + enum afi afi, const IPAddressRange *range)
> {
> struct cert_ip ip;
>
> @@ -287,29 +295,30 @@ sbgp_addr_range(struct parse *p, enum af
> ip.afi = afi;
> ip.type = CERT_IP_RANGE;
>
> - if (!ip_addr_parse(range->min, afi, p->fn, &ip.range.min)) {
> + if (!ip_addr_parse(range->min, afi, fn, &ip.range.min)) {
> warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
> - "invalid IP address", p->fn);
> + "invalid IP address", fn);
> return 0;
> }
>
> - if (!ip_addr_parse(range->max, afi, p->fn, &ip.range.max)) {
> + if (!ip_addr_parse(range->max, afi, fn, &ip.range.max)) {
> warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
> - "invalid IP address", p->fn);
> + "invalid IP address", fn);
> return 0;
> }
>
> if (!ip_cert_compose_ranges(&ip)) {
> warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
> - "IP address range reversed", p->fn);
> + "IP address range reversed", fn);
> return 0;
> }
>
> - return append_ip(p, &ip);
> + return append_ip(fn, ips, ipsz, &ip);
> }
>
> static int
> -sbgp_addr_inherit(struct parse *p, enum afi afi)
> +sbgp_addr_inherit(const char *fn, struct cert_ip *ips, size_t *ipsz,
> + enum afi afi)
> {
> struct cert_ip ip;
>
> @@ -318,7 +327,7 @@ sbgp_addr_inherit(struct parse *p, enum
> ip.afi = afi;
> ip.type = CERT_IP_INHERIT;
>
> - return append_ip(p, &ip);
> + return append_ip(fn, ips, ipsz, &ip);
> }
>
> /*
> @@ -380,7 +389,8 @@ sbgp_ipaddrblk(struct parse *p, X509_EXT
> }
>
> if (aors == NULL) {
> - if (!sbgp_addr_inherit(p, afi))
> + if (!sbgp_addr_inherit(p->fn, p->res->ips,
> + &p->res->ipsz, afi))
> goto out;
> continue;
> }
> @@ -389,12 +399,13 @@ sbgp_ipaddrblk(struct parse *p, X509_EXT
> aor = sk_IPAddressOrRange_value(aors, j);
> switch (aor->type) {
> case IPAddressOrRange_addressPrefix:
> - if (!sbgp_addr(p, afi, aor->u.addressPrefix))
> + if (!sbgp_addr(p->fn, p->res->ips,
> + &p->res->ipsz, afi, aor->u.addressPrefix))
> goto out;
> break;
> case IPAddressOrRange_addressRange:
> - if (!sbgp_addr_range(p, afi,
> - aor->u.addressRange))
> + if (!sbgp_addr_range(p->fn, p->res->ips,
> + &p->res->ipsz, afi, aor->u.addressRange))
> goto out;
> break;
> default:
> Index: cms.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rpki-client/cms.c,v
> retrieving revision 1.19
> diff -u -p -r1.19 cms.c
> --- cms.c 15 May 2022 16:43:34 -0000 1.19
> +++ cms.c 28 May 2022 09:04:10 -0000
> @@ -272,61 +272,3 @@ out:
>
> return res;
> }
> -
> -/*
> - * Wrapper around ASN1_get_object() that preserves the current start
> - * state and returns a more meaningful value.
> - * Return zero on failure, non-zero on success.
> - */
> -int
> -ASN1_frame(const char *fn, size_t sz,
> - const unsigned char **cnt, long *cntsz, int *tag)
> -{
> - int ret, pcls;
> -
> - ret = ASN1_get_object(cnt, cntsz, tag, &pcls, sz);
> - if ((ret & 0x80)) {
> - cryptowarnx("%s: ASN1_get_object", fn);
> - return 0;
> - }
> - return ASN1_object_size((ret & 0x01) ? 2 : 0, *cntsz, *tag);
> -}
> -
> -/*
> - * Check the version field in eContent.
> - * Returns -1 on failure, zero on success.
> - */
> -int
> -cms_econtent_version(const char *fn, const unsigned char **d, size_t dsz,
> - long *version)
> -{
> - ASN1_INTEGER *aint = NULL;
> - long plen;
> - int ptag, rc = -1;
> -
> - if (!ASN1_frame(fn, dsz, d, &plen, &ptag))
> - goto out;
> - if (ptag != 0) {
> - warnx("%s: eContent version: expected explicit tag [0]", fn);
> - goto out;
> - }
> -
> - aint = d2i_ASN1_INTEGER(NULL, d, plen);
> - if (aint == NULL) {
> - cryptowarnx("%s: eContent version: failed d2i_ASN1_INTEGER",
> - fn);
> - goto out;
> - }
> -
> - *version = ASN1_INTEGER_get(aint);
> - if (*version < 0) {
> - warnx("%s: eContent version: expected positive integer, got:"
> - " %ld", fn, *version);
> - goto out;
> - }
> -
> - rc = 0;
> -out:
> - ASN1_INTEGER_free(aint);
> - return rc;
> -}
> Index: extern.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
> retrieving revision 1.138
> diff -u -p -r1.138 extern.h
> --- extern.h 24 May 2022 09:20:49 -0000 1.138
> +++ extern.h 29 May 2022 21:05:03 -0000
> @@ -513,11 +513,6 @@ int valid_rsc(const char *, struct aut
> unsigned char *cms_parse_validate(X509 **, const char *,
> const unsigned char *, size_t,
> const ASN1_OBJECT *, size_t *);
> -int cms_econtent_version(const char *, const unsigned char **,
> - size_t, long *);
> -/* Helper for ASN1 parsing */
> -int ASN1_frame(const char *, size_t,
> - const unsigned char **, long *, int *);
>
> /* Work with RFC 3779 IP addresses, prefixes, ranges. */
>
> @@ -535,6 +530,11 @@ int ip_addr_check_covered(enum afi, co
> int ip_cert_compose_ranges(struct cert_ip *);
> void ip_roa_compose_ranges(struct roa_ip *);
>
> +int sbgp_addr(const char *, struct cert_ip *, size_t *,
> + enum afi, const ASN1_BIT_STRING *);
> +int sbgp_addr_range(const char *, struct cert_ip *, size_t *,
> + enum afi, const IPAddressRange *);
> +
> /* Work with RFC 3779 AS numbers, ranges. */
>
> int as_id_parse(const ASN1_INTEGER *, uint32_t *);
> @@ -542,6 +542,11 @@ int as_check_overlap(const struct cert
> const struct cert_as *, size_t);
> int as_check_covered(uint32_t, uint32_t,
> const struct cert_as *, size_t);
> +
> +int sbgp_as_id(const char *, struct cert_as *, size_t *,
> + const ASN1_INTEGER *);
> +int sbgp_as_range(const char *, struct cert_as *, size_t *,
> + const ASRange *);
>
> /* Parser-specific */
> void entity_free(struct entity *);
> Index: rpki-client.8
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rpki-client/rpki-client.8,v
> retrieving revision 1.64
> diff -u -p -r1.64 rpki-client.8
> --- rpki-client.8 20 May 2022 10:38:39 -0000 1.64
> +++ rpki-client.8 28 May 2022 09:04:10 -0000
> @@ -271,7 +271,7 @@ A Profile for BGPsec Router Certificates
> Certification Requests.
> .It RFC 8630
> Resource Public Key Infrastructure (RPKI) Trust Anchor Locator.
> -.It draft-ietf-sidrops-rpki-rsc-06
> +.It draft-ietf-sidrops-rpki-rsc-08
> A profile for Resource Public Key Infrastructure (RPKI) Signed Checklists
> (RSC).
> .El
> .Sh HISTORY
> Index: rsc.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rpki-client/rsc.c,v
> retrieving revision 1.4
> diff -u -p -r1.4 rsc.c
> --- rsc.c 15 May 2022 16:43:35 -0000 1.4
> +++ rsc.c 31 May 2022 11:09:26 -0000
> @@ -16,16 +16,17 @@
> * 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"
>
> @@ -40,520 +41,273 @@ struct parse {
> 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;
> +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);
>
> - 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;
> -}
> +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.1
> * 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;
> - }
> -
> - 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;
> - }
> + FileNameAndHash *fh;
> + ASN1_IA5STRING *fn;
> + struct rscfile *file;
> + size_t sz, i;
>
> - 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;
> -}
> -
> -/*
> - * 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;
> + for (i = 0; i < sz; i++) {
> + fh = sk_FileNameAndHash_value(checkList, i);
>
> - 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 AsList (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;
> + int i, asz;
>
> - if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
> - cryptowarnx("%s: ASRange failed ASN.1 seq parse", p->fn);
> - goto out;
> - }
> -
> - 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;
> - }
> -
> - 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;
> - }
> + if (asids == NULL)
> + return 1;
>
> - 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;
> - }
> -
> - if (!append_ip(p, &ip))
> - goto out;
> -
> - rc = 1;
> - out:
> - ASN1_OCTET_STRING_free(aos);
> - IPAddressOrRange_free(aor);
> - return rc;
> -}
> + const ConstrainedIPAddressFamily *af;
> + const IPAddressOrRanges *aors;
> + const IPAddressOrRange *aor;
> + size_t ipsz;
> + enum afi afi;
> + int i, j;
>
> -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 (ipAddrBlocks == NULL)
> + return 1;
>
> - if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
> - cryptowarnx("%s: RSC IPList: failed ASN.1 sequence parse",
> - p->fn);
> - goto out;
> + if (sk_ConstrainedIPAddressFamily_num(ipAddrBlocks) == 0) {
> + warnx("%s: RSC ipAddrBlocks empty", p->fn);
> + return 0;
> }
>
> - 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;
> + for (i = 0; i < sk_ConstrainedIPAddressFamily_num(ipAddrBlocks); i++) {
> + af = sk_ConstrainedIPAddressFamily_value(ipAddrBlocks, i);
> + aors = af->addressesOrRanges;
> +
> + 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;
> }
>
> /*
> @@ -564,88 +318,61 @@ rsc_parse_resourceblock(const ASN1_OCTET
> 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 = NULL;
> + 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;
> }
>
> @@ -657,10 +384,10 @@ struct rsc *
> 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;
>
--
:wq Claudio