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;
}
/*