Hi folks, Without this changeset, rpki-client will display diagnostic information about missing files like so:
$ doas rpki-client -t /etc/rpki/lacnic.tal -H repository.lacnic.net rpki-client: repository.lacnic.net/rpki/lacnic/a0c4b4a0-6417-4a7c-8758-9e6f4b0e9679/9783ac9bad2b7b922f648c90e881bf44978069ad.mft: bad message digest for aa78fd79d9a4dc5b9456cc52ce73dba02a1eabe4.roa rpki-client: repository.lacnic.net/rpki/lacnic/a0c4b4a0-6417-4a7c-8758-9e6f4b0e9679/9783ac9bad2b7b922f648c90e881bf44978069ad.mft: bad message digest for d5dc4167b95f994ae118a5c41a0e70425bc3e3f8.roa With the below changeset applied, it'll show a more intuitive error, and also print the manifestNumber (after the mft filename, prefixed with #) to aid debugging efforts (aka "when did this go wrong") rpki-client: .rrdp/4B9F4F9A8FFDEB194969CF392CB513D1C7743232CCD8794BF317D0969B7CD660/repository.lacnic.net/rpki/lacnic/a0c4b4a0-6417-4a7c-8758-9e6f4b0e9679/9783ac9bad2b7b922f648c90e881bf44978069ad.mft#0A1A: missing aa78fd79d9a4dc5b9456cc52ce73dba02a1eabe4.roa rpki-client: .rrdp/4B9F4F9A8FFDEB194969CF392CB513D1C7743232CCD8794BF317D0969B7CD660/repository.lacnic.net/rpki/lacnic/a0c4b4a0-6417-4a7c-8758-9e6f4b0e9679/9783ac9bad2b7b922f648c90e881bf44978069ad.mft#0A1A: missing d5dc4167b95f994ae118a5c41a0e70425bc3e3f8.roa Additionally, in cases where the file is corrupted (not missing), the expected and the computed hashes are printed: $ doas rpki-client -t /etc/rpki/ripe.tal -H rpki.ripe.net -H chloe.sobornost.net rpki-client: .rrdp/436FC6BD7B32853E42FCE5FD95B31D5E3EC1C32C46B7518C2067D568E7EAC119/chloe.sobornost.net/rpki/RIPE-nljobsnijders/cb/5EjPZ8Kw2_h5hRqKpwmjdnq7Tq8.roa: bad file digest for 5EjPZ8Kw2_h5hRqKpwmjdnq7Tq8.roa (expected: NFzQYsvSF+8jLhUXGuVwQ4NNoMyfrJnJbW6DNmbtXRc=, got dc0ZvFHMNWzESwFdWRLnde2EjRt5+hkxdLIc5tgznDo=) rpki-client: .rrdp/436FC6BD7B32853E42FCE5FD95B31D5E3EC1C32C46B7518C2067D568E7EAC119/chloe.sobornost.net/rpki/RIPE-nljobsnijders/cb/t7xg6ZtXdcYhy-YGTMk_ONTD31E.mft#052F: missing 5EjPZ8Kw2_h5hRqKpwmjdnq7Tq8.roa The above previously would be 1 error line, but now two lines are shown: 1 for the fact that a given ROA is corrupted and 1 as a result of the above the manifest that's now invalidated (RFC 9286). I think two messages is appropriate in such situations. OK? Kind regards, Job Index: extern.h =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v retrieving revision 1.181 diff -u -p -r1.181 extern.h --- extern.h 9 May 2023 10:34:32 -0000 1.181 +++ extern.h 10 May 2023 17:34:57 -0000 @@ -681,7 +681,8 @@ int valid_ta(const char *, struct auth const struct cert *); int valid_cert(const char *, struct auth *, const struct cert *); int valid_roa(const char *, struct cert *, struct roa *); -int valid_filehash(int, const char *, size_t); +int valid_filehash(int, const char *, const char *, + const unsigned char *, size_t); int valid_hash(unsigned char *, size_t, const char *, size_t); int valid_filename(const char *, size_t); int valid_uri(const char *, size_t, const char *); Index: parser.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v retrieving revision 1.93 diff -u -p -r1.93 parser.c --- parser.c 27 Apr 2023 08:37:53 -0000 1.93 +++ parser.c 10 May 2023 17:34:57 -0000 @@ -177,20 +177,21 @@ proc_parser_mft_check(const char *fn, st fd = open(path, O_RDONLY); if (fd == -1 && errno == ENOENT) noent++; - free(path); /* remember which path was checked */ m->location = loc[try]; - valid = valid_filehash(fd, m->hash, sizeof(m->hash)); + + valid = valid_filehash(fd, path, m->file, m->hash, + sizeof(m->hash)); + free(path); } if (!valid) { /* silently skip not-existing unknown files */ if (m->type == RTYPE_INVALID && noent == 2) continue; - warnx("%s: bad message digest for %s", fn, m->file); + warnx("%s#%s: missing %s", fn, p->seqnum, m->file); rc = 0; - continue; } } Index: repo.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/repo.c,v retrieving revision 1.44 diff -u -p -r1.44 repo.c --- repo.c 26 Apr 2023 16:32:41 -0000 1.44 +++ repo.c 10 May 2023 17:34:57 -0000 @@ -827,8 +827,7 @@ rrdp_handle_file(unsigned int id, enum p fd = open(fn, O_RDONLY); } while (fd == -1 && try < 2); - if (!valid_filehash(fd, hash, hlen)) { - warnx("%s: bad file digest for %s", rr->notifyuri, fn); + if (!valid_filehash(fd, rr->notifyuri, fn, hash, hlen)) { free(fn); return 0; } Index: validate.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/validate.c,v retrieving revision 1.60 diff -u -p -r1.60 validate.c --- validate.c 9 May 2023 10:34:32 -0000 1.60 +++ validate.c 10 May 2023 17:34:57 -0000 @@ -211,18 +211,22 @@ valid_roa(const char *fn, struct cert *c * Returns 1 if hash matched, 0 otherwise. Closes fd when done. */ int -valid_filehash(int fd, const char *hash, size_t hlen) +valid_filehash(int fd, const char *loc, const char *fn, + const unsigned char *hash, size_t hlen) { - SHA256_CTX ctx; - char filehash[SHA256_DIGEST_LENGTH]; - char buffer[8192]; - ssize_t nr; + SHA256_CTX ctx; + unsigned char filehash[SHA256_DIGEST_LENGTH]; + char buffer[8192]; + char *expected = NULL, *computed = NULL; + ssize_t nr; + int rc = 0; - if (hlen != sizeof(filehash)) + if (hlen != SHA256_DIGEST_LENGTH) errx(1, "bad hash size"); + /* non-existing file, error will be printed elsewhere (if needed) */ if (fd == -1) - return 0; + goto out; SHA256_Init(&ctx); while ((nr = read(fd, buffer, sizeof(buffer))) > 0) @@ -230,9 +234,21 @@ valid_filehash(int fd, const char *hash, close(fd); SHA256_Final(filehash, &ctx); - if (memcmp(hash, filehash, sizeof(filehash)) != 0) - return 0; - return 1; + if (memcmp(hash, filehash, SHA256_DIGEST_LENGTH) != 0) { + if (base64_encode(hash, hlen, &expected) == -1) + errx(1, "base64_encode failed"); + if (base64_encode(filehash, hlen, &computed) == -1) + errx(1, "base64_encode failed"); + warnx("%s: bad file digest for %s (expected: %s, got %s)", + loc, fn, expected, computed); + goto out; + } + + rc = 1; + out: + free(expected); + free(computed); + return rc; } /*