]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Support RFC8630, TALs can have comments and HTTPS URIs.
authorpcarana <pc.moreno2099@gmail.com>
Wed, 13 Nov 2019 23:47:58 +0000 (17:47 -0600)
committerpcarana <pc.moreno2099@gmail.com>
Wed, 13 Nov 2019 23:47:58 +0000 (17:47 -0600)
-Remove all references to RFC 7730 (docs and source comments), now obsolete.
-Indicate full RFC 8630 compliance at docs.
-Implement full validation of AIA (RFC 6487 section 4.8.7), since HTTPS URIs loaded from a TAL can cause the current validation to fail.
-The AIA validation function is now exposed, so that CAs and EEs can do it when the current certificate is being validated (and already loaded at heap).
-Allow to create uris that start with 'https://', let uri.c ready to validate https and/or rsync uris.
-Parse comments and https URIs from a tal file, comments are ignored. Whenever and https URI is found and utilized, the file is downloaded using the previously commited HTTP module.

14 files changed:
docs/intro-fort.md
docs/usage.md
man/fort.8
src/asn1/signed_data.c
src/cert_stack.c
src/certificate_refs.c
src/config.c
src/line_file.c
src/object/certificate.c
src/object/certificate.h
src/object/tal.c
src/object/tal.h
src/uri.c
src/uri.h

