]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
About 80% of RFC 6488
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Fri, 21 Sep 2018 22:42:58 +0000 (17:42 -0500)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Fri, 21 Sep 2018 22:43:16 +0000 (17:43 -0500)
15 files changed:
autogen.sh
configure.ac
src/Makefile.am
src/common.h
src/content_info.c [new file with mode: 0644]
src/content_info.h [new file with mode: 0644]
src/file.c [new file with mode: 0644]
src/file.h [new file with mode: 0644]
src/line_file.c
src/main.c
src/oid.c [new file with mode: 0644]
src/oid.h [new file with mode: 0644]
src/signed_data.c [new file with mode: 0644]
src/signed_data.h [new file with mode: 0644]
src/tal.h

index 042d19dfc5ac83d0fa0ceb2c883b7a66dd1e5267..c06a92499a896d5cc4c374079f1772579854171f 100755 (executable)
@@ -4,4 +4,4 @@
 # Run this file to generate the configure script.
 # You'll need Autoconf and Automake installed!
 
-aclocal && automake --add-missing --copy && autoconf
+autoreconf --install
index d65fdfb2e6619adae87e71d2918e27dce7be5b7b..f01b3f71317cdc899b704183b19303fb712d60a3 100644 (file)
@@ -23,11 +23,16 @@ AC_CHECK_HEADER_STDBOOL
 # Checks for library functions.
 AC_FUNC_MALLOC
 AC_CHECK_FUNCS([memset socket])
-AC_SEARCH_LIBS([pthread_create], [pthread])
+AC_SEARCH_LIBS([pthread_create], [pthread], [],
+       [AC_MSG_ERROR([unable to find the pthread() function])]
+)
+AC_SEARCH_LIBS([ber_decode], [cmscodec], [],
+       [AC_MSG_ERROR([unable to find the ber_decode() function])]
+)
 
 # Check dependencies.
+#PKG_CHECK_MODULES([OPENSSL], [openssl])
 PKG_CHECK_MODULES([CHECK], [check])
-PKG_CHECK_MODULES([GLIB], [glib-2.0])
 
 # Spit out the makefiles.
 AC_OUTPUT(Makefile src/Makefile test/Makefile)
index 36722ef6940e6a98ecb150cdfa35445c7ee7ac6a..8e0f5e77cb189e69a0afbf0598ccb41556200a2a 100644 (file)
@@ -2,10 +2,10 @@ bin_PROGRAMS = rpki_validator
 
 rpki_validator_SOURCES  = main.c
 rpki_validator_SOURCES += common.h
-rpki_validator_SOURCES += line_file.h
-rpki_validator_SOURCES += line_file.c
-rpki_validator_SOURCES += tal.h
-rpki_validator_SOURCES += tal.c
+rpki_validator_SOURCES += content_info.h content_info.c
+rpki_validator_SOURCES += file.h file.c
+rpki_validator_SOURCES += oid.h oid.c
+rpki_validator_SOURCES += signed_data.h signed_data.c
 
-rpki_validator_CFLAGS = -pedantic -Wall -std=gnu11 -O3 ${GLIB_CFLAGS}
-rpki_validator_LDADD = ${GLIB_LIBS}
+rpki_validator_CFLAGS = -pedantic -Wall -std=gnu11 -O0 -g ${OPENSSL_CFLAGS}
+rpki_validator_LDADD = ${OPENSSL_LIBS}
index 9c26620612a243090326e1c5c6fb371152498ec4..c682919ac623411432e20b88d3d2fc4000d23654 100644 (file)
@@ -1,6 +1,19 @@
 #ifndef SRC_RTR_COMMON_H_
 #define SRC_RTR_COMMON_H_
 
+#include <string.h>
+
 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
 
