summaryrefslogtreecommitdiff
path: root/trust/parser.c
diff options
context:
space:
mode:
authorStef Walter <stefw@gnome.org>2013-03-14 21:08:01 +0100
committerStef Walter <stefw@gnome.org>2013-03-15 18:00:10 +0100
commit2d75eb32793a569dc3de359bb623713c80393d24 (patch)
treeaa62978bc970d95082769c9725325d31cc413058 /trust/parser.c
parentd7d68de6c9de9190c85da36b731e61ae3421a811 (diff)
trust: Add a builder which builds objects out of parsed data
The builder completes the objects from the parsed data and takes over the responsibilities that the parser and adapter previously shared. This is necessary to prepare for arbitrary data coming from the p11-kit specific input files. https://bugs.freedesktop.org/show_bug.cgi?id=62329
Diffstat (limited to 'trust/parser.c')
-rw-r--r--trust/parser.c836
1 files changed, 196 insertions, 640 deletions
diff --git a/trust/parser.c b/trust/parser.c
index 0b62f01..978d30e 100644
--- a/trust/parser.c
+++ b/trust/parser.c
@@ -34,7 +34,6 @@
#include "config.h"
-#include "adapter.h"
#include "array.h"
#include "asn1.h"
#include "attrs.h"
@@ -63,359 +62,115 @@
#include <unistd.h>
struct _p11_parser {
+ p11_index *index;
+ p11_asn1_cache *asn1_cache;
p11_dict *asn1_defs;
-
- /* Set during a parse */
- p11_parser_sink sink;
- void *sink_data;
- const char *basename;
+ char *basename;
int flags;
-
- /* Parsing state */
- p11_array *parsing;
- node_asn *cert_asn;
- const unsigned char *cert_der;
- size_t cert_len;
};
+#define ID_LENGTH P11_CHECKSUM_SHA1_LENGTH
+
typedef int (* parser_func) (p11_parser *parser,
const unsigned char *data,
size_t length);
-static void
-begin_parsing (p11_parser *parser,
- node_asn *cert_asn,
- const unsigned char *cert_der,
- size_t cert_len)
+static CK_ATTRIBUTE *
+populate_trust (p11_parser *parser,
+ CK_ATTRIBUTE *attrs)
{
- return_if_fail (parser->parsing == NULL);
- return_if_fail (parser->cert_asn == NULL);
- return_if_fail (parser->cert_der == NULL);
+ CK_BBOOL trustedv;
+ CK_BBOOL distrustv;
- parser->parsing = p11_array_new (NULL);
+ CK_ATTRIBUTE trusted = { CKA_TRUSTED, &trustedv, sizeof (trustedv) };
+ CK_ATTRIBUTE distrust = { CKA_X_DISTRUSTED, &distrustv, sizeof (distrustv) };
/*
- * We make note of these for later looking up certificate
- * extensions. See p11_parsed_find_extension().
+ * If we're are parsing an anchor location, then warn about any ditsrusted
+ * certificates there, but don't go ahead and automatically make them
+ * trusted anchors.
*/
- parser->cert_asn = cert_asn;
- parser->cert_der = cert_der;
- parser->cert_len = cert_len;
-}
+ if (parser->flags & P11_PARSE_FLAG_ANCHOR) {
+ if (p11_attrs_find_bool (attrs, CKA_X_DISTRUSTED, &distrustv) && distrustv) {
+ p11_message ("certificate with distrust in location for anchors: %s", parser->basename);
+ return attrs;
-static void
-finish_parsing (p11_parser *parser,
- node_asn *cert_asn)
-{
- CK_ATTRIBUTE *attrs;
- int i;
+ }
- return_if_fail (parser->parsing != NULL);
+ trustedv = CK_TRUE;
+ distrustv = CK_FALSE;
- /* This is a double check */
- return_if_fail (parser->cert_asn == cert_asn);
+ /*
+ * If we're parsing a blacklist location, then force all certificates to
+ * be blacklisted, regardless of whether they contain anchor information.
+ */
+ } else if (parser->flags & P11_PARSE_FLAG_BLACKLIST) {
+ if (p11_attrs_find_bool (attrs, CKA_TRUSTED, &trustedv) && trustedv)
+ p11_message ("overriding trust for anchor in blacklist: %s", parser->basename);
- /* Update the certificate state */
- p11_parsing_update_certificate (parser, parser->parsing);
+ trustedv = CK_FALSE;
+ distrustv = CK_TRUE;
- /* Call all the hooks for generating further objects */
- p11_adapter_build_objects (parser, parser->parsing);
+ /*
+ * If the location doesn't have a flag, then fill in trust attributes
+ * if they are missing: neither an anchor or blacklist.
+ */
+ } else {
+ trustedv = CK_FALSE;
+ distrustv = CK_FALSE;
- for (i = 0; i < parser->parsing->num; i++) {
- attrs = parser->parsing->elem[i];
- if (parser->sink)
- (parser->sink) (attrs, parser->sink_data);
- else
- p11_attrs_free (attrs);
+ if (p11_attrs_find_valid (attrs, CKA_TRUSTED))
+ trusted.type = CKA_INVALID;
+ if (p11_attrs_find_valid (attrs, CKA_X_DISTRUSTED))
+ distrust.type = CKA_INVALID;
}
- p11_array_free (parser->parsing);
-
- parser->parsing = NULL;
- parser->cert_asn = NULL;
- parser->cert_der = NULL;
- parser->cert_len = 0;
+ return p11_attrs_build (attrs, &trusted, &distrust, NULL);
}
-#define ID_LENGTH P11_CHECKSUM_SHA1_LENGTH
-
static void
-id_generate (p11_parser *parser,
- CK_BYTE *vid)
+sink_object (p11_parser *parser,
+ CK_ATTRIBUTE *attrs)
{
- CK_ULONG val = p11_module_next_id ();
- p11_checksum_sha1 (vid, &val, sizeof (val), NULL);
-}
+ CK_OBJECT_CLASS klass;
+ CK_RV rv;
-static CK_ATTRIBUTE *
-build_object (p11_parser *parser,
- CK_OBJECT_CLASS vclass,
- CK_BYTE *vid,
- const char *vlabel)
-{
- CK_ATTRIBUTE *attrs = NULL;
- CK_BBOOL vtrue = CK_TRUE;
- CK_BBOOL vfalse = CK_FALSE;
-
- CK_ATTRIBUTE klass = { CKA_CLASS, &vclass, sizeof (vclass) };
- CK_ATTRIBUTE token = { CKA_TOKEN, &vtrue, sizeof (vtrue) };
- CK_ATTRIBUTE private = { CKA_PRIVATE, &vfalse, sizeof (vfalse) };
- CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &vfalse, sizeof (vfalse) };
- CK_ATTRIBUTE id = { CKA_ID, vid, ID_LENGTH };
- CK_ATTRIBUTE label = { CKA_LABEL, };
-
- if (!vlabel)
- vlabel = parser->basename;
- if (vlabel) {
- label.pValue = (void *)vlabel;
- label.ulValueLen = strlen (vlabel);
- } else {
- label.type = CKA_INVALID;
+ if (p11_attrs_find_ulong (attrs, CKA_CLASS, &klass) &&
+ klass == CKO_CERTIFICATE) {
+ attrs = populate_trust (parser, attrs);
+ return_if_fail (attrs != NULL);
}
- if (!vid)
- id.type = CKA_INVALID;
-
- return p11_attrs_build (attrs, &klass, &token, &private, &modifiable,
- &id, &label, NULL);
+ rv = p11_index_take (parser->index, attrs, NULL);
+ if (rv != CKR_OK)
+ p11_message ("couldn't load file into objects: %s", parser->basename);
}
static void
-calc_check_value (const unsigned char *data,
- size_t length,
- CK_BYTE *check_value)
-{
- unsigned char checksum[P11_CHECKSUM_SHA1_LENGTH];
- p11_checksum_sha1 (checksum, data, length, NULL);
- memcpy (check_value, checksum, 3);
-}
-
-static bool
-calc_date (node_asn *cert,
- const char *field,
- CK_DATE *date)
-{
- node_asn *choice;
- struct tm when;
- char buf[64];
- time_t timet;
- char *sub;
- int len;
- int ret;
-
- choice = asn1_find_node (cert, field);
- return_val_if_fail (choice != NULL, false);
-
- len = sizeof (buf) - 1;
- ret = asn1_read_value (cert, field, buf, &len);
- return_val_if_fail (ret == ASN1_SUCCESS, false);
-
- sub = strconcat (field, ".", buf, NULL);
-
- if (strcmp (buf, "generalTime") == 0) {
- len = sizeof (buf) - 1;
- ret = asn1_read_value (cert, sub, buf, &len);
- return_val_if_fail (ret == ASN1_SUCCESS, false);
- timet = p11_asn1_parse_general (buf, &when);
- return_val_if_fail (timet >= 0, false);
-
- } else if (strcmp (buf, "utcTime") == 0) {
- len = sizeof (buf) - 1;
- ret = asn1_read_value (cert, sub, buf, &len);
- return_val_if_fail (ret == ASN1_SUCCESS, false);
- timet = p11_asn1_parse_utc (buf, &when);
- return_val_if_fail (timet >= 0, false);
-
- } else {
- return_val_if_reached (false);
- }
-
- free (sub);
-
- assert (sizeof (date->year) == 4);
- snprintf ((char *)buf, 5, "%04d", 1900 + when.tm_year);
- memcpy (date->year, buf, 4);
-
- assert (sizeof (date->month) == 2);
- snprintf ((char *)buf, 3, "%02d", when.tm_mon + 1);
- memcpy (date->month, buf, 2);
-
- assert (sizeof (date->day) == 2);
- snprintf ((char *)buf, 3, "%02d", when.tm_mday);
- memcpy (date->day, buf, 2);
-
- return true;
-}
-
-static bool
-calc_element (node_asn *el,
- const unsigned char *data,
- size_t length,
- const char *field,
- CK_ATTRIBUTE *attr)
-{
- int ret;
- int start, end;
-
- ret = asn1_der_decoding_startEnd (el, data, length, field, &start, &end);
- return_val_if_fail (ret == ASN1_SUCCESS, false);
- return_val_if_fail (end >= start, false);
-
- attr->pValue = (void *)(data + start);
- attr->ulValueLen = (end - start) + 1;
- return true;
-}
-
-static CK_ATTRIBUTE *
-build_x509_certificate (p11_parser *parser,
- CK_BYTE *vid,
- node_asn *cert,
- const unsigned char *data,
- size_t length)
+id_generate (p11_parser *parser,
+ CK_BYTE *vid)
{
- CK_ATTRIBUTE *attrs;
- CK_CERTIFICATE_TYPE vx509 = CKC_X_509;
- CK_BYTE vchecksum[3];
- char *label;
-
- CK_DATE vstart;
- CK_DATE vend;
-
- /* Filled in later */
- CK_ULONG vcategory = 0;
- CK_BBOOL vtrusted = (parser->flags & P11_PARSE_FLAG_ANCHOR) ? CK_TRUE : CK_FALSE;
- CK_BBOOL vdistrusted = (parser->flags & P11_PARSE_FLAG_BLACKLIST) ? CK_TRUE : CK_FALSE;
-
- CK_ATTRIBUTE certificate_type = { CKA_CERTIFICATE_TYPE, &vx509, sizeof (vx509) };
- CK_ATTRIBUTE certificate_category = { CKA_CERTIFICATE_CATEGORY, &vcategory, sizeof (vcategory) };
- CK_ATTRIBUTE value = { CKA_VALUE, (void *)data, length };
-
- CK_ATTRIBUTE check_value = { CKA_CHECK_VALUE, &vchecksum, sizeof (vchecksum) };
- CK_ATTRIBUTE trusted = { CKA_TRUSTED, &vtrusted, sizeof (vtrusted) };
- CK_ATTRIBUTE distrusted = { CKA_X_DISTRUSTED, &vdistrusted, sizeof (vdistrusted) };
- CK_ATTRIBUTE start_date = { CKA_START_DATE, &vstart, sizeof (vstart) };
- CK_ATTRIBUTE end_date = { CKA_END_DATE, &vend, sizeof (vend) };
- CK_ATTRIBUTE subject = { CKA_SUBJECT, };
- CK_ATTRIBUTE issuer = { CKA_ISSUER, };
- CK_ATTRIBUTE serial_number = { CKA_SERIAL_NUMBER, };
-
- /*
- * The following are not present:
- * CKA_URL
- * CKA_HASH_OF_SUBJECT_PUBLIC_KEY
- * CKA_HASH_OF_ISSUER_PUBLIC_KEY
- * CKA_JAVA_MIDP_SECURITY_DOMAIN
- */
-
- calc_check_value (data, length, vchecksum);
-
- if (!calc_date (cert, "tbsCertificate.validity.notBefore", &vstart))
- start_date.type = CKA_INVALID;
- if (!calc_date (cert, "tbsCertificate.validity.notAfter", &vend))
- end_date.type = CKA_INVALID;
-
- if (!calc_element (cert, data, length, "tbsCertificate.issuer.rdnSequence", &issuer))
- issuer.type = CKA_INVALID;
- if (!calc_element (cert, data, length, "tbsCertificate.subject.rdnSequence", &subject))
- subject.type = CKA_INVALID;
- if (!calc_element (cert, data, length, "tbsCertificate.serialNumber", &serial_number))
- serial_number.type = CKA_INVALID;
-
- label = p11_x509_lookup_dn_name (parser->cert_asn, "tbsCertificate.subject",
- parser->cert_der, parser->cert_len, P11_OID_CN);
- if (!label)
- label = p11_x509_lookup_dn_name (parser->cert_asn, "tbsCertificate.subject",
- parser->cert_der, parser->cert_len, P11_OID_OU);
- if (!label)
- label = p11_x509_lookup_dn_name (parser->cert_asn, "tbsCertificate.subject",
- parser->cert_der, parser->cert_len, P11_OID_O);
-
- attrs = build_object (parser, CKO_CERTIFICATE, vid, label);
- return_val_if_fail (attrs != NULL, NULL);
- free (label);
-
- attrs = p11_attrs_build (attrs, &certificate_type, &certificate_category,
- &check_value, &trusted, &distrusted, &start_date, &end_date,
- &subject, &issuer, &serial_number, &value,
- NULL);
- return_val_if_fail (attrs != NULL, NULL);
-
- if (!p11_array_push (parser->parsing, attrs))
- return_val_if_reached (NULL);
-
- return attrs;
+ CK_ULONG val = p11_module_next_id ();
+ p11_checksum_sha1 (vid, &val, sizeof (val), NULL);
}
static CK_ATTRIBUTE *
-match_parsing_object (p11_parser *parser,
- CK_ATTRIBUTE *match)
-{
- CK_ATTRIBUTE *attrs;
- int i;
-
- for (i = 0; i < parser->parsing->num; i++) {
- attrs = parser->parsing->elem[i];
- if (p11_attrs_match (attrs, match))
- return attrs;
- }
-
- return NULL;
-}
-
-unsigned char *
-p11_parsing_get_extension (p11_parser *parser,
- p11_array *parsing,
- const unsigned char *oid,
- size_t *length)
+certificate_attrs (p11_parser *parser,
+ CK_BYTE *idv,
+ const unsigned char *der,
+ size_t der_len)
{
- CK_OBJECT_CLASS klass = CKO_X_CERTIFICATE_EXTENSION;
- CK_ATTRIBUTE *attrs;
- CK_ATTRIBUTE *attr;
-
- CK_ATTRIBUTE match[] = {
- { CKA_OBJECT_ID, (void *)oid, p11_oid_length (oid) },
- { CKA_CLASS, &klass, sizeof (klass) },
- { CKA_INVALID },
- };
-
- return_val_if_fail (parser != NULL, NULL);
- return_val_if_fail (parser->parsing == parsing, NULL);
- return_val_if_fail (length != NULL, NULL);
- return_val_if_fail (oid != NULL, NULL);
-
- attrs = match_parsing_object (parser, match);
- if (attrs != NULL) {
- attr = p11_attrs_find (attrs, CKA_VALUE);
- return_val_if_fail (attr != NULL, NULL);
-
- *length = attr->ulValueLen;
- return memdup (attr->pValue, attr->ulValueLen);
-
- /* Couldn't find a parsed extension, so look in the current certificate */
- } else if (parser->cert_asn) {
- return p11_x509_find_extension (parser->cert_asn, oid,
- parser->cert_der, parser->cert_len,
- length);
- }
-
- return NULL;
-}
-
-CK_ATTRIBUTE *
-p11_parsing_get_certificate (p11_parser *parser,
- p11_array *parsing)
-{
- CK_OBJECT_CLASS klass = CKO_CERTIFICATE;
-
- CK_ATTRIBUTE match[] = {
- { CKA_CLASS, &klass, sizeof (klass) },
- { CKA_INVALID },
- };
+ CK_OBJECT_CLASS klassv = CKO_CERTIFICATE;
+ CK_CERTIFICATE_TYPE x509 = CKC_X_509;
+ CK_BBOOL modifiablev = CK_FALSE;
- return_val_if_fail (parser != NULL, NULL);
- return_val_if_fail (parser->parsing == parsing, NULL);
+ CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &modifiablev, sizeof (modifiablev) };
+ CK_ATTRIBUTE klass = { CKA_CLASS, &klassv, sizeof (klassv) };
+ CK_ATTRIBUTE certificate_type = { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) };
+ CK_ATTRIBUTE value = { CKA_VALUE, (void *)der, der_len };
+ CK_ATTRIBUTE id = { CKA_ID, idv, ID_LENGTH };
- return match_parsing_object (parser, match);
+ return p11_attrs_build (NULL, &klass, &modifiable, &certificate_type, &value, &id, NULL);
}
static int
@@ -423,81 +178,72 @@ parse_der_x509_certificate (p11_parser *parser,
const unsigned char *data,
size_t length)
{
- CK_BYTE vid[ID_LENGTH];
+ CK_BYTE idv[ID_LENGTH];
CK_ATTRIBUTE *attrs;
+ CK_ATTRIBUTE *value;
node_asn *cert;
cert = p11_asn1_decode (parser->asn1_defs, "PKIX1.Certificate", data, length, NULL);
if (cert == NULL)
return P11_PARSE_UNRECOGNIZED;
- begin_parsing (parser, cert, data, length);
-
/* The CKA_ID links related objects */
- id_generate (parser, vid);
+ id_generate (parser, idv);
- attrs = build_x509_certificate (parser, vid, cert, data, length);
+ attrs = certificate_attrs (parser, idv, data, length);
return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE);
- finish_parsing (parser, cert);
- asn1_delete_structure (&cert);
+ value = p11_attrs_find (attrs, CKA_VALUE);
+ assert (value != NULL);
+ p11_asn1_cache_take (parser->asn1_cache, cert, "PKIX1.Certificate",
+ value->pValue, value->ulValueLen);
+
+ sink_object (parser, attrs);
return P11_PARSE_SUCCESS;
}
-static int
-build_der_extension (p11_parser *parser,
- CK_ATTRIBUTE *cert,
- const unsigned char *oid_der,
- CK_BBOOL vcritical,
- const unsigned char *ext_der,
- int ext_len)
+static CK_ATTRIBUTE *
+extension_attrs (p11_parser *parser,
+ CK_BYTE *idv,
+ const unsigned char *oid_der,
+ CK_BBOOL vcritical,
+ const unsigned char *ext_der,
+ int ext_len)
{
+ CK_OBJECT_CLASS klassv = CKO_X_CERTIFICATE_EXTENSION;
+ CK_BBOOL modifiablev = CK_FALSE;
+
+ CK_ATTRIBUTE klass = { CKA_CLASS, &klassv, sizeof (klassv) };
+ CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &modifiablev, sizeof (modifiablev) };
CK_ATTRIBUTE critical = { CKA_X_CRITICAL, &vcritical, sizeof (vcritical) };
CK_ATTRIBUTE oid = { CKA_OBJECT_ID, (void *)oid_der, p11_oid_length (oid_der) };
CK_ATTRIBUTE value = { CKA_VALUE, (void *)ext_der, ext_len };
- CK_ATTRIBUTE invalid = { CKA_INVALID, };
-
- CK_ATTRIBUTE *attrs;
- CK_ATTRIBUTE *id;
- CK_ATTRIBUTE *label;
+ CK_ATTRIBUTE id = { CKA_ID, idv, ID_LENGTH };
- attrs = build_object (parser, CKO_X_CERTIFICATE_EXTENSION, NULL, NULL);
- return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE);
-
- id = p11_attrs_find (cert, CKA_ID);
- if (id == NULL)
- id = &invalid;
- label = p11_attrs_find (cert, CKA_LABEL);
- if (id == NULL)
- label = &invalid;
-
- attrs = p11_attrs_build (attrs, id, label, &oid, &critical, &value, NULL);
- return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE);
+ if (ext_der == NULL)
+ value.type = CKA_INVALID;
- if (!p11_array_push (parser->parsing, attrs))
- return_val_if_reached (P11_PARSE_FAILURE);
-
- return P11_PARSE_SUCCESS;
+ return p11_attrs_build (NULL, &id, &klass, &modifiable, &oid, &critical, &value, NULL);
}
-static int
-build_stapled_extension (p11_parser *parser,
- CK_ATTRIBUTE *cert,
- const unsigned char *oid,
- CK_BBOOL critical,
- node_asn *ext)
+static CK_ATTRIBUTE *
+stapled_attrs (p11_parser *parser,
+ CK_BYTE *idv,
+ const unsigned char *oid,
+ CK_BBOOL critical,
+ node_asn *ext)
{
+ CK_ATTRIBUTE *attrs;
unsigned char *der;
size_t len;
- int ret;
- der = p11_asn1_encode (ext, &len);
- return_val_if_fail (der != NULL, P11_PARSE_FAILURE);
+ attrs = extension_attrs (parser, idv, oid, critical, NULL, 0);
+ return_val_if_fail (attrs != NULL, NULL);
- ret = build_der_extension (parser, cert, oid, critical, (unsigned char *)der, len);
- free (der);
+ der = p11_asn1_encode (ext, &len);
+ return_val_if_fail (der != NULL, NULL);
- return ret;
+ return p11_attrs_take (attrs, CKA_VALUE, der, len);
}
static p11_dict *
@@ -537,13 +283,14 @@ load_seq_of_oid_str (node_asn *node,
return oids;
}
-static int
-build_eku_extension (p11_parser *parser,
- CK_ATTRIBUTE *cert,
- const unsigned char *oid,
- CK_BBOOL critical,
- p11_dict *oid_strs)
+static CK_ATTRIBUTE *
+stapled_eku_attrs (p11_parser *parser,
+ CK_BYTE *idv,
+ const unsigned char *oid,
+ CK_BBOOL critical,
+ p11_dict *oid_strs)
{
+ CK_ATTRIBUTE *attrs;
p11_dictiter iter;
node_asn *dest;
int count = 0;
@@ -551,15 +298,15 @@ build_eku_extension (p11_parser *parser,
int ret;
dest = p11_asn1_create (parser->asn1_defs, "PKIX1.ExtKeyUsageSyntax");
- return_val_if_fail (dest != NULL, P11_PARSE_FAILURE);
+ return_val_if_fail (dest != NULL, NULL);
p11_dict_iterate (oid_strs, &iter);
while (p11_dict_next (&iter, NULL, &value)) {
ret = asn1_write_value (dest, "", "NEW", 1);
- return_val_if_fail (ret == ASN1_SUCCESS, P11_PARSE_FAILURE);
+ return_val_if_fail (ret == ASN1_SUCCESS, NULL);
ret = asn1_write_value (dest, "?LAST", value, -1);
- return_val_if_fail (ret == ASN1_SUCCESS, P11_PARSE_FAILURE);
+ return_val_if_fail (ret == ASN1_SUCCESS, NULL);
count++;
}
@@ -579,210 +326,40 @@ build_eku_extension (p11_parser *parser,
if (count == 0) {
ret = asn1_write_value (dest, "", "NEW", 1);
- return_val_if_fail (ret == ASN1_SUCCESS, P11_PARSE_FAILURE);
+ return_val_if_fail (ret == ASN1_SUCCESS, NULL);
ret = asn1_write_value (dest, "?LAST", P11_OID_RESERVED_PURPOSE_STR, -1);
- return_val_if_fail (ret == ASN1_SUCCESS, P11_PARSE_FAILURE);
+ return_val_if_fail (ret == ASN1_SUCCESS, NULL);
}
- ret = build_stapled_extension (parser, cert, oid, critical, dest);
+ attrs = stapled_attrs (parser, idv, oid, critical, dest);
asn1_delete_structure (&dest);
- return ret;
-}
-
-static int
-build_bc_extension (p11_parser *parser,
- CK_ATTRIBUTE *cert,
- CK_BBOOL critical,
- int is_ca)
-{
- node_asn *ext;
- int ret;
-
- ext = p11_asn1_create (parser->asn1_defs, "PKIX1.BasicConstraints");
- return_val_if_fail (ext != NULL, P11_PARSE_FAILURE);
-
- /* FALSE is the default, so clear if not CA */
- ret = asn1_write_value (ext, "cA", is_ca ? "TRUE" : NULL, is_ca ? -1 : 0);
- return_val_if_fail (ret == ASN1_SUCCESS, P11_PARSE_FAILURE);
-
- /* Clear this optional value */
- ret = asn1_write_value (ext, "pathLenConstraint", NULL, 0);
- return_val_if_fail (ret == ASN1_SUCCESS, P11_PARSE_FAILURE);
-
- ret = build_stapled_extension (parser, cert, P11_OID_BASIC_CONSTRAINTS, critical, ext);
- asn1_delete_structure (&ext);
-
- return ret;
-}
-
-static bool
-is_v1_x509_authority (CK_ATTRIBUTE *cert,
- node_asn *node)
-{
- CK_ATTRIBUTE *subject;
- CK_ATTRIBUTE *issuer;
- char buffer[16];
- int len;
- int ret;
-
- len = sizeof (buffer);
- ret = asn1_read_value (node, "tbsCertificate.version", buffer, &len);
-
- /* The default value */
- if (ret == ASN1_ELEMENT_NOT_FOUND) {
- ret = ASN1_SUCCESS;
- buffer[0] = 0;
- len = 1;
- }
-
- return_val_if_fail (ret == ASN1_SUCCESS, false);
-
- /*
- * In X.509 version v1 is the integer zero. Two's complement
- * integer, but zero is easy to read.
- */
- if (len != 1 || buffer[0] != 0)
- return false;
-
- /* Must be self-signed, ie: same subject and issuer */
- subject = p11_attrs_find (cert, CKA_SUBJECT);
- issuer = p11_attrs_find (cert, CKA_ISSUER);
- return (subject != NULL && issuer != NULL &&
- p11_attr_match_value (subject, issuer->pValue, issuer->ulValueLen));
-}
-
-static void
-update_category (p11_parser *parser,
- CK_ATTRIBUTE *cert)
-{
- CK_ATTRIBUTE *category;
- bool is_ca = 0;
- unsigned char *data;
- size_t length;
- int ret;
-
- /* See if we have a basic constraints extension */
- data = p11_parsing_get_extension (parser, parser->parsing, P11_OID_BASIC_CONSTRAINTS, &length);
- if (data) {
- if (!p11_x509_parse_basic_constraints (parser->asn1_defs, data, length, &is_ca))
- p11_message ("invalid basic constraints certificate extension");
- free (data);
-
- } else if (is_v1_x509_authority (cert, parser->cert_asn)) {
- /*
- * If there is no basic constraints extension, and the CA version is
- * v1, and is self-signed, then we assume this is a certificate authority.
- * So we add a BasicConstraints stapled certificate extension
- */
- is_ca = 1;
- ret = build_bc_extension (parser, cert, CK_FALSE, is_ca);
- return_if_fail (ret == P11_PARSE_SUCCESS);
- }
-
- category = p11_attrs_find (cert, CKA_CERTIFICATE_CATEGORY);
- assert (category != NULL);
- assert (category->pValue != NULL);
- assert (category->ulValueLen == sizeof (CK_ULONG));
-
- /*
- * In the PKCS#11 spec:
- * 0 = unspecified (default value)
- * 1 = token user
- * 2 = authority
- * 3 = other entity
- */
- *((CK_ULONG *)category->pValue) = is_ca ? 2 : 3;
-}
-
-static void
-update_trust_and_distrust (p11_parser *parser,
- CK_ATTRIBUTE *cert)
-{
- CK_ATTRIBUTE *attr;
- CK_BBOOL trusted;
- CK_BBOOL distrusted;
- unsigned char *data;
- size_t length;
- p11_array *ekus;
-
- /*
- * This function is called to update the CKA_TRUSTED and CKA_X_DISTRUSTED
- * fields (anchor and blacklist). Some other code may have updated the
- * related extensions, so this may be called more than once.
- *
- * Since some input like OpenSSL model blacklists as anchors with all
- * purposes being removed/rejected, we account for that here. If there
- * is an ExtendedKeyUsage without any useful purposes, then treat
- * like a blacklist.
- *
- * The certificate is an anchor if the parser is in anchor mode.
- */
-
- trusted = (parser->flags & P11_PARSE_FLAG_ANCHOR) ? CK_TRUE : CK_FALSE;
- distrusted = (parser->flags & P11_PARSE_FLAG_BLACKLIST) ? CK_TRUE : CK_FALSE;
-
- data = p11_parsing_get_extension (parser, parser->parsing, P11_OID_EXTENDED_KEY_USAGE, &length);
- if (data) {
- ekus = p11_x509_parse_extended_key_usage (parser->asn1_defs, data, length);
- if (ekus == NULL)
- p11_message ("invalid extendend key usage certificate extension");
- else if (ekus->num == 0) {
- distrusted = CK_TRUE;
- trusted = CK_FALSE;
- }
-
- p11_array_free (ekus);
- free (data);
- }
-
- attr = p11_attrs_find (cert, CKA_TRUSTED);
- assert (attr != NULL);
- assert (attr->pValue != NULL);
- assert (attr->ulValueLen == sizeof (CK_BBOOL));
- *((CK_BBOOL *)attr->pValue) = trusted;
-
- attr = p11_attrs_find (cert, CKA_X_DISTRUSTED);
- assert (attr != NULL);
- assert (attr->pValue != NULL);
- assert (attr->ulValueLen == sizeof (CK_BBOOL));
- *((CK_BBOOL *)attr->pValue) = distrusted;
-}
-
-void
-p11_parsing_update_certificate (p11_parser *parser,
- p11_array *parsing)
-{
- CK_ATTRIBUTE *cert;
-
- /* Find the certificate to update */
- cert = p11_parsing_get_certificate (parser, parsing);
- if (cert == NULL)
- return;
-
- /* This should match the above cert */
- assert (parser->cert_asn != NULL);
-
- update_category (parser, cert);
- update_trust_and_distrust (parser, cert);
+ return attrs;
}
-
-static int
+static CK_ATTRIBUTE *
build_openssl_extensions (p11_parser *parser,
CK_ATTRIBUTE *cert,
+ CK_BYTE *idv,
node_asn *aux,
const unsigned char *aux_der,
size_t aux_len)
{
+ CK_BBOOL trusted = CK_FALSE;
+ CK_BBOOL distrust = CK_FALSE;
+
+ CK_ATTRIBUTE trust_attrs[] = {
+ { CKA_TRUSTED, &trusted, sizeof (trusted) },
+ { CKA_X_DISTRUSTED, &distrust, sizeof (distrust) },
+ { CKA_INVALID },
+ };
+
+ CK_ATTRIBUTE *attrs;
p11_dict *trust = NULL;
p11_dict *reject = NULL;
p11_dictiter iter;
- CK_ATTRIBUTE *attr;
- CK_BBOOL trusted;
- CK_BBOOL distrust;
void *key;
int start;
int end;
@@ -800,7 +377,7 @@ build_openssl_extensions (p11_parser *parser,
trust = load_seq_of_oid_str (aux, "trust");
ret = asn1_number_of_elements (aux, "reject", &num);
- return_val_if_fail (ret == ASN1_SUCCESS || ret == ASN1_ELEMENT_NOT_FOUND, P11_PARSE_FAILURE);
+ return_val_if_fail (ret == ASN1_SUCCESS || ret == ASN1_ELEMENT_NOT_FOUND, NULL);
if (ret == ASN1_SUCCESS)
reject = load_seq_of_oid_str (aux, "reject");
@@ -818,8 +395,9 @@ build_openssl_extensions (p11_parser *parser,
*/
if (trust) {
- ret = build_eku_extension (parser, cert, P11_OID_EXTENDED_KEY_USAGE, CK_TRUE, trust);
- return_val_if_fail (ret == P11_PARSE_SUCCESS, ret);
+ attrs = stapled_eku_attrs (parser, idv, P11_OID_EXTENDED_KEY_USAGE, CK_TRUE, trust);
+ return_val_if_fail (attrs != NULL, NULL);
+ sink_object (parser, attrs);
}
/*
@@ -831,49 +409,37 @@ build_openssl_extensions (p11_parser *parser,
*/
if (reject && p11_dict_size (reject) > 0) {
- ret = build_eku_extension (parser, cert, P11_OID_OPENSSL_REJECT, CK_FALSE, reject);
- return_val_if_fail (ret == P11_PARSE_SUCCESS, ret);
+ attrs = stapled_eku_attrs (parser, idv, P11_OID_OPENSSL_REJECT, CK_FALSE, reject);
+ return_val_if_fail (attrs != NULL, NULL);
+ sink_object (parser, attrs);
}
/*
- * If loading from an blacklist flagged directory, then override all
- * trust assumptionsinformation and mark this as a blacklisted certificate
- */
-
- if (parser->flags & P11_PARSE_FLAG_BLACKLIST) {
- trusted = CK_FALSE;
- distrust = CK_TRUE;
-
- /*
* OpenSSL model blacklists as anchors with all purposes being removed/rejected,
* we account for that here. If there is an ExtendedKeyUsage without any
* useful purposes, then treat like a blacklist.
*/
- } else if (trust && p11_dict_size (trust) == 0) {
+ if (trust && p11_dict_size (trust) == 0) {
trusted = CK_FALSE;
distrust = CK_TRUE;
/*
* Otherwise a 'TRUSTED CERTIFICATE' in an input directory is enough to
- * mark this as a trusted certificate, even if we're not explicitly
- * parsing an directory with the anchors flag.
+ * mark this as a trusted certificate.
*/
- } else {
+ } else if (p11_dict_size (trust) > 0) {
trusted = CK_TRUE;
distrust = CK_FALSE;
}
- attr = p11_attrs_find (cert, CKA_TRUSTED);
- assert (attr != NULL);
- assert (attr->pValue != NULL);
- assert (attr->ulValueLen == sizeof (CK_BBOOL));
- *((CK_BBOOL *)attr->pValue) = trusted;
+ /*
+ * OpenSSL model blacklists as anchors with all purposes being removed/rejected,
+ * we account for that here. If there is an ExtendedKeyUsage without any
+ * useful purposes, then treat like a blacklist.
+ */
- attr = p11_attrs_find (cert, CKA_X_DISTRUSTED);
- assert (attr != NULL);
- assert (attr->pValue != NULL);
- assert (attr->ulValueLen == sizeof (CK_BBOOL));
- *((CK_BBOOL *)attr->pValue) = distrust;
+ cert = p11_attrs_merge (cert, p11_attrs_dup (trust_attrs), true);
+ return_val_if_fail (cert != NULL, NULL);
p11_dict_free (trust);
p11_dict_free (reject);
@@ -886,16 +452,17 @@ build_openssl_extensions (p11_parser *parser,
*/
ret = asn1_der_decoding_startEnd (aux, aux_der, aux_len, "keyid", &start, &end);
- return_val_if_fail (ret == ASN1_SUCCESS || ret == ASN1_ELEMENT_NOT_FOUND, P11_PARSE_FAILURE);
+ return_val_if_fail (ret == ASN1_SUCCESS || ret == ASN1_ELEMENT_NOT_FOUND, NULL);
if (ret == ASN1_SUCCESS) {
- ret = build_der_extension (parser, cert, P11_OID_SUBJECT_KEY_IDENTIFIER, CK_FALSE,
- aux_der + start, (end - start) + 1);
- return_val_if_fail (ret == P11_PARSE_SUCCESS, ret);
+ attrs = extension_attrs (parser, idv, P11_OID_SUBJECT_KEY_IDENTIFIER, CK_FALSE,
+ aux_der + start, (end - start) + 1);
+ return_val_if_fail (attrs != NULL, NULL);
+ sink_object (parser, attrs);
}
- return P11_PARSE_SUCCESS;
+ return cert;
}
static int
@@ -904,8 +471,8 @@ parse_openssl_trusted_certificate (p11_parser *parser,
size_t length)
{
CK_ATTRIBUTE *attrs;
- CK_BYTE vid[ID_LENGTH];
- CK_ATTRIBUTE *attr;
+ CK_BYTE idv[ID_LENGTH];
+ CK_ATTRIBUTE *value;
char *label = NULL;
node_asn *cert;
node_asn *aux;
@@ -934,14 +501,18 @@ parse_openssl_trusted_certificate (p11_parser *parser,
return P11_PARSE_UNRECOGNIZED;
}
- begin_parsing (parser, cert, data, cert_len);
-
/* The CKA_ID links related objects */
- id_generate (parser, vid);
+ id_generate (parser, idv);
- attrs = build_x509_certificate (parser, vid, cert, data, cert_len);
+ attrs = certificate_attrs (parser, idv, data, cert_len);
return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE);
+ /* Cache the parsed certificate ASN.1 for later use by the builder */
+ value = p11_attrs_find (attrs, CKA_VALUE);
+ assert (value != NULL);
+ p11_asn1_cache_take (parser->asn1_cache, cert, "PKIX1.Certificate",
+ value->pValue, value->ulValueLen);
+
/* Pull the label out of the CertAux */
len = 0;
ret = asn1_read_value (aux, "alias", NULL, &len);
@@ -951,20 +522,15 @@ parse_openssl_trusted_certificate (p11_parser *parser,
return_val_if_fail (label != NULL, P11_PARSE_FAILURE);
ret = asn1_read_value (aux, "alias", label, &len);
return_val_if_fail (ret == ASN1_SUCCESS, P11_PARSE_FAILURE);
-
- attr = p11_attrs_find (attrs, CKA_LABEL);
- assert (attr != NULL);
- free (attr->pValue);
- attr->pValue = label;
- attr->ulValueLen = strlen (label);
+ attrs = p11_attrs_take (attrs, CKA_LABEL, label, strlen (label));
+ return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE);
}
- ret = build_openssl_extensions (parser, attrs, aux, data + cert_len, length - cert_len);
- return_val_if_fail (ret == P11_PARSE_SUCCESS, ret);
-
- finish_parsing (parser, cert);
+ attrs = build_openssl_extensions (parser, attrs, idv, aux,
+ data + cert_len, length - cert_len);
+ return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE);
- asn1_delete_structure (&cert);
+ sink_object (parser, attrs);
asn1_delete_structure (&aux);
return P11_PARSE_SUCCESS;
@@ -979,6 +545,8 @@ on_pem_block (const char *type,
p11_parser *parser = user_data;
int ret;
+ p11_index_batch (parser->index);
+
if (strcmp (type, "CERTIFICATE") == 0) {
ret = parse_der_x509_certificate (parser, contents, length);
@@ -990,6 +558,8 @@ on_pem_block (const char *type,
ret = P11_PARSE_SUCCESS;
}
+ p11_index_finish (parser->index);
+
if (ret != P11_PARSE_SUCCESS)
p11_message ("Couldn't parse PEM block of type %s", type);
}
@@ -1016,12 +586,17 @@ static parser_func all_parsers[] = {
};
p11_parser *
-p11_parser_new (void)
+p11_parser_new (p11_index *index,
+ p11_asn1_cache *asn1_cache)
{
p11_parser parser = { 0, };
- parser.asn1_defs = p11_asn1_defs_load ();
- return_val_if_fail (parser.asn1_defs != NULL, NULL);
+ return_val_if_fail (index != NULL, NULL);
+ return_val_if_fail (asn1_cache != NULL, NULL);
+
+ parser.index = index;
+ parser.asn1_defs = p11_asn1_cache_defs (asn1_cache);
+ parser.asn1_cache = asn1_cache;
return memdup (&parser, sizeof (parser));
}
@@ -1029,10 +604,6 @@ p11_parser_new (void)
void
p11_parser_free (p11_parser *parser)
{
- if (!parser)
- return;
-
- p11_dict_free (parser->asn1_defs);
free (parser);
}
@@ -1041,38 +612,29 @@ p11_parse_memory (p11_parser *parser,
const char *filename,
int flags,
const unsigned char *data,
- size_t length,
- p11_parser_sink sink,
- void *sink_data)
+ size_t length)
{
int ret = P11_PARSE_UNRECOGNIZED;
char *base;
int i;
return_val_if_fail (parser != NULL, P11_PARSE_FAILURE);
- return_val_if_fail (parser->sink == NULL, P11_PARSE_FAILURE);
base = basename (filename);
parser->basename = base;
- parser->sink = sink;
- parser->sink_data = sink_data;
parser->flags = flags;
- /* Expected that state is cleaned via finish_parsing () */
- parser->parsing = NULL;
- parser->cert_asn = NULL;
- parser->cert_der = NULL;
- parser->cert_len = 0;
-
for (i = 0; all_parsers[i] != NULL; i++) {
+ p11_index_batch (parser->index);
ret = (all_parsers[i]) (parser, data, length);
+ p11_index_finish (parser->index);
+
if (ret != P11_PARSE_UNRECOGNIZED)
break;
}
+ p11_asn1_cache_flush (parser->asn1_cache);
parser->basename = NULL;
- parser->sink = NULL;
- parser->sink_data = NULL;
parser->flags = 0;
return ret;
@@ -1081,30 +643,24 @@ p11_parse_memory (p11_parser *parser,
int
p11_parse_file (p11_parser *parser,
const char *filename,
- int flags,
- p11_parser_sink sink,
- void *sink_data)
+ int flags)
{
p11_mmap *map;
void *data;
size_t size;
int ret;
+ return_val_if_fail (parser != NULL, P11_PARSE_FAILURE);
+ return_val_if_fail (filename != NULL, P11_PARSE_FAILURE);
+
map = p11_mmap_open (filename, &data, &size);
if (map == NULL) {
p11_message ("couldn't open and map file: %s: %s", filename, strerror (errno));
return P11_PARSE_FAILURE;
}
- ret = p11_parse_memory (parser, filename, flags, data, size, sink, sink_data);
+ ret = p11_parse_memory (parser, filename, flags, data, size);
p11_mmap_close (map);
return ret;
}
-
-p11_dict *
-p11_parser_get_asn1_defs (p11_parser *parser)
-{
- return_val_if_fail (parser != NULL, NULL);
- return parser->asn1_defs;
-}