Instead of adding similar checks all over the place introduce a
valid_uri() function that checks if a URI is valid enough for rpki-client.
rpki-client does not accept files or directories starting with ., bails on
URI that have strange characters and valid_uri() will also check that the
protocol is the expected one if provided.

This diff converts the 4 places where URI are handled.
-- 
:wq Claudio

Index: cert.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
retrieving revision 1.27
diff -u -p -r1.27 cert.c
--- cert.c      18 Feb 2021 16:23:17 -0000      1.27
+++ cert.c      5 Mar 2021 12:33:50 -0000
@@ -19,7 +19,6 @@
 
 #include <arpa/inet.h>
 #include <assert.h>
-#include <ctype.h>
 #include <err.h>
 #include <inttypes.h>
 #include <stdarg.h>
@@ -140,34 +139,22 @@ sbgp_addr(struct parse *p,
  * Returns zero on failure, non-zero on success.
  */
 static int
-sbgp_sia_resource_notify(struct parse *p,
-       const unsigned char *d, size_t dsz)
+sbgp_sia_resource_notify(struct parse *p, const char *d, size_t dsz)
 {
-       size_t i;
-
        if (p->res->notify != NULL) {
                warnx("%s: RFC 6487 section 4.8.8: SIA: "
                    "Notify location already specified", p->fn);
                return 0;
        }
 
+       if ((p->res->notify = strndup(d, dsz)) == NULL)
+               err(1, NULL);
+
        /* Make sure it's a https:// address. */
-       if (dsz <= 8 || strncasecmp(d, "https://";, 8)) {
-               warnx("%s: RFC 8182 section 3.2: not using https schema",
-                   p->fn);
+       if (!valid_uri(p->res->notify, "https://";)) {
+               warnx("%s: RFC 8182 section 3.2: bad Notify URI", p->fn);
                return 0;
        }
-       /* make sure only US-ASCII chars are in the URL */
-       for (i = 0; i < dsz; i++) {
-               if (isalnum(d[i]) || ispunct(d[i]))
-                       continue;
-               warnx("%s: invalid URI", p->fn);
-               return 0;
-       }
-
-
-       if ((p->res->notify = strndup((const char *)d, dsz)) == NULL)
-               err(1, NULL);
 
        return 1;
 }
@@ -177,40 +164,29 @@ sbgp_sia_resource_notify(struct parse *p
  * Returns zero on failure, non-zero on success.
  */
 static int
-sbgp_sia_resource_mft(struct parse *p,
-       const unsigned char *d, size_t dsz)
+sbgp_sia_resource_mft(struct parse *p, const char *d, size_t dsz)
 {
-       size_t i;
-
        if (p->res->mft != NULL) {
                warnx("%s: RFC 6487 section 4.8.8: SIA: "
                    "MFT location already specified", p->fn);
                return 0;
        }
 
-       /* Make sure it's an MFT rsync address. */
-       if (dsz <= 8 || strncasecmp(d, "rsync://", 8)) {
-               warnx("%s: RFC 6487 section 4.8.8: not using rsync schema",
-                   p->fn);
-               return 0;
-       }
-
        if (strcasecmp(d + dsz - 4, ".mft") != 0) {
                warnx("%s: RFC 6487 section 4.8.8: SIA: "
-                   "invalid rsync URI suffix", p->fn);
-               return 0;
-       }
-       /* make sure only US-ASCII chars are in the URL */
-       for (i = 0; i < dsz; i++) {
-               if (isalnum(d[i]) || ispunct(d[i]))
-                       continue;
-               warnx("%s: invalid URI", p->fn);
+                   "not an MFT file", p->fn);
                return 0;
        }
 
-       if ((p->res->mft = strndup((const char *)d, dsz)) == NULL)
+       if ((p->res->mft = strndup(d, dsz)) == NULL)
                err(1, NULL);
 
+       /* Make sure it's an MFT rsync address. */
+       if (!valid_uri(p->res->mft, "rsync://")) {
+               warnx("%s: RFC 6487 section 4.8.8: bad MFT location", p->fn);
+               return 0;
+       }
+
        return 1;
 }
 
@@ -219,35 +195,24 @@ sbgp_sia_resource_mft(struct parse *p,
  * Returns zero on failure, non-zero on success.
  */
 static int
-sbgp_sia_resource_carepo(struct parse *p,
-       const unsigned char *d, size_t dsz)
+sbgp_sia_resource_carepo(struct parse *p, const char *d, size_t dsz)
 {
-       size_t i;
-
        if (p->res->repo != NULL) {
                warnx("%s: RFC 6487 section 4.8.8: SIA: "
                    "CA repository already specified", p->fn);
                return 0;
        }
 
+       if ((p->res->repo = strndup(d, dsz)) == NULL)
+               err(1, NULL);
+
        /* Make sure it's an rsync:// address. */
-       if (dsz <= 8 || strncasecmp(d, "rsync://", 8)) {
-               warnx("%s: RFC 6487 section 4.8.8: not using rsync schema",
+       if (!valid_uri(p->res->repo, "rsync://")) {
+               warnx("%s: RFC 6487 section 4.8.8: bad CA repository URI",
                    p->fn);
                return 0;
        }
 
-       /* make sure only US-ASCII chars are in the URL */
-       for (i = 0; i < dsz; i++) {
-               if (isalnum(d[i]) || ispunct(d[i]))
-                       continue;
-               warnx("%s: invalid URI", p->fn);
-               return 0;
-       }
-
-       if ((p->res->repo = strndup((const char *)d, dsz)) == NULL)
-               err(1, NULL);
-
        return 1;
 }
 
@@ -1175,7 +1140,6 @@ out:
 struct cert *
 cert_parse(X509 **xp, const char *fn)
 {
-
        return cert_parse_inner(xp, fn, 0);
 }
 
Index: extern.h
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.50
diff -u -p -r1.50 extern.h
--- extern.h    4 Mar 2021 13:01:41 -0000       1.50
+++ extern.h    5 Mar 2021 12:36:51 -0000
@@ -354,6 +354,7 @@ int          valid_ta(const char *, struct auth
 int             valid_cert(const char *, struct auth_tree *,
                    const struct cert *);
 int             valid_roa(const char *, struct auth_tree *, struct roa *);
+int             valid_uri(const char *, const char *);
 
 /* Working with CMS files. */
 
Index: tal.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/tal.c,v
retrieving revision 1.27
diff -u -p -r1.27 tal.c
--- tal.c       19 Feb 2021 10:23:50 -0000      1.27
+++ tal.c       5 Mar 2021 12:34:54 -0000
@@ -82,7 +82,6 @@ tal_parse_buffer(const char *fn, char *b
        char            *nl, *line, *f, *file = NULL;
        unsigned char   *der;
        size_t           sz, dersz;
-       ssize_t          i;
        int              rc = 0;
        struct tal      *tal = NULL;
        EVP_PKEY        *pkey = NULL;
@@ -103,9 +102,7 @@ tal_parse_buffer(const char *fn, char *b
                        break;
 
                /* make sure only US-ASCII chars are in the URL */
-               for (i = 0; i < nl - line; i++) {
-                       if (isalnum(line[i]) || ispunct(line[i]))
-                               continue;
+               if (!valid_uri(line, NULL)) {
                        warnx("%s: invalid URI", fn);
                        goto out;
                }
Index: validate.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/validate.c,v
retrieving revision 1.11
diff -u -p -r1.11 validate.c
--- validate.c  12 Sep 2020 15:46:48 -0000      1.11
+++ validate.c  5 Mar 2021 12:36:40 -0000
@@ -19,7 +19,9 @@
 
 #include <arpa/inet.h>
 #include <assert.h>
+#include <ctype.h>
 #include <err.h>
+#include <fcntl.h>
 #include <inttypes.h>
 #include <stdarg.h>
 #include <stdlib.h>
@@ -235,6 +237,40 @@ valid_roa(const char *fn, struct auth_tr
                warnx("%s: RFC 6482: uncovered IP: "
                    "%s", fn, buf);
                tracewarn(a);
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * Validate a URI to make sure it is pure ASCII and does not point backwards
+ * or doing some other silly tricks. To enforce the protocol pass either
+ * https:// or rsync:// as proto, if NULL is passed no protocol is enforced.
+ * Returns 1 if valid, 0 otherwise.
+ */
+int
+valid_uri(const char *uri, const char *proto)
+{
+       const unsigned char *u;
+
+       for (u = uri; *u != '\0'; u++)
+               if (!isalnum(*u) && !ispunct(*u)) {
+                       warnx("URI: non-ascii %s", uri);
+                       return 0;
+               }
+
+       if (proto) {
+               size_t plen = strlen(proto);
+               if (strncasecmp(uri, proto, plen) != 0) {
+                       warnx("URI: not proto %s: %s", proto, uri);
+                       return 0;
+               }
+       }
+
+       /* do not allow files or directories to start with a . */
+       if (strstr(uri, "/.") != NULL) {
+               warnx("URI: dot-file %s", uri);
                return 0;
        }
 

Reply via email to