-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.
#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
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;;
+}
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_ */
#include "config.h"
#include "file.h"
#include "log.h"
+#include "crypto/base64.h"
#include "rtr/db/vrp.h"
char addr_buf[INET6_ADDRSTRLEN];
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
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);
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 */
#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"
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)
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)++;
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",
#include <stdlib.h>
#include "crypto/base64.c"
+#include "algorithm.c"
#include "common.c"
#include "file.c"
#include "impersonator.c"
#include <unistd.h>
#include <sys/queue.h>
+#include "algorithm.c"
#include "common.c"
#include "file.c"
#include "impersonator.c"