rpki_validator_SOURCES += file.h file.c
rpki_validator_SOURCES += line_file.h line_file.c
rpki_validator_SOURCES += log.h log.c
+rpki_validator_SOURCES += nid.h nid.c
rpki_validator_SOURCES += random.h random.c
rpki_validator_SOURCES += resource.h resource.c
rpki_validator_SOURCES += rpp.h rpp.c
#include <errno.h>
#include <arpa/inet.h> /* inet_ntop */
#include "log.h"
+#include "thread_var.h"
-static char const *
-addr2str4(struct in_addr *addr, char *buffer)
-{
- return inet_ntop(AF_INET, addr, buffer, INET_ADDRSTRLEN);
-}
-
-static char const *
-addr2str6(struct in6_addr *addr, char *buffer)
+/*
+ * Returns a mask you can use to extract the suffix bits of a 32-bit unsigned
+ * number whose prefix lengths @prefix_len.
+ * For example: Suppose that your number is 192.0.2.0/24.
+ * u32_suffix_mask(24) returns 0.0.0.255.
+ *
+ * The result is in host byte order.
+ */
+uint32_t
+u32_suffix_mask(unsigned int prefix_len)
{
- return inet_ntop(AF_INET6, addr, buffer, INET6_ADDRSTRLEN);
+ /* `a >> 32` is undefined if `a` is 32 bits. */
+ return (prefix_len < 32) ? (0xFFFFFFFFu >> prefix_len) : 0;
}
/**
- * Returns a mask you can use to extract the suffix bits of an address whose
- * prefix lengths @prefix_len.
- * For example: Suppose that your address is 192.0.2.0/24.
- * addr4_suffix_mask(24) returns 0.0.0.255.
+ * Same as u32_suffix_mask(), except the result is in network byte order
+ * ("be", for "big endian").
*/
uint32_t
-ipv4_suffix_mask(unsigned int prefix_len)
+be32_suffix_mask(unsigned int prefix_len)
{
- return htonl(0xFFFFFFFFu >> prefix_len);
+ return htonl(u32_suffix_mask(prefix_len));
}
+/**
+ * Enables all the suffix bits of @result (assuming its prefix length is
+ * @prefix_len).
+ * @result's prefix bits will not be modified.
+ */
void
ipv6_suffix_mask(unsigned int prefix_len, struct in6_addr *result)
{
if (prefix_len < 32) {
- result->s6_addr32[0] |= htonl(0xFFFFFFFFu >> prefix_len);
+ result->s6_addr32[0] |= be32_suffix_mask(prefix_len);
result->s6_addr32[1] = 0xFFFFFFFFu;
result->s6_addr32[2] = 0xFFFFFFFFu;
result->s6_addr32[3] = 0xFFFFFFFFu;
} else if (prefix_len < 64) {
- result->s6_addr32[1] |= htonl(0xFFFFFFFFu >> (prefix_len - 32));
+ result->s6_addr32[1] |= be32_suffix_mask(prefix_len - 32);
result->s6_addr32[2] = 0xFFFFFFFFu;
result->s6_addr32[3] = 0xFFFFFFFFu;
} else if (prefix_len < 96) {
- result->s6_addr32[2] |= htonl(0xFFFFFFFFu >> (prefix_len - 64));
+ result->s6_addr32[2] |= be32_suffix_mask(prefix_len - 64);
result->s6_addr32[3] = 0xFFFFFFFFu;
} else {
- result->s6_addr32[3] |= htonl(0xFFFFFFFFu >> (prefix_len - 96));
+ result->s6_addr32[3] |= be32_suffix_mask(prefix_len - 96);
}
}
+/**
+ * Translates an `IPAddress2_t` to its equivalent `struct ipv4_prefix`.
+ */
int
prefix4_decode(IPAddress2_t *str, struct ipv4_prefix *result)
{
int len;
- char buffer[INET_ADDRSTRLEN];
if (str->size > 4) {
return pr_err("IPv4 address has too many octets. (%u)",
result->len = len;
- if ((result->addr.s_addr & ipv4_suffix_mask(result->len)) != 0) {
- return pr_err("IPv4 prefix %s/%u has enabled suffix bits.",
- addr2str4(&result->addr, buffer), result->len);
+ if ((result->addr.s_addr & be32_suffix_mask(result->len)) != 0) {
+ return pr_err("IPv4 prefix '%s/%u' has enabled suffix bits.",
+ v4addr2str(&result->addr), result->len);
}
return 0;
}
+/**
+ * Translates an `IPAddress2_t` to its equivalent `struct ipv6_prefix`.
+ */
int
prefix6_decode(IPAddress2_t *str, struct ipv6_prefix *result)
{
struct in6_addr suffix;
int len;
- char buffer[INET6_ADDRSTRLEN];
if (str->size > 16) {
return pr_err("IPv6 address has too many octets. (%u)",
|| (result->addr.s6_addr32[1] & suffix.s6_addr32[1])
|| (result->addr.s6_addr32[2] & suffix.s6_addr32[2])
|| (result->addr.s6_addr32[3] & suffix.s6_addr32[3])) {
- return pr_err("IPv6 prefix %s/%u has enabled suffix bits.",
- addr2str6(&result->addr, buffer), result->len);
+ return pr_err("IPv6 prefix '%s/%u' has enabled suffix bits.",
+ v6addr2str(&result->addr), result->len);
}
return 0;
static int
check_order4(struct ipv4_range *result)
{
- char buffer_min[INET_ADDRSTRLEN];
- char buffer_max[INET_ADDRSTRLEN];
-
if (ntohl(result->min.s_addr) > ntohl(result->max.s_addr)) {
- return pr_err("The IPv4 range %s-%s is inverted.",
- addr2str4(&result->min, buffer_min),
- addr2str4(&result->max, buffer_max));
+ return pr_err("The IPv4 range '%s-%s' is inverted.",
+ v4addr2str(&result->min), v4addr2str2(&result->max));
}
return 0;
const uint32_t MIN = ntohl(range->min.s_addr);
const uint32_t MAX = ntohl(range->max.s_addr);
uint32_t mask;
- char buffer_min[INET_ADDRSTRLEN];
- char buffer_max[INET_ADDRSTRLEN];
for (mask = 0x80000000u; mask != 0; mask >>= 1)
if ((MIN & mask) != (MAX & mask))
if (((MIN & mask) != 0) || ((MAX & mask) == 0))
return 0;
- return pr_err("IPAddressRange %s-%s is a range, but should have been encoded as a prefix.",
- addr2str4(&range->min, buffer_min),
- addr2str4(&range->min, buffer_max));
+ return pr_err("IPAddressRange '%s-%s' is a range, but should have been encoded as a prefix.",
+ v4addr2str(&range->min), v4addr2str2(&range->max));
}
+/**
+ * Translates an `IPAddressRange_t` to its equivalent `struct ipv4_range`.
+ */
int
range4_decode(IPAddressRange_t *input, struct ipv4_range *result)
{
error = prefix4_decode(&input->max, &prefix);
if (error)
return error;
- result->max.s_addr = prefix.addr.s_addr | ipv4_suffix_mask(prefix.len);
+ result->max.s_addr = prefix.addr.s_addr | be32_suffix_mask(prefix.len);
error = check_order4(result);
if (error)
uint32_t min;
uint32_t max;
unsigned int quadrant;
- char buffer_min[INET6_ADDRSTRLEN];
- char buffer_max[INET6_ADDRSTRLEN];
for (quadrant = 0; quadrant < 4; quadrant++) {
min = ntohl(result->min.s6_addr32[quadrant]);
max = ntohl(result->max.s6_addr32[quadrant]);
if (min > max) {
- return pr_err("The IPv6 range %s-%s is inverted.",
- addr2str6(&result->min, buffer_min),
- addr2str6(&result->max, buffer_max));
+ return pr_err("The IPv6 range '%s-%s' is inverted.",
+ v6addr2str(&result->min),
+ v6addr2str2(&result->max));
} else if (min < max) {
return 0; /* result->min < result->max */
}
static int
pr_bad_encoding(struct ipv6_range *range)
{
- char buffer_min[INET6_ADDRSTRLEN];
- char buffer_max[INET6_ADDRSTRLEN];
return pr_err("IPAddressRange %s-%s is a range, but should have been encoded as a prefix.",
- addr2str6(&range->min, buffer_min),
- addr2str6(&range->max, buffer_max));
+ v6addr2str(&range->min), v6addr2str2(&range->max));
}
static int
-thingy(struct ipv6_range *range, unsigned int quadrant, uint32_t mask)
+__check_encoding6(struct ipv6_range *range, unsigned int quadrant,
+ uint32_t mask)
{
uint32_t min;
uint32_t max;
max = ntohl(range->max.s6_addr32[quadrant]);
for (mask = 0x80000000u; mask != 0; mask >>= 1)
if ((min & mask) != (max & mask))
- return thingy(range, quadrant, mask);
+ return __check_encoding6(range, quadrant, mask);
}
return pr_bad_encoding(range);
}
+/**
+ * Translates an `IPAddressRange_t` to its equivalent `struct ipv6_range`.
+ */
int
range6_decode(IPAddressRange_t *input, struct ipv6_range *result)
{
struct in6_addr max;
};
-uint32_t ipv4_suffix_mask(unsigned int);
+uint32_t u32_suffix_mask(unsigned int);
+uint32_t be32_suffix_mask(unsigned int);
void ipv6_suffix_mask(unsigned int, struct in6_addr *);
int prefix4_decode(IPAddress2_t *, struct ipv4_prefix *);
struct validation *state;
const unsigned char *tmp;
X509 *cert;
+ enum rpki_policy policy;
int error;
state = state_retrieve();
error = certificate_validate_rfc6487(cert, false);
if (error)
goto end2;
+ error = certificate_validate_extensions_ee(cert, sid, &args->refs,
+ &policy);
+ if (error)
+ goto end2;
if (args->res != NULL) {
+ /* TODO validate resources even if the SO lacks them */
+ resources_set_policy(args->res, policy);
error = certificate_get_resources(cert, args->res);
if (error)
goto end2;
}
- error = certificate_validate_extensions_ee(cert, sid, &args->refs);
-
end2:
X509_free(cert);
end1:
struct rpki_uri const *pp_crl;
if (refs->crldp == NULL)
- return pr_err("Programming error: Certificate's CRL Distribution Point was not recorded.");
+ return pr_crit("Certificate's CRL Distribution Point was not recorded.");
pp_crl = rpp_get_crl(pp);
if (pp_crl == NULL)
- return pr_err("Programming error: Manifest's CRL was not recorded.");
+ return pr_crit("Manifest's CRL was not recorded.");
if (strcmp(refs->crldp, pp_crl->global) != 0) {
return pr_err("Certificate's CRL Distribution Point ('%s') does not match manifest's CRL ('%s').",
struct rpki_uri const *parent;
if (refs->caIssuers == NULL)
- return pr_err("Programming error: Certificate's AIA was not recorded.");
+ return pr_crit("Certificate's AIA was not recorded.");
state = state_retrieve();
if (state == NULL)
return -EINVAL;
parent = validation_peek_cert_uri(state);
if (parent == NULL)
- return pr_err("Programming error: CA certificate has no parent.");
+ return pr_crit("CA certificate has no parent.");
if (strcmp(refs->caIssuers, parent->global) != 0) {
return pr_err("Certificate's AIA ('%s') does not match parent's URI ('%s').",
struct rpki_uri const *signedObject_uri)
{
if (refs->signedObject == NULL)
- return pr_err("Programming error: Certificate's signedObject was not recorded.");
+ return pr_crit("Certificate's signedObject was not recorded.");
if (strcmp(refs->signedObject, signedObject_uri->global) != 0) {
return pr_err("Certificate's signedObject ('%s') does not match the URI of its own signed object (%s).",
return error;
if (refs->signedObject != NULL) {
- return pr_err("Programming error: CA summary has a signedObject ('%s').",
+ return pr_crit("CA summary has a signedObject ('%s').",
refs->signedObject);
}
#include "log.h"
#include "thread_var.h"
-int NID_rpkiManifest;
-int NID_signedObject;
-int NID_rpkiNotify;
-int NID_certPolicyRpki;
-int NID_certPolicyRpkiV2;
-
/**
* Does not assume that @string is NULL-terminated.
*/
*/
#define ENOTRSYNC 3174
-extern int NID_rpkiManifest;
-extern int NID_signedObject;
-extern int NID_rpkiNotify;
-extern int NID_certPolicyRpki;
-extern int NID_certPolicyRpkiV2;
-
#define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0]))
int string_clone(void const *, size_t, char **);
#include "extension.h"
#include <errno.h>
+#include "common.h"
#include "log.h"
+#include "nid.h"
#include "thread_var.h"
#include "crypto/hash.h"
-const struct extension_metadata BC = {
- "Basic Constraints",
- NID_basic_constraints,
+static struct extension_metadata IR2 = {
+ "Amended IP Resources",
+ /* TODO NID_ipAddrBlocksv2 */ -1,
true,
};
-const struct extension_metadata SKI = {
- "Subject Key Identifier",
- NID_subject_key_identifier,
- false,
-};
-const struct extension_metadata AKI = {
- "Authority Key Identifier",
- NID_authority_key_identifier,
- false,
-};
-const struct extension_metadata KU = {
- "Key Usage",
- NID_key_usage,
- true,
-};
-const struct extension_metadata CDP = {
- "CRL Distribution Points",
- NID_crl_distribution_points,
- false,
-};
-const struct extension_metadata AIA = {
- "Authority Information Access",
- NID_info_access,
- false,
-};
-const struct extension_metadata SIA = {
- "Subject Information Access",
- NID_sinfo_access ,
- false,
-};
-const struct extension_metadata CP = {
- "Certificate Policies",
- NID_certificate_policies,
- true,
-};
-const struct extension_metadata IR = {
- "IP Resources",
- NID_sbgp_ipAddrBlock,
- true,
-};
-const struct extension_metadata AR = {
- "AS Resources",
- NID_sbgp_autonomousSysNum,
+
+static struct extension_metadata AR2 = {
+ "Amended AS Resources",
+ /* TODO NID_autonomousSysIdsv2 */ -1,
true,
};
-const struct extension_metadata CN = {
- "CRL Number",
- NID_crl_number,
- false,
-};
+
+int extension_init(void)
+{
+ IR2.nid = nid_ipAddrBlocksv2();
+ AR2.nid = nid_autonomousSysIdsv2();
+ return 0;
+}
+
+struct extension_metadata const *ext_bc(void)
+{
+ static const struct extension_metadata BC = {
+ "Basic Constraints",
+ NID_basic_constraints,
+ true,
+ };
+ return &BC;
+}
+
+struct extension_metadata const *ext_ski(void)
+{
+ static const struct extension_metadata SKI = {
+ "Subject Key Identifier",
+ NID_subject_key_identifier,
+ false,
+ };
+ return &SKI;
+}
+
+struct extension_metadata const *ext_aki(void)
+{
+ static const struct extension_metadata AKI = {
+ "Authority Key Identifier",
+ NID_authority_key_identifier,
+ false,
+ };
+ return &AKI;
+}
+
+struct extension_metadata const *ext_ku(void)
+{
+ static const struct extension_metadata KU = {
+ "Key Usage",
+ NID_key_usage,
+ true,
+ };
+ return &KU;
+}
+
+struct extension_metadata const *ext_cdp(void)
+{
+ static const struct extension_metadata CDP = {
+ "CRL Distribution Points",
+ NID_crl_distribution_points,
+ false,
+ };
+ return &CDP;
+}
+
+struct extension_metadata const *ext_aia(void)
+{
+ static const struct extension_metadata AIA = {
+ "Authority Information Access",
+ NID_info_access,
+ false,
+ };
+ return &AIA;
+}
+
+struct extension_metadata const *ext_sia(void)
+{
+ static const struct extension_metadata SIA = {
+ "Subject Information Access",
+ NID_sinfo_access ,
+ false,
+ };
+ return &SIA;
+}
+
+struct extension_metadata const *ext_cp(void)
+{
+ static const struct extension_metadata CP = {
+ "Certificate Policies",
+ NID_certificate_policies,
+ true,
+ };
+ return &CP;
+}
+
+struct extension_metadata const *ext_ir(void)
+{
+ static const struct extension_metadata IR = {
+ "IP Resources",
+ NID_sbgp_ipAddrBlock,
+ true,
+ };
+ return &IR;
+}
+
+struct extension_metadata const *ext_ar(void)
+{
+ static const struct extension_metadata AR = {
+ "AS Resources",
+ NID_sbgp_autonomousSysNum,
+ true,
+ };
+ return &AR;
+}
+
+struct extension_metadata const *ext_ir2(void)
+{
+ return &IR2;
+}
+
+struct extension_metadata const *ext_ar2(void)
+{
+ return &AR2;
+}
+
+struct extension_metadata const *ext_cn(void)
+{
+ static const struct extension_metadata CN = {
+ "CRL Number",
+ NID_crl_number,
+ false,
+ };
+ return &CN;
+}
static int
handle_extension(struct extension_handler *handlers, X509_EXTENSION *ext)
int e;
int error;
- /* TODO check that no other extensions are present? */
-
for (e = 0; e < sk_X509_EXTENSION_num(extensions); e++) {
error = handle_extension(handlers,
sk_X509_EXTENSION_value(extensions, e));
/* Hash the SPK, compare SPK hash with the SKI */
if (hash->length < 0 || SIZE_MAX < hash->length) {
return pr_err("%s length (%d) is out of bounds. (0-%zu)",
- SKI.name, hash->length, SIZE_MAX);
+ ext_ski()->name, hash->length, SIZE_MAX);
}
if (spk_len < 0 || SIZE_MAX < spk_len) {
return pr_err("Subject Public Key length (%d) is out of bounds. (0-%zu)",
error = hash_validate("sha1", hash->data, hash->length, spk, spk_len);
if (error) {
pr_err("The Subject Public Key's hash does not match the %s.",
- SKI.name);
+ ext_ski()->name);
}
return error;
aki = X509V3_EXT_d2i(ext);
if (aki == NULL)
- return cannot_decode(&AKI);
+ return cannot_decode(ext_aki());
if (aki->issuer != NULL) {
error = pr_err("%s extension contains an authorityCertIssuer.",
- AKI.name);
+ ext_aki()->name);
goto end;
}
if (aki->serial != NULL) {
error = pr_err("%s extension contains an authorityCertSerialNumber.",
- AKI.name);
+ ext_aki()->name);
goto end;
}
bool found;
};
-extern const struct extension_metadata BC;
-extern const struct extension_metadata SKI;
-extern const struct extension_metadata AKI;
-extern const struct extension_metadata KU;
-extern const struct extension_metadata CDP;
-extern const struct extension_metadata AIA;
-extern const struct extension_metadata SIA;
-extern const struct extension_metadata CP;
-extern const struct extension_metadata IR;
-extern const struct extension_metadata AR;
-extern const struct extension_metadata CN;
+int extension_init(void);
+
+struct extension_metadata const *ext_bc(void);
+struct extension_metadata const *ext_ski(void);
+struct extension_metadata const *ext_aki(void);
+struct extension_metadata const *ext_ku(void);
+struct extension_metadata const *ext_cdp(void);
+struct extension_metadata const *ext_aia(void);
+struct extension_metadata const *ext_sia(void);
+struct extension_metadata const *ext_cp(void);
+struct extension_metadata const *ext_ir(void);
+struct extension_metadata const *ext_ar(void);
+struct extension_metadata const *ext_ir2(void);
+struct extension_metadata const *ext_ar2(void);
+struct extension_metadata const *ext_cn(void);
int handle_extensions(struct extension_handler *,
STACK_OF(X509_EXTENSION) const *);
}
-#endif
-
void
pr_debug_prefix(void)
{
-#ifdef DEBUG
fprintf(STDOUT, "DBG: ");
pr_indent(STDOUT);
-#endif
}
void
pr_debug(const char *format, ...)
{
-#ifdef DEBUG
va_list args;
pr_debug_prefix();
vfprintf(STDOUT, format, args);
va_end(args);
fprintf(STDOUT, "\n");
-#endif
}
void
pr_debug_add(const char *format, ...)
{
-#ifdef DEBUG
va_list args;
pr_debug_prefix();
fprintf(STDOUT, "\n");
pr_add_indent();
-#endif
}
void
pr_debug_rm(const char *format, ...)
{
-#ifdef DEBUG
va_list args;
pr_rm_indent();
vfprintf(STDOUT, format, args);
va_end(args);
fprintf(STDOUT, "\n");
-#endif
}
+#endif
+
static void
-pr_err_prefix(void)
+pr_prefix(char const *level)
{
- fprintf(STDERR, "ERR: ");
+ fprintf(STDERR, "%s: ", level);
pr_indent(STDERR);
}
-#define PR_ERR(args) do { \
- pr_err_prefix(); \
+#define PR_PREFIX(level, args) do { \
+ pr_prefix(level); \
pr_file_name(STDERR); \
\
va_start(args, format); \
va_end(args); \
} while (0)
+/**
+ * Always appends a newline at the end. Always returs 0. (So you can interrupt
+ * whatever you're doing without failing validation.)
+ */
+int
+pr_warn(const char *format, ...)
+{
+ va_list args;
+ PR_PREFIX("WRN", args);
+ fprintf(STDERR, "\n");
+ return 0;
+}
+
/**
* Always appends a newline at the end. Always returs -EINVAL.
*/
pr_err(const char *format, ...)
{
va_list args;
- PR_ERR(args);
+ PR_PREFIX("ERR", args);
fprintf(STDERR, "\n");
return -EINVAL;
}
{
va_list args;
- PR_ERR(args);
+ PR_PREFIX("ERR", args);
if (error) {
fprintf(STDERR, ": %s", strerror(error));
va_list args;
int error;
- PR_ERR(args);
+ PR_PREFIX("ERR", args);
fprintf(STDERR, ": ");
error = ERR_GET_REASON(ERR_peek_last_error());
{
va_list args;
- pr_err_prefix();
+ pr_prefix("CRT");
pr_file_name(STDERR);
fprintf(STDERR, "Programming error: ");
* to ease debugging.
*/
+#ifdef DEBUG
+
void pr_debug(const char *, ...);
void pr_debug_add(const char *, ...);
void pr_debug_rm(const char *, ...);
void pr_debug_prefix(void);
+#else
+
+#define pr_debug(...)
+#define pr_debug_add(...)
+#define pr_debug_rm(...)
+#define pr_debug_prefix
+
+#endif
+
+int pr_warn(const char *, ...);
int pr_err(const char *, ...);
int pr_errno(int, const char *, ...);
int crypto_err(const char *, ...);
#include <err.h>
#include <errno.h>
#include <getopt.h>
-#include <openssl/objects.h>
#include "common.h"
#include "config.h"
#include "debug.h"
+#include "extension.h"
#include "log.h"
+#include "nid.h"
#include "rpp.h"
#include "thread_var.h"
#include "object/certificate.h"
#include "object/tal.h"
#include "rsync/rsync.h"
-/**
- * Registers the RPKI-specific OIDs in the SSL library.
- * LibreSSL needs it; not sure about OpenSSL.
- */
-static void
-add_rpki_oids(void)
-{
- NID_rpkiManifest = OBJ_create("1.3.6.1.5.5.7.48.10",
- "rpkiManifest",
- "RPKI Manifest (RFC 6487)");
- printf("rpkiManifest registered. Its nid is %d.\n", NID_rpkiManifest);
-
- NID_signedObject = OBJ_create("1.3.6.1.5.5.7.48.11",
- "signedObject",
- "RPKI Signed Object (RFC 6487)");
- printf("signedObject registered. Its nid is %d.\n", NID_signedObject);
-
- NID_rpkiNotify = OBJ_create("1.3.6.1.5.5.7.48.13",
- "rpkiNotify",
- "RPKI Update Notification File (RFC 8182)");
- printf("rpkiNotify registered. Its nid is %d.\n", NID_rpkiNotify);
-
- NID_certPolicyRpki = OBJ_create("1.3.6.1.5.5.7.14.2",
- "id-cp-ipAddr-asNumber (RFC 6484)",
- "Certificate Policy (CP) for the Resource PKI (RPKI)");
- printf("certPolicyRpki registered. Its nid is %d.\n", NID_certPolicyRpki);
-
- /* TODO implement RFC 8360 */
- NID_certPolicyRpkiV2 = OBJ_create("1.3.6.1.5.5.7.14.3",
- "id-cp-ipAddr-asNumber-v2 (RFC 8360)",
- "Certificate Policy for Use with Validation Reconsidered in the RPKI");
- printf("certPolicyRpkiV2 registered. Its nid is %d.\n",
- NID_certPolicyRpkiV2);
-}
-
/**
* Performs the whole validation walkthrough on uri @uri, which is assumed to
* have been extracted from a TAL.
config.shuffle_uris = false;
config.local_repository = NULL;
config.tal = NULL;
- config.maximum_certificate_depth = 32;
+ config.maximum_certificate_depth = 64;
while ((opt = getopt_long(argc, argv, "t:l:rsm:", long_options, NULL))
!= -1) {
if (error)
return error;
- add_rpki_oids();
+ error = nid_init();
+ if (error)
+ goto end;
+ error = extension_init();
+ if (error)
+ goto end;
thvar_init();
fnstack_store();
fnstack_push(config_get_tal());
tal_destroy(tal);
}
+end:
rsync_destroy();
return error;
}
--- /dev/null
+#include "nid.h"
+
+#include <errno.h>
+#include <openssl/objects.h>
+
+#include "log.h"
+
+static int NID_rpkiManifest;
+static int NID_signedObject;
+static int NID_rpkiNotify;
+static int NID_certPolicyRpki;
+static int NID_certPolicyRpkiV2;
+static int NID_ipAddrBlocksv2;
+static int NID_autonomousSysIdsv2;
+
+static int
+register_oid(const char *oid, const char *sn, const char *ln)
+{
+ int nid;
+
+ nid = OBJ_create(oid, sn, ln);
+ if (nid == 0)
+ return crypto_err("Unable to register the %s NID.", sn);
+
+ printf("%s registered. Its nid is %d.\n", sn, nid);
+ return nid;
+}
+
+/**
+ * Registers the RPKI-specific OIDs in the SSL library.
+ * LibreSSL needs it; not sure about OpenSSL.
+ */
+int
+nid_init(void)
+{
+ NID_rpkiManifest = register_oid("1.3.6.1.5.5.7.48.10",
+ "rpkiManifest",
+ "RPKI Manifest (RFC 6487)");
+ if (NID_rpkiManifest == 0)
+ return -EINVAL;
+
+ NID_signedObject = register_oid("1.3.6.1.5.5.7.48.11",
+ "signedObject",
+ "RPKI Signed Object (RFC 6487)");
+ if (NID_signedObject == 0)
+ return -EINVAL;
+
+ NID_rpkiNotify = register_oid("1.3.6.1.5.5.7.48.13",
+ "rpkiNotify",
+ "RPKI Update Notification File (RFC 8182)");
+ if (NID_rpkiNotify == 0)
+ return -EINVAL;
+
+ NID_certPolicyRpki = register_oid("1.3.6.1.5.5.7.14.2",
+ "id-cp-ipAddr-asNumber (RFC 6484)",
+ "Certificate Policy (CP) for the Resource PKI (RPKI)");
+ if (NID_certPolicyRpki == 0)
+ return -EINVAL;
+
+ NID_certPolicyRpkiV2 = register_oid("1.3.6.1.5.5.7.14.3",
+ "id-cp-ipAddr-asNumber-v2 (RFC 8360)",
+ "Certificate Policy for Use with Validation Reconsidered in the RPKI");
+ if (NID_certPolicyRpkiV2 == 0)
+ return -EINVAL;
+
+ NID_ipAddrBlocksv2 = register_oid("1.3.6.1.5.5.7.1.28",
+ "id-pe-ipAddrBlocks-v2",
+ "Amended IP Resources (RFC 8360)");
+ if (NID_ipAddrBlocksv2 == 0)
+ return -EINVAL;
+
+ NID_autonomousSysIdsv2 = register_oid("1.3.6.1.5.5.7.1.29",
+ "id-pe-autonomousSysIds-v2",
+ "Amended AS Resources (RFC 8360)");
+ if (NID_autonomousSysIdsv2 == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+int nid_rpkiManifest(void)
+{
+ return NID_rpkiManifest;
+}
+
+int nid_signedObject(void)
+{
+ return NID_signedObject;
+}
+
+int nid_rpkiNotify(void)
+{
+ return NID_rpkiNotify;
+}
+
+int nid_certPolicyRpki(void)
+{
+ return NID_certPolicyRpki;
+}
+
+int nid_certPolicyRpkiV2(void)
+{
+ return NID_certPolicyRpkiV2;
+}
+
+int nid_ipAddrBlocksv2(void)
+{
+ return NID_ipAddrBlocksv2;
+}
+
+int nid_autonomousSysIdsv2(void)
+{
+ return NID_autonomousSysIdsv2;
+}
--- /dev/null
+#ifndef SRC_NID_H_
+#define SRC_NID_H_
+
+int nid_init(void);
+
+int nid_rpkiManifest(void);
+int nid_signedObject(void);
+int nid_rpkiNotify(void);
+int nid_certPolicyRpki(void);
+int nid_certPolicyRpkiV2(void);
+int nid_ipAddrBlocksv2(void);
+int nid_autonomousSysIdsv2(void);
+
+#endif /* SRC_NID_H_ */
#include "extension.h"
#include "log.h"
#include "manifest.h"
+#include "nid.h"
#include "thread_var.h"
#include "asn1/decode.h"
#include "asn1/oid.h"
}
int
-certificate_get_resources(X509 *cert, struct resources *resources)
+__certificate_get_resources(X509 *cert, struct resources *resources,
+ int addr_nid, int asn_nid, int bad_addr_nid, int bad_asn_nid,
+ char const *policy_rfc, char const *bad_ext_rfc)
{
X509_EXTENSION *ext;
+ int nid;
int i;
int error;
bool ip_ext_found = false;
for (i = 0; i < X509_get_ext_count(cert); i++) {
ext = X509_get_ext(cert, i);
+ nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext));
- switch (OBJ_obj2nid(X509_EXTENSION_get_object(ext))) {
- case NID_sbgp_ipAddrBlock:
+ if (nid == addr_nid) {
if (ip_ext_found)
return pr_err("Multiple IP extensions found.");
if (!X509_EXTENSION_get_critical(ext))
if (error)
return error;
- break;
- case NID_sbgp_autonomousSysNum:
+ } else if (nid == asn_nid) {
if (asn_ext_found)
return pr_err("Multiple AS extensions found.");
if (!X509_EXTENSION_get_critical(ext))
if (error)
return error;
- break;
+
+ } else if (nid == bad_addr_nid) {
+ return pr_err("Certificate has an RFC%s policy, but contains an RFC%s IP extension.",
+ policy_rfc, bad_ext_rfc);
+ } else if (nid == bad_asn_nid) {
+ return pr_err("Certificate has an RFC%s policy, but contains an RFC%s ASN extension.",
+ policy_rfc, bad_ext_rfc);
}
}
return 0;
}
+int
+certificate_get_resources(X509 *cert, struct resources *resources)
+{
+ enum rpki_policy policy;
+
+ policy = resources_get_policy(resources);
+ switch (policy) {
+ case RPKI_POLICY_RFC6484:
+ return __certificate_get_resources(cert, resources,
+ NID_sbgp_ipAddrBlock, NID_sbgp_autonomousSysNum,
+ nid_ipAddrBlocksv2(), nid_autonomousSysIdsv2(),
+ "6484", "8360");
+ case RPKI_POLICY_RFC8360:
+ return __certificate_get_resources(cert, resources,
+ nid_ipAddrBlocksv2(), nid_autonomousSysIdsv2(),
+ NID_sbgp_ipAddrBlock, NID_sbgp_autonomousSysNum,
+ "8360", "6484");
+ }
+
+ return pr_crit("Unknown policy: %u", policy);
+}
+
static bool
is_rsync(ASN1_IA5STRING *uri)
{
bc = X509V3_EXT_d2i(ext);
if (bc == NULL)
- return cannot_decode(&BC);
+ return cannot_decode(ext_bc());
/*
* 'The issuer determines whether the "cA" boolean is set.'
error = (bc->pathlen == NULL)
? 0
- : pr_err("%s extension contains a Path Length Constraint.", BC.name);
+ : pr_err("%s extension contains a Path Length Constraint.",
+ ext_bc()->name);
BASIC_CONSTRAINTS_free(bc);
return error;
ski = X509V3_EXT_d2i(ext);
if (ski == NULL)
- return cannot_decode(&SKI);
+ return cannot_decode(ext_ski());
error = validate_public_key_hash(arg, ski);
ski = X509V3_EXT_d2i(ext);
if (ski == NULL)
- return cannot_decode(&SKI);
+ return cannot_decode(ext_ski());
args = arg;
error = validate_public_key_hash(args->cert, ski);
for (i = 0; i < X509_get_ext_count(cert); i++) {
other = X509_get_ext(cert, i);
- if (OBJ_obj2nid(X509_EXTENSION_get_object(other)) == SKI.nid) {
+ if (OBJ_obj2nid(X509_EXTENSION_get_object(other)) == ext_ski()->nid) {
if (extension_equals(aki, other))
return 0;
return pr_err("The '%s' does not equal the '%s'.",
- AKI.name, SKI.name);
+ ext_aki()->name, ext_ski()->name);
}
}
- pr_err("Certificate lacks the '%s' extension.", SKI.name);
+ pr_err("Certificate lacks the '%s' extension.", ext_ski()->name);
return -ESRCH;
}
ku = X509V3_EXT_d2i(ext);
if (ku == NULL)
- return cannot_decode(&KU);
+ return cannot_decode(ext_ku());
if (ku->length == 0) {
- error = pr_err("%s bit string has no enabled bits.", KU.name);
+ error = pr_err("%s bit string has no enabled bits.",
+ ext_ku()->name);
goto end;
}
crldp = X509V3_EXT_d2i(ext);
if (crldp == NULL)
- return cannot_decode(&CDP);
+ return cannot_decode(ext_cdp());
if (sk_DIST_POINT_num(crldp) != 1) {
error = pr_err("The %s extension has %u distribution points. (1 expected)",
- CDP.name, sk_DIST_POINT_num(crldp));
+ ext_cdp()->name, sk_DIST_POINT_num(crldp));
goto end;
}
error_msg = "lacks an RSYNC URI";
dist_point_error:
- error = pr_err("The %s extension's distribution point %s.", CDP.name,
- error_msg);
+ error = pr_err("The %s extension's distribution point %s.",
+ ext_cdp()->name, error_msg);
end:
sk_DIST_POINT_pop_free(crldp, DIST_POINT_free);
aia = X509V3_EXT_d2i(ext);
if (aia == NULL)
- return cannot_decode(&AIA);
+ return cannot_decode(ext_aia());
error = handle_ad("AIA", aia, "caIssuers", NID_ad_ca_issuers,
handle_caIssuers, arg);
sia = X509V3_EXT_d2i(ext);
if (sia == NULL)
- return cannot_decode(&SIA);
+ return cannot_decode(ext_sia());
/* rsync */
error = handle_ad("SIA", sia, "caRepository", NID_caRepository,
* (We won't actually touch the manifest until we know the certificate
* is fully valid.)
*/
- error = handle_ad("SIA", sia, "rpkiManifest",NID_rpkiManifest,
+ error = handle_ad("SIA", sia, "rpkiManifest", nid_rpkiManifest(),
handle_rpkiManifest, arg);
end:
sia = X509V3_EXT_d2i(ext);
if (sia == NULL)
- return cannot_decode(&SIA);
+ return cannot_decode(ext_sia());
- error = handle_ad("SIA", sia, "signedObject", NID_signedObject,
+ error = handle_ad("SIA", sia, "signedObject", nid_signedObject(),
handle_signedObject, arg);
AUTHORITY_INFO_ACCESS_free(sia);
static int
handle_cp(X509_EXTENSION *ext, void *arg)
{
+ enum rpki_policy *policy = arg;
CERTIFICATEPOLICIES *cp;
POLICYINFO *pi;
POLICYQUALINFO *pqi;
error = 0;
cp = X509V3_EXT_d2i(ext);
if (cp == NULL)
- return cannot_decode(&CP);
+ return cannot_decode(ext_cp());
if (sk_POLICYINFO_num(cp) != 1) {
error = pr_err("The %s extension has %u policy information's. (1 expected)",
- CP.name, sk_POLICYINFO_num(cp));
+ ext_cp()->name, sk_POLICYINFO_num(cp));
goto end;
}
/* rfc7318#section-2 and consider rfc8360#section-4.2.1 */
pi = sk_POLICYINFO_value(cp, 0);
nid_cp = OBJ_obj2nid(pi->policyid);
- if (nid_cp != NID_certPolicyRpki && nid_cp != NID_certPolicyRpkiV2) {
+ if (nid_cp == nid_certPolicyRpki()) {
+ if (policy != NULL)
+ *policy = RPKI_POLICY_RFC6484;
+ } else if (nid_cp == nid_certPolicyRpkiV2()) {
+ pr_debug("Found RFC8360 policy!");
+ if (policy != NULL)
+ *policy = RPKI_POLICY_RFC8360;
+ } else {
error = pr_err("Invalid certificate policy OID, isn't 'id-cp-ipAddr-asNumber' nor 'id-cp-ipAddr-asNumber-v2'");
goto end;
}
+
/* Exactly one policy qualifier MAY be included (so none is also valid) */
if (pi->qualifiers == NULL)
goto end;
goto end;
if (pqi_num != 1) {
error = pr_err("The %s extension has %d policy qualifiers. (none or only 1 expected)",
- CP.name, pqi_num);
+ ext_cp()->name, pqi_num);
goto end;
}
}
int
-certificate_validate_extensions_ta(X509 *cert, struct rpki_uri *mft)
+certificate_validate_extensions_ta(X509 *cert, struct rpki_uri *mft,
+ enum rpki_policy *policy)
{
struct extension_handler handlers[] = {
- /* ext reqd handler arg */
- { &BC, true, handle_bc, },
- { &SKI, true, handle_ski_ca, cert },
- { &AKI, false, handle_aki_ta, cert },
- { &KU, true, handle_ku_ca, },
- { &SIA, true, handle_sia_ca, mft },
- { &CP, true, handle_cp, },
- { &IR, false, handle_ir, },
- { &AR, false, handle_ar, },
+ /* ext reqd handler arg */
+ { ext_bc(), true, handle_bc, },
+ { ext_ski(), true, handle_ski_ca, cert },
+ { ext_aki(), false, handle_aki_ta, cert },
+ { ext_ku(), true, handle_ku_ca, },
+ { ext_sia(), true, handle_sia_ca, mft },
+ { ext_cp(), true, handle_cp, },
+ { ext_ir(), false, handle_ir, },
+ { ext_ar(), false, handle_ar, },
+ { ext_ir2(), false, handle_ir, },
+ { ext_ar2(), false, handle_ar, },
{ NULL },
};
int
certificate_validate_extensions_ca(X509 *cert, struct rpki_uri *mft,
- struct certificate_refs *refs)
+ struct certificate_refs *refs, enum rpki_policy *policy)
{
struct extension_handler handlers[] = {
- /* ext reqd handler arg */
- { &BC, true, handle_bc, },
- { &SKI, true, handle_ski_ca, cert },
- { &AKI, true, handle_aki, },
- { &KU, true, handle_ku_ca, },
- { &CDP, true, handle_cdp, refs },
- { &AIA, true, handle_aia, refs },
- { &SIA, true, handle_sia_ca, mft },
- { &CP, true, handle_cp, },
- { &IR, false, handle_ir, },
- { &AR, false, handle_ar, },
+ /* ext reqd handler arg */
+ { ext_bc(), true, handle_bc, },
+ { ext_ski(), true, handle_ski_ca, cert },
+ { ext_aki(), true, handle_aki, },
+ { ext_ku(), true, handle_ku_ca, },
+ { ext_cdp(), true, handle_cdp, refs },
+ { ext_aia(), true, handle_aia, refs },
+ { ext_sia(), true, handle_sia_ca, mft },
+ { ext_cp(), true, handle_cp, },
+ { ext_ir(), false, handle_ir, },
+ { ext_ar(), false, handle_ar, },
+ { ext_ir2(), false, handle_ir, },
+ { ext_ar2(), false, handle_ar, },
{ NULL },
};
int
certificate_validate_extensions_ee(X509 *cert, OCTET_STRING_t *sid,
- struct certificate_refs *refs)
+ struct certificate_refs *refs, enum rpki_policy *policy)
{
struct ski_arguments ski_args;
struct extension_handler handlers[] = {
- /* ext reqd handler arg */
- { &SKI, true, handle_ski_ee, &ski_args },
- { &AKI, true, handle_aki, },
- { &KU, true, handle_ku_ee, },
- { &CDP, true, handle_cdp, refs },
- { &AIA, true, handle_aia, refs },
- { &SIA, true, handle_sia_ee, refs },
- { &CP, true, handle_cp, },
- { &IR, false, handle_ir, },
- { &AR, false, handle_ar, },
+ /* ext reqd handler arg */
+ { ext_ski(), true, handle_ski_ee, &ski_args },
+ { ext_aki(), true, handle_aki, },
+ { ext_ku(), true, handle_ku_ee, },
+ { ext_cdp(), true, handle_cdp, refs },
+ { ext_aia(), true, handle_aia, refs },
+ { ext_sia(), true, handle_sia_ee, refs },
+ { ext_cp(), true, handle_cp, policy },
+ { ext_ir(), false, handle_ir, },
+ { ext_ar(), false, handle_ar, },
+ { ext_ir2(), false, handle_ir, },
+ { ext_ar2(), false, handle_ar, },
{ NULL },
};
X509 *cert;
struct rpki_uri mft;
struct certificate_refs refs;
+ enum rpki_policy policy;
struct rpp *pp;
int error;
if (error)
goto end2;
error = is_ta
- ? certificate_validate_extensions_ta(cert, &mft)
- : certificate_validate_extensions_ca(cert, &mft, &refs);
+ ? certificate_validate_extensions_ta(cert, &mft, &policy)
+ : certificate_validate_extensions_ca(cert, &mft, &refs, &policy);
if (error)
goto end2;
goto end3;
/* -- Validate the manifest (@mft) pointed by the certificate -- */
- error = validation_push_cert(state, cert_uri, cert, is_ta);
+ error = validation_push_cert(state, cert_uri, cert, policy, is_ta);
if (error)
goto end3;
* Also initializes the second argument as the URI of the rpkiManifest Access
* Description from the SIA extension.
*/
-int certificate_validate_extensions_ta(X509 *, struct rpki_uri *);
+int certificate_validate_extensions_ta(X509 *, struct rpki_uri *,
+ enum rpki_policy *);
/**
* Validates the certificate extensions, (intermediate) Certificate Authority
* style.
* extensions.
*/
int certificate_validate_extensions_ca(X509 *, struct rpki_uri *,
- struct certificate_refs *);
+ struct certificate_refs *, enum rpki_policy *);
/**
* Validates the certificate extensions, End-Entity style.
*
* extensions.
*/
int certificate_validate_extensions_ee(X509 *, OCTET_STRING_t *,
- struct certificate_refs *);
+ struct certificate_refs *, enum rpki_policy *);
int certificate_traverse(struct rpp *, struct rpki_uri const *,
STACK_OF(X509_CRL) *, bool);
revoked_stack = X509_CRL_get_REVOKED(crl);
if (revoked_stack == NULL)
- return pr_err("Likely programming error: CRL revoked stack is NULL.");
+ return 0; /* Guess the RFC doesn't enforce this thing. */
for (i = 0; i < sk_X509_REVOKED_num(revoked_stack); i++) {
revoked = sk_X509_REVOKED_value(revoked_stack, i);
{
struct extension_handler handlers[] = {
/* ext reqd handler arg */
- { &AKI, true, handle_aki, },
- { &CN, true, handle_crlnum, },
+ { ext_aki(), true, handle_aki, },
+ { ext_cn(), true, handle_crlnum, },
{ NULL },
};
return pr_err("The ROA's IPv4 maxLength isn't a valid unsigned long");
}
- if (max_length < 0 || 32 < max_length) {
+ if (max_length > 32) {
return pr_err("maxLength (%lu) is out of bounds (0-32).",
max_length);
}
return pr_err("The ROA's IPv6 maxLength isn't a valid unsigned long");
}
- if (max_length < 0 || 128 < max_length) {
+ if (max_length > 128) {
return pr_err("maxLength (%lu) is out of bounds (0-128).",
max_length);
}
#include "resource.h"
#include <errno.h>
-#include <arpa/inet.h>
#include <stdint.h> /* UINT32_MAX */
#include "address.h"
struct resources_ipv4 *ip4s;
struct resources_ipv6 *ip6s;
struct resources_asn *asns;
+ enum rpki_policy policy;
};
struct resources *
result->ip4s = NULL;
result->ip6s = NULL;
result->asns = NULL;
+ result->policy = RPKI_POLICY_RFC6484;
return result;
}
return (state != NULL) ? validation_peek_resource(state) : NULL;
}
-static void
-pr_debug_ip_prefix(int family, void *addr, unsigned int length)
-{
-#ifdef DEBUG
- char buffer[INET6_ADDRSTRLEN];
- char const *string;
-
- string = inet_ntop(family, addr, buffer, sizeof(buffer));
- if (string != NULL)
- pr_debug("Prefix: %s/%u", string, length);
- else {
- pr_debug("Prefix: (Cannot convert to string. Errcode %d)",
- errno);
- }
-#endif
-}
-
-static void
-pr_debug_range(int family, void *min, void *max)
-{
-#ifdef DEBUG
- char buffer_min[INET6_ADDRSTRLEN];
- char buffer_max[INET6_ADDRSTRLEN];
- char const *string_min;
- char const *string_max;
-
- string_min = inet_ntop(family, min, buffer_min, sizeof(buffer_min));
- if (string_min == NULL)
- goto fail;
-
- string_max = inet_ntop(family, max, buffer_max, sizeof(buffer_max));
- if (string_max == NULL)
- goto fail;
-
- pr_debug("Range: %s-%s", string_min, string_max);
- return;
-
-fail:
- pr_debug("Range: (Cannot convert to string. Errcode %d)", errno);
-#endif
-}
-
static int
inherit_aors(struct resources *resources, int family)
{
if (error)
return error;
- if (parent && !res4_contains_prefix(parent->ip4s, &prefix))
- return pr_err("Parent certificate doesn't own child's IPv4 resource.");
+ if (parent && !res4_contains_prefix(parent->ip4s, &prefix)) {
+ switch (resources->policy) {
+ case RPKI_POLICY_RFC6484:
+ return pr_err("Parent certificate doesn't own IPv4 prefix '%s/%u'.",
+ v4addr2str(&prefix.addr), prefix.len);
+ case RPKI_POLICY_RFC8360:
+ return pr_warn("Certificate is overclaiming the IPv4 prefix '%s/%u'.",
+ v4addr2str(&prefix.addr), prefix.len);
+ }
+ }
if (resources->ip4s == NULL) {
resources->ip4s = res4_create();
error = res4_add_prefix(resources->ip4s, &prefix);
if (error) {
- pr_err("Error adding IPv4 prefix to certificate resources: %s",
+ pr_err("Error adding IPv4 prefix '%s/%u' to certificate resources: %s",
+ v4addr2str(&prefix.addr), prefix.len,
sarray_err2str(error));
return error;
}
- pr_debug_ip_prefix(AF_INET, &prefix.addr, prefix.len);
+ pr_debug("Prefix: %s/%u", v4addr2str(&prefix.addr), prefix.len);
return 0;
}
if (error)
return error;
- if (parent && !res6_contains_prefix(parent->ip6s, &prefix))
- return pr_err("Parent certificate doesn't own child's IPv6 resource.");
+ if (parent && !res6_contains_prefix(parent->ip6s, &prefix)) {
+ switch (resources->policy) {
+ case RPKI_POLICY_RFC6484:
+ return pr_err("Parent certificate doesn't own IPv6 prefix '%s/%u'.",
+ v6addr2str(&prefix.addr), prefix.len);
+ case RPKI_POLICY_RFC8360:
+ return pr_warn("Certificate is overclaiming the IPv6 prefix '%s/%u'.",
+ v6addr2str(&prefix.addr), prefix.len);
+ }
+ }
if (resources->ip6s == NULL) {
resources->ip6s = res6_create();
error = res6_add_prefix(resources->ip6s, &prefix);
if (error) {
- pr_err("Error adding IPv6 prefix to certificate resources: %s",
+ pr_err("Error adding IPv6 prefix '%s/%u' to certificate resources: %s",
+ v6addr2str(&prefix.addr), prefix.len,
sarray_err2str(error));
return error;
}
- pr_debug_ip_prefix(AF_INET6, &prefix.addr, prefix.len);
+ pr_debug("Prefix: %s/%u", v6addr2str(&prefix.addr), prefix.len);
return 0;
}
if (error)
return error;
- if (parent && !res4_contains_range(parent->ip4s, &range))
- return pr_err("Parent certificate doesn't own child's IPv4 resource.");
+ if (parent && !res4_contains_range(parent->ip4s, &range)) {
+ switch (resources->policy) {
+ case RPKI_POLICY_RFC6484:
+ return pr_err("Parent certificate doesn't own IPv4 range '%s-%s'.",
+ v4addr2str(&range.min), v4addr2str2(&range.max));
+ case RPKI_POLICY_RFC8360:
+ return pr_warn("Certificate is overclaiming the IPv4 range '%s-%s'.",
+ v4addr2str(&range.min), v4addr2str2(&range.max));
+ }
+ }
if (resources->ip4s == NULL) {
resources->ip4s = res4_create();
error = res4_add_range(resources->ip4s, &range);
if (error) {
- pr_err("Error adding IPv4 range to certificate resources: %s",
+ pr_err("Error adding IPv4 range '%s-%s' to certificate resources: %s",
+ v4addr2str(&range.min), v4addr2str2(&range.max),
sarray_err2str(error));
return error;
}
- pr_debug_range(AF_INET, &range.min, &range.max);
+ pr_debug("Range: %s-%s", v4addr2str(&range.min),
+ v4addr2str2(&range.max));
return 0;
}
if (error)
return error;
- if (parent && !res6_contains_range(parent->ip6s, &range))
- return pr_err("Parent certificate doesn't own child's IPv6 resource.");
+ if (parent && !res6_contains_range(parent->ip6s, &range)) {
+ switch (resources->policy) {
+ case RPKI_POLICY_RFC6484:
+ return pr_err("Parent certificate doesn't own IPv6 range '%s-%s'.",
+ v6addr2str(&range.min), v6addr2str2(&range.max));
+ case RPKI_POLICY_RFC8360:
+ return pr_warn("Certificate is overclaiming the IPv6 range '%s-%s'.",
+ v6addr2str(&range.min), v6addr2str2(&range.max));
+ }
+ }
if (resources->ip6s == NULL) {
resources->ip6s = res6_create();
error = res6_add_range(resources->ip6s, &range);
if (error) {
- pr_err("Error adding IPv6 range to certificate resources: %s",
+ pr_err("Error adding IPv6 range '%s-%s' to certificate resources: %s",
+ v6addr2str(&range.min), v6addr2str2(&range.max),
sarray_err2str(error));
return error;
}
- pr_debug_range(AF_INET6, &range.min, &range.max);
+ pr_debug("Range: %s-%s", v6addr2str(&range.min),
+ v6addr2str2(&range.max));
return 0;
}
int i;
int error;
+ if (aors->list.count == 0)
+ return pr_err("IP extension's set of IP address records is empty.");
+
for (i = 0; i < aors->list.count; i++) {
aor = aors->list.array[i];
switch (aor->present) {
if (min > max)
return pr_err("The ASN range %lu-%lu is inverted.", min, max);
- if (parent && !rasn_contains(parent->asns, min, max))
- return pr_err("Parent certificate doesn't own child's ASN resource.");
+ if (parent && !rasn_contains(parent->asns, min, max)) {
+ switch (resources->policy) {
+ case RPKI_POLICY_RFC6484:
+ return pr_err("Parent certificate doesn't own ASN range '%lu-%lu'.",
+ min, max);
+ case RPKI_POLICY_RFC8360:
+ return pr_warn("Certificate is overclaiming the ASN range '%lu-%lu'.",
+ min, max);
+ }
+ }
if (resources->asns == NULL) {
resources->asns = rasn_create();
error = rasn_add(resources->asns, min, max);
if (error){
- pr_err("Error adding ASN range to certificate resources: %s",
- sarray_err2str(error));
+ pr_err("Error adding ASN range '%lu-%lu' to certificate resources: %s",
+ min, max, sarray_err2str(error));
return error;
}
return inherit_asiors(resources);
case ASIdentifierChoice_PR_asIdsOrRanges:
iors = &ids->asnum->choice.asIdsOrRanges;
+ if (iors->list.count == 0)
+ return pr_err("AS extension's set of AS number records is empty.");
for (i = 0; i < iors->list.count; i++) {
error = add_asior(resources, iors->list.array[i]);
if (error)
return res6_contains_prefix(res->ip6s, prefix);
}
+enum rpki_policy
+resources_get_policy(struct resources *res)
+{
+ return res->policy;
+}
+
+void
+resources_set_policy(struct resources *res, enum rpki_policy policy)
+{
+ res->policy = policy;
+}
#include <libcmscodec/IPAddressFamily.h>
#include "address.h"
+enum rpki_policy {
+ /**
+ * If certificate `x`'s resources are not a subset of `x - 1`'s
+ * resources, then `x` is to be rejected.
+ */
+ RPKI_POLICY_RFC6484,
+ /**
+ * If certificate `x`'s resources are not a subset of `x - 1`'s
+ * resources, then the overclaiming resources are to be ignored.
+ */
+ RPKI_POLICY_RFC8360,
+};
+
int get_addr_family(OCTET_STRING_t *);
struct resources;
bool resources_contains_ipv4(struct resources *, struct ipv4_prefix *);
bool resources_contains_ipv6(struct resources *, struct ipv6_prefix *);
+enum rpki_policy resources_get_policy(struct resources *);
+void resources_set_policy(struct resources *, enum rpki_policy);
+
#endif /* SRC_RESOURCE_H_ */
pton(struct ipv4_prefix *p, struct r4_node *n)
{
n->min = ntohl(p->addr.s_addr);
- n->max = n->min | (0xFFFFFFFFu >> p->len);
+ n->max = n->min | u32_suffix_mask(p->len);
}
static void
/* Did the TAL's public key match the root certificate's public key? */
enum pubkey_state pubkey_state;
+
+ /**
+ * Two buffers calling code will store stringified IP addresses in,
+ * to prevent proliferation of similar buffers on the stack.
+ *
+ * They are meant to be large enough to contain both IPv4 and IPv6
+ * addresses.
+ */
+ char addr_buffer1[INET6_ADDRSTRLEN];
+ char addr_buffer2[INET6_ADDRSTRLEN];
};
/*
*/
int
validation_push_cert(struct validation *state, struct rpki_uri const *cert_uri,
- X509 *x509, bool is_ta)
+ X509 *x509, enum rpki_policy policy, bool is_ta)
{
struct certificate *cert;
int ok;
goto end4;
}
+ resources_set_policy(cert->resources, policy);
error = certificate_get_resources(x509, cert->resources);
if (error)
goto end5;
return error;
}
+
+char *
+validation_get_ip_buffer1(struct validation *state)
+{
+ return state->addr_buffer1;
+}
+
+char *
+validation_get_ip_buffer2(struct validation *state)
+{
+ return state->addr_buffer2;
+}
enum pubkey_state validation_pubkey_state(struct validation *);
int validation_push_cert(struct validation *, struct rpki_uri const *, X509 *,
- bool);
+ enum rpki_policy, bool);
int validation_pop_cert(struct validation *);
X509 *validation_peek_cert(struct validation *);
struct rpki_uri const *validation_peek_cert_uri(struct validation *);
int validation_store_serial_number(struct validation *, BIGNUM *);
int validation_store_subject(struct validation *, char *);
+char *validation_get_ip_buffer1(struct validation *);
+char *validation_get_ip_buffer2(struct validation *);
+
#endif /* SRC_STATE_H_ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <arpa/inet.h>
static pthread_key_t state_key;
static pthread_key_t filenames_key;
files->len--;
}
+
+static char const *
+addr2str(int af, void *addr, char *(*buffer_cb)(struct validation *))
+{
+ struct validation *state;
+
+ state = state_retrieve();
+ if (!state)
+ return NULL;
+
+ return inet_ntop(af, addr, buffer_cb(state), INET6_ADDRSTRLEN);
+}
+
+/**
+ * Returns @addr, converted to a printable string. Intended for minimal clutter
+ * address printing.
+ *
+ * The buffer the string is stored in was allocated in a thread variable, so it
+ * will be overridden the next time you call this function. Also, you should not
+ * free it.
+ *
+ * The buffer is the same as v6addr2str()'s, so don't mix them either.
+ */
+char const *
+v4addr2str(struct in_addr *addr)
+{
+ return addr2str(AF_INET, addr, validation_get_ip_buffer1);
+}
+
+/**
+ * Same as v4addr2str(), except a different buffer is used.
+ */
+char const *
+v4addr2str2(struct in_addr *addr)
+{
+ return addr2str(AF_INET, addr, validation_get_ip_buffer2);
+}
+
+/**
+ * See v4addr2str().
+ */
+char const *
+v6addr2str(struct in6_addr *addr)
+{
+ return addr2str(AF_INET6, addr, validation_get_ip_buffer1);
+}
+
+/**
+ * See v4addr2str2().
+ */
+char const *
+v6addr2str2(struct in6_addr *addr)
+{
+ return addr2str(AF_INET6, addr, validation_get_ip_buffer2);
+}
char const *fnstack_peek(void);
void fnstack_pop(void);
+/* TODO use these more, to print better error messages. */
+char const *v4addr2str(struct in_addr *addr);
+char const *v4addr2str2(struct in_addr *addr);
+char const *v6addr2str(struct in6_addr *addr);
+char const *v6addr2str2(struct in6_addr *addr);
+
#endif /* SRC_THREAD_VAR_H_ */