+#define warnxerror0(error, msg) \
+       warnx(msg ": %s", strerror(error))
+#define warnxerrno0(msg) \
+       warnxerror0(errno, msg)
+#define warnxerror(error, msg, ...) \
+       warnx(msg ": %s", ##__VA_ARGS__, strerror(error))
+#define warnxerrno(msg, ...) \
+       warnxerror(errno, msg, ##__VA_ARGS__)
+
+#define pr_debug(msg, ...) printf("Debug: " msg "\n", ##__VA_ARGS__);
+
 #endif /* SRC_RTR_COMMON_H_ */
diff --git a/src/content_info.c b/src/content_info.c
new file mode 100644 (file)
index 0000000..6bb3295
--- /dev/null
@@ -0,0 +1,115 @@
+#include "content_info.h"
+
+#include <err.h>
+#include <errno.h>
+#include <libcmscodec/ContentType.h>
+#include "common.h"
+#include "file.h"
+
+static void
+content_type_print(FILE *stream, asn_oid_arc_t *arcs, unsigned int arc_count)
+{
+       unsigned int i;
+
+       for (i = 0; i < arc_count; i++) {
+               fprintf(stream, "%u", arcs[i]);
+               if (i != arc_count - 1)
+                       fprintf(stream, ".");
+       }
+}
+
+int
+content_type_validate(ContentType_t *ctype)
+{
+       asn_oid_arc_t expected[] = { 1, 2, 840, 113549, 1, 7, 2 };
+       asn_oid_arc_t actual[ARRAY_SIZE(expected)];
+       const unsigned int SLOTS = ARRAY_SIZE(expected);
+       ssize_t result;
+       unsigned int i;
+
+       result = OBJECT_IDENTIFIER_get_arcs(ctype, actual, SLOTS);
+       if (result != SLOTS)
+               goto failure;
+
+       for (i = 0; i < SLOTS; i++) {
+               if (expected[i] != actual[i])
+                       goto failure;
+       }
+
+       return 0;
+
+failure:
+       fprintf(stderr, "Incorrect content-type; expected ");
+       content_type_print(stderr, expected, SLOTS);
+       fprintf(stderr, ", got ");
+       content_type_print(stderr, actual, (result < SLOTS) ? result : SLOTS);
+       fprintf(stderr, ".\n");
+       return -EINVAL;
+}
+
+static int
+validate(struct ContentInfo *info)
+{
+       char error_msg[256];
+       size_t error_msg_size;
+       int error;
+
+       error_msg_size = sizeof(error_msg);
+       error = asn_check_constraints(&asn_DEF_ContentInfo, info, error_msg,
+           &error_msg_size);
+       if (error == -1) {
+               warnx("Error validating content info object: %s", error_msg);
+               return -EINVAL;
+       }
+
+       return content_type_validate(&info->contentType);
+}
+
+static int
+decode(struct file_contents *fc, struct ContentInfo **result)
+{
+       struct ContentInfo *info = NULL;
+       asn_dec_rval_t rval;
+       int error;
+
+       rval = ber_decode(0, &asn_DEF_ContentInfo, (void **) &info, fc->buffer,
+           fc->buffer_size);
+       if (rval.code != RC_OK) {
+               warnx("Error decoding content info object: %d", rval.code);
+               /* Must free partial content info according to API contracts. */
+               content_info_free(info);
+               return -EINVAL;
+       }
+
+       error = validate(info);
+       if (error) {
+               content_info_free(info);
+               return error;
+       }
+
+       *result = info;
+       return 0;
+}
+
+int
+content_info_load(const char *file_name, struct ContentInfo **result)
+{
+       struct file_contents fc;
+       int error;
+
+       error = file_load(file_name, &fc);
+       if (error)
+               return error;
+
+       error = decode(&fc, result);
+
+       file_free(&fc);
+       return error;
+}
+
+void
+content_info_free(struct ContentInfo *info)
+{
+       asn_DEF_ContentInfo.op->free_struct(&asn_DEF_ContentInfo, info,
+           ASFM_FREE_EVERYTHING);
+}
diff --git a/src/content_info.h b/src/content_info.h
new file mode 100644 (file)
index 0000000..87c7e61
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef SRC_CONTENT_INFO_H_
+#define SRC_CONTENT_INFO_H_
+
+/* Some wrappers for libcmscodec's ContentInfo. */
+
+#include <libcmscodec/ContentInfo.h>
+
+int content_info_load(const char *file_name, struct ContentInfo **result);
+void content_info_free(struct ContentInfo *info);
+
+#endif /* SRC_CONTENT_INFO_H_ */
diff --git a/src/file.c b/src/file.c
new file mode 100644 (file)
index 0000000..ea4d900
--- /dev/null
@@ -0,0 +1,88 @@
+#include "file.h"
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "common.h"
+
+/*
+ * Will also rewind the file as a side effect.
+ * This is currently perfect for calling users.
+ */
+static int
+get_file_size(FILE *file, long int *size)
+{
+       if (fseek(file, 0L, SEEK_END) == -1)
+               return errno ? errno : -EINVAL;
+       *size = ftell(file);
+       rewind(file);
+       return 0;
+}
+
+int
+file_load(const char *file_name, struct file_contents *fc)
+{
+       FILE *file;
+       long int file_size;
+       size_t fread_result;
+       int error;
+
+       file = fopen(file_name, "rb");
+       if (file == NULL) {
+               warnxerrno("Could not open file '%s'", file_name);
+               return errno;
+       }
+
+       error = get_file_size(file, &file_size);
+       if (error) {
+               warnxerror0(error, "Could not compute file size");
+               fclose(file);
+               return error;
+       }
+
+       fc->buffer_size = file_size;
+       fc->buffer = malloc(fc->buffer_size);
+       if (fc->buffer == NULL) {
+               warnx("Out of memory.");
+               fclose(file);
+               return -ENOMEM;
+       }
+
+       fread_result = fread(fc->buffer, 1, fc->buffer_size, file);
+       if (fread_result < fc->buffer_size) {
+               error = ferror(file);
+               if (error) {
+                       /*
+                        * The manpage doesn't say that the result is an error
+                        * code. It literally doesn't say how to obtain the
+                        * error code.
+                        */
+                       warnx("File read error. The errcode is presumably %d. (%s)",
+                           error, strerror(error));
+                       free(fc->buffer);
+                       fclose(file);
+                       return error;
+               }
+
+               /*
+                * As far as I can tell from the man page, feof() cannot return
+                * less bytes that requested like read() does.
+                */
+               warnx("Likely programming error: fread() < file size");
+               warnx("fr:%zu bs:%zu EOF:%d", fread_result, fc->buffer_size,
+                               feof(file));
+               free(fc->buffer);
+               fclose(file);
+               return -EINVAL;
+       }
+
+       fclose(file);
+       return 0;
+}
+
+void
+file_free(struct file_contents *fc)
+{
+       free(fc->buffer);
+}
diff --git a/src/file.h b/src/file.h
new file mode 100644 (file)
index 0000000..3ee0aa8
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef SRC_FILE_H_
+#define SRC_FILE_H_
+
+#include <stddef.h>
+
+/*
+ * The entire contents of the file, loaded into a buffer.
+ *
+ * Instances of this struct are expected to live on the stack.
+ */
+struct file_contents {
+       unsigned char *buffer;
+       size_t buffer_size;
+};
+
+int file_load(const char *file_name, struct file_contents *fc);
+void file_free(struct file_contents *fc);
+
+#endif /* SRC_FILE_H_ */
index 59cb66605acaf3fa8985b2e904712a9e955e5beb..e723c1e95b078acfc732590d312aba782e359ff1 100644 (file)
@@ -119,7 +119,7 @@ lfile_read(struct line_file *lfile, char **result)
         */
        for (i = 0; i < len; i++) {
                if (string[i] == '\0') {
-                       warnx("File %s has an illegal null character in its body. Please remove it.",
+                       warnx("File '%s' has an illegal null character in its body. Please remove it.",
                                        lfile_name(lfile));
                        free(string);
                        return -EINVAL;
index 94f713bebd4f2c9e09589221ec3eed3f05fb3c02..19c521089954e5c34d75da12dbbe49fb9d219b3d 100644 (file)
@@ -1,7 +1,31 @@
-#include <stdlib.h>
+#include "content_info.h"
+#include "signed_data.h"
+
+const char *FILE_NAME = "/home/ydahhrk/rpki-cache/repository/"
+               "ca.rg.net/rpki/RGnet/IZt-j9P0XqJjzM2Xi4RZKS60gOc.roa";
 
 int
 main(void)
 {
-       return EXIT_SUCCESS;
+       struct ContentInfo *cinfo;
+       struct SignedData *sdata;
+       int error;
+
+       error = content_info_load(FILE_NAME, &cinfo);
+       if (error)
+               return error;
+
+       error = signed_data_decode(&cinfo->content, &sdata);
+       if (error) {
+               content_info_free(cinfo);
+               return error;
+       }
+
+//     asn_fprint(stdout, &asn_DEF_ContentInfo, cinfo);
+//     printf("---------------------------------------------\n");
+//     asn_fprint(stdout, &asn_DEF_SignedData, sdata);
+
+       signed_data_free(sdata);
+       content_info_free(cinfo);
+       return 0;
 }
diff --git a/src/oid.c b/src/oid.c
new file mode 100644 (file)
index 0000000..b0867bf
--- /dev/null
+++ b/src/oid.c
@@ -0,0 +1,55 @@
+#include "oid.h"
+
+#include <errno.h>
+#include "common.h"
+
+#define MAX_ARCS 9
+
+/* Please update MAX_ARCS if you add an OID that has more arcs. */
+static asn_oid_arc_t OID_SHA224[] = { 2, 16, 840, 1, 101, 3, 4, 2, 4 };
+static asn_oid_arc_t OID_SHA256[] = { 2, 16, 840, 1, 101, 3, 4, 2, 1 };
+static asn_oid_arc_t OID_SHA384[] = { 2, 16, 840, 1, 101, 3, 4, 2, 2 };
+static asn_oid_arc_t OID_SHA512[] = { 2, 16, 840, 1, 101, 3, 4, 2, 3 };
+
+/*
+ * @a_oid is the original OID that's being tested.
+ * @a_arcs must be a stack-allocated array of size @len.
+ * @b_arcs is the expected array of arcs that needs to be compared to @a_oid.
+ * Its length must be @len.
+ */
+bool
+oid_equals(OBJECT_IDENTIFIER_t *const actual_oid,
+    asn_oid_arc_t const *expected_arcs,
+    size_t len)
+{
+       asn_oid_arc_t actual_arcs[MAX_ARCS];
+       ssize_t count;
+       long int i;
+
+       count = OBJECT_IDENTIFIER_get_arcs(actual_oid, actual_arcs, len);
+       if (count != len)
+               return false;
+
+       /* Most OIDs start with the same numbers, so iterate backwards. */
+       for (i = len - 1; i >= 0; i--) {
+               if (actual_arcs[i] != expected_arcs[i])
+                       return false;
+       }
+
+       return true;
+}
+
+void
+oid_print(OBJECT_IDENTIFIER_t *oid)
+{
+       asn_fprint(stdout, &asn_DEF_OBJECT_IDENTIFIER, oid);
+}
+
+bool
+is_digest_algorithm(AlgorithmIdentifier_t *algorithm)
+{
+       return OID_EQUALS(&algorithm->algorithm, OID_SHA224)
+           || OID_EQUALS(&algorithm->algorithm, OID_SHA256)
+           || OID_EQUALS(&algorithm->algorithm, OID_SHA384)
+           || OID_EQUALS(&algorithm->algorithm, OID_SHA512);
+}
diff --git a/src/oid.h b/src/oid.h
new file mode 100644 (file)
index 0000000..f898504
--- /dev/null
+++ b/src/oid.h
@@ -0,0 +1,39 @@
+#ifndef SRC_OID_H_
+#define SRC_OID_H_
+
+#include <stdbool.h>
+#include "libcmscodec/AlgorithmIdentifier.h"
+
+#include "common.h"
+
+typedef asn_oid_arc_t OID[];
+
+/* Please update MAX_ARCS if you add an OID that has more arcs. */
+static const OID CONTENT_TYPE_ATTR_OID = {
+    1, 2, 840, 113549, 1, 9, 3
+};
+static const OID MESSAGE_DIGEST_ATTR_OID = {
+    1, 2, 840, 113549, 1, 9, 4
+};
+static const OID SIGNING_TIME_ATTR_OID = {
+    1, 2, 840, 113549, 1, 9, 5
+};
+static const OID BINARY_SIGNING_TIME_ATTR_OID = {
+    1, 2, 840, 113549, 1, 9, 16, 2, 46
+};
+
+/* Use OID_EQUALS() instead. */
+bool oid_equals(OBJECT_IDENTIFIER_t *const actual_oid,
+    asn_oid_arc_t const *expected_arcs, size_t len);
+
+/*
+ * a is supposed to be a OBJECT_IDENTIFIER_t (from libcmscodec.)
+ * b is supposed to be an OID (from the typedef above.)
+ */
+#define OID_EQUALS(a, b) oid_equals(a, b, ARRAY_SIZE(b))
+
+void oid_print(OBJECT_IDENTIFIER_t *oid);
+
+bool is_digest_algorithm(AlgorithmIdentifier_t *algorithm);
+
+#endif /* SRC_OID_H_ */
diff --git a/src/signed_data.c b/src/signed_data.c
new file mode 100644 (file)
index 0000000..187047f
--- /dev/null
@@ -0,0 +1,275 @@
+#include "signed_data.h"
+
+#include <err.h>
+#include <errno.h>
+#include <libcmscodec/ContentType.h>
+#include "oid.h"
+
+/* TODO more consistent and informative error/warning messages.*/
+
+static int
+validate_content_type_attribute(CMSAttributeValue_t *value,
+    EncapsulatedContentInfo_t *eci)
+{
+       /* TODO need to decode value. */
+
+       /* eci->eContentType*/
+
+       return 0;
+}
+
+static int
+validate_message_digest_attribute(CMSAttributeValue_t *value)
+{
+       return 0; /* TODO need the content being signed */
+}
+
+static int
+validate_signed_attrs(struct SignerInfo *sinfo, EncapsulatedContentInfo_t *eci)
+{
+       struct CMSAttribute *attr;
+       struct CMSAttribute__attrValues *attrs;
+       unsigned int i;
+       bool content_type_found = false;
+       bool message_digest_found = false;
+       bool signing_time_found = false;
+       bool binary_signing_time_found = false;
+       int error;
+
+       if (sinfo->signedAttrs == NULL) {
+               warnx("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) {
+                       warnx("SignedAttrs array element %u is NULL.", i);
+                       continue;
+               }
+               attrs = &attr->attrValues;
+
+               if (attrs->list.count != 1) {
+                       warnx("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) {
+                       warnx("Programming error: Array size is 1 but array itself is NULL.");
+                       return -EINVAL;
+               }
+
+               if (OID_EQUALS(&attr->attrType, CONTENT_TYPE_ATTR_OID)) {
+                       if (content_type_found) {
+                               warnx("Multiple ContentTypes found.");
+                               return -EINVAL;
+                       }
+                       error = validate_content_type_attribute(attr->attrValues.list.array[0], eci);
+                       content_type_found = true;
+
+               } else if (OID_EQUALS(&attr->attrType, MESSAGE_DIGEST_ATTR_OID)) {
+                       if (message_digest_found) {
+                               warnx("Multiple MessageDigests found.");
+                               return -EINVAL;
+                       }
+                       error = validate_message_digest_attribute(attr->attrValues.list.array[0]);
+                       message_digest_found = true;
+
+               } else if (OID_EQUALS(&attr->attrType, SIGNING_TIME_ATTR_OID)) {
+                       if (signing_time_found) {
+                               warnx("Multiple SigningTimes found.");
+                               return -EINVAL;
+                       }
+                       error = 0; /* No validations needed for now. */
+                       signing_time_found = true;
+
+               } else if (OID_EQUALS(&attr->attrType, BINARY_SIGNING_TIME_ATTR_OID)) {
+                       if (binary_signing_time_found) {
+                               warnx("Multiple BinarySigningTimes found.");
+                               return -EINVAL;
+                       }
+                       error = 0; /* No validations needed for now. */
+                       binary_signing_time_found = true;
+
+               } else {
+                       warnx("Illegal attrType OID in SignerInfo.");
+                       return -EINVAL;
+               }
+
+               if (error)
+                       return error;
+       }
+
+       if (!content_type_found) {
+               warnx("SignerInfo lacks a ContentType attribute.");
+               return -EINVAL;
+       }
+       if (!message_digest_found) {
+               warnx("SignerInfo lacks a MessageDigest attribute.");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int
+validate(struct SignedData *sdata)
+{
+       char error_msg[256];
+       size_t error_msg_size;
+       int error;
+       struct SignerInfo *sinfo;
+
+       /* The lib's inbuilt validations. (Probably not much.) */
+       error_msg_size = sizeof(error_msg);
+       error = asn_check_constraints(&asn_DEF_SignedData, sdata, error_msg,
+           &error_msg_size);
+       if (error == -1) {
+               warnx("Error validating SignedData object: %s", error_msg);
+               return -EINVAL;
+       }
+
+       /* rfc6488#section-2.1 */
+       if (sdata->signerInfos.list.count != 1) {
+               warnx("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 */
+       if (sdata->version != 3) {
+               warnx("The SignedData version is only allowed to be 3. (Was %ld.)",
+                   sdata->version);
+               return -EINVAL;
+       }
+
+       /* rfc6488#section-2.1.2 */
+       if (sdata->digestAlgorithms.list.count != 1) {
+               warnx("The SignedData's digestAlgorithms set is supposed to have only one element. (%d given.)",
+                   sdata->digestAlgorithms.list.count);
+               return -EINVAL;
+       }
+
+       /*
+        * No idea what to do with struct DigestAlgorithmIdentifier; it's not
+        * defined anywhere and the code always seems to fall back to
+        * AlgorithmIdentifier instead. There's no API.
+        * This seems to work fine.
+        */
+       if (!is_digest_algorithm((DigestAlgorithmIdentifier_t *) sdata->digestAlgorithms.list.array[0])) {
+               warnx("The SignedData's digestAlgorithm OID is not listed in RFC 5754.");
+               return -EINVAL;
+       }
+
+       /* section-2.1.3 */
+       /* TODO need a callback for specific signed object types */
+
+       /* rfc6488#section-2.1.4 */
+       if (sdata->certificates == NULL) {
+               warnx("The SignedData does not contain certificates.");
+               return -EINVAL;
+       }
+
+       if (sdata->certificates->list.count != 1) {
+               warnx("The SignedData contains %d certificates, one expected.",
+                   sdata->certificates->list.count);
+               return -EINVAL;
+       }
+
+       /* rfc6488#section-2.1.5 */
+       if (sdata->crls != NULL && sdata->crls->list.count > 0) {
+               warnx("The SignedData contains at least one crls.");
+               return -EINVAL;
+       }
+
+       /* rfc6488#section-2.1.6.1 */
+       sinfo = sdata->signerInfos.list.array[0];
+       if (sinfo == NULL) {
+               warnx("The SignerInfo object is NULL.");
+               return -EINVAL;
+       }
+       if (sinfo->version != 3) {
+               warnx("The SignerInfo version is only allowed to be 3. (Was %ld.)",
+                   sinfo->version);
+               return -EINVAL;
+       }
+
+       /* rfc6488#section-2.1.6.2 */
+       /*
+        * TODO need the "EE certificate carried in the CMS certificates field."
+        */
+
+       /* rfc6488#section-2.1.6.3 */
+       if (!is_digest_algorithm((AlgorithmIdentifier_t *) &sinfo->digestAlgorithm)) {
+               warnx("The SignerInfo digestAlgorithm OID is not listed in RFC 5754.");
+               return -EINVAL;
+       }
+
+       /* rfc6488#section-2.1.6.4 */
+       error = validate_signed_attrs(sinfo, &sdata->encapContentInfo);
+       if (error)
+               return error;
+
+       /* rfc6488#section-2.1.6.5 */
+       /*
+        * RFC 6485 was obsoleted by 7935. 7935 simply refers to 5652.
+        *
+        * RFC 5652:
+        *
+        * > Since each signer can employ a different digital signature
+        * > technique, and future specifications could update the syntax, all
+        * > implementations MUST gracefully handle unimplemented versions of
+        * > SignerInfo.  Further, since all implementations will not support
+        * > every possible signature algorithm, all implementations MUST
+        * > gracefully handle unimplemented signature algorithms when they are
+        * > encountered.
+        *
+        * So, nothing to do for now.
+        */
+
+       /* rfc6488#section-2.1.6.6 */
+       /* Again, nothing to do for now. */
+
+       /* rfc6488#section-2.1.6.7 */
+       if (sinfo->unsignedAttrs != NULL && sinfo->unsignedAttrs->list.count > 0) {
+               warnx("SignerInfo has at least one unsignedAttr.");
+               return -EINVAL;
+       }
+
+       /* TODO section 3 */
+
+       return 0;
+}
+
+int
+signed_data_decode(ANY_t *coded, struct SignedData **result)
+{
+       struct SignedData *sdata = NULL;
+       asn_dec_rval_t rval;
+       int error;
+
+       rval = ber_decode(0, &asn_DEF_SignedData, (void **) &sdata, coded->buf,
+           coded->size);
+       if (rval.code != RC_OK) {
+               warnx("Error decoding signed data object: %d", rval.code);
+               /* Must free partial signed data according to API contracts. */
+               signed_data_free(sdata);
+               return -EINVAL;
+       }
+
+       error = validate(sdata);
+       if (error) {
+               signed_data_free(sdata);
+               return error;
+       }
+
+       *result = sdata;
+       return 0;
+}
+
+void
+signed_data_free(struct SignedData *sdata)
+{
+       asn_DEF_SignedData.op->free_struct(&asn_DEF_SignedData, sdata,
+           ASFM_FREE_EVERYTHING);
+}
diff --git a/src/signed_data.h b/src/signed_data.h
new file mode 100644 (file)
index 0000000..22923d4
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef SRC_SIGNED_DATA_H_
+#define SRC_SIGNED_DATA_H_
+
+/* Some wrappers for libcmscodec's SignedData. */
+
+#include <libcmscodec/SignedData.h>
+
+int signed_data_decode(ANY_t *coded, struct SignedData **result);
+void signed_data_free(struct SignedData *sdata);
+
+#endif /* SRC_SIGNED_DATA_H_ */
index 9dfa869b3b2c2431ac168541a66a0495b63446d2..79205cb5c6dfa30a3956ad9a257368e7fffc9347 100644 (file)
--- a/src/tal.h
+++ b/src/tal.h
@@ -1,6 +1,8 @@
 #ifndef TAL_H_
 #define TAL_H_
 
+/* This is RFC 7730. */
+
 struct tal;
 
 int tal_load(const char *, struct tal **);