]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Fix some BGPsec issues and complete output printing.
authorpcarana <pc.moreno2099@gmail.com>
Tue, 23 Jul 2019 22:28:10 +0000 (17:28 -0500)
committerpcarana <pc.moreno2099@gmail.com>
Tue, 23 Jul 2019 22:28:10 +0000 (17:28 -0500)
-The SLURM BGPsec arrays were loading only 1 element, and the AS wasn't set when filtering router keys (programmer errors ¬¬).
-Validate SLURM routerPublicKey as a SubjectPublicKeyInfo struct, including the expected algorithms for BGPsec certificates.
-Print router key info as base64url encoded strings, and update headers.

src/crypto/base64.c
src/crypto/base64.h
src/output_printer.c
src/slurm/slurm_db.c
src/slurm/slurm_parser.c
test/rtr/db/vrps_test.c
test/rtr/pdu_handler_test.c

index 6f8394b2d286e40324c5e924a667c9bedf802419..3366e72b15f507de4bd7a9a549d19922ec3ff810 100644 (file)
@@ -2,8 +2,10 @@
 
 #include <openssl/err.h>
 #include <openssl/evp.h>
+#include <openssl/buffer.h>
 #include <errno.h>
 #include <string.h>
+#include "log.h"
 
 /**
  * Converts error from libcrypto representation to this project's
@@ -198,3 +200,79 @@ free_copy:
        free(str_copy);
        return error;
 }
+
+static int
+to_base64url(char *base, size_t base_len, char **out)
+{
+       char *pad, *tmp;
+       size_t len;
+       int i;
+
+       /* Remove padding, if present */
+       len = base_len;
+       do {
+               pad = strchr(base, '=');
+               if (pad == NULL)
+                       break;
+               len = pad - base;
+       } while(0);
+
+       tmp = malloc(len + 1);
+       if (tmp == NULL)
+               return pr_enomem();
+
+       memcpy(tmp, base, len);
+       tmp[len] = '\0';
+
+       for (i = 0; i < len; i++) {
+               if (tmp[i] == '+')
+                       tmp[i] = '-';
+               else if (tmp[i] == '/')
+                       tmp[i] = '_';
+       }
+
+       *out = tmp;
+       return 0;
+}
+
+/*
+ * Encode @in (with size @in_len) as base64url without trailing pad, and
+ * allocate at @result.
+ */
+int
+base64url_encode(unsigned char const *in, int in_len, char **result)
+{
+       BIO *b64, *mem;
+       BUF_MEM *mem_buf;
+       int error;
+
+       ERR_clear_error();
+
+       mem = BIO_new(BIO_s_mem());
+       if (mem == NULL) {
+               error = ERR_peek_last_error();
+               return error ? error_ul2i(error) : -ENOMEM;
+       }
+
+       b64 = BIO_new(BIO_f_base64());
+       if (b64 == NULL) {
+               error = ERR_peek_last_error();
+               goto free_mem;
+       }
+       mem = BIO_push(b64, mem);
+       BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+
+       BIO_write(b64, in, in_len);
+       BIO_flush(b64);
+       BIO_get_mem_ptr(mem, &mem_buf);
+
+       error = to_base64url(mem_buf->data, mem_buf->length, result);
+       if (error)
+               goto free_mem;
+
+       BIO_free_all(b64);
+       return 0;
+free_mem:
+       BIO_free_all(b64);
+       return error ? error_ul2i(error) : -ENOMEM;;
+}
index a3d83ddd044c0e6bbf667dd54a7865f32cd6fa59..a545b0f930c73c6461d4aced5beaf508ef2b5263 100644 (file)
@@ -8,4 +8,6 @@
 int base64_decode(BIO *, unsigned char *, bool, size_t, size_t *);
 int base64url_decode(char const *, unsigned char **, size_t *);
 
+int base64url_encode(unsigned char const *, int, char **);
+
 #endif /* SRC_BASE64_H_ */
index a73319d551370dcdfecb083ac6e86a1feefc4efd..37a44909a114acba45e6473dec7715c7db49c886 100644 (file)
@@ -6,6 +6,7 @@
 #include "config.h"
 #include "file.h"
 #include "log.h"
+#include "crypto/base64.h"
 #include "rtr/db/vrp.h"
 
 char addr_buf[INET6_ADDRSTRLEN];
@@ -74,51 +75,28 @@ print_roa(struct vrp const *vrp, void *arg)
        return 0;
 }
 
-static int
-print_to_hex(unsigned char const *data, size_t len, char **out)
-{
-       char *tmp;
-       char *init;
-       int i;
-
-       tmp = malloc(len * 3 + 1);
-       if (tmp == NULL)
-               return pr_enomem();
-
-       init = tmp;
-       for (i = 0; i < len * 3; i+=3) {
-               *tmp = ':';
-               tmp++;
-               tmp += sprintf(tmp, "%02X", data[i/3]);
-       }
-       *tmp = '\0';
-
-       *out = init;
-       return 0;
-}
-
-/*
- * FIXME Improve this calls, maybe base64 encode and print?
- */
+/* Print as base64url strings without trailing pad */
 static int
 print_router_key(struct router_key const *key, void *arg)
 {
        FILE *out = arg;
-       char *buf1;
-       char *buf2;
+       char *buf1, *buf2;
        int error;
 
-       error = print_to_hex(key->ski, RK_SKI_LEN, &buf1);
+       error = base64url_encode(key->ski, RK_SKI_LEN, &buf1);
        if (error)
                return error;
-       error = print_to_hex(key->spk, RK_SPKI_LEN, &buf2);
+
+       error = base64url_encode(key->spk, RK_SPKI_LEN, &buf2);
        if (error)
-               return error;
+               goto free1;
+
        fprintf(out, "AS%u,%s,%s\n", key->as, buf1, buf2);
-       free(buf1);
-       free(buf2);
 
-       return 0;
+       free(buf2);
+free1:
+       free(buf1);
+       return error;
 }
 
 static int