index 34794c823c1ae31afa0a1d5ccba5a2d4f89dfbfd..b68dfb790f36434ff9dd245d758e5b209e744afe 100644 (file)
@@ -29,7 +29,6 @@ Further information can be found in the subsections below.
 | [6493](https://tools.ietf.org/html/rfc6493) (Ghostbusters)                 | 100%        |
 | [6810](https://tools.ietf.org/html/rfc6810) (RTR Version 0)                | 100%        |
 | [7318](https://tools.ietf.org/html/rfc7318) (Policy Qualifiers)            | 100%        |
-| [7730](https://tools.ietf.org/html/rfc7730) (TALs)                         | 100%        |
 | [7935](https://tools.ietf.org/html/rfc7935) (RPKI algorithms)              | 100%        |
 | [8182](https://tools.ietf.org/html/rfc8182) (RRDP)                         | 0%          |
 | [8209](https://tools.ietf.org/html/rfc8209) (BGPSec Certificates)          | 100%        |
@@ -37,7 +36,7 @@ Further information can be found in the subsections below.
 | [8360](https://tools.ietf.org/html/rfc8360) (Validation Reconsidered)      | 100%        |
 | [8416](https://tools.ietf.org/html/rfc8416) (SLURM)                        | 100%        |
 | [8608](https://tools.ietf.org/html/rfc8608) (BGPsec algorithms)            | 100%        |
-| [8630](https://tools.ietf.org/html/rfc8630) (TALs with HTTPS URIs)         | 0%          |
+| [8630](https://tools.ietf.org/html/rfc8630) (TALs with HTTPS URIs)         | 100%        |
 
 ### RFC 6350 (vCard)
 
@@ -57,10 +56,6 @@ These constitute the approximate missing 25%.
 
 RRDP is a protocol intended to replace RSYNC in the RPKI. Fort only implements RSYNC, currently.
 
-### RFC 8630 (TALs with HTTPS URIs)
-
-This RFC is relatively new (published in August 2019) and obsoletes the currently implemented [RFC 7730](https://tools.ietf.org/html/rfc7730).
-
 ## TO-DO
 
 - Reach 100% RFC compliance
index be7872eb923feb2c530412e75282445befc3e9b6..1ef9f44ac7e49c1e5ba463b7d10bd25b9b7e86da 100644 (file)
@@ -165,7 +165,7 @@ Whichever registry serves as root of the tree you want to validate is responsibl
 
 If you are paranoid, however, you'd be advised to get your own TALs.
 
-The TAL file format has been standardized in [RFC 7730](https://tools.ietf.org/html/rfc7730). It is a text file that contains a list of URLs (which serve as alternate access methods for the TA), followed by a blank line, followed by the Base64-encoded public key of the TA.
+The TAL file format has been standardized in [RFC 8630](https://tools.ietf.org/html/rfc8630). It is a text file that contains zero or more comments (each comment must start with the character "#" and end with a line break), a list of URLs (which serve as alternate access methods for the TA), followed by a blank line, followed by the Base64-encoded public key of the TA.
 
 Just for completeness sake, here's an example on what a typical TAL looks like:
 
index ee4cc2ca42266531d8288f393e40ee967e38c68e..143ecfb73c5ca1ebeb0119b3d9dd176bb7a513d7 100644 (file)
@@ -174,7 +174,7 @@ utilized by fort as TAL.
 .P
 The TAL ("Trust Anchor Locator") is a text file that lists a few URLs which can
 be used to access the "Trust Anchor" (the root of a particular RPKI tree) and
-its public key. (See RFC 7730.)
+its public key. (See RFC 8630.)
 .RE
 .P
 
index b40eb31ec6463440178dbe885516ecf16c6c6142..1305d9500db79500cf03ccdcc7bbcdb95d8bb607 100644 (file)
@@ -100,6 +100,9 @@ handle_sdata_certificate(ANY_t *cert_encoded, struct signed_object_args *args,
                goto end2;
        error = certificate_validate_extensions_ee(cert, sid, &args->refs,
            &policy);
+       if (error)
+               goto end2;
+       error = certificate_validate_aia(args->refs.caIssuers, cert);
        if (error)
                goto end2;
        error = certificate_validate_signature(cert, signedData, signature);
index a532d7f22a10abcd08205a7dcc803b3b78ba0163..deea8acf92ffc608e784cead2bc1e87556f8c008 100644 (file)
@@ -291,9 +291,9 @@ x509stack_push(struct cert_stack *stack, struct rpki_uri *uri, X509 *x509,
                goto end5;
 
        /*
-        * rfc7730#section-2.2
-        * "The INR extension(s) of this trust anchor MUST contain a non-empty
-        * set of number resources."
+        * rfc8630#section-2.3
+        * "The INR extension(s) of this TA MUST contain a non-empty set of
+        * number resources."
         * The "It MUST NOT use the "inherit" form of the INR extension(s)"
         * part is already handled in certificate_get_resources().
         */
index ed8e7826058a12fd700450743849dec34b4fcb22..134d0d92356df5d19ceafe7a7fb33d8692decdde 100644 (file)
@@ -40,31 +40,6 @@ validate_cdp(struct certificate_refs *refs, struct rpp const *pp)
        return 0;
 }
 
-static int
-validate_aia(struct certificate_refs *refs)
-{
-       struct validation *state;
-       struct rpki_uri *parent;
-
-       if (refs->caIssuers == NULL)
-               pr_crit("Certificate's AIA was not recorded.");
-
-       state = state_retrieve();
-       if (state == NULL)
-               return -EINVAL;
-       parent = x509stack_peek_uri(validation_certstack(state));
-       if (parent == NULL)
-               pr_crit("CA certificate has no parent.");
-
-       if (!uri_equals(refs->caIssuers, parent)) {
-               return pr_err("Certificate's AIA ('%s') does not match parent's URI ('%s').",
-                   uri_get_printable(refs->caIssuers),
-                   uri_get_printable(parent));
-       }
-
-       return 0;
-}
-
 static int
 validate_signedObject(struct certificate_refs *refs,
     struct rpki_uri *signedObject_uri)
@@ -100,10 +75,6 @@ refs_validate_ca(struct certificate_refs *refs, struct rpp const *pp)
        if (error)
                return error;
 
-       error = validate_aia(refs);
-       if (error)
-               return error;
-
        if (refs->signedObject != NULL)
                pr_crit("CA summary has a signedObject ('%s').",
                    uri_get_printable(refs->signedObject));
@@ -129,9 +100,5 @@ refs_validate_ee(struct certificate_refs *refs, struct rpp const *pp,
        if (error)
                return error;
 
-       error = validate_aia(refs);
-       if (error)
-               return error;
-
        return validate_signedObject(refs, uri);
 }
index 2f9668992ed3aa3fb7b279f0a650e44ebbefecd2..9b236e93f89b572cef648d7600f4f505e85a0e70 100644 (file)
@@ -38,7 +38,7 @@ struct rpki_config {
        enum sync_strategy sync_strategy;
        /**
         * Handle TAL URIs in random order?
-        * (https://tools.ietf.org/html/rfc7730#section-3, last
+        * (https://tools.ietf.org/html/rfc8630#section-3, last
         * paragraphs)
         */
        bool shuffle_tal_uris;
index a0f6b68a6d2783f07ab3a6f88307da49cd874b37..c6563e67544129a2126c49c2689dc2c11497365f 100644 (file)
@@ -81,7 +81,7 @@ lfile_read(struct line_file *lfile, char **result)
         * - The string WILL be NULL-terminated, but the NULL chara will not be
         *   included in the returned length. BUT IT'S THERE. Don't worry about
         *   writing past the allocated space on the last line.
-        * - Newline is `\n` according to POSIX, which is good, because RFC 7730
+        * - Newline is `\n` according to POSIX, which is good, because RFC 8630
         *   agrees. You will have to worry about `\r`, though.
         *
         * Also, the Linux man page claims the following:
index c1dff1e3d7c9ad663a49abe87ff60b8e99793512..7a31d3b6342c288e80adecc5966ada74bc3c7c2a 100644 (file)
@@ -216,7 +216,7 @@ check_dup_public_key(bool *duplicated, char const *file, void *arg)
                return error;
 
        /* Check if it's '.cer', otherwise treat as a signed object */
-       if (uri_has_extension(uri, ".cer")) {
+       if (uri_is_certificate(uri)) {
                error = certificate_load(uri, &rcvd_cert);
                if (error)
                        goto free_uri;
@@ -327,7 +327,7 @@ validate_spki(X509_PUBKEY *cert_spki)
        /*
         * We have a problem at this point:
         *
-        * RFC 7730 says "The public key used to verify the trust anchor MUST be
+        * RFC 8630 says "The public key used to verify the trust anchor MUST be
         * the same as the subjectPublicKeyInfo in the CA certificate and in the
         * TAL."
         *
@@ -515,7 +515,7 @@ certificate_validate_rfc6487(X509 *cert, enum cert_type type)
        /* libcrypto already does this. */
 
        /* rfc6487#section-4.7 */
-       /* Fragment of rfc7730#section-2.2 */
+       /* Fragment of rfc8630#section-2.3 */
        error = validate_public_key(cert, type);
        if (error)
                return error;
@@ -1723,6 +1723,109 @@ get_certificate_type(X509 *cert, bool is_ta)
        return EE;
 }
 
+/*
+ * It does some of the things from validate_issuer(), but we can not wait for
+ * such validation, since at this point the RSYNC URI at AIA extension must be
+ * verified to comply with rfc6487#section-4.8.7
+ */
+static int
+force_aia_validation(struct rpki_uri *caIssuers, void *arg)
+{
+       X509 *son = arg;
+       X509 *parent;
+       struct rfc5280_name *son_name;
+       struct rfc5280_name *parent_name;
+       int error;
+
+       pr_debug("AIA's URI didn't matched parent URI, doing AIA RSYNC");
+
+       /* RSYNC is still the prefered access mechanism */
+       error = download_files(caIssuers, false, false);
+       if (error)
+               return error;
+
+       error = certificate_load(caIssuers, &parent);
+       if (error)
+               return error;
+
+       error = x509_name_decode(X509_get_subject_name(parent), "subject",
+           &parent_name);
+       if (error)
+               goto free_parent;
+
+       error = x509_name_decode(X509_get_issuer_name(son), "issuer",
+           &son_name);
+       if (error)
+               goto free_parent_name;
+
+       if (x509_name_equals(parent_name, son_name))
+               error = 0; /* Everything its ok */
+       else
+               error = pr_err("Certificate subject from AIA ('%s') isn't issuer of this certificate.",
+                   uri_get_printable(caIssuers));
+
+       x509_name_put(son_name);
+free_parent_name:
+       x509_name_put(parent_name);
+free_parent:
+       X509_free(parent);
+       return error;
+}
+
+int
+certificate_validate_aia(struct rpki_uri *caIssuers, X509 *cert)
+{
+       struct validation *state;
+       struct rpki_uri *parent;
+
+       if (caIssuers == NULL)
+               pr_crit("Certificate's AIA was not recorded.");
+
+       state = state_retrieve();
+       if (state == NULL)
+               return -EINVAL;
+       parent = x509stack_peek_uri(validation_certstack(state));
+       if (parent == NULL)
+               pr_crit("Certificate has no parent.");
+
+       /*
+        * There are two possible issues here, specifically at first level root
+        * certificate's childs:
+        *
+        * - Considering that the root certificate can be published at one or
+        *   more rsync or HTTPS URIs (RFC 8630), the validation is done
+        *   considering the first valid downloaded certificate URI from the
+        *   list of URIs; so, that URI doesn't necessarily matches AIA. And
+        *   this issue is more likely to happen if the 'shuffle-uris' flag
+        *   is active an a TAL has more than one rsync/HTTPS uri.
+        *
+        * - If the TAL has only one URI, and such URI is HTTPS, the root
+        *   certificate will be located at a distinct point that what it's
+        *   expected, so this might be an error if such certificate (root
+        *   certificate) isn't published at an rsync repository. See RFC 6487
+        *   section-4.8.7:
+        *
+        *   "The preferred URI access mechanisms is "rsync", and an rsync URI
+        *   [RFC5781] MUST be specified with an accessMethod value of
+        *   id-ad-caIssuers.  The URI MUST reference the point of publication
+        *   of the certificate where this Issuer is the subject (the issuer's
+        *   immediate superior certificate)."
+        *
+        * November 2019: this isn't a problem, all five RIRs are using one URI
+        * at their TALs, that matches AIA from the first level root certificate
+        * childs. Anyways, we'll try to consult the subject at IETF.
+        */
+       if (uri_equals(caIssuers, parent))
+               return 0;
+
+       /*
+        * URI didn't match, try to match the immediate superior subject with
+        * the current issuer. This will force an RSYNC of AIA's URI, load
+        * the certificate and do the comparison.
+        */
+       return force_aia_validation(caIssuers, cert);
+}
+
 /** Boilerplate code for CA certificate validation and recursive traversal. */
 int
 certificate_traverse(struct rpp *rpp_parent, struct rpki_uri *cert_uri)
@@ -1812,6 +1915,12 @@ certificate_traverse(struct rpp *rpp_parent, struct rpki_uri *cert_uri)
        if (error)
                goto revert_cert;
 
+       if (!IS_TA) {
+               error = certificate_validate_aia(refs.caIssuers, cert);
+               if (error)
+                       goto revert_uris;
+       }
+
        error = refs_validate_ca(&refs, rpp_parent);
        if (error)
                goto revert_uris;
index 758a469d5c88aa9c19b42ad95f774de8ec39cdf6..d5bad7716585b71f170fb292ab528a77e4769795 100644 (file)
@@ -53,6 +53,12 @@ int certificate_get_resources(X509 *, struct resources *, enum cert_type);
 int certificate_validate_extensions_ee(X509 *, OCTET_STRING_t *,
     struct certificate_refs *, enum rpki_policy *);
 
+/*
+ * Specific validation of AIA (rfc6487#section-4.8.7) extension, public so that
+ * CAs and EEs can access it.
+ */
+int certificate_validate_aia(struct rpki_uri *, X509 *);
+
 int certificate_traverse(struct rpp *, struct rpki_uri *);
 
 #endif /* SRC_OBJECT_CERTIFICATE_H_ */
index f35fa4891e44f6db0afd9b351e82c0fa6858f71f..69eec5bec880a8c76c70148e3d707175f4acc747 100644 (file)
@@ -22,6 +22,7 @@
 #include "thread_var.h"
 #include "validation_handler.h"
 #include "crypto/base64.h"
+#include "http/http.h"
 #include "object/certificate.h"
 #include "rsync/rsync.h"
 #include "rtr/db/vrps.h"
@@ -105,6 +106,23 @@ read_uris(struct line_file *lfile, struct uris *uris)
        if (strcmp(uri, "") == 0) {
                free(uri);
                return pr_err("There's no URI in the first line of the TAL.");
+       } else if (strncmp(uri, "#", 1) == 0) {
+               /* More comments expected, or an URI */
+               do {
+                       free(uri); /* Ignore the comment */
+                       error = lfile_read(lfile, &uri);
+                       if (error)
+                               return error;
+                       if (uri == NULL)
+                               return pr_err("TAL file ended prematurely. (Expected more comments or an URI list.)");
+                       if (strcmp(uri, "") == 0) {
+                               free(uri);
+                               return pr_err("TAL file comments syntax error. (Expected more comments or an URI list.)");
+                       }
+                       /* Not a comment, probably the URI(s) */
+                       if (strncmp(uri, "#", 1) != 0)
+                               break;
+               } while (true);
        }
 
        error = uris_add(uris, uri);
@@ -359,11 +377,10 @@ foreach_uri(struct tal *tal, foreach_uri_cb cb, void *arg)
        int error;
 
        for (i = 0; i < tal->uris.count; i++) {
-               error = uri_create_str(&uri, tal->uris.array[i],
+               error = uri_create_mixed_str(&uri, tal->uris.array[i],
                    strlen(tal->uris.array[i]));
-               if (error == ENOTRSYNC) {
-                       /* Log level should probably be INFO. */
-                       pr_debug("TAL has non-RSYNC URI; ignoring.");
+               if (error == ENOTSUPPORTED) {
+                       pr_info("TAL has non-RSYNC/HTTPS URI; ignoring.");
                        continue;
                }
                if (error)
@@ -410,6 +427,26 @@ tal_get_spki(struct tal *tal, unsigned char const **buffer, size_t *len)
        *len = tal->spki_len;
 }
 
+static size_t
+write_http_cer(unsigned char *content, size_t size, size_t nmemb, void *arg)
+{
+       FILE *fd = arg;
+       size_t read = size * nmemb;
+       size_t written;
+
+       written = fwrite(content, size, nmemb, fd);
+       if (written != nmemb)
+               return -EINVAL;
+
+       return read;
+}
+
+static int
+handle_https_uri(struct rpki_uri *uri)
+{
+       return http_download_file(uri, write_http_cer);
+}
+
 /**
  * Performs the whole validation walkthrough on uri @uri, which is assumed to
  * have been extracted from a TAL.
@@ -426,7 +463,7 @@ handle_tal_uri(struct tal *tal, struct rpki_uri *uri, void *arg)
         *
         * A "soft error" is "the connection to the preferred URI fails, or the
         * retrieved CA certificate public key does not match the TAL public
-        * key." (RFC 7730)
+        * key." (RFC 8630)
         *
         * A "hard error" is any other error.
         */
@@ -446,9 +483,13 @@ handle_tal_uri(struct tal *tal, struct rpki_uri *uri, void *arg)
        if (error)
                return ENSURE_NEGATIVE(error);
 
-       error = download_files(uri, true, false);
+       if (uri_is_rsync(uri))
+               error = download_files(uri, true, false);
+       else
+               error = handle_https_uri(uri);
+
        if (error) {
-               pr_warn("TAL '%s' could not be RSYNC'd.",
+               pr_warn("TAL '%s' could not be downloaded.",
                    uri_get_printable(uri));
                validation_destroy(state);
                return ENSURE_NEGATIVE(error);
index 12e6669ca9b1ff2827294511df044e94c90949c3..19ff0811f2208ea74bdaa205368eb11857ee43ad 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef TAL_OBJECT_H_
 #define TAL_OBJECT_H_
 
-/* This is RFC 7730. */
+/* This is RFC 8630. */
 
 #include <stddef.h>
 #include "uri.h"
index 9a5b1f5d91e03d7a388bf4981beb7cbfa9c74add..a8ffd6741e75fcf463c8eae316839bbe26bb4d6e 100644 (file)
--- a/src/uri.c
+++ b/src/uri.c
@@ -1,10 +1,20 @@
 #include "uri.h"
 
+#include <errno.h>
 #include "common.h"
 #include "config.h"
 #include "log.h"
 #include "str.h"
 
+#define URI_VALID_RSYNC 0x01
+#define URI_VALID_HTTPS 0x02
+
+/* Expected URI types */
+enum rpki_uri_type {
+       URI_RSYNC,
+       URI_HTTPS,
+};
+
 /**
  * All rpki_uris are guaranteed to be RSYNC URLs right now.
  *
@@ -24,7 +34,7 @@
 struct rpki_uri {
        /**
         * "Global URI".
-        * The one that always starts with "rsync://".
+        * The one that always starts with "rsync://" or "https://".
         *
         * These things are IA5-encoded, which means you're not bound to get
         * non-ASCII characters.
@@ -53,6 +63,9 @@ struct rpki_uri {
        char *local;
        /* "local_len" is never needed right now. */
 
+       /* Type, currently rysnc and https are valid */
+       enum rpki_uri_type type;
+
        unsigned int references;
 };
 
@@ -178,6 +191,63 @@ succeed:
        return 0;
 }
 
+static int
+validate_uri_begin(char const *uri_pfx, const size_t uri_pfx_len,
+    char const *global, size_t global_len, size_t *size, int error)
+{
+       if (global_len < uri_pfx_len
+           || strncmp(uri_pfx, global, uri_pfx_len) != 0) {
+               if (!error)
+                       return -EINVAL;
+               pr_err("Global URI '%s' does not begin with '%s'.",
+                   global, uri_pfx);
+               return error;
+       }
+
+       (*size) = uri_pfx_len;
+       return 0;
+}
+
+static int
+validate_gprefix(char const *global, size_t global_len, uint8_t flags,
+    size_t *size, enum rpki_uri_type *type)
+{
+       static char const *const PFX_RSYNC = "rsync://";
+       static char const *const PFX_HTTPS = "https://";
+       size_t const PFX_RSYNC_LEN = strlen(PFX_RSYNC);
+       size_t const PFX_HTTPS_LEN = strlen(PFX_HTTPS);
+       int error;
+
+       if (flags == URI_VALID_RSYNC) {
+               (*type) = URI_RSYNC;
+               return validate_uri_begin(PFX_RSYNC, PFX_RSYNC_LEN, global,
+                   global_len, size, ENOTRSYNC);
+       }
+       if (flags == URI_VALID_HTTPS) {
+               (*type) = URI_HTTPS;
+               return validate_uri_begin(PFX_HTTPS, PFX_HTTPS_LEN, global,
+                   global_len, size, ENOTHTTPS);
+       }
+       if (flags != (URI_VALID_RSYNC & URI_VALID_HTTPS))
+               pr_crit("Unknown URI flag");
+
+       /* It has both flags */
+       error = validate_uri_begin(PFX_RSYNC, PFX_RSYNC_LEN, global, global_len,
+           size, 0);
+       if (!error) {
+               (*type) = URI_RSYNC;
+               return 0;
+       }
+       error = validate_uri_begin(PFX_HTTPS, PFX_HTTPS_LEN, global, global_len,
+           size, 0);
+       if (error)
+               return ENOTSUPPORTED;
+
+       /* @size was already set */
+       (*type) = URI_HTTPS;
+       return 0;
+}
+
 /**
  * Initializes @uri->local by converting @uri->global.
  *
@@ -185,30 +255,28 @@ succeed:
  * "rsync://rpki.ripe.net/repo/manifest.mft", initializes @uri->local as
  * "/tmp/rpki/rpki.ripe.net/repo/manifest.mft".
  *
- * By contract, if @guri is not RSYNC, this will return ENOTRSYNC.
+ * By contract, if @guri is not RSYNC nor HTTPS, this will return ENOTRSYNC.
  * This often should not be treated as an error; please handle gracefully.
  */
 static int
-g2l(char const *global, size_t global_len, char **result)
+g2l(char const *global, size_t global_len, uint8_t flags, char **result,
+    enum rpki_uri_type *result_type)
 {
-       static char const *const PREFIX = "rsync://";
        char const *repository;
        char *local;
        size_t prefix_len;
        size_t repository_len;
        size_t extra_slash;
        size_t offset;
+       enum rpki_uri_type type;
+       int error;
 
        repository = config_get_local_repository();
        repository_len = strlen(repository);
-       prefix_len = strlen(PREFIX);
 
-       if (global_len < prefix_len
-           || strncmp(PREFIX, global, prefix_len) != 0) {
-               pr_err("Global URI '%s' does not begin with '%s'.",
-                   global, PREFIX);
-               return ENOTRSYNC; /* Not an error, so not negative */
-       }
+       error = validate_gprefix(global, global_len, flags, &prefix_len, &type);
+       if (error)
+               return error;
 
        global += prefix_len;
        global_len -= prefix_len;
@@ -228,17 +296,20 @@ g2l(char const *global, size_t global_len, char **result)
        local[offset] = '\0';
 
        *result = local;
+       (*result_type) = type;
        return 0;
 }
 
 static int
-autocomplete_local(struct rpki_uri *uri)
+autocomplete_local(struct rpki_uri *uri, uint8_t flags)
 {
-       return g2l(uri->global, uri->global_len, &uri->local);
+       return g2l(uri->global, uri->global_len, flags, &uri->local,
+           &uri->type);
 }
 
-int
-uri_create(struct rpki_uri **result, void const *guri, size_t guri_len)
+static int
+uri_create(struct rpki_uri **result, uint8_t flags, void const *guri,
+    size_t guri_len)
 {
        struct rpki_uri *uri;
        int error;
@@ -253,7 +324,7 @@ uri_create(struct rpki_uri **result, void const *guri, size_t guri_len)
                return error;
        }
 
-       error = autocomplete_local(uri);
+       error = autocomplete_local(uri, flags);
        if (error) {
                free(uri->global);
                free(uri);
@@ -268,7 +339,15 @@ uri_create(struct rpki_uri **result, void const *guri, size_t guri_len)
 int
 uri_create_str(struct rpki_uri **uri, char const *guri, size_t guri_len)
 {
-       return uri_create(uri, guri, guri_len);
+       return uri_create(uri, URI_VALID_RSYNC, guri, guri_len);
+}
+
+/* A URI that can be rsync or https */
+int
+uri_create_mixed_str(struct rpki_uri **uri, char const *guri, size_t guri_len)
+{
+       return uri_create(uri, URI_VALID_RSYNC & URI_VALID_HTTPS, guri,
+           guri_len);
 }
 
 /*
@@ -290,7 +369,7 @@ uri_create_mft(struct rpki_uri **result, struct rpki_uri *mft, IA5String_t *ia5)
                return error;
        }
 
-       error = autocomplete_local(uri);
+       error = autocomplete_local(uri, URI_VALID_RSYNC);
        if (error) {
                free(uri->global);
                free(uri);
@@ -345,7 +424,8 @@ uri_create_ad(struct rpki_uri **uri, ACCESS_DESCRIPTION *ad)
         * directory our g2l version of @asn1_string should contain.
         * But ask the testers to keep an eye on it anyway.
         */
-       return uri_create(uri, ASN1_STRING_get0_data(asn1_string),
+       return uri_create(uri, URI_VALID_RSYNC,
+           ASN1_STRING_get0_data(asn1_string),
            ASN1_STRING_length(asn1_string));
 }
 
@@ -411,6 +491,12 @@ uri_is_certificate(struct rpki_uri *uri)
        return uri_has_extension(uri, ".cer");
 }
 
+bool
+uri_is_rsync(struct rpki_uri *uri)
+{
+       return uri->type == URI_RSYNC;
+}
+
 static char const *
 get_filename(char const *file_path)
 {
index a6e6bdba4254dcd44f0c7eef618f378a842f8b7e..d5434180e24dffc8357e6c8464c3a5dac01a1bd5 100644 (file)
--- a/src/uri.h
+++ b/src/uri.h
@@ -7,8 +7,8 @@
 
 struct rpki_uri;
 
-int uri_create(struct rpki_uri **, void const *, size_t);
 int uri_create_str(struct rpki_uri **, char const *, size_t);
+int uri_create_mixed_str(struct rpki_uri **, char const *, size_t);
 int uri_create_mft(struct rpki_uri **, struct rpki_uri *, IA5String_t *);
 int uri_create_ad(struct rpki_uri **, ACCESS_DESCRIPTION *);
 
@@ -26,6 +26,8 @@ size_t uri_get_global_len(struct rpki_uri *);
 bool uri_equals(struct rpki_uri *, struct rpki_uri *);
 bool uri_has_extension(struct rpki_uri *, char const *);
 bool uri_is_certificate(struct rpki_uri *);
+bool uri_is_rsync(struct rpki_uri *);
+
 char const *uri_get_printable(struct rpki_uri *);
 
 #endif /* SRC_URI_H_ */