rpki_validator_SOURCES += object/certificate.h object/certificate.c
rpki_validator_SOURCES += object/crl.h object/crl.c
+rpki_validator_SOURCES += object/ghostbusters.h object/ghostbusters.c
rpki_validator_SOURCES += object/manifest.h object/manifest.c
+rpki_validator_SOURCES += object/name.h object/name.c
rpki_validator_SOURCES += object/roa.h object/roa.c
rpki_validator_SOURCES += object/signed_object.h object/signed_object.c
rpki_validator_SOURCES += object/tal.h object/tal.c
+rpki_validator_SOURCES += object/vcard.h object/vcard.c
rpki_validator_SOURCES += resource/ip4.h resource/ip4.c
rpki_validator_SOURCES += resource/ip6.h resource/ip6.c
/* These objects are expected to live on the stack. */
struct oid_arcs {
+ char const *name;
asn_oid_arc_t *arcs;
size_t count;
};
-#define OID2ARCS(oid) { .arcs = oid, .count = ARRAY_LEN(oid) }
+#define OID2ARCS(_name, oid) { \
+ .name = _name, \
+ .arcs = oid, \
+ .count = ARRAY_LEN(oid), \
+}
void free_arcs(struct oid_arcs *);
#define OID_ROA { 1, 2, 840, 113549, 1, 9, 16, 1, 24 }
#define OID_MANIFEST { 1, 2, 840, 113549, 1, 9, 16, 1, 26 }
+#define OID_GHOSTBUSTERS { 1, 2, 840, 113549, 1, 9, 16, 1, 35 }
#define OID_RSA { 1, 2, 840, 113549, 1, 1, 1 }
#define OID_SHA256 { 2, 16, 840, 1, 101, 3, 4, 2, 1 }
#include "common.h"
-#include <errno.h>
#include <string.h>
#include "log.h"
-#include "thread_var.h"
/**
* Does not assume that @string is NULL-terminated.
? pr_err("CRL URI IA5String has unused bits.")
: string_clone(ia5->data, ia5->length, result);
}
-
-/**
- * Only prints error message if the result is not 0 nor -ESRCH.
- */
-int
-x509_name_decode(X509_NAME *name, int nid, char **_result)
-{
- char *result;
- int len1, len2;
-
- len1 = X509_NAME_get_text_by_NID(name, nid, NULL, 0);
- if (len1 < 0)
- return -ESRCH;
-
- if (_result == NULL)
- return 0;
-
- result = calloc(len1 + 1, sizeof(char));
- if (result == NULL)
- return pr_enomem();
-
- len2 = X509_NAME_get_text_by_NID(name, nid, result, len1 + 1);
- if (len1 != len2) {
- free(result);
- return pr_err("Likely programming error: X509_NAME_get_text_by_NID() returned inconsistent lengths: %d,%d",
- len1, len2);
- }
-
- *_result = result;
- return 0;
-}
-
-struct rfc5280_names {
- char *commonName;
- char *serialNumber;
-};
-
-static int
-get_names(X509_NAME *name, char const *what, struct rfc5280_names *result)
-{
- int error;
-
- error = x509_name_decode(name, NID_commonName, &result->commonName);
- if (error == -ESRCH) {
- return pr_err("The '%s' name lacks a commonName attribute.",
- what);
- }
- if (error)
- return error;
-
- error = x509_name_decode(name, NID_serialNumber, &result->serialNumber);
- if (error == -ESRCH) {
- result->serialNumber = NULL;
- return 0;
- }
- if (error) {
- free(result->commonName);
- return error;
- }
-
- return 0;
-}
-
-/**
- * Also checks NULL.
- *
- * Does assume that @str1 and @str2 are NULL-terminated.
- */
-static bool str_equals(char const *str1, char const *str2)
-{
- if (str1 == str2)
- return true;
- if (str1 == NULL || str2 == NULL)
- return false;
- return strcmp(str1, str2) == 0;
-}
-
-int
-validate_issuer_name(char const *container, X509_NAME *issuer)
-{
- struct validation *state;
- X509 *parent;
- struct rfc5280_names parent_subject = { 0 };
- struct rfc5280_names child_issuer = { 0 };
- int error;
-
- /*
- * Not sure whether "the CRL issuer is the CA" means that the issuer
- * name should equal the parent's subject name or not, because that's
- * very much not what rfc6487#section-4.4 is asking us to check.
- * But let's check it anyway.
- */
-
- state = state_retrieve();
- if (state == NULL)
- return -EINVAL;
- parent = validation_peek_cert(state);
- if (parent == NULL) {
- return pr_err("%s appears to have no parent certificate.",
- container);
- }
-
- error = get_names(X509_get_subject_name(parent), "subject",
- &parent_subject);
- if (error)
- return error;
- error = get_names(issuer, "issuer", &child_issuer);
- if (error)
- goto end2;
-
- if (strcmp(parent_subject.commonName, child_issuer.commonName) != 0) {
- error = pr_err("%s's issuer commonName ('%s') does not equal issuer certificate's commonName ('%s').",
- container, parent_subject.commonName,
- child_issuer.commonName);
- goto end1;
- }
-
- if (!str_equals(parent_subject.serialNumber,
- child_issuer.serialNumber)) {
- error = pr_err("%s's issuer serialNumber ('%s') does not equal issuer certificate's serialNumber ('%s').",
- container, parent_subject.serialNumber,
- child_issuer.serialNumber);
- goto end1;
- }
-
-end1:
- free(child_issuer.commonName);
- free(child_issuer.serialNumber);
-end2:
- free(parent_subject.commonName);
- free(parent_subject.serialNumber);
- return error;
-}
#ifndef SRC_RTR_COMMON_H_
#define SRC_RTR_COMMON_H_
-#include <stdbool.h>
-#include <openssl/x509v3.h>
+#include <stddef.h>
+#include <openssl/x509.h>
/* "I think that this is not supposed to be implemented." */
#define ENOTSUPPORTED 3172
int string_clone(void const *, size_t, char **);
int ia5s2string(ASN1_IA5STRING *, char **);
-int x509_name_decode(X509_NAME *, int, char **);
-int validate_issuer_name(char const *, X509_NAME *);
-
#endif /* SRC_RTR_COMMON_H_ */
void
pr_debug_suffix(void)
{
- fprintf(STDOUT, "%s\n", COLOR_RESET);
+ if (config_get_color_output())
+ fprintf(STDOUT, "%s", COLOR_RESET);
+ fprintf(STDOUT, "\n");
}
void
#include "asn1/decode.h"
#include "asn1/oid.h"
#include "crypto/hash.h"
+#include "object/name.h"
#include "rsync/rsync.h"
/* Just to prevent some line breaking. */
#include <errno.h>
#include "algorithm.h"
-#include "common.h"
#include "extension.h"
#include "log.h"
#include "thread_var.h"
+#include "object/name.h"
static int
__crl_load(struct rpki_uri const *uri, X509_CRL **result)
--- /dev/null
+#include "object/ghostbusters.h"
+
+#include "log.h"
+#include "thread_var.h"
+#include "asn1/oid.h"
+#include "asn1/signed_data.h"
+#include "object/signed_object.h"
+#include "vcard.h"
+
+static int
+handle_vcard(OCTET_STRING_t *vcard, void *arg)
+{
+ return handle_ghostbusters_vcard(vcard);
+}
+
+int
+handle_ghostbusters(struct rpki_uri const *uri, struct rpp *pp,
+ STACK_OF(X509_CRL) *crls)
+{
+ static OID oid = OID_GHOSTBUSTERS;
+ struct oid_arcs arcs = OID2ARCS("ghostbusters", oid);
+ struct signed_object_args sobj_args;
+ int error;
+
+ pr_debug_add("Ghostbusters %s {", uri->global);
+ fnstack_push(uri->global);
+
+ error = signed_object_args_init(&sobj_args, uri, crls);
+ if (error)
+ goto end1;
+
+ error = signed_object_decode(&sobj_args, &arcs, handle_vcard, NULL);
+ if (error)
+ goto end2;
+
+ error = refs_validate_ee(&sobj_args.refs, pp, sobj_args.uri);
+
+end2:
+ signed_object_args_cleanup(&sobj_args);
+end1:
+ pr_debug_rm("}");
+ fnstack_pop();
+ return error;
+}
--- /dev/null
+#ifndef SRC_OBJECT_GHOSTBUSTERS_H_
+#define SRC_OBJECT_GHOSTBUSTERS_H_
+
+#include <openssl/x509.h>
+#include "uri.h"
+#include "rpp.h"
+
+int handle_ghostbusters(struct rpki_uri const *, struct rpp *,
+ STACK_OF(X509_CRL) *);
+
+#endif /* SRC_OBJECT_GHOSTBUSTERS_H_ */
#include "log.h"
#include "thread_var.h"
+#include "asn1/decode.h"
#include "asn1/oid.h"
#include "crypto/hash.h"
#include "object/certificate.h"
char const *file_path;
};
+static int
+manifest_decode(OCTET_STRING_t *string, void *arg)
+{
+ return asn1_decode_octet_string(string, &asn_DEF_Manifest, arg);
+}
+
static int
validate_dates(GeneralizedTime_t *this, GeneralizedTime_t *next)
{
error = rpp_add_roa(*pp, &uri);
else if (uri_has_extension(&uri, ".crl"))
error = rpp_add_crl(*pp, &uri);
+ else if (uri_has_extension(&uri, ".gbr"))
+ error = rpp_add_ghostbusters(*pp, &uri);
else
uri_cleanup(&uri); /* ignore it. */
struct rpp **pp)
{
static OID oid = OID_MANIFEST;
- struct oid_arcs arcs = OID2ARCS(oid);
+ struct oid_arcs arcs = OID2ARCS("manifest", oid);
struct signed_object_args sobj_args;
struct manifest mft;
int error;
goto end1;
mft.file_path = uri->global;
- error = signed_object_decode(&sobj_args, &asn_DEF_Manifest, &arcs,
- (void **) &mft.obj);
+ error = signed_object_decode(&sobj_args, &arcs,
+ manifest_decode, &mft.obj);
if (error)
goto end2;
--- /dev/null
+#include "object/name.h"
+
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "log.h"
+#include "thread_var.h"
+
+/**
+ * Only prints error message if the result is not 0 nor -ESRCH.
+ */
+int
+x509_name_decode(X509_NAME *name, int nid, char **_result)
+{
+ char *result;
+ int len1, len2;
+
+ len1 = X509_NAME_get_text_by_NID(name, nid, NULL, 0);
+ if (len1 < 0)
+ return -ESRCH;
+
+ if (_result == NULL)
+ return 0;
+
+ result = calloc(len1 + 1, sizeof(char));
+ if (result == NULL)
+ return pr_enomem();
+
+ len2 = X509_NAME_get_text_by_NID(name, nid, result, len1 + 1);
+ if (len1 != len2) {
+ free(result);
+ return pr_err("Likely programming error: X509_NAME_get_text_by_NID() returned inconsistent lengths: %d,%d",
+ len1, len2);
+ }
+
+ *_result = result;
+ return 0;
+}
+
+struct rfc5280_names {
+ char *commonName;
+ char *serialNumber;
+};
+
+static int
+get_names(X509_NAME *name, char const *what, struct rfc5280_names *result)
+{
+ int error;
+
+ error = x509_name_decode(name, NID_commonName, &result->commonName);
+ if (error == -ESRCH) {
+ return pr_err("The '%s' name lacks a commonName attribute.",
+ what);
+ }
+ if (error)
+ return error;
+
+ error = x509_name_decode(name, NID_serialNumber, &result->serialNumber);
+ if (error == -ESRCH) {
+ result->serialNumber = NULL;
+ return 0;
+ }
+ if (error) {
+ free(result->commonName);
+ return error;
+ }
+
+ return 0;
+}
+
+/**
+ * Also checks NULL.
+ *
+ * Does assume that @str1 and @str2 are NULL-terminated.
+ */
+static bool str_equals(char const *str1, char const *str2)
+{
+ if (str1 == str2)
+ return true;
+ if (str1 == NULL || str2 == NULL)
+ return false;
+ return strcmp(str1, str2) == 0;
+}
+
+int
+validate_issuer_name(char const *container, X509_NAME *issuer)
+{
+ struct validation *state;
+ X509 *parent;
+ struct rfc5280_names parent_subject = { 0 };
+ struct rfc5280_names child_issuer = { 0 };
+ int error;
+
+ /*
+ * Not sure whether "the CRL issuer is the CA" means that the issuer
+ * name should equal the parent's subject name or not, because that's
+ * very much not what rfc6487#section-4.4 is asking us to check.
+ * But let's check it anyway.
+ */
+
+ state = state_retrieve();
+ if (state == NULL)
+ return -EINVAL;
+ parent = validation_peek_cert(state);
+ if (parent == NULL) {
+ return pr_err("%s appears to have no parent certificate.",
+ container);
+ }
+
+ error = get_names(X509_get_subject_name(parent), "subject",
+ &parent_subject);
+ if (error)
+ return error;
+ error = get_names(issuer, "issuer", &child_issuer);
+ if (error)
+ goto end2;
+
+ if (strcmp(parent_subject.commonName, child_issuer.commonName) != 0) {
+ error = pr_err("%s's issuer commonName ('%s') does not equal issuer certificate's commonName ('%s').",
+ container, parent_subject.commonName,
+ child_issuer.commonName);
+ goto end1;
+ }
+
+ if (!str_equals(parent_subject.serialNumber,
+ child_issuer.serialNumber)) {
+ error = pr_err("%s's issuer serialNumber ('%s') does not equal issuer certificate's serialNumber ('%s').",
+ container, parent_subject.serialNumber,
+ child_issuer.serialNumber);
+ goto end1;
+ }
+
+end1:
+ free(child_issuer.commonName);
+ free(child_issuer.serialNumber);
+end2:
+ free(parent_subject.commonName);
+ free(parent_subject.serialNumber);
+ return error;
+}
--- /dev/null
+#ifndef SRC_OBJECT_NAME_H_
+#define SRC_OBJECT_NAME_H_
+
+#include <openssl/x509.h>
+
+int x509_name_decode(X509_NAME *, int, char **);
+int validate_issuer_name(char const *, X509_NAME *);
+
+#endif /* SRC_OBJECT_NAME_H_ */
#include "log.h"
#include "thread_var.h"
+#include "asn1/decode.h"
#include "asn1/oid.h"
#include "object/signed_object.h"
+static int
+roa_decode(OCTET_STRING_t *string, void *arg)
+{
+ return asn1_decode_octet_string(string, &asn_DEF_RouteOriginAttestation,
+ arg);
+}
+
static int
print_addr4(struct resources *parent, unsigned long asn,
struct ROAIPAddress *roa_addr)
STACK_OF(X509_CRL) *crls)
{
static OID oid = OID_ROA;
- struct oid_arcs arcs = OID2ARCS(oid);
+ struct oid_arcs arcs = OID2ARCS("roa", oid);
struct signed_object_args sobj_args;
struct RouteOriginAttestation *roa;
int error;
if (error)
goto end1;
- error = signed_object_decode(&sobj_args,
- &asn_DEF_RouteOriginAttestation, &arcs, (void **) &roa);
+ error = signed_object_decode(&sobj_args, &arcs, roa_decode, &roa);
if (error)
goto end2;
#include <errno.h>
#include "log.h"
#include "asn1/content_info.h"
-#include "asn1/decode.h"
static int
-validate_eContentType(struct SignedData *sdata,
- asn_TYPE_descriptor_t const *descriptor,
- struct oid_arcs const *oid)
+validate_eContentType(struct SignedData *sdata, struct oid_arcs const *oid)
{
struct oid_arcs arcs;
bool equals;
equals = arcs_equal(&arcs, oid);
free_arcs(&arcs);
if (!equals) {
- return pr_err("SignedObject's encapContentInfo lacks the OID of a %s.",
- descriptor->name);
+ return pr_err("The OID of the SignedObject's encapContentInfo is not '%s'.",
+ oid->name);
}
return 0;
}
static int
-validate_content_type(struct SignedData *sdata,
- asn_TYPE_descriptor_t const *descriptor,
- struct oid_arcs const *oid)
+validate_content_type(struct SignedData *sdata, struct oid_arcs const *oid)
{
OBJECT_IDENTIFIER_t *ctype;
struct oid_arcs arcs;
equals = arcs_equal(&arcs, oid);
free_arcs(&arcs);
if (!equals) {
- return pr_err("SignedObject's content type attribute lacks the OID of a %s.",
- descriptor->name);
+ return pr_err("The OID of the SignedObject's content type attribute is not '%s'.",
+ oid->name);
}
return 0;
int
signed_object_decode(struct signed_object_args *args,
- asn_TYPE_descriptor_t const *descriptor,
struct oid_arcs const *oid,
- void **result)
+ signed_object_cb cb,
+ void *cb_arg)
{
struct ContentInfo *cinfo;
struct SignedData *sdata;
/* rfc6482#section-2 */
/* rfc6486#section-4.1 */
/* rfc6486#section-4.4.1 */
- error = validate_eContentType(sdata, descriptor, oid);
+ error = validate_eContentType(sdata, oid);
if (error)
goto end3;
/* rfc6482#section-2 */
/* rfc6486#section-4.3 */
- error = validate_content_type(sdata, descriptor, oid);
+ error = validate_content_type(sdata, oid);
if (error)
goto end3;
- error = asn1_decode_octet_string(sdata->encapContentInfo.eContent,
- descriptor, result);
+ error = cb(sdata->encapContentInfo.eContent, cb_arg);
end3: signed_data_free(sdata);
end2: content_info_free(cinfo);
#include "asn1/oid.h"
#include "asn1/signed_data.h"
-int signed_object_decode(struct signed_object_args *args,
- asn_TYPE_descriptor_t const *, struct oid_arcs const *, void **);
+typedef int (*signed_object_cb)(OCTET_STRING_t *, void *);
+
+int signed_object_decode(struct signed_object_args *, struct oid_arcs const *,
+ signed_object_cb, void *);
#endif /* SRC_OBJECT_SIGNED_OBJECT_H_ */
--- /dev/null
+#include "vcard.h"
+
+#include <errno.h>
+#include <stdbool.h>
+
+#include "log.h"
+
+/**
+ * Reminder: UTF-8 strings are **not** C strings.
+ * They can contain null characters, which do not terminate them.
+ * DO NOT use standard string operations on them. (Except for the `n` ones).
+ */
+struct utf8_string {
+ uint8_t *val;
+ /** Number of bytes in @val. */
+ size_t len;
+ /** Actual allocated size of @val. */
+ size_t size;
+};
+
+struct vcard_line {
+ /**
+ * This is a copy of the actual vCard value.
+ * It does not include the newline and has folding characters removed.
+ */
+ struct utf8_string str;
+ size_t octet_string_offset;
+};
+
+enum string_analysis {
+ SA_COPY_CHARA,
+ SA_LINE_ENDED,
+ SA_SKIP_THREE_CHARAS,
+ SA_ERROR,
+};
+
+/**
+ * Returns a pointer to the character at the right of string[pos], if it exists.
+ *
+ * Assumes that string->len > 0.
+ */
+static uint8_t *
+next_chara(struct utf8_string *string, size_t pos)
+{
+ return (pos < string->len - 1) ? (string->val + pos + 1) : NULL;
+}
+
+/**
+ * Assumes that pos < string_len and that string_len > 0.
+ */
+static enum string_analysis
+analyze_pos(struct utf8_string *string, size_t pos)
+{
+ /*
+ * Special cases:
+ *
+ * 1. \r\n: Normal line/property end
+ * 2. \r\n\w (where '\w' is space or tab): Folded line
+ *
+ * Each vCard line must end with \r\n.
+ */
+
+ uint8_t *next1;
+ uint8_t *next2;
+
+ if (string->val[pos] != '\r')
+ return SA_COPY_CHARA; /* Typical path */
+
+ /* At this point, we have a \r. */
+
+ next1 = next_chara(string, pos);
+ if (next1 == NULL) {
+ pr_err("vCard's final newline is incomplete ('\\r').");
+ return SA_ERROR;
+ }
+ if (*next1 != '\n')
+ return SA_COPY_CHARA; /* Random stray \r; no problem for now. */
+
+ /* At this point, we have a \r\n. */
+
+ next2 = next_chara(string, pos + 1);
+ if (next2 == NULL)
+ return SA_LINE_ENDED; /* \r\n<eof> */
+ if (*next2 == ' ' || *next2 == '\t')
+ return SA_SKIP_THREE_CHARAS; /* Folded line */
+
+ return SA_LINE_ENDED; /* \r\n<more lines> */
+}
+
+static int
+double_line_size(struct vcard_line *line)
+{
+ uint8_t *tmp;
+
+ line->str.size *= 2;
+ tmp = realloc(line->str.val, line->str.size);
+ if (tmp == NULL)
+ return pr_enomem();
+ line->str.val = tmp;
+
+ return 0;
+}
+
+static int
+add_chara(struct vcard_line *line, uint8_t chara, bool inc_str_len)
+{
+ int error;
+
+ if (line->str.len + 1 == line->str.size) {
+ error = double_line_size(line);
+ if (error)
+ return error;
+ }
+
+ line->str.val[line->str.len] = chara;
+ if (inc_str_len)
+ line->str.len++;
+
+ return 0;
+}
+
+/**
+ * Will remove the newline (\r\n). Just assume that there is a valid newline at
+ * the end.
+ * The result will not be a C string, but will still have a null character at
+ * the end (not accounted by line->str.len), in case you want to print it.
+ */
+static int
+line_next(struct vcard_line *line, OCTET_STRING_t *string8)
+{
+ struct utf8_string string;
+ size_t string_pos;
+ int error;
+
+ if (string8->size == line->octet_string_offset)
+ return pr_err("vCard ends prematurely. (Expected an END line)");
+
+ string.val = string8->buf + line->octet_string_offset;
+ string.len = string8->size - line->octet_string_offset;
+ string.size = 0;
+ line->str.len = 0;
+
+ for (string_pos = 0; string_pos < string.len; string_pos++) {
+ switch (analyze_pos(&string, string_pos)) {
+ case SA_COPY_CHARA:
+ error = add_chara(line, string.val[string_pos], true);
+ if (error)
+ return error;
+ break;
+
+ case SA_LINE_ENDED:
+ line->octet_string_offset += string_pos + 2;
+ return add_chara(line, 0, false);
+
+ case SA_SKIP_THREE_CHARAS:
+ string_pos += 2;
+ break;
+
+ case SA_ERROR:
+ return -EINVAL;
+ }
+ }
+
+ return pr_err("vCard line does not end with a \\r\\n-style newline.");
+}
+
+static int
+line_validate(struct vcard_line *line, char const *expected)
+{
+ size_t expected_len = strlen(expected);
+
+ if (line->str.len != expected_len)
+ goto fail;
+
+ /*
+ * RFC 6350:
+ * "Property names and parameter names are case-insensitive"
+ * "Parameter values that are not explicitly defined as being
+ * case-sensitive are case-insensitive."
+ */
+ if (strncasecmp((char *) line->str.val, expected, expected_len) != 0)
+ goto fail;
+
+ return 0;
+
+fail:
+ return pr_err("Expected vCard property '%s', got '%s'.",
+ expected, line->str.val);
+}
+
+/**
+ * @tag must contain the colon. This simplifies the code.
+ */
+static int
+line_starts_with(struct vcard_line *line, char const *tag)
+{
+ /* RFC6350: "Property names and parameter names are case-insensitive" */
+ return strncasecmp((char *) line->str.val, tag, strlen(tag)) == 0;
+}
+
+static int
+__handle_ghostbusters_vcard(OCTET_STRING_t *vcard, struct vcard_line *line)
+{
+ bool fn_found = false;
+ bool useful_found = false;
+ int error;
+
+ error = line_next(line, vcard);
+ if (error)
+ return error;
+ error = line_validate(line, "BEGIN:VCARD");
+ if (error)
+ return error;
+
+ error = line_next(line, vcard);
+ if (error)
+ return error;
+ error = line_validate(line, "VERSION:4.0");
+ if (error)
+ return error;
+
+ do {
+ error = line_next(line, vcard);
+ if (error)
+ return error;
+
+ if (line_starts_with(line, "FN:")) {
+ fn_found = true;
+
+ } else if (line_starts_with(line, "ORG:")
+ || line_starts_with(line, "ADR:")
+ || line_starts_with(line, "TEL:")
+ || line_starts_with(line, "EMAIL:")) {
+ useful_found = true;
+
+ } else if (line_starts_with(line, "END:")) {
+ break;
+
+ } else {
+ return pr_err("Unexpected vCard line: '%s'",
+ line->str.val);
+ }
+
+ } while (true);
+
+ error = line_validate(line, "END:VCARD");
+ if (error)
+ return error;
+ if (vcard->size != line->octet_string_offset)
+ return pr_err("vCard has content after the END tag.");
+
+ if (!fn_found)
+ return pr_err("vCard lacks the 'FN' property.");
+ if (!useful_found)
+ return pr_err("vCard lacks the 'ORG', 'ADR', 'TEL' and/or 'EMAIL' properties.");
+
+ return 0;
+}
+
+int
+handle_ghostbusters_vcard(OCTET_STRING_t *vcard)
+{
+ struct vcard_line line;
+ int error;
+
+ line.str.size = 81; /* Okay default, assuming there is no folding. */
+ line.str.len = 0;
+ line.str.val = malloc(line.str.size);
+ if (line.str.val == NULL)
+ return pr_enomem();
+ line.octet_string_offset = 0;
+
+ error = __handle_ghostbusters_vcard(vcard, &line);
+
+ free(line.str.val);
+ return error;
+}
--- /dev/null
+#ifndef SRC_OBJECT_VCARD_H_
+#define SRC_OBJECT_VCARD_H_
+
+#include <libcmscodec/OCTET_STRING.h>
+
+int handle_ghostbusters_vcard(OCTET_STRING_t *);
+
+#endif /* SRC_OBJECT_VCARD_H_ */
#include "uri.h"
#include "object/certificate.h"
#include "object/crl.h"
+#include "object/ghostbusters.h"
#include "object/roa.h"
ARRAY_LIST(uris, struct rpki_uri)
/* The Manifest is not needed for now. */
struct uris roas; /* Route Origin Attestations */
+
+ struct uris ghostbusters;
};
struct rpp *
result->crl_set = false;
if (uris_init(&result->roas) != 0)
goto fail3;
+ if (uris_init(&result->ghostbusters) != 0)
+ goto fail4;
return result;
+fail4:
+ uris_cleanup(&result->roas, uri_cleanup);
fail3:
uris_cleanup(&result->certs, uri_cleanup);
fail2:
{
uris_cleanup(&pp->certs, uri_cleanup);
uris_cleanup(&pp->roas, uri_cleanup);
+ uris_cleanup(&pp->ghostbusters, uri_cleanup);
free(pp);
}
return uris_add(&pp->roas, uri);
}
+int
+rpp_add_ghostbusters(struct rpp *pp, struct rpki_uri *uri)
+{
+ return uris_add(&pp->ghostbusters, uri);
+}
+
int
rpp_add_crl(struct rpp *pp, struct rpki_uri *uri)
{
goto end;
/* Use CRL stack to validate certificates, and also traverse them. */
- ARRAYLIST_FOREACH(&pp->certs, uri) {
+ ARRAYLIST_FOREACH(&pp->certs, uri)
certificate_traverse(pp, uri, crls, false);
- }
/* Use valid address ranges to print ROAs that match them. */
ARRAYLIST_FOREACH(&pp->roas, uri)
handle_roa(uri, pp, crls);
+ ARRAYLIST_FOREACH(&pp->ghostbusters, uri)
+ handle_ghostbusters(uri, pp, crls);
+
end:
sk_X509_CRL_pop_free(crls, X509_CRL_free);
return error;
int rpp_add_cert(struct rpp *, struct rpki_uri *);
int rpp_add_crl(struct rpp *, struct rpki_uri *);
int rpp_add_roa(struct rpp *, struct rpki_uri *);
+int rpp_add_ghostbusters(struct rpp *, struct rpki_uri *);
struct rpki_uri const *rpp_get_crl(struct rpp const *);
static char const *const RSYNC_PREFIX = "rsync://";
static bool rsync_enabled;
-//static const char *rsync_command[] = {"rsync", "--recursive", "--delete", "--times", NULL};
-
int
rsync_init(bool is_rsync_enable)
{
if (cert == NULL)
return 0; /* The TA lacks siblings, so subject is unique. */
- ARRAYLIST_FOREACH(&cert->subjects, cursor)
- if (strcmp(*cursor, subject) == 0)
- return pr_err("Subject name '%s' is not unique.",
+ ARRAYLIST_FOREACH(&cert->subjects, cursor) {
+ if (strcmp(*cursor, subject) == 0) {
+ /*
+ * I had to downgrade this because lots of people are
+ * breaking this rule.
+ * TODO (next iteration) make a framework so the user
+ * can choose the severity of each error.
+ */
+ return pr_warn("Subject name '%s' is not unique.",
subject);
+ }
+ }
duplicate = strdup(subject);
if (duplicate == NULL)
AM_CFLAGS = -pedantic -Wall -std=gnu11 -I../src -DUNIT_TESTING ${CHECK_CFLAGS}
MY_LDADD = ${CHECK_LIBS}
-
-check_PROGRAMS = address.test line_file.test rsync.test tal.test
+BASIC_MODULES = ../src/config.c ../src/config.h
+BASIC_MODULES += ../src/log.c ../src/log.h
+BASIC_MODULES += impersonator.c
+
+check_PROGRAMS = address.test
+check_PROGRAMS += vcard.test
+check_PROGRAMS += line_file.test
+check_PROGRAMS += rsync.test
+check_PROGRAMS += tal.test
TESTS = ${check_PROGRAMS}
-address_test_SOURCES = ../src/address.h
-address_test_SOURCES += ../src/log.c ../src/log.h
+address_test_SOURCES = ${BASIC_MODULES}
+address_test_SOURCES += ../src/address.h
address_test_SOURCES += address_test.c
address_test_LDADD = ${MY_LDADD}
-line_file_test_SOURCES = ../src/file.c ../src/file.h ../src/log.c ../src/log.h
-line_file_test_SOURCES += ../src/common.c ../src/common.h
-line_file_test_SOURCES += line_file_test.c ../src/line_file.c ../src/line_file.h
+vcard_test_SOURCES = ${BASIC_MODULES}
+vcard_test_SOURCES += vcard_test.c
+vcard_test_LDADD = ${MY_LDADD}
+
+line_file_test_SOURCES = ${BASIC_MODULES}
+line_file_test_SOURCES += ../src/file.c ../src/file.h
+line_file_test_SOURCES += ../src/line_file.c ../src/line_file.h
+line_file_test_SOURCES += line_file_test.c
line_file_test_LDADD = ${MY_LDADD}
-tal_test_SOURCES = ../src/file.c ../src/file.h ../src/log.c ../src/log.h
-tal_test_SOURCES += ../src/config.c ../src/config.h
-tal_test_SOURCES += ../src/toml_handler.c ../src/toml_handler.h
+rsync_test_SOURCES = ${BASIC_MODULES}
+rsync_test_SOURCES += ../src/common.c ../src/common.h
+rsync_test_SOURCES += ../src/uri.c ../src/uri.h
+rsync_test_SOURCES += rsync_test.c
+rsync_test_LDADD = ${MY_LDADD}
+
+tal_test_SOURCES = ${BASIC_MODULES}
+tal_test_SOURCES += ../src/file.c ../src/file.h
tal_test_SOURCES += ../src/common.c ../src/common.h
tal_test_SOURCES += ../src/crypto/base64.c ../src/crypto/base64.h
tal_test_SOURCES += ../src/random.c ../src/random.h
tal_test_SOURCES += ../src/uri.c ../src/uri.h
-tal_test_SOURCES += tal_test.c ../src/line_file.c ../src/line_file.h
-tal_test_CFLAGS = ${AM_CFLAGS} ${GLIB_CFLAGS}
-tal_test_LDADD = ${MY_LDADD} ${GLIB_LIBS}
-
-rsync_test_SOURCES = ../src/file.c ../src/file.h ../src/log.c ../src/log.h
-rsync_test_SOURCES += ../src/config.c ../src/config.h
-rsync_test_SOURCES += ../src/toml_handler.c ../src/toml_handler.h
-rsync_test_SOURCES += ../src/uri.c ../src/uri.h
-rsync_test_SOURCES += ../src/common.c ../src/common.h
-rsync_test_SOURCES += rsync_test.c
-rsync_test_LDADD = ${MY_LDADD}
+tal_test_SOURCES += ../src/line_file.c ../src/line_file.h
+tal_test_SOURCES += tal_test.c
+tal_test_CFLAGS = ${AM_CFLAGS}
+tal_test_LDADD = ${MY_LDADD}
--- /dev/null
+#include <arpa/inet.h>
+
+/**
+ * Some core functions, as linked from unit testing code.
+ */
+
+static char addr_buffer1[INET6_ADDRSTRLEN];
+static char addr_buffer2[INET6_ADDRSTRLEN];
+
+char const *
+v4addr2str(struct in_addr *addr)
+{
+ return inet_ntop(AF_INET, addr, addr_buffer1, sizeof(addr_buffer1));
+}
+
+char const *
+v4addr2str2(struct in_addr *addr)
+{
+ return inet_ntop(AF_INET, addr, addr_buffer2, sizeof(addr_buffer2));
+}
+
+char const *
+v6addr2str(struct in6_addr *addr)
+{
+ return inet_ntop(AF_INET6, addr, addr_buffer1, sizeof(addr_buffer1));
+}
+
+char const *
+v6addr2str2(struct in6_addr *addr)
+{
+ return inet_ntop(AF_INET6, addr, addr_buffer2, sizeof(addr_buffer2));
+}
+
+int
+set_config_from_file(char *config_file)
+{
+ return 0;
+}
}
END_TEST
-Suite *lfile_read_suite(void)
+Suite *ghostbusters_suite(void)
{
Suite *suite;
TCase *core, *limits, *errors;
SRunner *runner;
int tests_failed;
- suite = lfile_read_suite();
+ suite = ghostbusters_suite();
runner = srunner_create(suite);
srunner_run_all(runner, CK_NORMAL);
error = get_path_only(string, strlen(string), rsync_prefix_len, &result);
if (error) {
-// free(string);
+ free(string);
return;
}
--- /dev/null
+#include "object/vcard.c"
+
+#include <check.h>
+
+#define VC_BEGIN "BEGIN:VCARD\r\n"
+#define VC_VERSION "VERSION:4.0\r\n"
+#define VC_FN "FN:name\r\n"
+#define VC_ORG "ORG:organization\r\n"
+#define VC_ADR "ADR:address\r\n"
+#define VC_TEL "TEL:12345678\r\n"
+#define VC_EMAIL "EMAIL:e@ma.il\r\n"
+#define VC_END "END:VCARD\r\n"
+
+#define INIT_STR8(name, str) do { \
+ printf("- %s:\n", name); \
+ str8.buf = (uint8_t *) (str); \
+ str8.size = strlen(str); \
+} while (0)
+
+START_TEST(vcard_normal)
+{
+ OCTET_STRING_t str8;
+
+ INIT_STR8(
+ "Minimal",
+ VC_BEGIN VC_VERSION VC_FN VC_ORG VC_END
+ );
+ ck_assert_int_eq(0, handle_ghostbusters_vcard(&str8));
+
+ INIT_STR8(
+ "Full",
+ VC_BEGIN VC_VERSION VC_FN VC_ORG VC_ADR VC_TEL VC_EMAIL VC_END
+ );
+ ck_assert_int_eq(0, handle_ghostbusters_vcard(&str8));
+
+ INIT_STR8(
+ "Missing locator",
+ VC_BEGIN VC_VERSION VC_FN VC_END
+ );
+ ck_assert_int_eq(-EINVAL, handle_ghostbusters_vcard(&str8));
+
+ INIT_STR8(
+ "Missing name",
+ VC_BEGIN VC_VERSION VC_ORG VC_END
+ );
+ ck_assert_int_eq(-EINVAL, handle_ghostbusters_vcard(&str8));
+
+ INIT_STR8(
+ "Unknown property",
+ VC_BEGIN VC_VERSION VC_FN VC_ORG "POTATO:potato\r\n" VC_END
+ );
+ ck_assert_int_eq(-EINVAL, handle_ghostbusters_vcard(&str8));
+
+ INIT_STR8(
+ "No newline",
+ VC_BEGIN VC_VERSION "FN:name" VC_ORG VC_END
+ );
+ ck_assert_int_eq(-EINVAL, handle_ghostbusters_vcard(&str8));
+
+ INIT_STR8(
+ "\\r newline",
+ VC_BEGIN VC_VERSION "FN:name\r" VC_ORG VC_END
+ );
+ ck_assert_int_eq(-EINVAL, handle_ghostbusters_vcard(&str8));
+
+ INIT_STR8(
+ "\\n newline",
+ VC_BEGIN VC_VERSION "FN:name\n" VC_ORG VC_END
+ );
+ ck_assert_int_eq(-EINVAL, handle_ghostbusters_vcard(&str8));
+
+ INIT_STR8(
+ "Last line has no valid newline",
+ VC_BEGIN VC_VERSION VC_FN VC_ORG "END:VCARD"
+ );
+ ck_assert_int_eq(-EINVAL, handle_ghostbusters_vcard(&str8));
+
+ INIT_STR8(
+ "Stray null character (in non-constant)",
+ VC_BEGIN VC_VERSION "FN:n\0ame\r\n" VC_ORG VC_END
+ );
+ str8.size += strlen(" ame\r\n" VC_ORG VC_END);
+ ck_assert_int_eq(0, handle_ghostbusters_vcard(&str8));
+
+ INIT_STR8(
+ "Stray null character (in constant)",
+ VC_BEGIN "VERSION:4.\00\r\n" VC_FN VC_ORG VC_END
+ );
+ str8.size += strlen(" 0\r\n" VC_FN VC_ORG VC_END);
+ ck_assert_int_eq(-EINVAL, handle_ghostbusters_vcard(&str8));
+
+ INIT_STR8(
+ "Garbage after END",
+ VC_BEGIN VC_VERSION VC_FN VC_ORG VC_END VC_EMAIL
+ );
+ ck_assert_int_eq(-EINVAL, handle_ghostbusters_vcard(&str8));
+}
+END_TEST
+
+Suite *ghostbusters_suite(void)
+{
+ Suite *suite;
+ TCase *hgv;
+
+ hgv = tcase_create("handle_ghostbusters_vcard()");
+ tcase_add_test(hgv, vcard_normal);
+
+ suite = suite_create("vCard");
+ suite_add_tcase(suite, hgv);
+ return suite;
+}
+
+int main(void)
+{
+ Suite *suite;
+ SRunner *runner;
+ int tests_failed;
+
+ suite = ghostbusters_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;
+}