@@ -169,7 +147,7 @@ print_router_keys(struct db_table *db)
        if (error)
                return;
 
-       fprintf(out, "ASN,SKI,SPK\n");
+       fprintf(out, "ASN,Subject Key Identifier,Subject Public Key Info\n");
        error = db_table_foreach_router_key(db, print_router_key, out);
        if (fopen)
                file_close(out);
index 55410d6f6b66766ac90e28228220aa58a9a88704..5f683be9748fdcc62236e4928bfa2717c83038f5 100644 (file)
@@ -202,6 +202,7 @@ slurm_db_bgpsec_is_filtered(struct router_key const *key)
                return false;
        }
        slurm_bgpsec.data_flag = SLURM_COM_FLAG_ASN | SLURM_BGPS_FLAG_SKI;
+       slurm_bgpsec.asn = key->as;
        memcpy(tmp, key->ski, RK_SKI_LEN);
        slurm_bgpsec.ski = tmp;
        /* Router public key isn't used at filters */
index ab19bb65c82d026872bb08403e618848fc66c997..a432de2788d247bbfbaf9747fffa0fae4fd526e5 100644 (file)
@@ -4,10 +4,12 @@
 #include <stdint.h>
 #include <string.h>
 #include <openssl/evp.h>
+#include <openssl/x509.h>
 #include <sys/types.h> /* AF_INET, AF_INET6 (needed in OpenBSD) */
 #include <sys/socket.h> /* AF_INET, AF_INET6 (needed in OpenBSD) */
 
 #include "crypto/base64.h"
+#include "algorithm.h"
 #include "log.h"
 #include "address.h"
 #include "json_parser.h"
@@ -264,6 +266,36 @@ set_ski(json_t *object, bool is_assertion, struct slurm_bgpsec *result,
        return 0;
 }
 
+/*
+ * Use the provided X509_PUBKEY struct, and validate expected algorithms for a
+ * BGPsec certificate.
+ */
+static int
+validate_router_spki(unsigned char *data, size_t len)
+{
+       unsigned char const *tmp;
+       X509_PUBKEY *spki;
+       X509_ALGOR *pa;
+       ASN1_OBJECT *alg;
+       int ok;
+       int error;
+
+       tmp = data;
+       spki = d2i_X509_PUBKEY(NULL, &tmp, len);
+       if (spki == NULL)
+               return crypto_err("Not a valid router public key");
+
+       ok = X509_PUBKEY_get0_param(&alg, NULL, NULL, &pa, spki);
+       if (!ok) {
+               X509_PUBKEY_free(spki);
+               return crypto_err("X509_PUBKEY_get0_param() returned %d", ok);
+       }
+
+       error = validate_certificate_public_key_algorithm(pa, true);
+       X509_PUBKEY_free(spki);
+       return error; /* Error 0 is ok */
+}
+
 static int
 set_router_pub_key(json_t *object, bool is_assertion,
     struct slurm_bgpsec *result, size_t *members_loaded)
@@ -297,20 +329,15 @@ set_router_pub_key(json_t *object, bool is_assertion,
                return pr_err("'%s' couldn't be decoded", str_encoded);
 
        /*
-        * TODO (next iteration) Reuse the functions to validate that
-        * 'routerPublicKey' is: "the equivalent to the subjectPublicKeyInfo
-        * value of the router certificate's public key, as described in
-        * [RFC8208]. This is the full ASN.1 DER encoding of the
+        * Validate that "is the full ASN.1 DER encoding of the
         * subjectPublicKeyInfo, including the ASN.1 tag and length values
-        * of the subjectPublicKeyInfo SEQUENCE.
-        *
-        * #include <asn1/asn1c/SubjectPublicKeyInfo.h>
-        * #include "asn1/decode.h"
-        * struct SubjectPublicKeyInfo *router_pki;
-        * error = asn1_decode(result->router_public_key,
-        *     result->router_public_key_len, &asn_DEF_SubjectPublicKeyInfo,
-        *     (void **) &router_pki);
+        * of the subjectPublicKeyInfo SEQUENCE." (RFC 8416 section 3.4.2)
         */
+       error = validate_router_spki(result->router_public_key, spk_len);
+       if (error) {
+               free(result->router_public_key);
+               return error;
+       }
 
        result->data_flag = result->data_flag | SLURM_BGPS_FLAG_ROUTER_KEY;
        (*members_loaded)++;
@@ -554,7 +581,7 @@ load_bgpsec_array(json_t *array, bool is_assertion)
        json_array_foreach(array, index, element) {
                error = load_single_bgpsec(element, is_assertion);
                if (!error)
-                       break;
+                       continue;
                if (error == -EEXIST)
                        pr_err(
                            "The bgpsec %s element #%d, is duplicated or covered by another %s; SLURM loading will be stopped",
index 39a17766612e711a825e50db91c7b6fbd18bf564..b3c9c621c2d71d95b4d966a7825a901275f9cee0 100644 (file)
@@ -3,6 +3,7 @@
 #include <stdlib.h>
 
 #include "crypto/base64.c"
+#include "algorithm.c"
 #include "common.c"
 #include "file.c"
 #include "impersonator.c"
index d1424bc95cc0d83d105f300403e0bec2f8ceb7cd..da04f9bd71af25c0587847f1da32d9f942187e0d 100644 (file)
@@ -3,6 +3,7 @@
 #include <unistd.h>
 #include <sys/queue.h>
 
+#include "algorithm.c"
 #include "common.c"
 #include "file.c"
 #include "impersonator.c"