Download raw body.
rpki-client: convert mft.c to opaque ASN1_STRING
On Mon, Dec 01, 2025 at 04:09:37PM +0100, Theo Buehler wrote:
> First, more of the same. I'm not sure I like the data/length reuse
> in mft_parse_filehash(), but using fdata/flength and hdata/hlength
> or similar didn't seem to make things any better.
>
> I added an XXX for a future check to avoid the possibility of someone
> fiddling with the unused bits octet if the hash ends in a few 0 bits.
> Tihs will be easier once we have API and I'll have audit the other bit
> strings anyway.
>
> For the two comparison functions, we can use ASN1_STRING_cmp()
> for simplicity. If length and data compare equal, this adds a type check,
> which is fine since the template ensures that we compare two IA5 or
> two bit strings. The assert can be dropped since the uniequeness check
> comes after the length check in mft_parse_filehash().
This looks fine. I don't really want to understand the horror of the
unused bits octet but doesn't the current code have the same issue?
OK claudio@
> Index: mft.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rpki-client/mft.c,v
> diff -u -p -r1.133 mft.c
> --- mft.c 13 Nov 2025 15:18:53 -0000 1.133
> +++ mft.c 1 Dec 2025 14:55:13 -0000
> @@ -149,23 +149,31 @@ static int
> mft_parse_filehash(const char *fn, struct mft *mft, const FileAndHash *fh,
> int *found_crl)
> {
> + const unsigned char *data;
> char *file = NULL;
> - int rc = 0;
> + int length, rc = 0;
> struct mftfile *fent;
> enum rtype type;
> size_t new_idx = 0;
>
> - if (!valid_mft_filename(fh->file->data, fh->file->length)) {
> + data = ASN1_STRING_get0_data(fh->file);
> + length = ASN1_STRING_length(fh->file);
> +
> + if (!valid_mft_filename(data, length)) {
> warnx("%s: RFC 9286 section 4.2.2: bad filename", fn);
> goto out;
> }
> - file = strndup(fh->file->data, fh->file->length);
> + file = strndup(data, length);
> if (file == NULL)
> err(1, NULL);
>
> - if (fh->hash->length != SHA256_DIGEST_LENGTH) {
> + /* XXX - malleability: ensure unused bits are 0. */
> + data = ASN1_STRING_get0_data(fh->hash);
> + length = ASN1_STRING_length(fh->hash);
> +
> + if (length != SHA256_DIGEST_LENGTH) {
> warnx("%s: RFC 9286 section 4.2.1: hash: "
> - "invalid SHA256 length, have %d", fn, fh->hash->length);
> + "invalid SHA256 length, have %d", fn, length);
> goto out;
> }
>
> @@ -181,7 +189,7 @@ mft_parse_filehash(const char *fn, struc
> goto out;
> }
> /* remember the filehash for the CRL in struct mft */
> - memcpy(mft->crlhash, fh->hash->data, SHA256_DIGEST_LENGTH);
> + memcpy(mft->crlhash, data, length);
> *found_crl = 1;
> }
>
> @@ -197,7 +205,7 @@ mft_parse_filehash(const char *fn, struc
> fent->type = type;
> fent->file = file;
> file = NULL;
> - memcpy(fent->hash, fh->hash->data, SHA256_DIGEST_LENGTH);
> + memcpy(fent->hash, data, length);
>
> rc = 1;
> out:
> @@ -208,21 +216,13 @@ mft_parse_filehash(const char *fn, struc
> static int
> mft_fh_cmp_name(const FileAndHash *const *a, const FileAndHash *const *b)
> {
> - if ((*a)->file->length < (*b)->file->length)
> - return -1;
> - if ((*a)->file->length > (*b)->file->length)
> - return 1;
> -
> - return memcmp((*a)->file->data, (*b)->file->data, (*b)->file->length);
> + return ASN1_STRING_cmp((*a)->file, (*b)->file);
> }
>
> static int
> mft_fh_cmp_hash(const FileAndHash *const *a, const FileAndHash *const *b)
> {
> - assert((*a)->hash->length == SHA256_DIGEST_LENGTH);
> - assert((*b)->hash->length == SHA256_DIGEST_LENGTH);
> -
> - return memcmp((*a)->hash->data, (*b)->hash->data, (*b)->hash->length);
> + return ASN1_STRING_cmp((*a)->hash, (*b)->hash);
> }
>
> /*
> @@ -247,7 +247,8 @@ mft_has_unique_names_and_hashes(const ch
>
> if (mft_fh_cmp_name(&curr, &next) == 0) {
> warnx("%s: duplicate name: %.*s", fn,
> - curr->file->length, curr->file->data);
> + ASN1_STRING_length(curr->file),
> + ASN1_STRING_get0_data(curr->file));
> goto err;
> }
> }
> @@ -261,8 +262,10 @@ mft_has_unique_names_and_hashes(const ch
>
> if (mft_fh_cmp_hash(&curr, &next) == 0) {
> warnx("%s: duplicate hash for %.*s and %.*s", fn,
> - curr->file->length, curr->file->data,
> - next->file->length, next->file->data);
> + ASN1_STRING_length(curr->file),
> + ASN1_STRING_get0_data(curr->file),
> + ASN1_STRING_length(next->file),
> + ASN1_STRING_get0_data(next->file));
> goto err;
> }
> }
>
--
:wq Claudio
rpki-client: convert mft.c to opaque ASN1_STRING