summaryrefslogtreecommitdiff
path: root/trust/parser.c
diff options
context:
space:
mode:
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;
-}