Download raw body.
rpki-client: encode Trust Anchor SubjectKeyIdentifiers into CCR output
This diff makes it so that the SubjectKeyIdentifiers of the valid & used Trust
Anchor certificates are added to the CCR output.
$ cat /var/db/rpki-client/rpki.ccr | der2ascii | tail -n 13 | head -n 9
[4] {
SEQUENCE {
OCTET_STRING { `0b9cca90dd0d7a8a37666b19217fe0d84037b7a2` }
OCTET_STRING { `13d4f24f9a9fcd98db36f930631808c88f3974bc` }
OCTET_STRING { `e8552b1fd6d1a4f7e404c6d8e5680d1ebc163fc3` }
OCTET_STRING { `eb680f38f5d6c71bb4b106b8bd06585012da31b6` }
OCTET_STRING { `fc8a9cb3ed184e17d30eea1e0fa7615ce4b1af47` }
}
}
OK?
Index: ccr.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/ccr.c,v
diff -u -p -r1.2 ccr.c
--- ccr.c 23 Aug 2025 11:16:50 -0000 1.2
+++ ccr.c 6 Sep 2025 05:09:26 -0000
@@ -41,15 +41,10 @@
* BEGIN
*
* IMPORTS
- * CONTENT-TYPE, Digest, DigestAlgorithmIdentifier
+ * CONTENT-TYPE, Digest, DigestAlgorithmIdentifier, SubjectKeyIdentifier
* FROM CryptographicMessageSyntax-2010 -- in [RFC6268]
* { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
- * pkcs-9(9) smime(16) modules(0) id-mod-cms-2009(58) };
- *
- * KeyIdentifier
- * FROM PKIX1Implicit88 -- in [RFC5280]
- * { iso(1) identified-organization(3) dod(6) internet(1) security(5)
- * mechanisms(5) pkix(7) id-mod(0) id-pkix1-implicit(19) }
+ * pkcs-9(9) smime(16) modules(0) id-mod-cms-2009(58) }
*
* -- in [draft-spaghetti-sidrops-rpki-erik-protocol-01]
* -- https://sobornost.net/~job/draft-spaghetti-sidrops-rpki-erik-protocol.html
@@ -62,6 +57,7 @@
* FROM RPKI-ROA-2023 -- in [RFC9582]
* { so(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
* pkcs9(9) smime(16) mod(0) id-mod-rpkiROA-2023(75) }
+ * ;
*
* ct-rpkiCanonicalCacheRepresentation CONTENT-TYPE ::=
* { TYPE RpkiCanonicalCacheRepresentation
@@ -78,11 +74,13 @@
* mfts [1] ManifestState OPTIONAL,
* vrps [2] ROAPayloadState OPTIONAL,
* vaps [3] ASPAPayloadState OPTIONAL,
+ * taskis [4] SEQUENCE (SIZE(1..MAX)) OF SubjectKeyIdentifier OPTIONAL,
* ... }
- * -- at least one of mfts, vrps or vaps MUST be present
+ * -- at least one of mfts, vrps, vaps, or taskis MUST be present
* ( WITH COMPONENTS { ..., mfts PRESENT } |
* WITH COMPONENTS { ..., vrps PRESENT } |
- * WITH COMPONENTS { ..., vaps PRESENT } )
+ * WITH COMPONENTS { ..., vaps PRESENT } |
+ * WITH COMPONENTS { ..., taskis PRESENT } )
*
* ManifestState ::= SEQUENCE {
* mftrefs SEQUENCE OF ManifestRef,
@@ -136,6 +134,8 @@ ASN1_SEQUENCE(CanonicalCacheRepresentati
ASN1_EXP_OPT(CanonicalCacheRepresentation, mfts, ManifestState, 1),
ASN1_EXP_OPT(CanonicalCacheRepresentation, vrps, ROAPayloadState, 2),
ASN1_EXP_OPT(CanonicalCacheRepresentation, vaps, ASPAPayloadState, 3),
+ ASN1_EXP_SEQUENCE_OF_OPT(CanonicalCacheRepresentation, taskis,
+ ASN1_OCTET_STRING, 4),
} ASN1_SEQUENCE_END(CanonicalCacheRepresentation);
IMPLEMENT_ASN1_FUNCTIONS(CanonicalCacheRepresentation);
@@ -456,6 +456,31 @@ generate_aspapayloadstate(struct validat
return vaps;
}
+static STACK_OF(ASN1_OCTET_STRING) *
+generate_taskis(struct validation_data *vd)
+{
+ STACK_OF(ASN1_OCTET_STRING) *taskis = NULL;
+ ASN1_OCTET_STRING *astr = NULL;
+ struct ccr_taski *taski;
+
+ if ((taskis = sk_ASN1_OCTET_STRING_new_null()) == NULL)
+ errx(1, "sk_ASN1_OCTET_STRING_new_null");
+
+ RB_FOREACH(taski, ccr_taski_tree, &vd->ccr.taskis) {
+ if ((astr = ASN1_OCTET_STRING_new()) == NULL)
+ errx(1, "ASN1_OCTET_STRING_new");
+
+ if (!ASN1_OCTET_STRING_set(astr, taski->keyid,
+ sizeof(taski->keyid)))
+ errx(1, "ASN1_OCTET_STRING_set");
+
+ if ((sk_ASN1_OCTET_STRING_push(taskis, astr)) <= 0)
+ errx(1, "sk_ASN1_OCTET_STRING_push");
+ }
+
+ return taskis;
+}
+
static CanonicalCacheRepresentation *
generate_ccr(struct validation_data *vd)
{
@@ -481,6 +506,9 @@ generate_ccr(struct validation_data *vd)
if ((ccr->vaps = generate_aspapayloadstate(vd)) == NULL)
errx(1, "generate_aspapayloadstate");
+ if ((ccr->taskis = generate_taskis(vd)) == NULL)
+ errx(1, "generate_taskis");
+
return ccr;
}
@@ -520,6 +548,30 @@ serialize_ccr_content(struct validation_
ContentInfo_free(ci);
}
+static inline int
+ccr_taski_cmp(const struct ccr_taski *a, const struct ccr_taski *b)
+{
+ return memcmp(a->keyid, b->keyid, SHA_DIGEST_LENGTH);
+}
+
+RB_GENERATE(ccr_taski_tree, ccr_taski, entry, ccr_taski_cmp);
+
+void
+ccr_insert_taski(struct ccr_taski_tree *tree, const struct cert *cert)
+{
+ struct ccr_taski *taski;
+
+ assert(cert->aki == NULL && cert->aia == NULL);
+
+ if ((taski = calloc(1, sizeof(*taski))) == NULL)
+ err(1, NULL);
+
+ if ((hex_decode(cert->ski, taski->keyid, sizeof(taski->keyid))) != 0)
+ err(1, NULL);
+
+ if (RB_INSERT(ccr_taski_tree, tree, taski) != NULL)
+ errx(1, "CCR TASKI tree corrupted");
+}
static inline int
ccr_mft_cmp(const struct ccr_mft *a, const struct ccr_mft *b)
Index: extern.h
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
diff -u -p -r1.260 extern.h
--- extern.h 24 Aug 2025 12:17:12 -0000 1.260
+++ extern.h 6 Sep 2025 05:09:26 -0000
@@ -476,9 +476,18 @@ RB_PROTOTYPE(ccr_mft_tree, ccr_mft, entr
RB_HEAD(ccr_vrp_tree, vrp);
RB_PROTOTYPE(ccr_vrp_tree, vrp, entry, ccr_vrp_cmp);
+struct ccr_taski {
+ RB_ENTRY(ccr_taski) entry;
+ unsigned char keyid[SHA_DIGEST_LENGTH];
+};
+
+RB_HEAD(ccr_taski_tree, ccr_taski);
+RB_PROTOTYPE(ccr_taski_tree, ccr_taski, entry, ccr_taski_cmp);
+
struct ccr {
struct ccr_mft_tree mfts;
struct ccr_vrp_tree vrps;
+ struct ccr_taski_tree taskis;
char *mfts_hash;
char *vrps_hash;
char *vaps_hash;
@@ -1018,6 +1027,7 @@ int output_ccr_der(FILE *, struct vali
*/
void ccr_insert_mft(struct ccr_mft_tree *, const struct mft *);
void ccr_insert_roa(struct ccr_vrp_tree *, const struct roa *);
+void ccr_insert_taski(struct ccr_taski_tree *, const struct cert *);
void serialize_ccr_content(struct validation_data *);
void logx(const char *fmt, ...)
Index: main.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v
diff -u -p -r1.296 main.c
--- main.c 5 Sep 2025 17:38:03 -0000 1.296
+++ main.c 6 Sep 2025 05:09:26 -0000
@@ -634,6 +634,8 @@ entity_process(struct ibuf *b, struct va
cert = cert_read(b);
switch (cert->purpose) {
case CERT_PURPOSE_TA:
+ ccr_insert_taski(&vd->ccr.taskis, cert);
+ /* FALLTHROUGH */
case CERT_PURPOSE_CA:
queue_add_from_cert(cert, &vd->ncas);
break;
@@ -1025,6 +1027,7 @@ main(int argc, char *argv[])
RB_INIT(&vd.ncas);
RB_INIT(&vd.ccr.mfts);
RB_INIT(&vd.ccr.vrps);
+ RB_INIT(&vd.ccr.taskis);
/* If started as root, priv-drop to _rpki-client */
if (getuid() == 0) {
Index: rpki-asn1.h
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/rpki-asn1.h,v
diff -u -p -r1.2 rpki-asn1.h
--- rpki-asn1.h 23 Aug 2025 09:13:14 -0000 1.2
+++ rpki-asn1.h 6 Sep 2025 05:09:26 -0000
@@ -133,6 +133,16 @@ typedef struct {
DECLARE_ASN1_FUNCTIONS(ASPAPayloadState);
+DECLARE_STACK_OF(ASN1_OCTET_STRING);
+
+#ifndef DEFINE_STACK_OF
+#define sk_ASN1_OCTET_STRING_new_null() SKM_sk_new_null(ASN1_OCTET_STRING)
+#define sk_ASN1_OCTET_STRING_push(st, i) \
+ SKM_sk_push(ASN1_OCTET_STRING, (st), (i))
+#endif
+
+DECLARE_ASN1_FUNCTIONS(ASN1_OCTET_STRING);
+
typedef struct {
ASN1_INTEGER *version;
ASN1_OBJECT *hashAlg;
@@ -140,6 +150,7 @@ typedef struct {
ManifestState *mfts;
ROAPayloadState *vrps;
ASPAPayloadState *vaps;
+ STACK_OF(ASN1_OCTET_STRING) *taskis;
} CanonicalCacheRepresentation;
DECLARE_ASN1_FUNCTIONS(CanonicalCacheRepresentation);
rpki-client: encode Trust Anchor SubjectKeyIdentifiers into CCR output