Download raw body.
rpki-client: in filemode read concatenated sequence of objects
RPKI objects are self-delimited. This changeset adds in filemode the
ability to read a concatenated sequence of DER-encoded objects. This is
particularly useful when debugging erik protocol data where concatenated
sequences are used:
https://datatracker.ietf.org/doc/html/draft-ietf-sidrops-rpki-erik-protocol-05#section-6.1
Example:
$ find /var/cache/rpki-client/ta -type f | xargs cat > /tmp/stream
$ rpki-client -f /tmp/stream | egrep -v "^File:" | sha256
fba67a4329c65c8bc2473dd60890ece977cbc132a2a882351c2e2cac5d49e978
$ find /var/cache/rpki-client/ta -type f | xargs rpki-client -f | egrep -v "^File:" | sha256
fba67a4329c65c8bc2473dd60890ece977cbc132a2a882351c2e2cac5d49e978
There is an XXX to also add support to be able to read concatenated gzip
streams. Later on I'd also like to add the ability to read from stdin
('rpki-client -f -'). Man page will also need a slight tweak.
Before wandering off too far, I thought I should check in with the group.
Feedback?
Index: filemode.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/filemode.c,v
diff -u -p -r1.86 filemode.c
--- filemode.c 9 Jul 2026 11:39:19 -0000 1.86
+++ filemode.c 12 Jul 2026 11:57:44 -0000
@@ -456,28 +456,6 @@ proc_parser_file(char *file, unsigned ch
}
}
- if (rtype_from_file_extension(file) == RTYPE_GZ) {
- unsigned char *full_buf = NULL;
- size_t full_len;
- char *gz_ext;
-
- if ((full_buf = inflate_buffer(buf, len, &full_len)) == NULL) {
- warnx("%s: gzip decompression failed", file);
- goto out;
- }
- if (buf != in_buf)
- free(buf);
- buf = full_buf;
- len = full_len;
-
- /* zap trailing .gz */
- if ((gz_ext = strrchr(file, '.')) == NULL) {
- warnx("%s: unreachable: missing . in filename?", file);
- goto out;
- }
- *gz_ext = '\0';
- }
-
if (!EVP_Digest(buf, len, filehash, NULL, EVP_sha256(), NULL))
errx(1, "EVP_Digest failed in %s", __func__);
Index: main.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v
diff -u -p -r1.311 main.c
--- main.c 8 Jul 2026 17:49:04 -0000 1.311
+++ main.c 12 Jul 2026 11:57:45 -0000
@@ -45,6 +45,8 @@
#include <imsg.h>
+#include <openssl/asn1.h>
+
#include "extern.h"
#include "version.h"
@@ -480,21 +482,84 @@ queue_add_from_mft(const struct mft *mft
static void
queue_add_file(const char *file, enum rtype type, int talid)
{
- unsigned char *buf = NULL;
- char *nfile;
- size_t len = 0;
+ unsigned char *buf = NULL, *obj_buf;
+ const unsigned char *cbuf, *objp;
+ char *nfile;
+ ASN1_SEQUENCE_ANY *as;
+ size_t len = 0, buf_len, obj_len;
if (!filemode || strncmp(file, RSYNC_PROTO, RSYNC_PROTO_LEN) != 0) {
buf = load_file(file, &len);
if (buf == NULL)
err(1, "%s", file);
}
+
+ if (type == RTYPE_TAL || rtype_from_file_extension(file) == RTYPE_TAL) {
+ if ((nfile = strdup(file)) == NULL)
+ err(1, NULL);
+ entityq_add(NULL, nfile, type, DIR_UNKNOWN, NULL, buf, len,
+ talid, 0, NULL);
+ return;
+ }
- if ((nfile = strdup(file)) == NULL)
- err(1, NULL);
- /* Not in a repository, so directly add to queue. */
- entityq_add(NULL, nfile, type, DIR_UNKNOWN, NULL, buf, len, talid, 0,
- NULL);
+ /* In case of rsync URI, load the object later on from the cachedir. */
+ if (filemode && strncmp(file, RSYNC_PROTO, RSYNC_PROTO_LEN) == 0) {
+ if ((nfile = strdup(file)) == NULL)
+ err(1, NULL);
+ entityq_add(NULL, nfile, type, DIR_UNKNOWN, NULL, NULL, 0,
+ talid, 0, NULL);
+ return;
+ }
+
+ assert(filemode);
+
+ /* XXX: only inflates the first gzip member contained in buf */
+ if (rtype_from_file_extension(file) == RTYPE_GZ) {
+ unsigned char *full_buf = NULL;
+ size_t full_len;
+ char *gz_ext;
+
+ if ((full_buf = inflate_buffer(buf, len, &full_len)) == NULL) {
+ warnx("%s: gzip decompression failed", file);
+ free(buf);
+ return;
+ }
+ free(buf);
+ buf = full_buf;
+ len = full_len;
+
+ /* zap trailing .gz */
+ if ((gz_ext = strrchr(file, '.')) == NULL)
+ errx(1, "%s: unreachable: no . in filename?", file);
+ *gz_ext = '\0';
+ }
+
+ cbuf = buf;
+ buf_len = len;
+ do {
+ objp = cbuf;
+ if ((as = d2i_ASN1_SEQUENCE_ANY(NULL, &cbuf, len)) == NULL) {
+ warnx("%s: malformed DER object", file);
+ goto out;
+ }
+ ASN1_item_free((ASN1_VALUE *)as, &ASN1_SEQUENCE_ANY_it);
+ as = NULL;
+
+ obj_len = cbuf - objp;
+ len = len - obj_len;
+
+ if ((obj_buf = calloc(1, obj_len)) == NULL)
+ err(1, NULL);
+ memcpy(obj_buf, objp, obj_len);
+
+ if ((nfile = strdup(file)) == NULL)
+ err(1, NULL);
+ entityq_add(NULL, nfile, type, DIR_UNKNOWN, NULL, obj_buf,
+ obj_len, 0, 0, NULL);
+ } while (cbuf != buf + buf_len);
+
+ out:
+ free(buf);
}
/*
rpki-client: in filemode read concatenated sequence of objects