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

Reply via email to