Includes an implementation of RFC 3779.
There's a lot of diff pollution due to another log.c refactor.
I can't seem to nail the right implementation of that thing.
rpki_validator_SOURCES = main.c
+rpki_validator_SOURCES += address.h address.c
rpki_validator_SOURCES += common.h common.c
rpki_validator_SOURCES += debug.h debug.c
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 += resource.h resource.c
+rpki_validator_SOURCES += sorted_array.h sorted_array.c
rpki_validator_SOURCES += state.h state.c
rpki_validator_SOURCES += asn1/content_info.h asn1/content_info.c
--- /dev/null
+#include "address.h"
+
+#include <string.h>
+
+bool
+prefix4_contains(const struct ipv4_prefix *a, const struct ipv4_prefix *b)
+{
+ uint32_t maskbits;
+ uint32_t a_bits;
+ uint32_t b_bits;
+
+ if (a->len > b->len)
+ return false;
+
+ maskbits = ((uint64_t) 0xffffffffU) << (32 - a->len);
+ a_bits = ntohl(a->addr.s_addr) & maskbits;
+ b_bits = ntohl(b->addr.s_addr) & maskbits;
+
+ return a_bits == b_bits;
+}
+
+bool
+prefix6_contains(const struct ipv6_prefix *a, const struct ipv6_prefix *b)
+{
+ struct in6_addr a2;
+ struct in6_addr b2;
+ unsigned int quadrant;
+ uint32_t mask;
+ unsigned int i;
+
+ if (a->len > b->len)
+ return false;
+
+ memcpy(&a2, &a->addr, sizeof(a2));
+ memcpy(&b2, &b->addr, sizeof(b2));
+
+ /* Zeroize the suffixes of a2 and b2 */
+ quadrant = a->len >> 5; /* ">> 5" is the same as "/ 32" */
+ if (quadrant > 3)
+ quadrant = 3;
+ mask = ((uint64_t) 0xffffffffU) << (32 - (a->len & 0x1f));
+ a2.s6_addr32[quadrant] = htonl(ntohl(a2.s6_addr32[quadrant]) & mask);
+ b2.s6_addr32[quadrant] = htonl(ntohl(b2.s6_addr32[quadrant]) & mask);
+ for (i = quadrant + 1; i < 4; i++) {
+ a2.s6_addr32[i] = 0;
+ b2.s6_addr32[i] = 0;
+ }
+
+ /* Finally compare */
+ return memcmp(&a2, &b2, sizeof(a2)) == 0;
+}
--- /dev/null
+#ifndef SRC_ADDRESS_H_
+#define SRC_ADDRESS_H_
+
+#include <stdbool.h>
+#include <netinet/in.h>
+
+struct ipv4_prefix {
+ struct in_addr addr;
+ int len;
+};
+
+struct ipv6_prefix {
+ struct in6_addr addr;
+ int len;
+};
+
+bool prefix4_contains(const struct ipv4_prefix *, const struct ipv4_prefix *);
+bool prefix6_contains(const struct ipv6_prefix *, const struct ipv6_prefix *);
+
+#endif /* SRC_ADDRESS_H_ */
}
static int
-decode(struct validation *state, struct file_contents *fc,
- struct ContentInfo **result)
+decode(struct file_contents *fc, struct ContentInfo **result)
{
struct ContentInfo *cinfo;
int error;
- error = asn1_decode_fc(state, fc, &asn_DEF_ContentInfo, (void **) &cinfo);
+ error = asn1_decode_fc(fc, &asn_DEF_ContentInfo, (void **) &cinfo);
if (error)
return error;
}
int
-content_info_load(struct validation *state, const char *file_name,
- struct ContentInfo **result)
+content_info_load(const char *file_name, struct ContentInfo **result)
{
struct file_contents fc;
int error;
- error = file_load(state, file_name, &fc);
+ error = file_load(file_name, &fc);
if (error)
return error;
- error = decode(state, &fc, result);
+ error = decode(&fc, result);
file_free(&fc);
return error;
/* Some wrappers for libcmscodec's ContentInfo. */
#include <libcmscodec/ContentInfo.h>
-#include "state.h"
-int content_info_load(struct validation *, const char *, struct ContentInfo **);
+int content_info_load(const char *, struct ContentInfo **);
void content_info_free(struct ContentInfo *);
#endif /* SRC_CONTENT_INFO_H_ */
#include "log.h"
static int
-validate(struct validation *state, asn_TYPE_descriptor_t const *descriptor,
- void *result)
+validate(asn_TYPE_descriptor_t const *descriptor, void *result)
{
char error_msg[256];
size_t error_msg_size;
error = asn_check_constraints(descriptor, result, error_msg,
&error_msg_size);
if (error == -1) {
- pr_err(state, "Error validating ASN.1 object: %s", error_msg);
+ pr_err("Error validating ASN.1 object: %s", error_msg);
return -EINVAL;
}
}
int
-asn1_decode(struct validation *state, const void *buffer, size_t buffer_size,
+asn1_decode(const void *buffer, size_t buffer_size,
asn_TYPE_descriptor_t const *descriptor, void **result)
{
asn_dec_rval_t rval;
rval = ber_decode(0, descriptor, result, buffer, buffer_size);
if (rval.code != RC_OK) {
/* TODO if rval.code == RC_WMORE (1), more work is needed */
- pr_err(state, "Error decoding ASN.1 object: %d", rval.code);
+ pr_err("Error decoding ASN.1 object: %d", rval.code);
/* Must free partial object according to API contracts. */
ASN_STRUCT_FREE(*descriptor, *result);
return -EINVAL;
}
- error = validate(state, descriptor, *result);
+ error = validate(descriptor, *result);
if (error) {
ASN_STRUCT_FREE(*descriptor, *result);
return error;
}
int
-asn1_decode_any(struct validation *state, ANY_t *any,
- asn_TYPE_descriptor_t const *descriptor, void **result)
+asn1_decode_any(ANY_t *any, asn_TYPE_descriptor_t const *descriptor,
+ void **result)
{
- return asn1_decode(state, any->buf, any->size, descriptor, result);
+ return asn1_decode(any->buf, any->size, descriptor, result);
}
int
-asn1_decode_octet_string(struct validation *state, OCTET_STRING_t *string,
+asn1_decode_octet_string(OCTET_STRING_t *string,
asn_TYPE_descriptor_t const *descriptor, void **result)
{
- return asn1_decode(state, string->buf, string->size, descriptor,
- result);
+ return asn1_decode(string->buf, string->size, descriptor, result);
}
int
-asn1_decode_fc(struct validation *state, struct file_contents *fc,
+asn1_decode_fc(struct file_contents *fc,
asn_TYPE_descriptor_t const *descriptor, void **result)
{
- return asn1_decode(state, fc->buffer, fc->buffer_size, descriptor,
- result);
+ return asn1_decode(fc->buffer, fc->buffer_size, descriptor, result);
}
#include <libcmscodec/ANY.h>
#include <libcmscodec/constr_TYPE.h>
#include "file.h"
-#include "state.h"
-int asn1_decode(struct validation *, const void *, size_t,
- asn_TYPE_descriptor_t const *, void **);
-int asn1_decode_any(struct validation *, ANY_t *, asn_TYPE_descriptor_t const *,
+int asn1_decode(const void *, size_t, asn_TYPE_descriptor_t const *, void **);
+int asn1_decode_any(ANY_t *, asn_TYPE_descriptor_t const *, void **);
+int asn1_decode_octet_string(OCTET_STRING_t *, asn_TYPE_descriptor_t const *,
+ void **);
+int asn1_decode_fc(struct file_contents *, asn_TYPE_descriptor_t const *,
void **);
-int asn1_decode_octet_string(struct validation *, OCTET_STRING_t *,
- asn_TYPE_descriptor_t const *, void **);
-int asn1_decode_fc(struct validation *, struct file_contents *,
- asn_TYPE_descriptor_t const *, void **);
#endif /* SRC_ASN1_DECODE_H_ */
/* Callers must free @result. */
int
-any2arcs(struct validation *state, ANY_t *any, struct oid_arcs *result)
+any2arcs(ANY_t *any, struct oid_arcs *result)
{
OBJECT_IDENTIFIER_t *oid;
int error;
- error = asn1_decode_any(state, any, &asn_DEF_OBJECT_IDENTIFIER,
+ error = asn1_decode_any(any, &asn_DEF_OBJECT_IDENTIFIER,
(void **) &oid);
if (error)
return error;
#include <stdbool.h>
#include <libcmscodec/AlgorithmIdentifier.h>
#include "common.h"
-#include "state.h"
/* These objects are expected to live on the stack. */
struct oid_arcs {
#define OID_SHA512 { 2, 16, 840, 1, 101, 3, 4, 2, 3 }
int oid2arcs(OBJECT_IDENTIFIER_t *, struct oid_arcs *);
-int any2arcs(struct validation *, ANY_t *, struct oid_arcs *);
+int any2arcs(ANY_t *, struct oid_arcs *);
bool arcs_equal(struct oid_arcs const *, struct oid_arcs const *);
/* Use ARCS_EQUAL_OID() instead. */
}
static int
-validate_content_type_attribute(struct validation *state,
- CMSAttributeValue_t *value, EncapsulatedContentInfo_t *eci)
+validate_content_type_attribute(CMSAttributeValue_t *value,
+ EncapsulatedContentInfo_t *eci)
{
struct oid_arcs attrValue_arcs;
struct oid_arcs EncapContentInfo_arcs;
/* rfc6488#section-3.1.h */
- error = any2arcs(state, value, &attrValue_arcs);
+ error = any2arcs(value, &attrValue_arcs);
if (error)
return error;
}
if (!arcs_equal(&attrValue_arcs, &EncapContentInfo_arcs)) {
- pr_err(state,
- "The eContentType in the EncapsulatedContentInfo does not match the attrValues in the content-type attribute.");
+ pr_err("The eContentType in the EncapsulatedContentInfo does not match the attrValues in the content-type attribute.");
error = -EINVAL;
}
}
static int
-validate_message_digest_attribute(struct validation *state, CMSAttributeValue_t *value)
+validate_message_digest_attribute(CMSAttributeValue_t *value)
{
return 0; /* TODO need the content being signed */
}
static int
-validate_signed_attrs(struct validation *state, struct SignerInfo *sinfo,
- EncapsulatedContentInfo_t *eci)
+validate_signed_attrs(struct SignerInfo *sinfo, EncapsulatedContentInfo_t *eci)
{
struct CMSAttribute *attr;
struct CMSAttribute__attrValues *attrs;
int error;
if (sinfo->signedAttrs == NULL) {
- pr_err(state, "The SignerInfo's signedAttrs field is NULL.");
+ pr_err("The SignerInfo's signedAttrs field is NULL.");
return -EINVAL;
}
for (i = 0; i < sinfo->signedAttrs->list.count; i++) {
attr = sinfo->signedAttrs->list.array[i];
if (attr == NULL) {
- pr_err(state, "SignedAttrs array element %u is NULL.",
- i);
+ pr_err("SignedAttrs array element %u is NULL.", i);
continue;
}
attrs = &attr->attrValues;
if (attrs->list.count != 1) {
- pr_err(state, 0,
+ pr_err(0,
"signedAttrs's attribute set size (%d) is different than 1.",
attr->attrValues.list.count);
return -EINVAL;
}
if (attrs->list.array == NULL || attrs->list.array[0] == NULL) {
- pr_err(state,
- "Programming error: Array size is 1 but array itself is NULL.");
+ pr_err("Programming error: Array size is 1 but array itself is NULL.");
return -EINVAL;
}
if (ARCS_EQUAL_OIDS(&attrType, oid_cta)) {
if (content_type_found) {
- pr_err(state, "Multiple ContentTypes found.");
+ pr_err("Multiple ContentTypes found.");
goto illegal_attrType;
}
- error = validate_content_type_attribute(state,
+ error = validate_content_type_attribute(
attr->attrValues.list.array[0], eci);
content_type_found = true;
} else if (ARCS_EQUAL_OIDS(&attrType, oid_mda)) {
if (message_digest_found) {
- pr_err(state, "Multiple MessageDigests found.");
+ pr_err("Multiple MessageDigests found.");
goto illegal_attrType;
}
- error = validate_message_digest_attribute(state,
+ error = validate_message_digest_attribute(
attr->attrValues.list.array[0]);
message_digest_found = true;
} else if (ARCS_EQUAL_OIDS(&attrType, oid_sta)) {
if (signing_time_found) {
- pr_err(state, "Multiple SigningTimes found.");
+ pr_err("Multiple SigningTimes found.");
goto illegal_attrType;
}
error = 0; /* No validations needed for now. */
} else if (ARCS_EQUAL_OIDS(&attrType, oid_bst)) {
if (binary_signing_time_found) {
- pr_err(state, "Multiple BinarySigningTimes found.");
+ pr_err("Multiple BinarySigningTimes found.");
goto illegal_attrType;
}
error = 0; /* No validations needed for now. */
} else {
/* rfc6488#section-3.1.g */
- pr_err(state, "Illegal attrType OID in SignerInfo.");
+ pr_err("Illegal attrType OID in SignerInfo.");
goto illegal_attrType;
}
/* rfc6488#section-3.1.f */
if (!content_type_found) {
- pr_err(state, "SignerInfo lacks a ContentType attribute.");
+ pr_err("SignerInfo lacks a ContentType attribute.");
return -EINVAL;
}
if (!message_digest_found) {
- pr_err(state, "SignerInfo lacks a MessageDigest attribute.");
+ pr_err("SignerInfo lacks a MessageDigest attribute.");
return -EINVAL;
}
}
static int
-validate(struct validation *state, struct SignedData *sdata)
+validate(struct SignedData *sdata)
{
struct SignerInfo *sinfo;
bool is_digest;
/* rfc6488#section-2.1 */
if (sdata->signerInfos.list.count != 1) {
- pr_err(state,
- "The SignedData's SignerInfo set is supposed to have only one element. (%d given.)",
+ pr_err("The SignedData's SignerInfo set is supposed to have only one element. (%d given.)",
sdata->signerInfos.list.count);
return -EINVAL;
}
/* rfc6488#section-2.1.1 */
/* rfc6488#section-3.1.b */
if (sdata->version != 3) {
- pr_err(state,
- "The SignedData version is only allowed to be 3. (Was %ld.)",
+ pr_err("The SignedData version is only allowed to be 3. (Was %ld.)",
sdata->version);
return -EINVAL;
}
/* rfc6488#section-2.1.2 */
/* rfc6488#section-3.1.j 1/2 */
if (sdata->digestAlgorithms.list.count != 1) {
- pr_err(state,
- "The SignedData's digestAlgorithms set is supposed to have only one element. (%d given.)",
+ pr_err("The SignedData's digestAlgorithms set is supposed to have only one element. (%d given.)",
sdata->digestAlgorithms.list.count);
return -EINVAL;
}
if (error)
return error;
if (!is_digest) {
- pr_err(state,
- "The SignedData's digestAlgorithm OID is not listed in RFC 5754.");
+ pr_err("The SignedData's digestAlgorithm OID is not listed in RFC 5754.");
return -EINVAL;
}
/* rfc6488#section-2.1.4 */
/* rfc6488#section-3.1.c TODO missing half of the requirement. */
if (sdata->certificates == NULL) {
- pr_err(state, "The SignedData does not contain certificates.");
+ pr_err("The SignedData does not contain certificates.");
return -EINVAL;
}
if (sdata->certificates->list.count != 1) {
- pr_err(state,
- "The SignedData contains %d certificates, one expected.",
+ pr_err("The SignedData contains %d certificates, one expected.",
sdata->certificates->list.count);
return -EINVAL;
}
/* rfc6488#section-2.1.5 */
/* rfc6488#section-3.1.d */
if (sdata->crls != NULL && sdata->crls->list.count > 0) {
- pr_err(state, "The SignedData contains at least one crls.");
+ pr_err("The SignedData contains at least one crls.");
return -EINVAL;
}
/* rfc6488#section-3.1.e */
sinfo = sdata->signerInfos.list.array[0];
if (sinfo == NULL) {
- pr_err(state, "The SignerInfo object is NULL.");
+ pr_err("The SignerInfo object is NULL.");
return -EINVAL;
}
if (sinfo->version != 3) {
- pr_err(state,
- "The SignerInfo version is only allowed to be 3. (Was %ld.)",
+ pr_err("The SignerInfo version is only allowed to be 3. (Was %ld.)",
sinfo->version);
return -EINVAL;
}
if (error)
return error;
if (!is_digest) {
- pr_err(state,
- "The SignerInfo digestAlgorithm OID is not listed in RFC 5754.");
+ pr_err("The SignerInfo digestAlgorithm OID is not listed in RFC 5754.");
return -EINVAL;
}
/* rfc6488#section-2.1.6.4 */
- error = validate_signed_attrs(state, sinfo, &sdata->encapContentInfo);
+ error = validate_signed_attrs(sinfo, &sdata->encapContentInfo);
if (error)
return error;
/* rfc6488#section-2.1.6.7 */
/* rfc6488#section-3.1.i */
if (sinfo->unsignedAttrs != NULL && sinfo->unsignedAttrs->list.count > 0) {
- pr_err(state, "SignerInfo has at least one unsignedAttr.");
+ pr_err("SignerInfo has at least one unsignedAttr.");
return -EINVAL;
}
}
int
-signed_data_decode(struct validation *state, ANY_t *coded,
- struct SignedData **result)
+signed_data_decode(ANY_t *coded, struct SignedData **result)
{
struct SignedData *sdata;
int error;
/* rfc6488#section-3.1.l TODO this is BER, not guaranteed to be DER. */
- error = asn1_decode_any(state, coded, &asn_DEF_SignedData,
- (void **) &sdata);
+ error = asn1_decode_any(coded, &asn_DEF_SignedData, (void **) &sdata);
if (error)
return error;
- error = validate(state, sdata);
+ error = validate(sdata);
if (error) {
signed_data_free(sdata);
return error;
/* Caller must free *@result. */
int
-get_content_type_attr(struct validation *state, struct SignedData *sdata,
- OBJECT_IDENTIFIER_t **result)
+get_content_type_attr(struct SignedData *sdata, OBJECT_IDENTIFIER_t **result)
{
struct SignedAttributes *signedAttrs;
struct CMSAttribute *attr;
return -EINVAL;
if (attr->attrValues.list.array[0] == NULL)
return -EINVAL;
- return asn1_decode_any(state,
- attr->attrValues.list.array[0],
+ return asn1_decode_any(attr->attrValues.list.array[0],
&asn_DEF_OBJECT_IDENTIFIER,
(void **) result);
}
/* Some wrappers for libcmscodec's SignedData. */
#include <libcmscodec/SignedData.h>
-#include "state.h"
-int signed_data_decode(struct validation *, ANY_t *, struct SignedData **);
+int signed_data_decode(ANY_t *, struct SignedData **);
void signed_data_free(struct SignedData *);
-int get_content_type_attr(struct validation *, struct SignedData *,
- OBJECT_IDENTIFIER_t **);
+int get_content_type_attr(struct SignedData *, OBJECT_IDENTIFIER_t **);
#endif /* SRC_SIGNED_DATA_H_ */
* You need to free the result once you're done.
*/
int
-uri_g2l(struct validation *state, char const *guri, char **result)
+uri_g2l(char const *guri, char **result)
{
char const *const PREFIX = "rsync://";
char *luri;
prefix_len = strlen(PREFIX);
if (strncmp(PREFIX, guri, prefix_len) != 0) {
- if (state == NULL) {
- warnx("Global URI %s does not begin with '%s'.", guri,
- PREFIX);
- } else {
- pr_err(state, "Global URI %s does not begin with '%s'.",
- guri, PREFIX);
- }
+ pr_err("Global URI %s does not begin with '%s'.", guri,
+ PREFIX);
return -EINVAL;
}
}
int
-gn2uri(struct validation *state, GENERAL_NAME *gn, char const **uri)
+gn2uri(GENERAL_NAME *gn, char const **uri)
{
ASN1_STRING *asn_string;
int type;
asn_string = GENERAL_NAME_get0_value(gn, &type);
if (type != GEN_URI) {
- pr_debug(state, "Unknown GENERAL_NAME type: %d", type);
+ pr_err("Unknown GENERAL_NAME type: %d", type);
return -ENOTSUPPORTED;
}
#include <stdbool.h>
#include <openssl/x509v3.h>
-#include "state.h"
/* "I think that this is not supposed to be implemented." */
#define ENOTSUPPORTED 3172
#define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0]))
bool file_has_extension(char const *, char const *);
-int uri_g2l(struct validation *, char const *, char **);
-int gn2uri(struct validation *, GENERAL_NAME *, char const **);
+int uri_g2l(char const *, char **);
+int gn2uri(GENERAL_NAME *, char const **);
#endif /* SRC_RTR_COMMON_H_ */
}
int
-file_load(struct validation *state, const char *file_name,
- struct file_contents *fc)
+file_load(const char *file_name, struct file_contents *fc)
{
FILE *file;
long int file_size;
int error;
file = fopen(file_name, "rb");
- if (file == NULL) {
- return pr_errno(state, errno, "Could not open file '%s'",
- file_name);
- }
+ if (file == NULL)
+ return pr_errno(errno, "Could not open file '%s'", file_name);
/* TODO if @file is a directory, this returns a very large integer. */
error = get_file_size(file, &file_size);
if (error) {
- pr_errno(state, error, "Could not compute the file size of %s",
+ pr_errno(error, "Could not compute the file size of %s",
file_name);
fclose(file);
return error;
fc->buffer_size = file_size;
fc->buffer = malloc(fc->buffer_size);
if (fc->buffer == NULL) {
- pr_err(state, "Out of memory.");
+ pr_err("Out of memory.");
fclose(file);
return -ENOMEM;
}
* code. It literally doesn't say how to obtain the
* error code.
*/
- pr_errno(state, error,
+ pr_errno(error,
"File reading error. Error message (apparently)",
file_name);
free(fc->buffer);
* As far as I can tell from the man page, feof() cannot return
* less bytes that requested like read() does.
*/
- pr_err(state, "Likely programming error: fread() < file size");
- pr_err(state, "fr:%zu bs:%zu EOF:%d", fread_result,
- fc->buffer_size, feof(file));
+ pr_err("Likely programming error: fread() < file size");
+ pr_err("fr:%zu bs:%zu EOF:%d", fread_result, fc->buffer_size,
+ feof(file));
free(fc->buffer);
fclose(file);
return -EINVAL;
#define SRC_FILE_H_
#include <stddef.h>
-#include "state.h"
/*
* The entire contents of the file, loaded into a buffer.
size_t buffer_size;
};
-int file_load(struct validation *, const char *, struct file_contents *);
+int file_load(const char *, struct file_contents *);
void file_free(struct file_contents *);
#endif /* SRC_FILE_H_ */
static unsigned int indent;
static void
-pr_indent(BIO *stream)
+pr_indent(void)
{
unsigned int __indent = indent;
unsigned int i;
// __indent = INDENT_MAX;
for (i = 0; i < __indent; i++)
- BIO_printf(stream, " ");
+ printf(" ");
}
static void
}
static void
-print_debug_prefix(BIO *bio)
+print_debug_prefix(void)
{
- BIO_printf(bio, "DBG: ");
- pr_indent(bio);
+ printf("DBG: ");
+ pr_indent();
}
#endif
void
-pr_debug(struct validation *state, const char *format, ...)
+pr_debug(const char *format, ...)
{
#ifdef DEBUG
- BIO *bio = validation_stdout(state);
va_list args;
- print_debug_prefix(bio);
+ print_debug_prefix();
va_start(args, format);
- BIO_vprintf(bio, format, args);
+ vprintf(format, args);
va_end(args);
- BIO_printf(bio, "\n");
+ printf("\n");
#endif
}
void
-pr_debug_add(struct validation *state, const char *format, ...)
+pr_debug_add(const char *format, ...)
{
#ifdef DEBUG
- BIO *bio = validation_stdout(state);
va_list args;
- print_debug_prefix(bio);
+ print_debug_prefix();
va_start(args, format);
- BIO_vprintf(bio, format, args);
+ vprintf(format, args);
va_end(args);
- BIO_printf(bio, "\n");
+ printf("\n");
pr_add_indent();
#endif
}
void
-pr_debug_rm(struct validation *state, const char *format, ...)
+pr_debug_rm(const char *format, ...)
{
#ifdef DEBUG
- BIO *bio = validation_stdout(state);
va_list args;
pr_rm_indent();
- print_debug_prefix(bio);
+ print_debug_prefix();
va_start(args, format);
- BIO_vprintf(bio, format, args);
+ vprintf(format, args);
va_end(args);
- BIO_printf(bio, "\n");
+ printf("\n");
#endif
}
* Always appends a newline at the end.
*/
void
-pr_err(struct validation *state, const char *format, ...)
+pr_err(const char *format, ...)
{
- BIO *bio = validation_stderr(state);
va_list args;
va_start(args, format);
- BIO_vprintf(bio, format, args);
+ vfprintf(stderr, format, args);
va_end(args);
- BIO_printf(bio, "\n");
+ fprintf(stderr, "\n");
}
/**
* Always appends a newline at the end.
*/
int
-pr_errno(struct validation *state, int error, const char *format, ...)
+pr_errno(int error, const char *format, ...)
{
- BIO *bio = validation_stderr(state);
va_list args;
va_start(args, format);
- BIO_vprintf(bio, format, args);
+ vfprintf(stderr, format, args);
va_end(args);
if (error) {
- BIO_printf(bio, ": %s", strerror(error));
+ fprintf(stderr, ": %s", strerror(error));
} else {
/* We should assume that there WAS an error; go generic. */
error = -EINVAL;
}
- BIO_printf(bio, "\n");
+ fprintf(stderr, "\n");
return error;
}
va_start(args, format);
BIO_vprintf(bio, format, args);
va_end(args);
+ BIO_printf(bio, ": ");
if (error) {
- BIO_printf(bio, ": ");
/*
* Reminder: This clears the error queue.
* BTW: The string format is pretty ugly. Maybe override this.
ERR_print_errors(bio);
} else {
/* We should assume that there WAS an error; go generic. */
+ BIO_printf(bio, "(There are no error messages in the stack.)");
error = -EINVAL;
}
#include "state.h"
-void pr_debug(struct validation *, const char *, ...);
-void pr_debug_add(struct validation *, const char *, ...);
-void pr_debug_rm(struct validation *, const char *, ...);
+void pr_debug(const char *, ...);
+void pr_debug_add(const char *, ...);
+void pr_debug_rm(const char *, ...);
-void pr_err(struct validation *, const char *, ...);
-int pr_errno(struct validation *, int, const char *, ...);
+void pr_err(const char *, ...);
+int pr_errno(int, const char *, ...);
int crypto_err(struct validation *, const char *, ...);
-#define PR_DEBUG(msg) \
- printf("%s:%d (%s()): " msg "\n", __FILE__, __LINE__, __func__)
+#define PR_DEBUG printf("%s:%d (%s())\n", __FILE__, __LINE__, __func__)
#endif /* SRC_LOG_H_ */
char *cert_file;
int error;
- error = uri_g2l(NULL, uri, &cert_file);
+ error = uri_g2l(uri, &cert_file);
if (error)
return error;
if (error)
goto end1;
- pr_debug_add(state, "TAL URI %s {", uri);
+ pr_debug_add("TAL URI %s {", uri);
if (!is_certificate(uri)) {
- pr_err(state,
- "TAL file does not point to a certificate. (Expected .cer, got '%s')",
+ pr_err("TAL file does not point to a certificate. (Expected .cer, got '%s')",
uri);
error = -ENOTSUPPORTED;
goto end2;
}
- error = certificate_handle_extensions(state, validation_peek(state));
+ error = certificate_traverse(state, validation_peek_cert(state));
end2:
- pr_debug_rm(state, "}");
+ pr_debug_rm("}");
validation_destroy(state);
end1:
free(cert_file);
#include <libcmscodec/SubjectInfoAccessSyntax.h>
#include <openssl/err.h>
-#include <openssl/x509.h>
#include <openssl/x509v3.h>
+#include <libcmscodec/ASIdentifiers.h>
+#include <libcmscodec/IPAddrBlocks.h>
#include "common.h"
#include "log.h"
return file_has_extension(file_name, "cer");
}
-X509 *
-certificate_load(struct validation *state, const char *file)
+int
+certificate_load(struct validation *state, const char *file, X509 **result)
{
X509 *cert = NULL;
BIO *bio;
+ int error;
bio = BIO_new(BIO_s_file());
- if (bio == NULL) {
- crypto_err(state, "BIO_new(BIO_s_file()) returned NULL");
- goto end;
- }
+ if (bio == NULL)
+ return crypto_err(state, "BIO_new(BIO_s_file()) returned NULL");
if (BIO_read_filename(bio, file) <= 0) {
- crypto_err(state, "Error reading certificate '%s'", file);
+ error = crypto_err(state, "Error reading certificate '%s'", file);
goto end;
}
cert = d2i_X509_bio(bio, NULL);
- if (cert == NULL)
- crypto_err(state, "Error parsing certificate '%s'", file);
+ if (cert == NULL) {
+ error = crypto_err(state, "Error parsing certificate '%s'", file);
+ goto end;
+ }
+
+ *result = cert;
+ error = 0;
end:
BIO_free(bio);
- return cert;
+ return error;
}
int
-certificate_handle_extensions(struct validation *state, X509 *cert)
+certificate_validate(struct validation *state, X509 *cert,
+ STACK_OF(X509_CRL) *crls)
+{
+ /*
+ * TODO
+ * The only difference between -CAfile and -trusted, as it seems, is
+ * that -CAfile consults the default file location, while -trusted does
+ * not. As far as I can tell, this means that we absolutely need to use
+ * -trusted.
+ * So, just in case, enable -no-CAfile and -no-CApath.
+ */
+
+ X509_STORE_CTX *ctx;
+ int ok;
+ int error;
+
+ ctx = X509_STORE_CTX_new();
+ if (ctx == NULL) {
+ crypto_err(state, "X509_STORE_CTX_new() returned NULL");
+ return -EINVAL;
+ }
+
+ /* Returns 0 or 1 , all callers test ! only. */
+ ok = X509_STORE_CTX_init(ctx, validation_store(state), cert, NULL);
+ if (!ok) {
+ crypto_err(state, "X509_STORE_CTX_init() returned %d", ok);
+ goto abort;
+ }
+
+ X509_STORE_CTX_trusted_stack(ctx, validation_certs(state));
+ X509_STORE_CTX_set0_crls(ctx, crls);
+
+ /*
+ * HERE'S THE MEAT OF LIBCRYPTO'S VALIDATION.
+ *
+ * Can return negative codes, all callers do <= 0.
+ *
+ * Debugging BTW: If you're looking for ctx->verify,
+ * it might be internal_verify() from x509_vfy.c.
+ */
+ ok = X509_verify_cert(ctx);
+ if (ok <= 0) {
+ /*
+ * ARRRRGGGGGGGGGGGGG
+ * Do not use crypto_err() here; for some reason the proper
+ * error code is stored in the context.
+ */
+ error = X509_STORE_CTX_get_error(ctx);
+ if (error) {
+ pr_err("Certificate validation failed: %s",
+ X509_verify_cert_error_string(error));
+ } else {
+ /*
+ * ...But don't trust X509_STORE_CTX_get_error() either.
+ * That said, there's not much to do about !error,
+ * so hope for the best.
+ */
+ crypto_err(state, "Certificate validation failed: %d",
+ ok);
+ }
+
+ goto abort;
+ }
+
+ X509_STORE_CTX_free(ctx);
+ return 0;
+
+abort:
+ X509_STORE_CTX_free(ctx);
+ return -EINVAL;
+}
+
+/*
+ * "GENERAL_NAME, global to local"
+ * Result has to be freed.
+ */
+static int
+gn_g2l(GENERAL_NAME *name, char **luri)
{
- SIGNATURE_INFO_ACCESS *sia;
- ACCESS_DESCRIPTION *ad;
char const *uri;
- char *luri;
- int nid;
+ int error;
+
+ error = gn2uri(name, &uri);
+ if (error)
+ return error;
+
+ return uri_g2l(uri, luri);
+}
+
+static int
+handle_ip_extension(struct validation *state, X509_EXTENSION *ext,
+ struct resources *resources)
+{
+ ASN1_OCTET_STRING *string;
+ struct IPAddrBlocks *blocks;
int i;
int error;
- sia = X509_get_ext_d2i(cert, NID_sinfo_access, &error, NULL);
- if (sia == NULL) {
- switch (error) {
- case -1:
- pr_err(state, "Certificate lacks an SIA extension.");
- return -ESRCH;
- case -2:
- pr_err(state, "Certificate has more than one SIA extension.");
- return -EINVAL;
- default:
- pr_err(state,
- "X509_get_ext_d2i() returned unknown error code %d.",
- error);
- return -EINVAL;
- }
+ string = X509_EXTENSION_get_data(ext);
+ error = asn1_decode(string->data, string->length, &asn_DEF_IPAddrBlocks,
+ (void **) &blocks);
+ if (error)
+ return error;
+
+ /*
+ * TODO There MUST be only one IPAddressFamily SEQUENCE per AFI.
+ * Each SEQUENCE MUST be ordered by ascending addressFamily values.
+ */
+ for (i = 0; i < blocks->list.count; i++) {
+ error = resources_add_ip(resources, blocks->list.array[i],
+ validation_peek_resource(state));
+ if (error)
+ break;
}
- pr_debug_add(state, "SIA {");
- error = 0;
+ ASN_STRUCT_FREE(asn_DEF_IPAddrBlocks, blocks);
+ return error;
+}
- for (i = 0; i < sk_ACCESS_DESCRIPTION_num(sia); i++) {
- ad = sk_ACCESS_DESCRIPTION_value(sia, i);
- nid = OBJ_obj2nid(ad->method);
+static int
+handle_asn_extension(struct validation *state, X509_EXTENSION *ext,
+ struct resources *resources)
+{
+ ASN1_OCTET_STRING *string;
+ struct ASIdentifiers *ids;
+ int error;
- if (nid == NID_rpkiManifest) {
- error = gn2uri(state, ad->location, &uri);
- if (error)
- goto end;
- error = uri_g2l(state, uri, &luri);
- if (error)
- goto end;
- error = handle_manifest(state, luri);
- free(luri);
- if (error)
- goto end;
+ string = X509_EXTENSION_get_data(ext);
+ error = asn1_decode(string->data, string->length,
+ &asn_DEF_ASIdentifiers, (void **) &ids);
+ if (error)
+ return error;
- } else if (nid == NID_rpkiNotify) {
- /* TODO Another fucking RFC... */
- pr_debug(state, "Unimplemented thingy: rpkiNotify");
+ error = resources_add_asn(resources, ids,
+ validation_peek_resource(state));
- } else if (nid == NID_caRepository) {
- error = gn2uri(state, ad->location, &uri);
- if (error)
- goto end;
- /* TODO no idea what to do with this. */
- pr_debug(state, "CA Repository URI: %s", uri);
+ ASN_STRUCT_FREE(asn_DEF_ASIdentifiers, ids);
+ return error;
+}
- } else {
- pr_debug(state, "Unknown NID: %d", nid);
- goto end;
+int
+certificate_get_resources(struct validation *state, X509 *cert,
+ struct resources *resources)
+{
+ X509_EXTENSION *ext;
+ int i;
+ int error = 0;
+
+ /* Reference: X509_get_ext_d2i */
+ /* TODO ensure that each extension can only be found once. */
+
+ for (i = 0; i < X509_get_ext_count(cert); i++) {
+ ext = X509_get_ext(cert, i);
+
+ switch (OBJ_obj2nid(X509_EXTENSION_get_object(ext))) {
+ case NID_sbgp_ipAddrBlock:
+ pr_debug_add("IP {");
+ error = handle_ip_extension(state, ext, resources);
+ pr_debug_rm("}");
+ break;
+ case NID_sbgp_autonomousSysNum:
+ pr_debug_add("ASN {");
+ error = handle_asn_extension(state, ext, resources);
+ pr_debug_rm("}");
+ break;
}
+
+ if (error)
+ return error;
}
-end:
- AUTHORITY_INFO_ACCESS_free(sia);
- pr_debug_rm(state, "}");
return error;
}
-int
-certificate_handle(struct validation *state, char const *file)
+int certificate_traverse(struct validation *state, X509 *cert)
{
- X509 *certificate;
+ SIGNATURE_INFO_ACCESS *sia;
+ ACCESS_DESCRIPTION *ad;
+ char *uri;
+ int i;
int error;
- pr_debug_add(state, "Certificate {");
-
- certificate = certificate_load(state, file);
- if (certificate == NULL) {
- /* TODO get the right one through the ERR_* functions. */
- error = -EINVAL;
- goto end;
+ sia = X509_get_ext_d2i(cert, NID_sinfo_access, NULL, NULL);
+ if (sia == NULL) {
+ pr_err("Certificate lacks a Subject Information Access extension.");
+ return -ESRCH;
}
- error = validation_push(state, certificate);
- if (error)
- goto end;
+ error = 0;
+ for (i = 0; i < sk_ACCESS_DESCRIPTION_num(sia); i++) {
+ ad = sk_ACCESS_DESCRIPTION_value(sia, i);
- error = certificate_handle_extensions(state, certificate);
- validation_pop(state);
+ if (OBJ_obj2nid(ad->method) == NID_rpkiManifest) {
+ error = gn_g2l(ad->location, &uri);
+ if (error)
+ goto end;
+ error = handle_manifest(state, uri);
+ free(uri);
+ if (error)
+ goto end;
+ }
+ }
end:
- pr_debug_rm(state, "}");
+ AUTHORITY_INFO_ACCESS_free(sia);
return error;
}
#define SRC_OBJECT_CERTIFICATE_H_
#include <stdbool.h>
+#include <openssl/x509.h>
+#include "resource.h"
#include "state.h"
bool is_certificate(char const *);
-X509 *certificate_load(struct validation *, const char *);
-int certificate_handle(struct validation *, char const *);
-int certificate_handle_extensions(struct validation *, X509 *);
+int certificate_load(struct validation *, const char *, X509 **);
+
+/*
+ * Note: You actually need all three of these functions for a full validation;
+ * certificate_validate() checks the certificate's relationship with its
+ * parents, certificate_get_resources() covers the IP and ASN extensions, and
+ * you will need certificate_traverse() to walk through the children.
+ */
+
+int certificate_validate(struct validation *, X509 *, STACK_OF(X509_CRL) *);
+int certificate_get_resources(struct validation *, X509 *, struct resources *);
+int certificate_traverse(struct validation *, X509 *);
#endif /* SRC_OBJECT_CERTIFICATE_H_ */
#include <libcmscodec/SubjectInfoAccessSyntax.h>
#include <openssl/err.h>
-#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include "common.h"
#include "manifest.h"
#include "asn1/decode.h"
-bool is_crl(char const *file_name)
-{
- return file_has_extension(file_name, "crl");
-}
-
-static X509_CRL *
-load_crl(struct validation *state, const char *file)
+static int
+__crl_load(struct validation *state, const char *file, X509_CRL **result)
{
X509_CRL *crl = NULL;
BIO *bio;
+ int error;
bio = BIO_new(BIO_s_file());
- if (bio == NULL) {
- crypto_err(state, "BIO_new(BIO_s_file()) returned NULL");
- goto end;
- }
+ if (bio == NULL)
+ return crypto_err(state, "BIO_new(BIO_s_file()) returned NULL");
if (BIO_read_filename(bio, file) <= 0) {
- crypto_err(state, "Error reading CRL '%s'", file);
+ error = crypto_err(state, "Error reading CRL '%s'", file);
goto end;
}
crl = d2i_X509_CRL_bio(bio, NULL);
- if (crl == NULL)
- crypto_err(state, "Error parsing CRL '%s'", file);
-
-end:
- BIO_free(bio);
- return crl;
-}
-
-static int
-handle_authority_key_identifier(struct validation *state, X509_EXTENSION *ext)
-{
- /* TODO */
- pr_debug(state, "Unimplemented still: Authority Key Identifier");
- /* AUTHORITY_KEYID *aki = X509V3_EXT_d2i(ext); */
- /* AUTHORITY_KEYID_free(aki); */
- return 0;
-}
-
-static int
-handle_revoked(struct validation *state, X509_REVOKED *revoked)
-{
- const ASN1_INTEGER *serialNumber;
- const ASN1_TIME *revocationDate;
-
- serialNumber = X509_REVOKED_get0_serialNumber(revoked);
- revocationDate = X509_REVOKED_get0_revocationDate(revoked);
-
- if (serialNumber == NULL) {
- pr_err(state, "Revoked entry's serial number is NULL.");
- return -EINVAL;
- }
- if (revocationDate == NULL) {
- pr_err(state, "Revoked entry's revocation date is NULL.");
- return -EINVAL;
- }
- if (X509_REVOKED_get0_extensions(revoked) != NULL) {
- pr_err(state, "Revoked entry's extension list is not NULL.");
- return -EINVAL;
- }
-
- pr_debug(state, "Revoked:%ld", ASN1_INTEGER_get(serialNumber));
-// ASN1_TIME_print(bio_err, revocationDate);
-// printf("\n");
- return 0;
-}
-
-static int
-handle_revoked_list(struct validation *state, X509_CRL *crl)
-{
- STACK_OF(X509_REVOKED) *list;
- unsigned int i;
- int error;
-
- list = X509_CRL_get_REVOKED(crl);
- for (i = 0; i < sk_X509_REVOKED_num(list); i++) {
- error = handle_revoked(state, sk_X509_REVOKED_value(list, i));
- if (error)
- return error;
+ if (crl == NULL) {
+ error = crypto_err(state, "Error parsing CRL '%s'", file);
+ goto end;
}
- return 0;
-}
+ *result = crl;
+ error = 0;
-static int
-handle_crl_number(struct validation *state, X509_EXTENSION *ext)
-{
- pr_debug(state, "Unimplemented still: CRL Number"); /* TODO */
- return 0;
-}
-
-static int
-handle_extensions(struct validation *state, X509_CRL *crl)
-{
- const STACK_OF(X509_EXTENSION) *exts;
- X509_EXTENSION *ext;
- unsigned int i;
- int nid;
- int error;
-
- exts = X509_CRL_get0_extensions(crl);
- for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
- ext = sk_X509_EXTENSION_value(exts, i);
- nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext));
-
- switch (nid) {
- case NID_authority_key_identifier:
- error = handle_authority_key_identifier(state, ext);
- break;
- case NID_crl_number:
- error = handle_crl_number(state, ext);
- break;
- default:
- pr_err(state, "CRL has illegal extension: NID %d", nid);
- return -EINVAL;
- }
-
- if (error)
- return error;
- }
-
- return 0;
+end:
+ BIO_free(bio);
+ return error;
}
int
-handle_crl(struct validation *state, char const *file)
+crl_load(struct validation *state, char const *file, X509_CRL **result)
{
- X509_CRL *crl;
int error;
- pr_debug_add(state, "CRL {");
-
- crl = load_crl(state, file);
- if (!crl) {
- /* TODO get the right one through the ERR_* functions. */
- error = -EINVAL;
- goto abort2;
- }
-
- error = handle_revoked_list(state, crl);
- if (error)
- goto abort3;
-
- error = handle_extensions(state, crl);
+ pr_debug_add("CRL {");
+ error = __crl_load(state, file, result);
+ pr_debug_rm("}");
-abort3:
- X509_CRL_free(crl);
-abort2:
- pr_debug_rm(state, "}");
return error;
}
#define SRC_OBJECT_CRL_H_
#include <stdbool.h>
+#include <openssl/x509.h>
#include "state.h"
-bool is_crl(char const *);
-int handle_crl(struct validation *, char const *);
+int crl_load(struct validation *, char const *, X509_CRL **);
#endif /* SRC_OBJECT_CRL_H_ */
#include "common.h"
#include "log.h"
+#include "resource.h"
#include "asn1/oid.h"
#include "object/certificate.h"
#include "object/crl.h"
#include "object/roa.h"
#include "object/signed_object.h"
-/* TODO not being called right now. */
-bool
-is_manifest(char const *file_name)
-{
- return file_has_extension(file_name, "mft");
-}
+struct manifest {
+ struct Manifest *obj;
+ char const *file_path;
+};
static int
validate_dates(GeneralizedTime_t *this, GeneralizedTime_t *next)
return 0;
}
+typedef int (*foreach_cb)(struct validation *, char *, void *);
+
+struct foreach_args {
+ STACK_OF(X509_CRL) *crls;
+ struct resources *resources;
+};
+
static int
-handle_file(struct validation *state, char const *mft, IA5String_t *string)
+foreach_file(struct validation *state, struct manifest *mft, char *extension,
+ foreach_cb cb, void *arg)
{
- char *luri;
+ char *uri;
+ char *luri; /* "Local URI". As in "URI that we can easily reference." */
+ int i;
int error;
- /* TODO Treating string->buf as a C string is probably not correct. */
-// pr_debug_add(state, "File %s {", string->buf);
+ for (i = 0; i < mft->obj->fileList.list.count; i++) {
+ /* TODO This cast is probably not correct. */
+ uri = (char *) mft->obj->fileList.list.array[i]->file.buf;
+
+ if (file_has_extension(uri, extension)) {
+ error = get_relative_file(mft->file_path, uri, &luri);
+ if (error)
+ return error;
+ error = cb(state, luri, arg);
+ free(luri);
+ if (error)
+ return error;
+ }
+ }
+
+ return 0;
+}
- error = get_relative_file(mft, (char const *) string->buf, &luri);
+static int
+pile_crls(struct validation *state, char *file, void *crls)
+{
+ X509_CRL *crl;
+ int error;
+ int idx;
+
+ error = crl_load(state, file, &crl);
if (error)
- goto end;
+ return error;
+
+ idx = sk_X509_CRL_push(crls, crl);
+ if (idx <= 0) {
+ error = crypto_err(state, "Could not add CRL to a CRL stack");
+ X509_CRL_free(crl);
+ return error;
+ }
+
+ return 0;
+}
+
+static int
+pile_addr_ranges(struct validation *state, char *file, void *__args)
+{
+ struct foreach_args *args = __args;
+ struct resources *resources;
+ X509 *cert;
+ int error = 0;
+
+ pr_debug_add("Certificate {");
+
+ /*
+ * Errors on some of these functions should not interrupt the tree
+ * traversal, so ignore them.
+ * (Error messages should have been printed in stderr.)
+ */
- pr_debug_add(state, "File %s {", luri);
+ if (certificate_load(state, file, &cert))
+ goto end; /* Fine */
- if (is_certificate(luri))
- error = certificate_handle(state, luri);
- else if (is_crl(luri))
- error = handle_crl(state, luri);
- else if (is_roa(luri))
- error = handle_roa(state, luri);
- else
- pr_debug(state, "Unhandled file type.");
+ if (certificate_validate(state, cert, args->crls))
+ goto revert; /* Fine */
- free(luri);
+ resources = resources_create();
+ if (resources == NULL) {
+ error = -ENOMEM; /* Not fine */
+ goto revert;
+ }
+
+ if (certificate_get_resources(state, cert, resources))
+ goto revert2; /* Fine */
+
+ if (validation_push_cert(state, cert, resources)) {
+ /*
+ * Validation_push_cert() only fails on OPENSSL_sk_push().
+ * The latter really only fails on memory allocation fault.
+ * That's grounds to interrupt tree traversal.
+ */
+ error = -EINVAL; /* Not fine */
+ goto revert2;
+ }
+ certificate_traverse(state, cert); /* Error code is useless. */
+ validation_pop_cert(state); /* Error code is useless. */
+
+ error = resources_join(args->resources, resources); /* Not fine */
+
+revert2:
+ resources_destroy(resources);
+revert:
+ X509_free(cert);
end:
- pr_debug_rm(state, "}");
+ pr_debug_rm("}");
return error;
}
static int
-__handle_manifest(struct validation *state, char const *mft,
- struct Manifest *manifest)
+print_roa(struct validation *state, char *file, void *arg)
{
- int i;
+ /* TODO */
+ handle_roa(file);
+ return 0;
+}
+
+static int
+__handle_manifest(struct validation *state, struct manifest *mft)
+{
+ struct foreach_args args;
int error;
- for (i = 0; i < manifest->fileList.list.count; i++) {
- error = handle_file(state, mft,
- &manifest->fileList.list.array[i]->file);
- if (error)
- return error;
+ /* Init */
+ args.crls = sk_X509_CRL_new_null();
+ if (args.crls == NULL) {
+ pr_err("Out of memory.");
+ return -ENOMEM;
}
- return 0;
+ args.resources = resources_create();
+ if (args.resources == NULL) {
+ sk_X509_CRL_free(args.crls);
+ return -ENOMEM;
+ }
+
+ /* Get CRLs as a stack. There will usually only be one. */
+ error = foreach_file(state, mft, "crl", pile_crls, args.crls);
+ if (error)
+ goto end;
+
+ /*
+ * Use CRL stack to validate certificates.
+ * Pile up valid address ranges from the valid certificates.
+ */
+ error = foreach_file(state, mft, "cer", pile_addr_ranges, &args);
+ if (error)
+ goto end;
+
+ /* Use valid address ranges to print ROAs that match them. */
+ error = foreach_file(state, mft, "roa", print_roa, &args);
+
+end:
+ resources_destroy(args.resources);
+ sk_X509_CRL_pop_free(args.crls, X509_CRL_free);
+ return error;
}
int
{
static OID oid = OID_MANIFEST;
struct oid_arcs arcs = OID2ARCS(oid);
- struct Manifest *manifest;
+ struct manifest mft;
int error;
- error = signed_object_decode(state, file_path, &asn_DEF_Manifest, &arcs,
- (void **) &manifest);
+ mft.file_path = file_path;
+
+ error = signed_object_decode(file_path, &asn_DEF_Manifest, &arcs,
+ (void **) &mft.obj);
if (error)
return error;
- error = validate_manifest(manifest);
+ error = validate_manifest(mft.obj);
if (!error)
- error = __handle_manifest(state, file_path, manifest);
+ error = __handle_manifest(state, &mft);
- ASN_STRUCT_FREE(asn_DEF_Manifest, manifest);
+ ASN_STRUCT_FREE(asn_DEF_Manifest, mft.obj);
return error;
}
#include <stdbool.h>
#include "state.h"
-bool is_manifest(char const *);
int handle_manifest(struct validation *, char const *);
#endif /* SRC_OBJECT_MANIFEST_H_ */
#include "asn1/oid.h"
#include "object/signed_object.h"
-bool is_roa(char const *file_name)
-{
- return file_has_extension(file_name, "roa");
-}
-
static int
-validate_roa(struct validation *state, struct RouteOriginAttestation *roa)
+validate_roa(struct RouteOriginAttestation *roa)
{
/* rfc6482#section-3.1 */
if (roa->version != 0) {
- pr_err(state, "ROA's version (%ld) is nonzero.", roa->version);
+ pr_err("ROA's version (%ld) is nonzero.", roa->version);
return -EINVAL;
}
}
static int
-print_addr(struct validation *state, long asn, uint8_t family,
- struct ROAIPAddress *roa_addr)
+print_addr(long asn, uint8_t family, struct ROAIPAddress *roa_addr)
{
union {
struct in6_addr ip6;
family = AF_INET6;
break;
default:
- pr_err(state, "Unknown family value: %u", family);
+ pr_err("Unknown family value: %u", family);
return -EINVAL;
}
memcpy(&addr, roa_addr->address.buf, roa_addr->address.size);
str2 = inet_ntop(family, &addr, str.ip6, sizeof(str));
if (str2 == NULL)
- return pr_errno(state, errno, "Cannot parse IP address");
+ return pr_errno(errno, "Cannot parse IP address");
prefix_len = 8 * roa_addr->address.size - roa_addr->address.bits_unused;
}
static int
-__handle_roa(struct validation *state, struct RouteOriginAttestation *roa)
+__handle_roa(struct RouteOriginAttestation *roa)
{
struct ROAIPAddressFamily *block;
int b;
if (block->addresses.list.array == NULL)
return -EINVAL;
for (a = 0; a < block->addresses.list.count; a++) {
- error = print_addr(state, roa->asID,
+ error = print_addr(roa->asID,
block->addressFamily.buf[1],
block->addresses.list.array[a]);
if (error)
return 0;
}
-int handle_roa(struct validation *state, char const *file)
+int handle_roa(char const *file)
{
static OID oid = OID_ROA;
struct oid_arcs arcs = OID2ARCS(oid);
struct RouteOriginAttestation *roa;
int error;
- error = signed_object_decode(state, file,
- &asn_DEF_RouteOriginAttestation, &arcs, (void **) &roa);
+ pr_debug_add("ROA {");
+
+ error = signed_object_decode(file, &asn_DEF_RouteOriginAttestation,
+ &arcs, (void **) &roa);
if (error)
- return error;
+ goto end;
- error = validate_roa(state, roa);
+ error = validate_roa(roa);
if (!error)
- error = __handle_roa(state, roa);
+ error = __handle_roa(roa);
ASN_STRUCT_FREE(asn_DEF_RouteOriginAttestation, roa);
+end:
+ pr_debug_rm("}");
return error;
}
#define SRC_OBJECT_ROA_H_
#include <stdbool.h>
-#include "state.h"
-bool is_roa(char const *);
-int handle_roa(struct validation *, char const *);
+int handle_roa(char const *);
#endif /* SRC_OBJECT_ROA_H_ */
#include "asn1/signed_data.h"
static int
-validate_eContentType(struct validation *state,
- struct SignedData *sdata,
+validate_eContentType(struct SignedData *sdata,
asn_TYPE_descriptor_t const *descriptor,
struct oid_arcs const *oid)
{
equals = arcs_equal(&arcs, oid);
free_arcs(&arcs);
if (!equals) {
- pr_err(state,
- "SignedObject's encapContentInfo lacks the OID of a %s.",
+ pr_err("SignedObject's encapContentInfo lacks the OID of a %s.",
descriptor->name);
return -EINVAL;
}
}
static int
-validate_content_type(struct validation *state,
- struct SignedData *sdata,
+validate_content_type(struct SignedData *sdata,
asn_TYPE_descriptor_t const *descriptor,
struct oid_arcs const *oid)
{
bool equals;
int error;
- error = get_content_type_attr(state, sdata, &ctype);
+ error = get_content_type_attr(sdata, &ctype);
if (error)
return error;
error = oid2arcs(ctype, &arcs);
equals = arcs_equal(&arcs, oid);
free_arcs(&arcs);
if (!equals) {
- pr_err(state,
- "SignedObject's content type attribute lacks the OID of a %s.",
+ pr_err("SignedObject's content type attribute lacks the OID of a %s.",
descriptor->name);
return -EINVAL;
}
}
int
-signed_object_decode(struct validation *state,
- char const *file,
+signed_object_decode(char const *file,
asn_TYPE_descriptor_t const *descriptor,
struct oid_arcs const *oid,
void **result)
struct SignedData *sdata;
int error;
- error = content_info_load(state, file, &cinfo);
+ error = content_info_load(file, &cinfo);
if (error)
goto end1;
- error = signed_data_decode(state, &cinfo->content, &sdata);
+ error = signed_data_decode(&cinfo->content, &sdata);
if (error)
goto end2;
/* rfc6482#section-2 */
/* rfc6486#section-4.1 */
/* rfc6486#section-4.4.1 */
- error = validate_eContentType(state, sdata, descriptor, oid);
+ error = validate_eContentType(sdata, descriptor, oid);
if (error)
goto end3;
/* rfc6482#section-2 */
/* rfc6486#section-4.3 */
- error = validate_content_type(state, sdata, descriptor, oid);
+ error = validate_content_type(sdata, descriptor, oid);
if (error)
goto end3;
- error = asn1_decode_octet_string(state,
- sdata->encapContentInfo.eContent, descriptor, result);
+ error = asn1_decode_octet_string(sdata->encapContentInfo.eContent,
+ descriptor, result);
end3: signed_data_free(sdata);
end2: content_info_free(cinfo);
#include "asn1/oid.h"
-int signed_object_decode(struct validation *, char const *,
- asn_TYPE_descriptor_t const *, struct oid_arcs const *, void **);
+int signed_object_decode(char const *, asn_TYPE_descriptor_t const *,
+ struct oid_arcs const *, void **);
#endif /* SRC_OBJECT_SIGNED_OBJECT_H_ */
--- /dev/null
+#include "resource.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+
+#include "address.h"
+#include "log.h"
+#include "sorted_array.h"
+
+struct resource4 {
+ struct ipv4_prefix prefix;
+};
+
+struct resource6 {
+ struct ipv6_prefix prefix;
+};
+
+struct resource_asn {
+ ASId_t min;
+ ASId_t max;
+};
+
+/* The resources we extracted from one certificate. */
+struct resources {
+ struct sorted_array *ip4s;
+ struct sorted_array *ip6s;
+ struct sorted_array *asns;
+
+ /*
+ * Used by restack. Points to the resources of the parent certificate.
+ */
+ SLIST_ENTRY(resources) next;
+};
+
+/*
+ * "Resource stack". It's a chain of resources, to complement a chain of
+ * certificates.
+ */
+SLIST_HEAD(restack, resources);
+
+static enum sarray_comparison
+ip4_cmp(void *arg1, void *arg2)
+{
+ struct ipv4_prefix *p1 = &((struct resource4 *) arg1)->prefix;
+ struct ipv4_prefix *p2 = &((struct resource4 *) arg2)->prefix;
+ uint32_t a1;
+ uint32_t a2;
+
+ if (p1->addr.s_addr == p2->addr.s_addr && p1->len == p2->len)
+ return SACMP_EQUAL;
+ if (prefix4_contains(p1, p2))
+ return SACMP_CHILD;
+ if (prefix4_contains(p2, p1))
+ return SACMP_PARENT;
+
+ a1 = ntohl(p1->addr.s_addr);
+ a2 = ntohl(p2->addr.s_addr);
+ if (a1 < a2)
+ return SACMP_RIGHT;
+ if (a2 < a1)
+ return SACMP_LEFT;
+
+ /* TODO Actually an error. Do something about it? */
+ return SACMP_INTERSECTION;
+}
+
+static enum sarray_comparison
+ip6_cmp(void *arg1, void *arg2)
+{
+ struct ipv6_prefix *p1 = &((struct resource6 *) arg1)->prefix;
+ struct ipv6_prefix *p2 = &((struct resource6 *) arg2)->prefix;
+ struct in6_addr *a1 = &p1->addr;
+ struct in6_addr *a2 = &p2->addr;
+ uint32_t q1;
+ uint32_t q2;
+ unsigned int q;
+
+ if (memcmp(a1, a2, sizeof(*a1)) == 0 && p1->len == p2->len)
+ return SACMP_EQUAL;
+ if (prefix6_contains(p1, p2))
+ return SACMP_CHILD;
+ if (prefix6_contains(p2, p1))
+ return SACMP_PARENT;
+
+ for (q = 0; q < 4; q++) {
+ q1 = ntohl(p1->addr.s6_addr32[q]);
+ q2 = ntohl(p2->addr.s6_addr32[q]);
+ if (q1 < q2)
+ return SACMP_RIGHT;
+ if (q2 < q1)
+ return SACMP_LEFT;
+ }
+
+ /* TODO Actually an error. Do something about it? */
+ return SACMP_INTERSECTION;
+}
+
+static enum sarray_comparison
+asn_cmp(void *arg1, void *arg2)
+{
+ struct resource_asn *asn1 = arg1;
+ struct resource_asn *asn2 = arg2;
+
+ if (asn1->min == asn2->min && asn1->max == asn2->max)
+ return SACMP_EQUAL;
+ if (asn1->min <= asn2->min && asn2->max <= asn1->max)
+ return SACMP_CHILD;
+ if (asn2->min <= asn1->min && asn1->max <= asn2->max)
+ return SACMP_PARENT;
+ if (asn1->max < asn2->min)
+ return SACMP_RIGHT;
+ if (asn2->max < asn1->min)
+ return SACMP_LEFT;
+
+ return SACMP_INTERSECTION;
+}
+
+SARRAY_API(r4array, resource4, ip4_cmp)
+SARRAY_API(r6array, resource6, ip6_cmp)
+SARRAY_API(asnarray, resource_asn, asn_cmp)
+
+struct resources *
+resources_create(void)
+{
+ struct resources *result;
+
+ result = malloc(sizeof(struct resources));
+ if (result == NULL) {
+ pr_err("Out of memory.");
+ return NULL;
+ }
+
+ result->ip4s = NULL;
+ result->ip6s = NULL;
+ result->asns = NULL;
+
+ return result;
+}
+
+void
+resources_destroy(struct resources *resources)
+{
+ if (resources->ip4s != NULL)
+ r4array_put(resources->ip4s);
+ if (resources->ip6s != NULL)
+ r6array_put(resources->ip6s);
+ if (resources->asns != NULL)
+ asnarray_put(resources->asns);
+ free(resources);
+}
+
+static int
+get_addr_family(OCTET_STRING_t *octets)
+{
+ if (octets->size != 2) {
+ pr_err("Address family has %d octets. (2 expected.)",
+ octets->size);
+ return -1;
+ }
+
+ if (octets->buf[0] != 0)
+ goto unknown;
+ switch (octets->buf[1]) {
+ case 1:
+ return AF_INET;
+ case 2:
+ return AF_INET6;
+ }
+
+unknown:
+ pr_err("Address family has unknown value 0x%02x%02x.", octets->buf[0],
+ octets->buf[1]);
+ return -1;
+}
+
+static void
+pr_debug_prefix(int family, void *addr, 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 int
+inherit_aors(struct resources *resources, int family, struct resources *parent)
+{
+ switch (family) {
+ case AF_INET:
+ if (resources->ip4s != NULL) {
+ pr_err("Oh noes4"); /* TODO */
+ return -EINVAL;
+ }
+ if (parent->ip4s == NULL) {
+ pr_err("Certificate inherits IPv4 resources from parent, but parent lacks IPv4 resources.");
+ return -EINVAL;
+ }
+ resources->ip4s = parent->ip4s;
+ r4array_get(resources->ip4s);
+ return 0;
+
+ case AF_INET6:
+ if (resources->ip6s != NULL) {
+ pr_err("Oh noes6"); /* TODO */
+ return -EINVAL;
+ }
+ if (parent->ip6s == NULL) {
+ pr_err("Certificate inherits IPv6 resources from parent, but parent lacks IPv6 resources.");
+ return -EINVAL;
+ }
+ resources->ip6s = parent->ip6s;
+ r6array_get(resources->ip6s);
+ return 0;
+ }
+
+ pr_err("Programming error: Unknown IP family: %d", family);
+ return -EINVAL;
+}
+
+static int
+decode_prefix4(BIT_STRING_t *str, struct ipv4_prefix *result)
+{
+ /* TODO validate bits unused and stuff */
+ if (str->size > 4) {
+ pr_err("IPv4 address has too many octets. (%u)", str->size);
+ return -EINVAL;
+ }
+
+ memset(&result->addr, 0, sizeof(result->addr));
+ memcpy(&result->addr, str->buf, str->size);
+ result->len = 8 * str->size - str->bits_unused;
+ return 0;
+}
+
+static int
+decode_prefix6(BIT_STRING_t *str, struct ipv6_prefix *result)
+{
+ if (str->size > 16) {
+ pr_err("IPv6 address has too many octets. (%u)", str->size);
+ return -EINVAL;
+ }
+
+ memset(&result->addr, 0, sizeof(result->addr));
+ memcpy(&result->addr, str->buf, str->size);
+ result->len = 8 * str->size - str->bits_unused;
+ return 0;
+}
+
+static int
+add_prefix4(struct resources *resources, IPAddress2_t *addr,
+ struct resources *parent)
+{
+ struct resource4 r4;
+ int error;
+
+ error = decode_prefix4(addr, &r4.prefix);
+ if (error)
+ return error;
+
+ if (parent && !r4array_contains(parent->ip4s, &r4)) {
+ pr_err("Parent certificate doesn't own child's IPv4 resource.");
+ return -EINVAL;
+ }
+
+ if (resources->ip4s == NULL) {
+ resources->ip4s = r4array_create();
+ if (resources->ip4s == NULL) {
+ pr_err("Out of memory.");
+ return -ENOMEM;
+ }
+ }
+
+ error = r4array_add(resources->ip4s, &r4);
+ if (error)
+ return error; /* TODO error message */
+
+ pr_debug_prefix(AF_INET, &r4.prefix.addr, r4.prefix.len);
+ return 0;
+}
+
+static int
+add_prefix6(struct resources *resources, IPAddress2_t *addr,
+ struct resources *parent)
+{
+ struct resource6 r6;
+ int error;
+
+ error = decode_prefix6(addr, &r6.prefix);
+ if (error)
+ return error;
+
+ if (parent && !r6array_contains(parent->ip6s, &r6)) {
+ pr_err("Parent certificate doesn't own child's IPv6 resource.");
+ return -EINVAL;
+ }
+
+ if (resources->ip6s == NULL) {
+ resources->ip6s = r6array_create();
+ if (resources->ip6s == NULL) {
+ pr_err("Out of memory.");
+ return -ENOMEM;
+ }
+ }
+
+ error = r6array_add(resources->ip6s, &r6);
+ if (error)
+ return error; /* TODO error message */
+
+ pr_debug_prefix(AF_INET6, &r6.prefix.addr, r6.prefix.len);
+ return 0;
+}
+
+static int
+add_prefix(struct resources *resources, int family, IPAddress2_t *addr,
+ struct resources *parent)
+{
+ switch (family) {
+ case AF_INET:
+ return add_prefix4(resources, addr, parent);
+ case AF_INET6:
+ return add_prefix6(resources, addr, parent);
+ }
+
+ pr_err("Unknown address family: %d", family);
+ return 0;
+}
+
+static int
+add_aors(struct resources *resources, int family,
+ struct IPAddressChoice__addressesOrRanges *aors, struct resources *parent)
+{
+ struct IPAddressOrRange *aor;
+ int i;
+ int error = 0;
+
+ /*
+ * TODO The addressPrefix and addressRange elements MUST be sorted
+ * using the binary representation of (...)
+ * TODO Any pair of IPAddressOrRange choices in
+ * an extension MUST NOT overlap each other.
+ */
+
+ for (i = 0; i < aors->list.count; i++) {
+ aor = aors->list.array[i];
+ switch (aor->present) {
+ case IPAddressOrRange_PR_addressPrefix:
+ error = add_prefix(resources, family,
+ &aor->choice.addressPrefix, parent);
+ if (error)
+ return error;
+ break;
+ case IPAddressOrRange_PR_addressRange:
+ /*
+ * We're definitely not supposed to support this.
+ *
+ * rfc3779#section-2.2.3.7 says "This specification
+ * requires that any range of addresses that can be
+ * encoded as a prefix MUST be encoded using an
+ * IPAddress element (...), and any range that cannot be
+ * encoded as a prefix MUST be encoded using an
+ * IPAddressRange (...).
+ *
+ * rfc6482#section-3.3 says "Note that the syntax here
+ * is more restrictive than that used in the IP address
+ * delegation extension defined in RFC 3779. That
+ * extension can represent arbitrary address ranges,
+ * whereas ROAs need to represent only prefixes."
+ */
+ pr_err("IPAddressOrRange is a range. This is unsupported.");
+ return -EINVAL;
+ case IPAddressOrRange_PR_NOTHING:
+ /* rfc3779#section-2.2.3.7 */
+ pr_err("Unknown IPAddressOrRange type: %d",
+ aor->present);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int
+resources_add_ip(struct resources *resources, struct IPAddressFamily *obj,
+ struct resources *parent)
+{
+ int family;
+
+ family = get_addr_family(&obj->addressFamily);
+ if (family == -1)
+ return -EINVAL;
+
+ switch (obj->ipAddressChoice.present) {
+ case IPAddressChoice_PR_NOTHING:
+ break;
+ case IPAddressChoice_PR_inherit:
+ return inherit_aors(resources, family, parent);
+ case IPAddressChoice_PR_addressesOrRanges:
+ return add_aors(resources, family,
+ &obj->ipAddressChoice.choice.addressesOrRanges, parent);
+ }
+
+ /* rfc3779#section-2.2.3.4 */
+ pr_err("Unknown ipAddressChoice type: %d",
+ obj->ipAddressChoice.present);
+ return -EINVAL;
+}
+
+static int
+inherit_asiors(struct resources *resources, struct resources *parent)
+{
+ if (resources->asns != NULL) {
+ pr_err("Oh noesa"); /* TODO */
+ return -EINVAL;
+ }
+ if (parent->asns == NULL) {
+ pr_err("Certificate inherits ASN resources from parent, but parent lacks ASN resources.");
+ return -EINVAL;
+ }
+ resources->asns = parent->asns;
+ asnarray_get(resources->asns);
+ return 0;
+}
+
+static int
+add_asn(struct resources *resources, ASId_t min, ASId_t max,
+ struct resources *parent)
+{
+ struct resource_asn ra;
+ int error;
+
+ if (resources->asns == NULL) {
+ resources->asns = asnarray_create();
+ if (resources->asns == NULL) {
+ pr_err("Out of memory.");
+ return -ENOMEM;
+ }
+ }
+
+ ra.min = min;
+ ra.max = max;
+ error = asnarray_add(resources->asns, &ra);
+ if (error)
+ return error; /* TODO error msg */
+
+ if (min == max)
+ pr_debug("ASN: %ld", min);
+ else
+ pr_debug("ASN: %ld-%ld", min, max);
+ return 0;
+}
+
+static int
+add_asior(struct resources *resources, struct ASIdOrRange *obj,
+ struct resources *parent)
+{
+ switch (obj->present) {
+ case ASIdOrRange_PR_NOTHING:
+ break;
+ case ASIdOrRange_PR_id:
+ return add_asn(resources, obj->choice.id, obj->choice.id,
+ parent);
+ case ASIdOrRange_PR_range:
+ return add_asn(resources, obj->choice.range.min,
+ obj->choice.range.max, parent);
+ }
+
+ pr_err("Unknown ASIdOrRange type: %d", obj->present);
+ return -EINVAL;
+}
+
+int
+resources_add_asn(struct resources *resources, struct ASIdentifiers *ids,
+ struct resources *parent)
+{
+ struct ASIdentifierChoice__asIdsOrRanges *iors;
+ int i;
+ int error;
+
+ if (ids->asnum == NULL) {
+ pr_err("ASN extension lacks 'asnum' element.");
+ return -EINVAL;
+ }
+ if (ids->rdi != NULL) {
+ pr_err("ASN extension has 'rdi' element. (Prohibited by RFC6487)");
+ return -EINVAL;
+ }
+
+ switch (ids->asnum->present) {
+ case ASIdentifierChoice_PR_inherit:
+ return inherit_asiors(resources, parent);
+ case ASIdentifierChoice_PR_asIdsOrRanges:
+ /*
+ * TODO
+ * Any pair of items in the asIdsOrRanges SEQUENCE MUST NOT
+ * overlap. Any contiguous series of AS identifiers MUST be
+ * combined into a single range whenever possible. The AS
+ * identifiers in the asIdsOrRanges element MUST be sorted by
+ * increasing numeric value.
+ */
+ iors = &ids->asnum->choice.asIdsOrRanges;
+ for (i = 0; i < iors->list.count; i++) {
+ error = add_asior(resources, iors->list.array[i],
+ parent);
+ if (error)
+ return error;
+ }
+ return 0;
+
+ case ASIdentifierChoice_PR_NOTHING:
+ break;
+ }
+
+ pr_err("Unknown ASIdentifierChoice: %d", ids->asnum->present);
+ return -EINVAL;
+}
+
+int
+resources_join(struct resources *r1, struct resources *r2)
+{
+ int error;
+
+ if (r1->ip4s != NULL) {
+ error = r4array_join(r1->ip4s, r2->ip4s);
+ if (error)
+ return error;
+ }
+ if (r1->ip6s != NULL) {
+ error = r6array_join(r1->ip6s, r2->ip6s);
+ if (error)
+ return error;
+ }
+ if (r1->asns != NULL) {
+ error = asnarray_join(r1->asns, r2->asns);
+ if (error)
+ return error;
+ }
+
+ return 0;
+}
+
+struct restack *
+restack_create(void)
+{
+ struct restack *result;
+
+ result = malloc(sizeof(struct restack));
+ if (result == NULL) {
+ pr_err("Out of memory.");
+ return NULL;
+ }
+
+ SLIST_INIT(result);
+ return result;
+}
+
+void
+restack_destroy(struct restack *stack)
+{
+ struct resources *resources;
+ unsigned int r = 0;
+
+ while (!SLIST_EMPTY(stack)) {
+ resources = SLIST_FIRST(stack);
+ SLIST_REMOVE_HEAD(stack, next);
+ resources_destroy(resources);
+ r++;
+ }
+
+ free(stack);
+ pr_debug("Deleted %u resources from the stack.", r);
+}
+
+void
+restack_push(struct restack *stack, struct resources *new)
+{
+ SLIST_INSERT_HEAD(stack, new, next);
+}
+
+struct resources *
+restack_pop(struct restack *stack)
+{
+ struct resources *res;
+
+ res = SLIST_FIRST(stack);
+ if (res != NULL) {
+ SLIST_REMOVE_HEAD(stack, next);
+ SLIST_NEXT(res, next) = NULL;
+ }
+
+ return res;
+}
+
+struct resources *
+restack_peek(struct restack *stack)
+{
+ return SLIST_FIRST(stack);
+}
--- /dev/null
+#ifndef SRC_RESOURCE_H_
+#define SRC_RESOURCE_H_
+
+#include <libcmscodec/ASIdentifiers.h>
+#include <libcmscodec/ASIdOrRange.h>
+#include <libcmscodec/IPAddressFamily.h>
+#include <openssl/safestack.h>
+#include <sys/queue.h>
+
+struct resources;
+struct restack;
+
+struct resources *resources_create(void);
+void resources_destroy(struct resources *);
+
+int resources_add_ip(struct resources *, struct IPAddressFamily *,
+ struct resources *);
+int resources_add_asn(struct resources *, struct ASIdentifiers *,
+ struct resources *);
+
+int resources_join(struct resources *, struct resources *);
+
+struct restack *restack_create(void);
+void restack_destroy(struct restack *);
+
+void restack_push(struct restack *, struct resources *);
+struct resources *restack_pop(struct restack *);
+struct resources *restack_peek(struct restack *);
+
+#endif /* SRC_RESOURCE_H_ */
--- /dev/null
+#include "sorted_array.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include "log.h"
+
+struct sorted_array {
+ void *array;
+ /* Actual number of elements in @array */
+ unsigned int count;
+ /* Total allocated slots in @array */
+ unsigned int len;
+ /* Size of each array element */
+ size_t size;
+ /* Comparison function for element insertion */
+ sarray_cmp cmp;
+
+ unsigned int refcount;
+};
+
+struct sorted_array *
+sarray_create(size_t elem_size, sarray_cmp cmp)
+{
+ struct sorted_array *result;
+
+ result = malloc(sizeof(struct sorted_array));
+ if (result == NULL)
+ return NULL;
+
+ result->array = calloc(8, elem_size);
+ if (result->array == NULL) {
+ free(result);
+ return NULL;
+ }
+ result->count = 0;
+ result->len = 8;
+ result->size = elem_size;
+ result->cmp = cmp;
+ result->refcount = 1;
+
+ return result;
+}
+
+void
+sarray_get(struct sorted_array *sarray)
+{
+ sarray->refcount++;
+}
+
+void
+sarray_put(struct sorted_array *sarray)
+{
+ sarray->refcount--;
+ if (sarray->refcount == 0) {
+ free(sarray->array);
+ free(sarray);
+ }
+}
+
+void
+sarray_destroy(struct sorted_array *sarray)
+{
+ free(sarray->array);
+ free(sarray);
+}
+
+/* Does not check boundaries. */
+static void *
+get_nth_element(struct sorted_array *sarray, unsigned int index)
+{
+ return ((char *)sarray->array) + index * sarray->size;
+}
+
+static int
+compare(struct sorted_array *sarray, void *new)
+{
+ enum sarray_comparison cmp;
+
+ if (sarray->count == 0)
+ return 0;
+
+ cmp = sarray->cmp(get_nth_element(sarray, sarray->count - 1), new);
+ switch (cmp) {
+ case SACMP_EQUAL:
+ return -EEQUAL;
+ case SACMP_CHILD:
+ return -ECHILD;
+ case SACMP_PARENT:
+ return -EPARENT;
+ case SACMP_LEFT:
+ return -ELEFT;
+ case SACMP_RIGHT:
+ return 0;
+ case SACMP_INTERSECTION:
+ return -EINTERSECTION;
+ }
+
+ pr_err("Programming error: Unknown comparison value: %d", cmp);
+ return -EINVAL;
+}
+
+int
+sarray_add(struct sorted_array *sarray, void *element)
+{
+ int error;
+ void *tmp;
+
+ error = compare(sarray, element);
+ if (error)
+ return error;
+
+ if (sarray->count >= sarray->len) {
+ tmp = realloc(sarray->array, 2 * sarray->len * sarray->size);
+ if (tmp == NULL)
+ return -ENOMEM;
+ sarray->array = tmp;
+ sarray->len *= 2;
+ }
+
+ memcpy(get_nth_element(sarray, sarray->count), element, sarray->size);
+ sarray->count++;
+ return 0;
+}
+
+/* https://stackoverflow.com/questions/364985 */
+static int
+pow2roundup(unsigned int x)
+{
+ --x;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ return x + 1;
+}
+
+/*
+ * Appends the elements from @addend to @sarray's tail.
+ */
+int
+sarray_join(struct sorted_array *sarray, struct sorted_array *addend)
+{
+ int error;
+ unsigned int new_count;
+ size_t new_len;
+ void *tmp;
+
+ if (addend == NULL || addend->count == 0)
+ return 0;
+
+ error = compare(sarray, addend->array);
+ if (error)
+ return error;
+
+ new_count = sarray->count + addend->count;
+ if (new_count > sarray->len) {
+ new_len = pow2roundup(new_count);
+ tmp = realloc(sarray->array, new_len * sarray->size);
+ if (tmp == NULL)
+ return -ENOMEM;
+ sarray->array = tmp;
+ sarray->len = new_len;
+ }
+
+ memcpy(get_nth_element(sarray, sarray->count), addend->array,
+ new_count * sarray->size);
+ sarray->count += addend->count;
+ return 0;
+}
+
+bool
+sarray_contains(struct sorted_array *sarray, void *elem)
+{
+ unsigned int left, mid, right;
+ enum sarray_comparison cmp;
+
+ if (sarray == NULL || sarray->count == 0)
+ return false;
+
+ left = 0;
+ right = sarray->count - 1;
+
+ while (left <= right) {
+ mid = left + (right - left) / 2;
+ cmp = sarray->cmp(get_nth_element(sarray, mid), elem);
+ switch (cmp) {
+ case SACMP_LEFT:
+ right = mid - 1;
+ continue;
+ case SACMP_RIGHT:
+ left = mid + 1;
+ continue;
+ case SACMP_EQUAL:
+ case SACMP_CHILD:
+ return true;
+ case SACMP_PARENT:
+ return false;
+ case SACMP_INTERSECTION:
+ /* Fall through; it's not supposed to happen here. */
+ break;
+ }
+
+ pr_err("Programming error: Unknown comparison value: %d", cmp);
+ return false;
+ }
+
+ return false;
+}
--- /dev/null
+#ifndef SRC_SORTED_ARRAY_H_
+#define SRC_SORTED_ARRAY_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+
+/*
+ * This implementation is not a generic sorted array; It's intended to store RFC
+ * 3779 resources, which requires the elements to be sorted.
+ * So you can only add elements to the tail of the array. The implementation
+ * will validate this and prevent collisions too.
+ */
+
+struct sorted_array;
+
+enum sarray_comparison {
+ SACMP_EQUAL,
+ SACMP_CHILD,
+ SACMP_PARENT,
+ SACMP_LEFT,
+ SACMP_RIGHT,
+ SACMP_INTERSECTION,
+};
+
+typedef enum sarray_comparison (*sarray_cmp)(void *, void *);
+
+struct sorted_array *sarray_create(size_t, sarray_cmp);
+void sarray_get(struct sorted_array *);
+void sarray_put(struct sorted_array *);
+
+#define EEQUAL 7894
+#define ECHILD2 7895
+#define EPARENT 7896
+#define ELEFT 7897
+#define EINTERSECTION 7898
+
+int sarray_add(struct sorted_array *, void *);
+int sarray_join(struct sorted_array *, struct sorted_array *);
+
+bool sarray_contains(struct sorted_array *, void *);
+
+
+#define SARRAY_API(name, type, cmp) \
+static struct sorted_array * \
+name##_create(void) \
+{ \
+ return sarray_create(sizeof(struct type), cmp); \
+} \
+static void \
+name##_get(struct sorted_array *sarray) \
+{ \
+ sarray_get(sarray); \
+} \
+static void \
+name##_put(struct sorted_array *sarray) \
+{ \
+ sarray_put(sarray); \
+} \
+static int \
+name##_add(struct sorted_array *sarray, struct type *element) \
+{ \
+ return sarray_add(sarray, element); \
+} \
+static int \
+name##_join(struct sorted_array *sarray, struct sorted_array *addend) \
+{ \
+ return sarray_join(sarray, addend); \
+} \
+static bool \
+name##_contains(struct sorted_array *sarray, struct type *element) \
+{ \
+ return sarray_contains(sarray, element); \
+}
+
+
+#endif /* SRC_SORTED_ARRAY_H_ */
#include <errno.h>
#include <openssl/err.h>
-#include <openssl/x509.h>
#include <openssl/x509v3.h>
+#include <sys/queue.h>
#include "common.h"
#include "log.h"
#include "object/certificate.h"
/** Certificates we've already validated. */
STACK_OF(X509) *trusted;
+ /**
+ * The resources owned by the certificates from @trusted.
+ *
+ * (One for each certificate; these two stacks should practically always
+ * have the same size. The reason why I don't combine them is because
+ * libcrypto's validation function wants the stack of X509 and I'm not
+ * creating it over and over again.)
+ *
+ * (This is a SLIST and not a STACK_OF because the OpenSSL stack
+ * implementation is different than the LibreSSL one, and the latter is
+ * seemingly not intended to be used outside of its library.)
+ */
+ struct restack *rsrcs;
};
/*
int ok;
int error;
- cert = certificate_load(result, root);
- if (cert == NULL)
- return -EINVAL;
+ error = certificate_load(result, root, &cert);
+ if (error)
+ return error;
result->trusted = sk_X509_new_null();
if (result->trusted == NULL) {
validation_create(struct validation **out, char *root)
{
struct validation *result;
+ struct resources *resources;
int error = -ENOMEM;
result = malloc(sizeof(struct validation));
if (error)
goto abort4;
+ result->rsrcs = restack_create();
+ if (!result->rsrcs)
+ goto abort5;
+
+ resources = resources_create();
+ if (resources == NULL)
+ goto abort6;
+
+ error = certificate_get_resources(result, validation_peek_cert(result),
+ resources);
+ if (error)
+ goto abort7;
+
+ restack_push(result->rsrcs, resources);
*out = result;
return 0;
+abort7:
+ resources_destroy(resources);
+abort6:
+ restack_destroy(result->rsrcs);
+abort5:
+ sk_X509_pop_free(result->trusted, X509_free);
abort4:
X509_STORE_free(result->store);
abort3:
*/
cert_num = sk_X509_num(state->trusted);
if (cert_num != 1) {
- pr_err(state, "Error: validation state has %d certificates. (1 expected)",
+ pr_err("Error: validation state has %d certificates. (1 expected)",
cert_num);
}
+ restack_destroy(state->rsrcs);
sk_X509_pop_free(state->trusted, X509_free);
X509_STORE_free(state->store);
BIO_free_all(state->err);
free(state);
}
-/**
- * "Swallows" @cert; do not delete it.
- */
-int
-validation_push(struct validation *state, X509 *cert)
+BIO *
+validation_stdout(struct validation *state)
{
- /*
- * TODO
- * The only difference between -CAfile and -trusted, as it seems, is
- * that -CAfile consults the default file location, while -trusted does
- * not. As far as I can tell, this means that we absolutely need to use
- * -trusted.
- * So, just in case, enable -no-CAfile and -no-CApath.
- */
+ return state->out;
+}
- X509_STORE_CTX *ctx;
- int ok;
+BIO *
+validation_stderr(struct validation *state)
+{
+ return state->err;
+}
- ctx = X509_STORE_CTX_new();
- if (ctx == NULL) {
- crypto_err(state, "X509_STORE_CTX_new() returned NULL");
- goto end1;
- }
+X509_STORE *
+validation_store(struct validation *state)
+{
+ return state->store;
+}
- /* Returns 0 or 1 , all callers test ! only. */
- ok = X509_STORE_CTX_init(ctx, state->store, cert, NULL);
- if (!ok) {
- crypto_err(state, "X509_STORE_CTX_init() returned %d", ok);
- goto end2;
- }
+STACK_OF(X509) *
+validation_certs(struct validation *state)
+{
+ return state->trusted;
+}
- X509_STORE_CTX_trusted_stack(ctx, state->trusted);
+struct restack *
+validation_resources(struct validation *state)
+{
+ return state->rsrcs;
+}
- /* Can return negative codes, all callers do <= 0. */
- ok = X509_verify_cert(ctx);
- if (ok <= 0) {
- crypto_err(state, "Certificate validation failed: %d", ok);
- goto end2;
- }
+int
+validation_push_cert(struct validation *state, X509 *cert,
+ struct resources *resources)
+{
+ int ok;
- /* Returns number of stack elements or 0 */
ok = sk_X509_push(state->trusted, cert);
if (ok <= 0) {
crypto_err(state,
"Could not add certificate to trusted stack: %d", ok);
- goto end2;
+ return -ENOMEM; /* Presumably */
}
- X509_STORE_CTX_free(ctx);
- return 0;
+ restack_push(state->rsrcs, resources);
-end2:
- X509_STORE_CTX_free(ctx);
-end1:
- X509_free(cert);
- return -EINVAL;
+ return 0;
}
-void
-validation_pop(struct validation *state)
+int
+validation_pop_cert(struct validation *state)
{
- X509 *cert = sk_X509_pop(state->trusted);
- X509_free(cert);
+ if (sk_X509_pop(state->trusted) == NULL) {
+ return crypto_err(state,
+ "Programming error: Attempted to pop empty cert stack");
+ }
+ if (restack_pop(state->rsrcs) == NULL) {
+ pr_err("Programming error: Attempted to pop empty resource stack");
+ return -EINVAL;
+ }
+
+ return 0;
}
X509 *
-validation_peek(struct validation *state)
+validation_peek_cert(struct validation *state)
{
return sk_X509_value(state->trusted, sk_X509_num(state->trusted) - 1);
}
-BIO *
-validation_stdout(struct validation *state)
-{
- return state->out;
-}
-
-BIO *
-validation_stderr(struct validation *state)
+struct resources *
+validation_peek_resource(struct validation *state)
{
- return state->err;
+ return restack_peek(state->rsrcs);
}
#define SRC_STATE_H_
#include <openssl/bio.h>
+#include <openssl/x509.h>
+#include "resource.h"
struct validation;
int validation_create(struct validation **, char *);
void validation_destroy(struct validation *);
-int validation_push(struct validation *, X509 *);
-void validation_pop(struct validation *);
-X509 *validation_peek(struct validation *);
-
BIO *validation_stdout(struct validation *);
BIO *validation_stderr(struct validation *);
+X509_STORE *validation_store(struct validation *);
+STACK_OF(X509) *validation_certs(struct validation *);
+struct restack *validation_resources(struct validation *);
+
+int validation_push_cert(struct validation *, X509 *, struct resources *);
+int validation_pop_cert(struct validation *);
+X509 *validation_peek_cert(struct validation *);
+
+struct resources *validation_peek_resource(struct validation *);
#endif /* SRC_STATE_H_ */
AM_CFLAGS = -pedantic -Wall -std=gnu11 -I../src ${CHECK_CFLAGS}
MY_LDADD = ${CHECK_LIBS}
-check_PROGRAMS = line_file.test tal.test
+check_PROGRAMS = address.test line_file.test tal.test
TESTS = ${check_PROGRAMS}
+address_test_SOURCES = address_test.c ../src/address.c ../src/address.h
+address_test_LDADD = ${MY_LDADD}
+
line_file_test_SOURCES = line_file_test.c ../src/line_file.c ../src/line_file.h
line_file_test_LDADD = ${MY_LDADD}
--- /dev/null
+#include "address.h"
+
+#include <check.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static bool
+p4test(uint32_t a1, int l1, uint32_t a2, int l2)
+{
+ struct ipv4_prefix a, b;
+
+ a.addr.s_addr = htonl(a1);
+ a.len = l1;
+ b.addr.s_addr = htonl(a2);
+ b.len = l2;
+
+ return prefix4_contains(&a, &b);
+}
+
+START_TEST(test_prefix4_contains)
+{
+ unsigned int i;
+
+ /* Prefix-only tests */
+
+ ck_assert_int_eq(false, p4test(0x12345678u, 32, 0x12345677u, 32));
+ ck_assert_int_eq(true, p4test(0x12345678u, 32, 0x12345678u, 32));
+ ck_assert_int_eq(false, p4test(0x12345678u, 32, 0x12345679u, 32));
+
+ ck_assert_int_eq(false, p4test(0x01020304u, 30, 0x01020303u, 32));
+ ck_assert_int_eq(true, p4test(0x01020304u, 30, 0x01020304u, 32));
+ ck_assert_int_eq(true, p4test(0x01020304u, 30, 0x01020305u, 32));
+ ck_assert_int_eq(true, p4test(0x01020304u, 30, 0x01020306u, 32));
+ ck_assert_int_eq(true, p4test(0x01020304u, 30, 0x01020307u, 32));
+ ck_assert_int_eq(false, p4test(0x01020304u, 30, 0x01020308u, 32));
+
+ ck_assert_int_eq(true, p4test(0x00000000u, 0, 0x00000000u, 32));
+ ck_assert_int_eq(true, p4test(0x00000000u, 0, 0x12345678u, 32));
+ ck_assert_int_eq(true, p4test(0x00000000u, 0, 0xFFFFFFFFu, 32));
+
+ /* Length-only tests */
+
+ for (i = 0; i < 33; i++)
+ ck_assert_int_eq(true, p4test(0, i, 0, 32));
+ for (i = 0; i < 32; i++)
+ ck_assert_int_eq(false, p4test(0, 32, 0, i));
+ for (i = 0; i < 33; i++)
+ ck_assert_int_eq(true, p4test(0, 0, 0, i));
+ for (i = 1; i < 33; i++)
+ ck_assert_int_eq(false, p4test(0, i, 0, 0));
+}
+END_TEST
+
+static void
+p6init(struct ipv6_prefix *p, uint32_t q1, uint32_t q2, uint32_t q3,
+ uint32_t q4, int len)
+{
+ p->addr.s6_addr32[0] = htonl(q1);
+ p->addr.s6_addr32[1] = htonl(q2);
+ p->addr.s6_addr32[2] = htonl(q3);
+ p->addr.s6_addr32[3] = htonl(q4);
+ p->len = len;
+}
+
+START_TEST(test_prefix6_contains)
+{
+ struct ipv6_prefix a, b;
+
+ p6init(&a, 0, 0, 0, 0, 128);
+ p6init(&b, 0, 0, 0, 0, 128);
+
+ /* Length-only tests */
+
+ for (a.len = 0; a.len < 129; a.len++)
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ a.len = 128;
+ for (b.len = 0; b.len < 128; b.len++)
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+
+ a.len = 0;
+ for (b.len = 0; b.len < 129; b.len++)
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ b.len = 0;
+ for (a.len = 1; a.len < 129; a.len++)
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+
+ /* Full quadrants */
+
+ /* pl = 0 */
+ p6init(&a, 0, 0, 0, 0, 0);
+ p6init(&b, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 128);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+ /* Others were already tested above. */
+
+ /* pl = 32 */
+ p6init(&a, 0x13131313u, 0, 0, 0, 32);
+ p6init(&b, 0x13131313u, 0, 0, 0, 32);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ p6init(&b, 0x13131313u, 0xffffffffu, 0xffffffffu, 0xffffffffu, 128);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ p6init(&b, 0x13151313u, 0xffffffffu, 0xffffffffu, 0xffffffffu, 128);
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+
+ /* pl = 64 */
+ p6init(&a, 0x13131313u, 0x13131313u, 0, 0, 64);
+ p6init(&b, 0x13131313u, 0x13131313u, 0, 0, 64);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ p6init(&b, 0x13131313u, 0x13131313u, 0xffffffffu, 0xffffffffu, 128);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ p6init(&b, 0x13151313u, 0x13131313u, 0, 0, 128);
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+ p6init(&b, 0x13131313u, 0x13151313u, 0xffffffffu, 0xffffffffu, 128);
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+
+ /* pl = 96 */
+ p6init(&a, 0x13131313u, 0x13131313u, 0x13131313u, 0, 96);
+ p6init(&b, 0x13131313u, 0x13131313u, 0x13131313u, 0, 96);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ p6init(&b, 0x13131313u, 0x13131313u, 0x13131313u, 0xffffffffu, 128);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ p6init(&b, 0x13151313u, 0x13131313u, 0x13131313u, 0, 128);
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+ p6init(&b, 0x13131313u, 0x13151313u, 0x13131313u, 0x12345678u, 128);
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+ p6init(&b, 0x13131313u, 0x13131313u, 0x13151313u, 0xffffffffu, 128);
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+
+ /* Try different prefixes in the same quadrant*/
+
+ p6init(&a, 0x20010000u, 0, 0, 0, 16);
+ p6init(&b, 0x20000000u, 0, 0, 0, 0);
+ for (b.len = 0; b.len < 129; b.len++)
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+
+ p6init(&a, 0, 0x20010000u, 0, 0, 48);
+ p6init(&b, 0, 0x20000000u, 0, 0, 0);
+ for (b.len = 0; b.len < 129; b.len++)
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+
+ p6init(&a, 0, 0, 0x20010000u, 0, 80);
+ p6init(&b, 0, 0, 0x20000000u, 0, 0);
+ for (b.len = 0; b.len < 129; b.len++)
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+
+ p6init(&a, 0, 0, 0, 0x20010000u, 112);
+ p6init(&b, 0, 0, 0, 0x20000000u, 0);
+ for (b.len = 0; b.len < 129; b.len++)
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+
+ /* Try different prefixes in different quadrants */
+
+ /* q2 */
+ p6init(&a, 1, 0x20010000u, 0, 0, 48);
+ p6init(&b, 0, 0x20010000u, 0, 0, 0);
+ for (b.len = 0; b.len < 129; b.len++)
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+
+ /* q3 */
+ p6init(&a, 1, 0, 0x20010000u, 0, 80);
+ p6init(&b, 0, 0, 0x20000000u, 0, 0);
+ for (b.len = 0; b.len < 129; b.len++)
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+
+ p6init(&a, 0, 1, 0x20010000u, 0, 80);
+ for (b.len = 0; b.len < 129; b.len++)
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+
+ /* q4 */
+ p6init(&a, 1, 0, 0, 0x20010000u, 112);
+ p6init(&b, 0, 0, 0, 0x20000000u, 0);
+ for (b.len = 0; b.len < 129; b.len++)
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+
+ p6init(&a, 0, 1, 0, 0x20010000u, 112);
+ for (b.len = 0; b.len < 129; b.len++)
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+
+ p6init(&a, 0, 0, 1, 0x20010000u, 112);
+ for (b.len = 0; b.len < 129; b.len++)
+ ck_assert_int_eq(false, prefix6_contains(&a, &b));
+
+ /* Try actually containing prefixes */
+
+ /* q1 */
+ p6init(&a, 0x20010000u, 0, 0, 0, 16);
+ p6init(&b, 0x20010000u, 0, 0, 0, 16);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ p6init(&b, 0x2001ffffu, 0, 0, 0, 32);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ p6init(&b, 0x2001ffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 128);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ /* q2 */
+ p6init(&a, 0x20010000u, 0x20010000u, 0, 0, 48);
+ p6init(&b, 0x20010000u, 0x20010000u, 0, 0, 48);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ p6init(&b, 0x20010000u, 0x2001ffffu, 0, 0, 64);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ p6init(&b, 0x20010000u, 0x2001ffffu, 0xffffffffu, 0xffffffffu, 128);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ /* q3 */
+ p6init(&a, 0x20010000u, 0x20010000u, 0x20010000u, 0, 80);
+ p6init(&b, 0x20010000u, 0x20010000u, 0x20010000u, 0, 80);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ p6init(&b, 0x20010000u, 0x20010000u, 0x2001ffffu, 0, 96);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ p6init(&b, 0x20010000u, 0x20010000u, 0x2001ffffu, 0xffffffff, 128);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ /* q4 */
+ p6init(&a, 0x20010000u, 0x20010000u, 0x20010000u, 0x20010000, 112);
+ p6init(&b, 0x20010000u, 0x20010000u, 0x20010000u, 0x20010000, 112);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+
+ p6init(&b, 0x20010000u, 0x20010000u, 0x20010000u, 0x2001ffff, 128);
+ ck_assert_int_eq(true, prefix6_contains(&a, &b));
+}
+END_TEST
+
+Suite *lfile_read_suite(void)
+{
+ Suite *suite;
+ TCase *core;
+
+ core = tcase_create("Core");
+ tcase_add_test(core, test_prefix6_contains);
+ tcase_add_test(core, test_prefix4_contains);
+
+ suite = suite_create("address");
+ suite_add_tcase(suite, core);
+ return suite;
+}
+
+int main(void)
+{
+ Suite *suite;
+ SRunner *runner;
+ int tests_failed;
+
+ suite = lfile_read_suite();
+
+ runner = srunner_create(suite);
+ srunner_run_all(runner, CK_NORMAL);
+ tests_failed = srunner_ntests_failed(runner);
+ srunner_free(runner);
+
+ return (tests_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
-#include "tal.c"
+#include "object/tal.c"
#include <check.h>
#include <errno.h>
{
struct tal *tal;
struct uri *uri;
+ /*
unsigned int i;
+ */
/* Got this by feeding the subjectPublicKeyInfo to `base64 -d`. */
+ /*
unsigned char decoded[] = {
0x30, 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48,
0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
0xD4, 0x32, 0xB7, 0x11, 0x38, 0x71, 0xCF, 0xF3, 0xA4, 0x0F, 0x64,
0x83, 0x63, 0x0D, 0x02, 0x03, 0x01, 0x00, 0x01
};
+ */
ck_assert_int_eq(tal_load("tal/lacnic.tal", &tal), 0);
uri = SLIST_NEXT(uri, next);
ck_assert(uri == NULL);
+ /*
ck_assert_uint_eq(ARRAY_LEN(decoded), tal->spki_size);
for (i = 0; i < ARRAY_LEN(decoded); i++)
ck_assert_uint_eq(tal->spki[i], decoded[i]);
+ */
tal_destroy(tal);
}