Index | Thread | Search

From:
Theo Buehler <tb@theobuehler.org>
Subject:
rpki-client: last but not least... convert ccr
To:
tech@openbsd.org
Date:
Wed, 3 Dec 2025 14:23:21 +0100

Download raw body.

Thread
This converts most of ccr.c to opaque ASN1_STRING

There already is a base64 encoding helper. Hoist that to the top, rename
it and add hex and copy helpers to remove quite a bit of duplication.

While the copy helper could be used in a couple of places outside of ccr,
the precise length check isn't ideal for an extern.h API but required
here.

The rest is straightforward. It leaves a write to abs->flags in ccr.c which
will need another new API: https://github.com/openssl/openssl/issues/29185

Index: ccr.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/ccr.c,v
diff -u -p -r1.29 ccr.c
--- ccr.c	3 Dec 2025 10:21:53 -0000	1.29
+++ ccr.c	3 Dec 2025 10:45:02 -0000
@@ -190,6 +190,35 @@ ASN1_SEQUENCE(RouterKey) = {
 
 IMPLEMENT_ASN1_FUNCTIONS(RouterKey);
 
+static char *
+hex_encode_asn1_string(const ASN1_STRING *str)
+{
+	return hex_encode(ASN1_STRING_get0_data(str), ASN1_STRING_length(str));
+}
+
+static int
+base64_encode_asn1_string(const ASN1_OCTET_STRING *astr, char **out)
+{
+	const unsigned char *data = ASN1_STRING_get0_data(astr);
+	int length = ASN1_STRING_length(astr);
+
+	return base64_encode(data, length, out) == 0;
+}
+
+static int
+copy_asn1_string(const ASN1_STRING *astr, unsigned char *buf, size_t len)
+{
+	const unsigned char *data = ASN1_STRING_get0_data(astr);
+	int length = ASN1_STRING_length(astr);
+
+	if (length < 0 || (size_t)length != len)
+		return 0;
+
+	memcpy(buf, data, length);
+
+	return 1;
+}
+
 static void
 hash_asn1_item(ASN1_OCTET_STRING *astr, const ASN1_ITEM *it, void *val)
 {
@@ -219,7 +248,7 @@ validate_asn1_hash(const char *fn, const
 		goto out;
 	}
 
-	hex = hex_encode(hash->data, hash->length);
+	hex = hex_encode_asn1_string(hash);
  out:
 	ASN1_OCTET_STRING_free(astr);
 	return hex;
@@ -316,12 +345,6 @@ append_cached_manifest(STACK_OF(Manifest
 		errx(1, "sk_ManifestInstance_push");
 }
 
-static int
-base64_encode_asn1str(const ASN1_OCTET_STRING *astr, char **out)
-{
-	return base64_encode(astr->data, astr->length, out) == 0;
-}
-
 static ManifestState *
 generate_manifeststate(struct validation_data *vd)
 {
@@ -346,8 +369,8 @@ generate_manifeststate(struct validation
 
 	hash_asn1_item(ms->hash, ASN1_ITEM_rptr(ManifestInstances), ms->mis);
 
-	if (!base64_encode_asn1str(ms->hash, &ccr->mfts_hash))
-		errx(1, "base64_encode_asn1str");
+	if (!base64_encode_asn1_string(ms->hash, &ccr->mfts_hash))
+		errx(1, "base64_encode_asn1_string");
 
 	return ms;
 }
@@ -440,8 +463,8 @@ generate_roapayloadstate(struct validati
 
 	hash_asn1_item(vrps->hash, ASN1_ITEM_rptr(ROAPayloadSets), vrps->rps);
 
-	if (!base64_encode_asn1str(vrps->hash, &ccr->vrps_hash))
-		errx(1, "base64_encode_asn1str");
+	if (!base64_encode_asn1_string(vrps->hash, &ccr->vrps_hash))
+		errx(1, "base64_encode_asn1_string");
 
 	return vrps;
 }
@@ -491,8 +514,8 @@ generate_aspapayloadstate(struct validat
 
 	hash_asn1_item(vaps->hash, ASN1_ITEM_rptr(ASPAPayloadSets), vaps->aps);
 
-	if (!base64_encode_asn1str(vaps->hash, &ccr->vaps_hash))
-		errx(1, "base64_encode_asn1str");
+	if (!base64_encode_asn1_string(vaps->hash, &ccr->vaps_hash))
+		errx(1, "base64_encode_asn1_string");
 
 	return vaps;
 }
@@ -528,8 +551,8 @@ generate_trustanchorstate(struct validat
 	hash_asn1_item(tas->hash, ASN1_ITEM_rptr(SubjectKeyIdentifiers),
 	    tas->skis);
 
-	if (!base64_encode_asn1str(tas->hash, &vd->ccr.tas_hash))
-		errx(1, "base64_encode_asn1str");
+	if (!base64_encode_asn1_string(tas->hash, &vd->ccr.tas_hash))
+		errx(1, "base64_encode_asn1_string");
 
 	return tas;
 }
@@ -593,8 +616,8 @@ generate_routerkeystate(struct validatio
 
 	hash_asn1_item(rks->hash, ASN1_ITEM_rptr(RouterKeySets), rks->rksets);
 
-	if (!base64_encode_asn1str(rks->hash, &vd->ccr.brks_hash))
-		errx(1, "base64_encode_asn1str");
+	if (!base64_encode_asn1_string(rks->hash, &vd->ccr.brks_hash))
+		errx(1, "base64_encode_asn1_string");
 
 	return rks;
 }
@@ -981,11 +1004,11 @@ parse_mft_instances(const char *fn, stru
 
 		mi = sk_ManifestInstance_value(mis, i);
 
-		if (mi->hash->length != sizeof(ccr_mft->hash)) {
+		if (!copy_asn1_string(mi->hash,
+		    ccr_mft->hash, sizeof(ccr_mft->hash))) {
 			warnx("%s: manifest instance #%d corrupted", fn, i);
 			goto out;
 		}
-		memcpy(ccr_mft->hash, mi->hash->data, mi->hash->length);
 
 		if (prev != NULL) {
 			if (ccr_mft_cmp(ccr_mft, prev) <= 0) {
@@ -994,11 +1017,11 @@ parse_mft_instances(const char *fn, stru
 			}
 		}
 
-		if (mi->aki->length != sizeof(ccr_mft->aki)) {
+		if (!copy_asn1_string(mi->aki,
+		    ccr_mft->aki, sizeof(ccr_mft->aki))) {
 			warnx("%s: manifest instance #%d corrupted", fn, i);
 			goto out;
 		}
-		memcpy(ccr_mft->aki, mi->aki->data, mi->aki->length);
 
 		if (!ASN1_INTEGER_get_uint64(&size, mi->size)) {
 			warnx("%s: manifest instance #%d corrupted", fn, i);
@@ -1039,12 +1062,11 @@ parse_mft_instances(const char *fn, stru
 				err(1, NULL);
 
 			s = sk_SubjectKeyIdentifier_value(mi->subordinates, j);
-			if (s->length != sizeof(sub->ski)) {
+			if (!copy_asn1_string(s, sub->ski, sizeof(sub->ski))) {
 				warnx("%s: manifest instance #%d corrupted",
-				    fn, j);
+				    fn, i);
 				goto out;
 			}
-			memcpy(sub->ski, s->data, sizeof(sub->ski));
 			SLIST_INSERT_HEAD(&ccr_mft->subordinates, sub, entry);
 			sub = NULL;
 		}
@@ -1391,13 +1413,11 @@ parse_tas_skis(const char *fn, struct cc
 
 		ski = sk_SubjectKeyIdentifier_value(skis, i);
 
-		if (ski->length != sizeof(cts->keyid)) {
+		if (!copy_asn1_string(ski, cts->keyid, sizeof(cts->keyid))) {
 			warnx("%s: TAS SKI #%d corrupted", fn, i);
 			goto out;
 		}
 
-		memcpy(cts->keyid, ski->data, ski->length);
-
 		if (prev != NULL) {
 			if (ccr_tas_ski_cmp(cts, prev) <= 0) {
 				warnx("%s: misordered TrustAnchorState", fn);
@@ -1463,12 +1483,12 @@ parse_routerkeys(const char *fn, struct 
 
 		rk = sk_RouterKey_value(routerkeys, i);
 
-		if (rk->ski->length != SHA_DIGEST_LENGTH) {
+		if (ASN1_STRING_length(rk->ski) != SHA_DIGEST_LENGTH) {
 			warnx("%s: AS%d RouterKey SKI corrupted", fn, asid);
 			goto out;
 		}
 
-		brk->ski = hex_encode(rk->ski->data, rk->ski->length);
+		brk->ski = hex_encode_asn1_string(rk->ski);
 
 		der = NULL;
 		if ((der_len = i2d_X509_PUBKEY(rk->spki, &der)) <= 0) {