diff options
author | Stef Walter <stefw@gnome.org> | 2013-03-14 21:08:01 +0100 |
---|---|---|
committer | Stef Walter <stefw@gnome.org> | 2013-03-15 18:00:10 +0100 |
commit | 2d75eb32793a569dc3de359bb623713c80393d24 (patch) | |
tree | aa62978bc970d95082769c9725325d31cc413058 | |
parent | d7d68de6c9de9190c85da36b731e61ae3421a811 (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
-rw-r--r-- | build/certs/entrust-invalid.der | bin | 0 -> 1120 bytes | |||
-rw-r--r-- | build/certs/verisign-v1.der | bin | 0 -> 576 bytes | |||
-rw-r--r-- | trust/Makefile.am | 2 | ||||
-rw-r--r-- | trust/adapter.c | 472 | ||||
-rw-r--r-- | trust/builder.c | 1556 | ||||
-rw-r--r-- | trust/builder.h (renamed from trust/adapter.h) | 36 | ||||
-rw-r--r-- | trust/parser.c | 836 | ||||
-rw-r--r-- | trust/parser.h | 45 | ||||
-rw-r--r-- | trust/session.c | 7 | ||||
-rw-r--r-- | trust/session.h | 2 | ||||
-rw-r--r-- | trust/tests/Makefile.am | 1 | ||||
-rw-r--r-- | trust/tests/test-builder.c | 1611 | ||||
-rw-r--r-- | trust/tests/test-data.c | 2 | ||||
-rw-r--r-- | trust/tests/test-module.c | 28 | ||||
-rw-r--r-- | trust/tests/test-parser.c | 666 | ||||
-rw-r--r-- | trust/tests/test-token.c | 58 | ||||
-rw-r--r-- | trust/token.c | 21 |
17 files changed, 3593 insertions, 1750 deletions
diff --git a/build/certs/entrust-invalid.der b/build/certs/entrust-invalid.der Binary files differnew file mode 100644 index 0000000..7be5c18 --- /dev/null +++ b/build/certs/entrust-invalid.der diff --git a/build/certs/verisign-v1.der b/build/certs/verisign-v1.der Binary files differnew file mode 100644 index 0000000..bcd5ebb --- /dev/null +++ b/build/certs/verisign-v1.der diff --git a/trust/Makefile.am b/trust/Makefile.am index af4d327..0f84205 100644 --- a/trust/Makefile.am +++ b/trust/Makefile.am @@ -11,7 +11,7 @@ INCLUDES = \ $(NULL) MODULE_SRCS = \ - adapter.c adapter.h \ + builder.c builder.h \ index.c index.h \ parser.c parser.h \ module.c module.h \ diff --git a/trust/adapter.c b/trust/adapter.c deleted file mode 100644 index 08e4c78..0000000 --- a/trust/adapter.c +++ /dev/null @@ -1,472 +0,0 @@ -/* - * Copyright (C) 2012 Red Hat Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * * Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * * The names of contributors to this software may not be - * used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * Author: Stef Walter <stefw@redhat.com> - */ - -#include "config.h" - -#include "adapter.h" -#include "attrs.h" -#include "checksum.h" -#include "dict.h" -#define P11_DEBUG_FLAG P11_DEBUG_TRUST -#include "debug.h" -#include "library.h" -#include "oid.h" -#include "parser.h" -#include "pkcs11.h" -#include "pkcs11x.h" -#include "x509.h" - -#include <stdlib.h> -#include <string.h> - -static CK_ATTRIBUTE * -build_trust_object_ku (p11_parser *parser, - p11_array *parsing, - CK_ATTRIBUTE *object, - CK_TRUST present) -{ - unsigned char *data = NULL; - unsigned int ku = 0; - p11_dict *defs; - size_t length; - CK_TRUST defawlt; - CK_ULONG i; - - struct { - CK_ATTRIBUTE_TYPE type; - unsigned int ku; - } ku_attribute_map[] = { - { CKA_TRUST_DIGITAL_SIGNATURE, P11_KU_DIGITAL_SIGNATURE }, - { CKA_TRUST_NON_REPUDIATION, P11_KU_NON_REPUDIATION }, - { CKA_TRUST_KEY_ENCIPHERMENT, P11_KU_KEY_ENCIPHERMENT }, - { CKA_TRUST_DATA_ENCIPHERMENT, P11_KU_DATA_ENCIPHERMENT }, - { CKA_TRUST_KEY_AGREEMENT, P11_KU_KEY_AGREEMENT }, - { CKA_TRUST_KEY_CERT_SIGN, P11_KU_KEY_CERT_SIGN }, - { CKA_TRUST_CRL_SIGN, P11_KU_CRL_SIGN }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE attrs[sizeof (ku_attribute_map)]; - - defawlt = present; - - /* If blacklisted, don't even bother looking at extensions */ - if (present != CKT_NSS_NOT_TRUSTED) - data = p11_parsing_get_extension (parser, parsing, P11_OID_KEY_USAGE, &length); - - if (data) { - /* - * If the certificate extension was missing, then *all* key - * usages are to be set. If the extension was invalid, then - * fail safe to none of the key usages. - */ - defawlt = CKT_NSS_TRUST_UNKNOWN; - - defs = p11_parser_get_asn1_defs (parser); - if (!p11_x509_parse_key_usage (defs, data, length, &ku)) - p11_message ("invalid key usage certificate extension"); - free (data); - } - - for (i = 0; ku_attribute_map[i].type != CKA_INVALID; i++) { - attrs[i].type = ku_attribute_map[i].type; - if (data && (ku & ku_attribute_map[i].ku) == ku_attribute_map[i].ku) { - attrs[i].pValue = &present; - attrs[i].ulValueLen = sizeof (present); - } else { - attrs[i].pValue = &defawlt; - attrs[i].ulValueLen = sizeof (defawlt); - } - } - - return p11_attrs_buildn (object, attrs, i); -} - -static bool -strv_to_dict (const char **array, - p11_dict **dict) -{ - int i; - - if (!array) { - *dict = NULL; - return true; - } - - *dict = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, NULL, NULL); - return_val_if_fail (*dict != NULL, false); - - for (i = 0; array[i] != NULL; i++) { - if (!p11_dict_set (*dict, (void *)array[i], (void *)array[i])) - return_val_if_reached (false); - } - - return true; -} - -static CK_ATTRIBUTE * -build_trust_object_eku (p11_parser *parser, - p11_array *parsing, - CK_ATTRIBUTE *object, - CK_TRUST allow, - const char **purposes, - const char **rejects) -{ - p11_dict *dict_purp; - p11_dict *dict_rej; - CK_TRUST neutral; - CK_TRUST disallow; - CK_ULONG i; - - struct { - CK_ATTRIBUTE_TYPE type; - const char *oid; - } eku_attribute_map[] = { - { CKA_TRUST_SERVER_AUTH, P11_OID_SERVER_AUTH_STR }, - { CKA_TRUST_CLIENT_AUTH, P11_OID_CLIENT_AUTH_STR }, - { CKA_TRUST_CODE_SIGNING, P11_OID_CODE_SIGNING_STR }, - { CKA_TRUST_EMAIL_PROTECTION, P11_OID_EMAIL_PROTECTION_STR }, - { CKA_TRUST_IPSEC_END_SYSTEM, P11_OID_IPSEC_END_SYSTEM_STR }, - { CKA_TRUST_IPSEC_TUNNEL, P11_OID_IPSEC_TUNNEL_STR }, - { CKA_TRUST_IPSEC_USER, P11_OID_IPSEC_USER_STR }, - { CKA_TRUST_TIME_STAMPING, P11_OID_TIME_STAMPING_STR }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE attrs[sizeof (eku_attribute_map)]; - - if (!strv_to_dict (purposes, &dict_purp) || - !strv_to_dict (rejects, &dict_rej)) - return_val_if_reached (NULL); - - /* The neutral value is set if an purpose is not present */ - if (allow == CKT_NSS_NOT_TRUSTED) - neutral = CKT_NSS_NOT_TRUSTED; - - /* If anything explicitly set, then neutral is unknown */ - else if (purposes || rejects) - neutral = CKT_NSS_TRUST_UNKNOWN; - - /* Otherwise neutral will allow any purpose */ - else - neutral = allow; - - /* The value set if a purpose is explictly rejected */ - disallow = CKT_NSS_NOT_TRUSTED; - - for (i = 0; eku_attribute_map[i].type != CKA_INVALID; i++) { - attrs[i].type = eku_attribute_map[i].type; - if (dict_rej && p11_dict_get (dict_rej, eku_attribute_map[i].oid)) { - attrs[i].pValue = &disallow; - attrs[i].ulValueLen = sizeof (disallow); - } else if (dict_purp && p11_dict_get (dict_purp, eku_attribute_map[i].oid)) { - attrs[i].pValue = &allow; - attrs[i].ulValueLen = sizeof (allow); - } else { - attrs[i].pValue = &neutral; - attrs[i].ulValueLen = sizeof (neutral); - } - } - - p11_dict_free (dict_purp); - p11_dict_free (dict_rej); - - return p11_attrs_buildn (object, attrs, i); -} - -static void -build_nss_trust_object (p11_parser *parser, - p11_array *parsing, - CK_ATTRIBUTE *cert, - CK_BBOOL trust, - CK_BBOOL distrust, - CK_BBOOL authority, - const char **purposes, - const char **rejects) -{ - CK_ATTRIBUTE *object = NULL; - CK_TRUST allow; - - CK_OBJECT_CLASS vclass = CKO_NSS_TRUST; - CK_BYTE vsha1_hash[P11_CHECKSUM_SHA1_LENGTH]; - CK_BYTE vmd5_hash[P11_CHECKSUM_MD5_LENGTH]; - CK_BBOOL vfalse = CK_FALSE; - CK_BBOOL vtrue = CK_TRUE; - - 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 invalid = { CKA_INVALID, }; - - CK_ATTRIBUTE md5_hash = { CKA_CERT_MD5_HASH, vmd5_hash, sizeof (vmd5_hash) }; - CK_ATTRIBUTE sha1_hash = { CKA_CERT_SHA1_HASH, vsha1_hash, sizeof (vsha1_hash) }; - - CK_ATTRIBUTE step_up_approved = { CKA_TRUST_STEP_UP_APPROVED, &vfalse, sizeof (vfalse) }; - - CK_ATTRIBUTE_PTR label; - CK_ATTRIBUTE_PTR id; - CK_ATTRIBUTE_PTR der; - CK_ATTRIBUTE_PTR subject; - CK_ATTRIBUTE_PTR issuer; - CK_ATTRIBUTE_PTR serial_number; - - /* Setup the hashes of the DER certificate value */ - der = p11_attrs_find (cert, CKA_VALUE); - return_if_fail (der != NULL); - p11_checksum_md5 (vmd5_hash, der->pValue, der->ulValueLen, NULL); - p11_checksum_sha1 (vsha1_hash, der->pValue, der->ulValueLen, NULL); - - /* Copy all of the following attributes from certificate */ - id = p11_attrs_find (cert, CKA_ID); - return_if_fail (id != NULL); - subject = p11_attrs_find (cert, CKA_SUBJECT); - return_if_fail (subject != NULL); - issuer = p11_attrs_find (cert, CKA_ISSUER); - return_if_fail (issuer != NULL); - serial_number = p11_attrs_find (cert, CKA_SERIAL_NUMBER); - return_if_fail (serial_number != NULL); - - /* Try to use the same label */ - label = p11_attrs_find (cert, CKA_LABEL); - if (label == NULL) - label = &invalid; - - object = p11_attrs_build (NULL, &klass, &token, &private, &modifiable, id, label, - subject, issuer, serial_number, &md5_hash, &sha1_hash, - &step_up_approved, NULL); - return_if_fail (object != NULL); - - /* Calculate the default allow trust */ - if (distrust) - allow = CKT_NSS_NOT_TRUSTED; - else if (trust && authority) - allow = CKT_NSS_TRUSTED_DELEGATOR; - else if (trust) - allow = CKT_NSS_TRUSTED; - else - allow = CKT_NSS_TRUST_UNKNOWN; - - object = build_trust_object_ku (parser, parsing, object, allow); - return_if_fail (object != NULL); - - object = build_trust_object_eku (parser, parsing, object, allow, purposes, rejects); - return_if_fail (object != NULL); - - if (!p11_array_push (parsing, object)) - return_if_reached (); -} - -static void -build_assertions (p11_parser *parser, - p11_array *parsing, - CK_ATTRIBUTE *cert, - CK_X_ASSERTION_TYPE type, - const char **oids) -{ - CK_OBJECT_CLASS assertion = CKO_X_TRUST_ASSERTION; - CK_BBOOL vtrue = CK_TRUE; - CK_BBOOL vfalse = CK_FALSE; - - CK_ATTRIBUTE klass = { CKA_CLASS, &assertion, sizeof (assertion) }; - 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 assertion_type = { CKA_X_ASSERTION_TYPE, &type, sizeof (type) }; - CK_ATTRIBUTE purpose = { CKA_X_PURPOSE, }; - CK_ATTRIBUTE invalid = { CKA_INVALID, }; - - CK_ATTRIBUTE *issuer; - CK_ATTRIBUTE *serial; - CK_ATTRIBUTE *value; - CK_ATTRIBUTE *label; - CK_ATTRIBUTE *id; - CK_ATTRIBUTE *object; - int i; - - label = p11_attrs_find (cert, CKA_LABEL); - if (label == NULL) - label = &invalid; - - id = p11_attrs_find (cert, CKA_ID); - issuer = p11_attrs_find (cert, CKA_ISSUER); - serial = p11_attrs_find (cert, CKA_SERIAL_NUMBER); - value = p11_attrs_find (cert, CKA_VALUE); - - return_if_fail (id != NULL && issuer != NULL && serial != NULL && value != NULL); - - for (i = 0; oids[i] != NULL; i++) { - purpose.pValue = (void *)oids[i]; - purpose.ulValueLen = strlen (oids[i]); - - object = p11_attrs_build (NULL, &klass, &token, &private, &modifiable, - id, label, &assertion_type, &purpose, - issuer, serial, value, NULL); - return_if_fail (object != NULL); - - if (!p11_array_push (parsing, object)) - return_if_reached (); - } -} - -static void -build_trust_assertions (p11_parser *parser, - p11_array *parsing, - CK_ATTRIBUTE *cert, - CK_BBOOL trust, - CK_BBOOL distrust, - CK_BBOOL authority, - const char **purposes, - const char **rejects) -{ - const char *all_purposes[] = { - P11_OID_SERVER_AUTH_STR, - P11_OID_CLIENT_AUTH_STR, - P11_OID_CODE_SIGNING_STR, - P11_OID_EMAIL_PROTECTION_STR, - P11_OID_IPSEC_END_SYSTEM_STR, - P11_OID_IPSEC_TUNNEL_STR, - P11_OID_IPSEC_USER_STR, - P11_OID_TIME_STAMPING_STR, - NULL, - }; - - /* Build assertions for anything that's explicitly rejected */ - if (rejects) { - build_assertions (parser, parsing, cert, - CKT_X_DISTRUSTED_CERTIFICATE, rejects); - } - - if (distrust) { - /* - * Trust assertions are defficient in that they don't blacklist a certificate - * for any purposes. So we just have to go wild and write out a bunch of - * assertions for all our known purposes. - */ - build_assertions (parser, parsing, cert, - CKT_X_DISTRUSTED_CERTIFICATE, all_purposes); - } - - /* - * TODO: Build pinned certificate assertions. That is, trusted - * certificates where not an authority. - */ - - if (trust && authority) { - if (purposes) { - /* If purposes explicitly set, then anchor for those purposes */ - build_assertions (parser, parsing, cert, - CKT_X_ANCHORED_CERTIFICATE, purposes); - } else { - /* If purposes not-explicitly set, then anchor for all known */ - build_assertions (parser, parsing, cert, - CKT_X_ANCHORED_CERTIFICATE, all_purposes); - } - } -} - -void -p11_adapter_build_objects (p11_parser *parser, - p11_array *parsing) -{ - CK_ATTRIBUTE *cert; - CK_ULONG category; - CK_BBOOL trust = CK_FALSE; - CK_BBOOL distrust = CK_FALSE; - CK_BBOOL authority = CK_FALSE; - p11_array *purposes = NULL; - p11_array *rejects = NULL; - const char **purposev; - const char **rejectv; - unsigned char *data; - p11_dict *defs; - size_t length; - - cert = p11_parsing_get_certificate (parser, parsing); - return_if_fail (cert != NULL); - - /* - * We look up all this information in advance, since it's used - * by the various adapter objects, and we don't have to parse - * it multiple times. - */ - - if (!p11_attrs_find_bool (cert, CKA_TRUSTED, &trust)) - trust = CK_FALSE; - if (!p11_attrs_find_bool (cert, CKA_X_DISTRUSTED, &distrust)) - distrust = CK_FALSE; - if (p11_attrs_find_ulong (cert, CKA_CERTIFICATE_CATEGORY, &category) && category == 2) - authority = CK_TRUE; - - if (!distrust) { - data = p11_parsing_get_extension (parser, parsing, P11_OID_EXTENDED_KEY_USAGE, &length); - if (data) { - defs = p11_parser_get_asn1_defs (parser); - purposes = p11_x509_parse_extended_key_usage (defs, data, length); - if (purposes == NULL) - p11_message ("invalid extended key usage certificate extension"); - free (data); - } - - data = p11_parsing_get_extension (parser, parsing, P11_OID_OPENSSL_REJECT, &length); - if (data) { - defs = p11_parser_get_asn1_defs (parser); - rejects = p11_x509_parse_extended_key_usage (defs, data, length); - if (rejects == NULL) - p11_message ("invalid reject key usage certificate extension"); - free (data); - } - } - - /* null-terminate these arrays and use as strv's */ - purposev = rejectv = NULL; - if (rejects) { - if (!p11_array_push (rejects, NULL)) - return_if_reached (); - rejectv = (const char **)rejects->elem; - } - if (purposes) { - if (!p11_array_push (purposes, NULL)) - return_if_reached (); - purposev = (const char **)purposes->elem; - } - - build_nss_trust_object (parser, parsing, cert, trust, distrust, - authority, purposev, rejectv); - build_trust_assertions (parser, parsing, cert, trust, distrust, - authority, purposev, rejectv); - - p11_array_free (purposes); - p11_array_free (rejects); -} diff --git a/trust/builder.c b/trust/builder.c new file mode 100644 index 0000000..4397b9b --- /dev/null +++ b/trust/builder.c @@ -0,0 +1,1556 @@ +/* + * Copyright (C) 2012 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@redhat.com> + */ + +#include "config.h" + +#define P11_DEBUG_FLAG P11_DEBUG_TRUST + +#include "array.h" +#include "asn1.h" +#include "attrs.h" +#include "builder.h" +#include "checksum.h" +#include "constants.h" +#include "debug.h" +#include "index.h" +#include "library.h" +#include "oid.h" +#include "pkcs11x.h" +#include "x509.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +struct _p11_builder { + p11_asn1_cache *asn1_cache; + p11_dict *asn1_defs; + int flags; +}; + +enum { + NONE = 0, + CREATE = 1 << 0, + MODIFY = 1 << 1, + REQUIRE = 1 << 2, + WANT = 1 << 3, +}; + +enum { + NORMAL_BUILD = 0, + GENERATED_CLASS = 1 << 0, +}; + +typedef struct { + int build_flags; + struct { + CK_ATTRIBUTE_TYPE type; + int flags; + } attrs[32]; + CK_ATTRIBUTE * (*populate) (p11_builder *, p11_index *, CK_ATTRIBUTE *); +} builder_schema; + +static node_asn * +decode_or_get_asn1 (p11_builder *builder, + const char *struct_name, + const unsigned char *der, + size_t length) +{ + node_asn *node; + + node = p11_asn1_cache_get (builder->asn1_cache, struct_name, der, length); + if (node != NULL) + return node; + + node = p11_asn1_decode (builder->asn1_defs, struct_name, der, length, NULL); + if (node != NULL) + p11_asn1_cache_take (builder->asn1_cache, node, struct_name, der, length); + + return node; +} + +static unsigned char * +lookup_extension (p11_builder *builder, + p11_index *index, + CK_ATTRIBUTE *cert, + const unsigned char *oid, + size_t *ext_len) +{ + CK_OBJECT_CLASS klass = CKO_X_CERTIFICATE_EXTENSION; + CK_OBJECT_HANDLE obj; + CK_ATTRIBUTE *attrs; + unsigned char *ext; + CK_ATTRIBUTE *value; + CK_ATTRIBUTE *id; + node_asn *node; + + CK_ATTRIBUTE match[] = { + { CKA_ID, }, + { CKA_OBJECT_ID, (void *)oid, p11_oid_length (oid) }, + { CKA_CLASS, &klass, sizeof (klass) }, + { CKA_INVALID }, + }; + + /* Look for a stapled certificate extension */ + id = p11_attrs_find (cert, CKA_ID); + if (id != NULL) { + match[0].pValue = id->pValue; + match[0].ulValueLen = id->ulValueLen; + + obj = p11_index_find (index, match); + attrs = p11_index_lookup (index, obj); + if (attrs != NULL) { + value = p11_attrs_find (attrs, CKA_VALUE); + return_val_if_fail (value != NULL, NULL); + + *ext_len = value->ulValueLen; + ext = memdup (value->pValue, value->ulValueLen); + return_val_if_fail (ext != NULL, NULL); + return ext; + } + } + + /* Couldn't find a parsed extension, so look in the current certificate */ + value = p11_attrs_find (cert, CKA_VALUE); + if (value != NULL) { + node = decode_or_get_asn1 (builder, "PKIX1.Certificate", + value->pValue, value->ulValueLen); + return_val_if_fail (node != NULL, false); + + return p11_x509_find_extension (node, oid, value->pValue, + value->ulValueLen, ext_len); + } + + return NULL; +} + +static CK_OBJECT_HANDLE * +lookup_related (p11_index *index, + CK_OBJECT_CLASS klass, + CK_ATTRIBUTE *id) +{ + CK_ATTRIBUTE match[] = { + { CKA_ID, }, + { CKA_CLASS, &klass, sizeof (klass) }, + { CKA_INVALID } + }; + + return_val_if_fail (id != NULL, NULL); + + match[0].pValue = id->pValue; + match[0].ulValueLen = id->ulValueLen; + + return p11_index_find_all (index, match); +} + +p11_builder * +p11_builder_new (int flags) +{ + p11_builder *builder; + + builder = calloc (1, sizeof (p11_builder)); + return_val_if_fail (builder != NULL, NULL); + + builder->asn1_cache = p11_asn1_cache_new (); + return_val_if_fail (builder->asn1_cache, NULL); + builder->asn1_defs = p11_asn1_cache_defs (builder->asn1_cache); + + builder->flags = flags; + return builder; +} + +#define COMMON_ATTRS \ + { CKA_CLASS, REQUIRE | CREATE }, \ + { CKA_TOKEN, CREATE | WANT }, \ + { CKA_MODIFIABLE, CREATE | WANT }, \ + { CKA_PRIVATE, CREATE }, \ + { CKA_LABEL, CREATE | MODIFY | WANT }, \ + { CKA_X_GENERATED, CREATE } + +static CK_ATTRIBUTE * +common_populate (p11_builder *builder, + p11_index *index, + CK_ATTRIBUTE *unused) +{ + CK_BBOOL tokenv = CK_FALSE; + CK_BBOOL modifiablev = CK_TRUE; + CK_BBOOL privatev = CK_FALSE; + CK_BBOOL generatedv = CK_FALSE; + + CK_ATTRIBUTE token = { CKA_TOKEN, &tokenv, sizeof (tokenv), }; + CK_ATTRIBUTE privat = { CKA_PRIVATE, &privatev, sizeof (privatev) }; + CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &modifiablev, sizeof (modifiablev) }; + CK_ATTRIBUTE generated = { CKA_X_GENERATED, &generatedv, sizeof (generatedv) }; + CK_ATTRIBUTE label = { CKA_LABEL, "", 0 }; + + if (builder->flags & P11_BUILDER_FLAG_TOKEN) { + tokenv = CK_TRUE; + modifiablev = CK_FALSE; + } + + return p11_attrs_build (NULL, &token, &privat, &modifiable, &label, &generated, NULL); +} + +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 *node, + const char *field, + CK_DATE *date) +{ + node_asn *choice; + struct tm when; + char buf[64]; + time_t timet; + char *sub; + int len; + int ret; + + if (!node) + return false; + + choice = asn1_find_node (node, field); + return_val_if_fail (choice != NULL, false); + + len = sizeof (buf) - 1; + ret = asn1_read_value (node, 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 (node, 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 (node, 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 *node, + const unsigned char *data, + size_t length, + const char *field, + CK_ATTRIBUTE *attr) +{ + int ret; + int start, end; + + if (!node) + return false; + + ret = asn1_der_decoding_startEnd (node, 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 bool +is_v1_x509_authority (p11_builder *builder, + CK_ATTRIBUTE *cert) +{ + CK_ATTRIBUTE subject; + CK_ATTRIBUTE issuer; + CK_ATTRIBUTE *value; + char buffer[16]; + node_asn *node; + int len; + int ret; + + value = p11_attrs_find_valid (cert, CKA_VALUE); + if (value == NULL) + return false; + + node = decode_or_get_asn1 (builder, "PKIX1.Certificate", + value->pValue, value->ulValueLen); + return_val_if_fail (node != NULL, false); + + 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 */ + if (!calc_element (node, value->pValue, value->ulValueLen, "tbsCertificate.subject", &subject)) + return_val_if_reached (false); + if (!calc_element (node, value->pValue, value->ulValueLen, "tbsCertificate.issuer", &issuer)) + return_val_if_reached (false); + return p11_attr_match_value (&subject, issuer.pValue, issuer.ulValueLen); +} + +static bool +calc_certificate_category (p11_builder *builder, + p11_index *index, + CK_ATTRIBUTE *cert, + CK_ULONG *category) +{ + unsigned char *ext; + size_t ext_len; + bool is_ca = 0; + bool ret; + + /* + * In the PKCS#11 spec: + * 0 = unspecified (default value) + * 1 = token user + * 2 = authority + * 3 = other entity + */ + + /* See if we have a basic constraints extension */ + ext = lookup_extension (builder, index, cert, P11_OID_BASIC_CONSTRAINTS, &ext_len); + if (ext != NULL) { + ret = p11_x509_parse_basic_constraints (builder->asn1_defs, ext, ext_len, &is_ca); + free (ext); + if (!ret) { + p11_message ("invalid basic constraints certificate extension"); + return false; + } + + } else if (is_v1_x509_authority (builder, cert)) { + /* + * 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; + + } else if (!p11_attrs_find_valid (cert, CKA_VALUE)) { + /* + * If we have no certificate value, then this is unknown + */ + *category = 0; + return true; + + } + + *category = is_ca ? 2 : 3; + return true; +} + +static CK_ATTRIBUTE * +certificate_value_attrs (CK_ATTRIBUTE *attrs, + node_asn *node, + const unsigned char *der, + size_t der_len) +{ + CK_BBOOL falsev = CK_FALSE; + CK_ULONG zero = 0UL; + CK_BYTE checkv[3]; + CK_DATE startv; + CK_DATE endv; + char *labelv = NULL; + + CK_ATTRIBUTE trusted = { CKA_TRUSTED, &falsev, sizeof (falsev) }; + CK_ATTRIBUTE distrusted = { CKA_X_DISTRUSTED, &falsev, sizeof (falsev) }; + CK_ATTRIBUTE url = { CKA_URL, "", 0 }; + CK_ATTRIBUTE hash_of_subject_public_key = { CKA_HASH_OF_SUBJECT_PUBLIC_KEY, "", 0 }; + CK_ATTRIBUTE hash_of_issuer_public_key = { CKA_HASH_OF_ISSUER_PUBLIC_KEY, "", 0 }; + CK_ATTRIBUTE java_midp_security_domain = { CKA_JAVA_MIDP_SECURITY_DOMAIN, &zero, sizeof (zero) }; + CK_ATTRIBUTE check_value = { CKA_CHECK_VALUE, &checkv, sizeof (checkv) }; + CK_ATTRIBUTE start_date = { CKA_START_DATE, &startv, sizeof (startv) }; + CK_ATTRIBUTE end_date = { CKA_END_DATE, &endv, sizeof (endv) }; + CK_ATTRIBUTE subject = { CKA_SUBJECT, }; + CK_ATTRIBUTE issuer = { CKA_ISSUER, "", 0 }; + CK_ATTRIBUTE serial_number = { CKA_SERIAL_NUMBER, "", 0 }; + CK_ATTRIBUTE label = { CKA_LABEL }; + + return_val_if_fail (attrs != NULL, NULL); + + if (der == NULL) + check_value.type = CKA_INVALID; + else + calc_check_value (der, der_len, checkv); + + if (!calc_date (node, "tbsCertificate.validity.notBefore", &startv)) + start_date.ulValueLen = 0; + if (!calc_date (node, "tbsCertificate.validity.notAfter", &endv)) + end_date.ulValueLen = 0; + + calc_element (node, der, der_len, "tbsCertificate.issuer.rdnSequence", &issuer); + if (!calc_element (node, der, der_len, "tbsCertificate.subject.rdnSequence", &subject)) + subject.type = CKA_INVALID; + calc_element (node, der, der_len, "tbsCertificate.serialNumber", &serial_number); + + if (node) { + labelv = p11_x509_lookup_dn_name (node, "tbsCertificate.subject", + der, der_len, P11_OID_CN); + if (!labelv) + labelv = p11_x509_lookup_dn_name (node, "tbsCertificate.subject", + der, der_len, P11_OID_OU); + if (!labelv) + labelv = p11_x509_lookup_dn_name (node, "tbsCertificate.subject", + der, der_len, P11_OID_O); + } + + if (labelv) { + label.pValue = labelv; + label.ulValueLen = strlen (labelv); + } else { + label.type = CKA_INVALID; + } + + attrs = p11_attrs_build (attrs, &trusted, &distrusted, &url, &hash_of_issuer_public_key, + &hash_of_subject_public_key, &java_midp_security_domain, + &check_value, &start_date, &end_date, + &subject, &issuer, &serial_number, &label, + NULL); + return_val_if_fail (attrs != NULL, NULL); + + return attrs; +} + +static CK_ATTRIBUTE * +certificate_populate (p11_builder *builder, + p11_index *index, + CK_ATTRIBUTE *cert) +{ + CK_ULONG categoryv = 0UL; + CK_ATTRIBUTE *attrs = NULL; + CK_ATTRIBUTE *value; + node_asn *node = NULL; + unsigned char *der = NULL; + size_t der_len = 0; + + CK_ATTRIBUTE category = { CKA_CERTIFICATE_CATEGORY, &categoryv, sizeof (categoryv) }; + CK_ATTRIBUTE empty_value = { CKA_VALUE, "", 0 }; + + attrs = common_populate (builder, index, cert); + return_val_if_fail (attrs != NULL, NULL); + + value = p11_attrs_find_valid (cert, CKA_VALUE); + if (value != NULL) { + der = value->pValue; + der_len = value->ulValueLen; + node = decode_or_get_asn1 (builder, "PKIX1.Certificate", + value->pValue, value->ulValueLen); + } + + attrs = certificate_value_attrs (attrs, node, der, der_len); + return_val_if_fail (attrs != NULL, NULL); + + if (!calc_certificate_category (builder, index, cert, &categoryv)) + categoryv = 0; + + return p11_attrs_build (attrs, &category, &empty_value, NULL); +} + +const static builder_schema certificate_schema = { + NORMAL_BUILD, + { COMMON_ATTRS, + { CKA_CERTIFICATE_TYPE, REQUIRE | CREATE }, + { CKA_TRUSTED, }, + { CKA_X_DISTRUSTED, }, + { CKA_CERTIFICATE_CATEGORY, CREATE | MODIFY | WANT }, + { CKA_CHECK_VALUE, CREATE | MODIFY | WANT }, + { CKA_START_DATE, CREATE | MODIFY | WANT }, + { CKA_END_DATE, CREATE | MODIFY | WANT }, + { CKA_SUBJECT, CREATE | WANT }, + { CKA_ID, CREATE | MODIFY | WANT }, + { CKA_ISSUER, CREATE | MODIFY | WANT }, + { CKA_SERIAL_NUMBER, CREATE | MODIFY | WANT }, + { CKA_VALUE, CREATE }, + { CKA_URL, CREATE }, + { CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CREATE }, + { CKA_HASH_OF_ISSUER_PUBLIC_KEY, CREATE }, + { CKA_JAVA_MIDP_SECURITY_DOMAIN, CREATE }, + { CKA_INVALID }, + }, certificate_populate, +}; + +static CK_ATTRIBUTE * +extension_populate (p11_builder *builder, + p11_index *index, + CK_ATTRIBUTE *extension) +{ + CK_ATTRIBUTE *attrs = NULL; + + attrs = common_populate (builder, index, extension); + return_val_if_fail (attrs != NULL, NULL); + + if (!p11_attrs_find_valid (extension, CKA_X_CRITICAL)) { + CK_BBOOL falsev = CK_FALSE; + CK_ATTRIBUTE critical = { CKA_X_CRITICAL, &falsev, sizeof (falsev) }; + attrs = p11_attrs_build (attrs, &critical, NULL); + return_val_if_fail (attrs != NULL, NULL); + } + + return attrs; +} + +const static builder_schema extension_schema = { + NORMAL_BUILD, + { COMMON_ATTRS, + { CKA_VALUE, REQUIRE | CREATE }, + { CKA_X_CRITICAL, WANT }, + { CKA_OBJECT_ID, REQUIRE | CREATE }, + { CKA_ID, CREATE | MODIFY | WANT }, + { CKA_INVALID }, + }, extension_populate, +}; + +static CK_ATTRIBUTE * +data_populate (p11_builder *builder, + p11_index *index, + CK_ATTRIBUTE *data) +{ + static CK_ATTRIBUTE value = { CKA_VALUE, "", 0 }; + static CK_ATTRIBUTE application = { CKA_APPLICATION, "", 0 }; + static CK_ATTRIBUTE object_id = { CKA_OBJECT_ID, "", 0 }; + CK_ATTRIBUTE *attrs; + + attrs = common_populate (builder, index, data); + return_val_if_fail (attrs != NULL, NULL); + + return p11_attrs_build (attrs, &value, &application, &object_id, NULL); +} + +const static builder_schema data_schema = { + NORMAL_BUILD, + { COMMON_ATTRS, + { CKA_VALUE, CREATE | MODIFY | WANT }, + { CKA_APPLICATION, CREATE | MODIFY | WANT }, + { CKA_OBJECT_ID, CREATE | MODIFY | WANT }, + { CKA_INVALID }, + }, data_populate, +}; + +const static builder_schema trust_schema = { + GENERATED_CLASS, + { COMMON_ATTRS, + { CKA_CERT_SHA1_HASH, CREATE }, + { CKA_CERT_MD5_HASH, CREATE }, + { CKA_ISSUER, CREATE }, + { CKA_SUBJECT, CREATE }, + { CKA_SERIAL_NUMBER, CREATE }, + { CKA_TRUST_SERVER_AUTH, CREATE }, + { CKA_TRUST_CLIENT_AUTH, CREATE }, + { CKA_TRUST_EMAIL_PROTECTION, CREATE }, + { CKA_TRUST_CODE_SIGNING, CREATE }, + { CKA_TRUST_IPSEC_END_SYSTEM, CREATE }, + { CKA_TRUST_IPSEC_TUNNEL, CREATE }, + { CKA_TRUST_IPSEC_USER, CREATE }, + { CKA_TRUST_TIME_STAMPING, CREATE }, + { CKA_TRUST_DIGITAL_SIGNATURE, CREATE }, + { CKA_TRUST_NON_REPUDIATION, CREATE }, + { CKA_TRUST_KEY_ENCIPHERMENT, CREATE }, + { CKA_TRUST_DATA_ENCIPHERMENT, CREATE }, + { CKA_TRUST_KEY_AGREEMENT, CREATE }, + { CKA_TRUST_KEY_CERT_SIGN, CREATE }, + { CKA_TRUST_CRL_SIGN, CREATE }, + { CKA_TRUST_STEP_UP_APPROVED, CREATE }, + { CKA_ID, CREATE }, + { CKA_INVALID }, + }, common_populate +}; + +const static builder_schema assertion_schema = { + GENERATED_CLASS, + { COMMON_ATTRS, + { CKA_X_PURPOSE, REQUIRE | CREATE }, + { CKA_VALUE, CREATE }, + { CKA_X_ASSERTION_TYPE, REQUIRE | CREATE }, + { CKA_ISSUER, CREATE }, + { CKA_SERIAL_NUMBER, CREATE }, + { CKA_X_PEER, CREATE }, + { CKA_ID, CREATE }, + { CKA_INVALID }, + }, common_populate +}; + +const static builder_schema builtin_schema = { + GENERATED_CLASS, + { COMMON_ATTRS, + { CKA_INVALID }, + }, common_populate +}; + +static void +attrs_filter_if_unchanged (CK_ATTRIBUTE *attrs, + CK_ATTRIBUTE *merge) +{ + CK_ATTRIBUTE *attr; + int in, out; + + assert (attrs != NULL); + assert (merge != NULL); + + for (in = 0, out = 0; !p11_attrs_is_empty (merge + in); in++) { + attr = p11_attrs_find (attrs, merge[in].type); + if (attr && p11_attr_equal (attr, merge + in)) { + free (merge[in].pValue); + merge[in].pValue = NULL; + merge[in].ulValueLen = 0; + } else { + if (in != out) + memcpy (merge + out, merge + in, sizeof (CK_ATTRIBUTE)); + out++; + } + } + + merge[out].type = CKA_INVALID; + assert (p11_attrs_is_empty (merge + out)); +} + +static const char * +value_name (const p11_constant *info, + CK_ATTRIBUTE_TYPE type) +{ + const char *name = p11_constant_name (info, type); + return name ? name : "unknown"; +} + +static const char * +type_name (CK_ATTRIBUTE_TYPE type) +{ + return value_name (p11_constant_types, type); +} + +static CK_RV +build_for_schema (p11_builder *builder, + p11_index *index, + const builder_schema *schema, + CK_ATTRIBUTE **object, + CK_ATTRIBUTE *merge) +{ + CK_ATTRIBUTE *extra; + CK_ATTRIBUTE *attrs; + CK_BBOOL modifiable; + bool modifying; + bool creating; + bool populate; + bool loading; + bool found; + int flags; + int i, j; + + attrs = *object; + populate = false; + + /* Signifies that data is being loaded */ + loading = p11_index_in_batch (index); + + /* Signifies that this is being created by a caller, instead of loaded */ + creating = (attrs == NULL && !loading); + + /* Item is being modified by a caller */ + modifying = (attrs != NULL && !loading); + + /* This item may not be modifiable */ + if (modifying) { + if (!p11_attrs_find_bool (attrs, CKA_MODIFIABLE, &modifiable) || !modifiable) { + p11_message ("the object is not modifiable"); + return CKR_ATTRIBUTE_READ_ONLY; + } + } + + if (attrs != NULL) + attrs_filter_if_unchanged (attrs, merge); + + if (creating) { + if (schema->build_flags & GENERATED_CLASS) { + p11_message ("objects of this type cannot be created"); + return CKR_TEMPLATE_INCONSISTENT; + } + } + + for (i = 0; merge[i].type != CKA_INVALID; i++) { + found = false; + for (j = 0; schema->attrs[j].type != CKA_INVALID; j++) { + if (schema->attrs[j].type != merge[i].type) + continue; + + flags = schema->attrs[j].flags; + if (creating && !(flags & CREATE)) { + p11_message ("the %s attribute cannot be set", + type_name (schema->attrs[j].type)); + return CKR_ATTRIBUTE_READ_ONLY; + } + if (modifying && !(flags & MODIFY)) { + p11_message ("the %s attribute cannot be changed", + type_name (schema->attrs[j].type)); + return CKR_ATTRIBUTE_READ_ONLY; + } + found = true; + break; + } + + if (!found) { + p11_message ("the %s attribute is not valid for the object", + type_name (merge[i].type)); + return CKR_TEMPLATE_INCONSISTENT; + } + } + + if (attrs == NULL) { + for (j = 0; schema->attrs[j].type != CKA_INVALID; j++) { + flags = schema->attrs[j].flags; + found = false; + + if ((flags & REQUIRE) || (flags & WANT)) { + for (i = 0; merge[i].type != CKA_INVALID; i++) { + if (schema->attrs[j].type == merge[i].type) { + found = true; + break; + } + } + } + + if (!found) { + if (flags & REQUIRE) { + p11_message ("missing the %s attribute", + type_name (schema->attrs[j].type)); + return CKR_TEMPLATE_INCOMPLETE; + } else if (flags & WANT) { + populate = true; + } + } + } + } + + if (populate && schema->populate) { + extra = schema->populate (builder, index, merge); + if (extra != NULL) + merge = p11_attrs_merge (merge, extra, false); + } + + /* + * TODO: Validate the result, before committing to the change. We can + * do this by doing a shallow copy of merge + attrs and then validating + * that. Although there may be duplicate attributets, the validation + * code will see the new ones because they're first. + */ + + *object = p11_attrs_merge (attrs, merge, true); + return_val_if_fail (*object != NULL, CKR_HOST_MEMORY); + + return CKR_OK; +} + +CK_RV +p11_builder_build (void *bilder, + p11_index *index, + CK_ATTRIBUTE **object, + CK_ATTRIBUTE *merge) +{ + p11_builder *builder = bilder; + CK_ATTRIBUTE *attrs; + CK_OBJECT_CLASS klass; + CK_CERTIFICATE_TYPE type; + CK_BBOOL token; + + return_val_if_fail (builder != NULL, CKR_GENERAL_ERROR); + return_val_if_fail (index != NULL, CKR_GENERAL_ERROR); + return_val_if_fail (merge != NULL, CKR_GENERAL_ERROR); + + attrs = *object; + + if (!p11_attrs_find_ulong (attrs ? attrs : merge, CKA_CLASS, &klass)) { + p11_message ("no CKA_CLASS attribute found"); + return CKR_TEMPLATE_INCOMPLETE; + } + + if (!attrs && p11_attrs_find_bool (merge, CKA_TOKEN, &token)) { + if (token != ((builder->flags & P11_BUILDER_FLAG_TOKEN) ? CK_TRUE : CK_FALSE)) { + p11_message ("cannot create a %s object", token ? "token" : "non-token"); + return CKR_TEMPLATE_INCONSISTENT; + } + } + + switch (klass) { + case CKO_CERTIFICATE: + if (!p11_attrs_find_ulong (attrs ? attrs : merge, CKA_CERTIFICATE_TYPE, &type)) { + p11_message ("missing %s on object", type_name (CKA_CERTIFICATE_TYPE)); + return CKR_TEMPLATE_INCOMPLETE; + } else if (type == CKC_X_509) { + return build_for_schema (builder, index, &certificate_schema, object, merge); + } else { + p11_message ("%s unsupported %s", value_name (p11_constant_certs, type), + type_name (CKA_CERTIFICATE_TYPE)); + return CKR_TEMPLATE_INCONSISTENT; + } + + case CKO_X_CERTIFICATE_EXTENSION: + return build_for_schema (builder, index, &extension_schema, object, merge); + + case CKO_DATA: + return build_for_schema (builder, index, &data_schema, object, merge); + + case CKO_NSS_TRUST: + return build_for_schema (builder, index, &trust_schema, object, merge); + + case CKO_NSS_BUILTIN_ROOT_LIST: + return build_for_schema (builder, index, &builtin_schema, object, merge); + + case CKO_X_TRUST_ASSERTION: + return build_for_schema (builder, index, &assertion_schema, object, merge); + + default: + p11_message ("%s unsupported object class", + value_name (p11_constant_classes, klass)); + return CKR_TEMPLATE_INCONSISTENT; + } +} + +void +p11_builder_free (p11_builder *builder) +{ + return_if_fail (builder != NULL); + + p11_asn1_cache_free (builder->asn1_cache); + free (builder); +} + +p11_asn1_cache * +p11_builder_get_cache (p11_builder *builder) +{ + return_val_if_fail (builder != NULL, NULL); + return builder->asn1_cache; +} + +static CK_ATTRIBUTE * +build_trust_object_ku (p11_builder *builder, + p11_index *index, + CK_ATTRIBUTE *cert, + CK_ATTRIBUTE *object, + CK_TRUST present) +{ + unsigned char *data = NULL; + unsigned int ku = 0; + size_t length; + CK_TRUST defawlt; + CK_ULONG i; + + struct { + CK_ATTRIBUTE_TYPE type; + unsigned int ku; + } ku_attribute_map[] = { + { CKA_TRUST_DIGITAL_SIGNATURE, P11_KU_DIGITAL_SIGNATURE }, + { CKA_TRUST_NON_REPUDIATION, P11_KU_NON_REPUDIATION }, + { CKA_TRUST_KEY_ENCIPHERMENT, P11_KU_KEY_ENCIPHERMENT }, + { CKA_TRUST_DATA_ENCIPHERMENT, P11_KU_DATA_ENCIPHERMENT }, + { CKA_TRUST_KEY_AGREEMENT, P11_KU_KEY_AGREEMENT }, + { CKA_TRUST_KEY_CERT_SIGN, P11_KU_KEY_CERT_SIGN }, + { CKA_TRUST_CRL_SIGN, P11_KU_CRL_SIGN }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE attrs[sizeof (ku_attribute_map)]; + + defawlt = present; + + /* If blacklisted, don't even bother looking at extensions */ + if (present != CKT_NSS_NOT_TRUSTED) + data = lookup_extension (builder, index, cert, P11_OID_KEY_USAGE, &length); + + if (data) { + /* + * If the certificate extension was missing, then *all* key + * usages are to be set. If the extension was invalid, then + * fail safe to none of the key usages. + */ + defawlt = CKT_NSS_TRUST_UNKNOWN; + + if (!p11_x509_parse_key_usage (builder->asn1_defs, data, length, &ku)) + p11_message ("invalid key usage certificate extension"); + free (data); + } + + for (i = 0; ku_attribute_map[i].type != CKA_INVALID; i++) { + attrs[i].type = ku_attribute_map[i].type; + if (data && (ku & ku_attribute_map[i].ku) == ku_attribute_map[i].ku) { + attrs[i].pValue = &present; + attrs[i].ulValueLen = sizeof (present); + } else { + attrs[i].pValue = &defawlt; + attrs[i].ulValueLen = sizeof (defawlt); + } + } + + return p11_attrs_buildn (object, attrs, i); +} + +static bool +strv_to_dict (const char **array, + p11_dict **dict) +{ + int i; + + if (!array) { + *dict = NULL; + return true; + } + + *dict = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, NULL, NULL); + return_val_if_fail (*dict != NULL, false); + + for (i = 0; array[i] != NULL; i++) { + if (!p11_dict_set (*dict, (void *)array[i], (void *)array[i])) + return_val_if_reached (false); + } + + return true; +} + +static CK_ATTRIBUTE * +build_trust_object_eku (CK_ATTRIBUTE *object, + CK_TRUST allow, + const char **purposes, + const char **rejects) +{ + p11_dict *dict_purp; + p11_dict *dict_rej; + CK_TRUST neutral; + CK_TRUST disallow; + CK_ULONG i; + + struct { + CK_ATTRIBUTE_TYPE type; + const char *oid; + } eku_attribute_map[] = { + { CKA_TRUST_SERVER_AUTH, P11_OID_SERVER_AUTH_STR }, + { CKA_TRUST_CLIENT_AUTH, P11_OID_CLIENT_AUTH_STR }, + { CKA_TRUST_CODE_SIGNING, P11_OID_CODE_SIGNING_STR }, + { CKA_TRUST_EMAIL_PROTECTION, P11_OID_EMAIL_PROTECTION_STR }, + { CKA_TRUST_IPSEC_END_SYSTEM, P11_OID_IPSEC_END_SYSTEM_STR }, + { CKA_TRUST_IPSEC_TUNNEL, P11_OID_IPSEC_TUNNEL_STR }, + { CKA_TRUST_IPSEC_USER, P11_OID_IPSEC_USER_STR }, + { CKA_TRUST_TIME_STAMPING, P11_OID_TIME_STAMPING_STR }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE attrs[sizeof (eku_attribute_map)]; + + if (!strv_to_dict (purposes, &dict_purp) || + !strv_to_dict (rejects, &dict_rej)) + return_val_if_reached (NULL); + + /* The neutral value is set if an purpose is not present */ + if (allow == CKT_NSS_NOT_TRUSTED) + neutral = CKT_NSS_NOT_TRUSTED; + + /* If anything explicitly set, then neutral is unknown */ + else if (purposes || rejects) + neutral = CKT_NSS_TRUST_UNKNOWN; + + /* Otherwise neutral will allow any purpose */ + else + neutral = allow; + + /* The value set if a purpose is explictly rejected */ + disallow = CKT_NSS_NOT_TRUSTED; + + for (i = 0; eku_attribute_map[i].type != CKA_INVALID; i++) { + attrs[i].type = eku_attribute_map[i].type; + if (dict_rej && p11_dict_get (dict_rej, eku_attribute_map[i].oid)) { + attrs[i].pValue = &disallow; + attrs[i].ulValueLen = sizeof (disallow); + } else if (dict_purp && p11_dict_get (dict_purp, eku_attribute_map[i].oid)) { + attrs[i].pValue = &allow; + attrs[i].ulValueLen = sizeof (allow); + } else { + attrs[i].pValue = &neutral; + attrs[i].ulValueLen = sizeof (neutral); + } + } + + p11_dict_free (dict_purp); + p11_dict_free (dict_rej); + + return p11_attrs_buildn (object, attrs, i); +} + +static void +replace_nss_trust_object (p11_builder *builder, + p11_index *index, + CK_ATTRIBUTE *cert, + CK_BBOOL trust, + CK_BBOOL distrust, + CK_BBOOL authority, + const char **purposes, + const char **rejects) +{ + CK_ATTRIBUTE *attrs = NULL; + CK_TRUST allow; + CK_RV rv; + + CK_OBJECT_CLASS klassv = CKO_NSS_TRUST; + CK_BYTE sha1v[P11_CHECKSUM_SHA1_LENGTH]; + CK_BYTE md5v[P11_CHECKSUM_MD5_LENGTH]; + CK_BBOOL generated = CK_FALSE; + CK_BBOOL falsev = CK_FALSE; + CK_BBOOL truev = CK_TRUE; + + CK_ATTRIBUTE klass = { CKA_CLASS, &klassv, sizeof (klassv) }; + CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &falsev, sizeof (falsev) }; + CK_ATTRIBUTE autogen = { CKA_X_GENERATED, &truev, sizeof (truev) }; + CK_ATTRIBUTE invalid = { CKA_INVALID, }; + + CK_ATTRIBUTE md5_hash = { CKA_CERT_MD5_HASH, md5v, sizeof (md5v) }; + CK_ATTRIBUTE sha1_hash = { CKA_CERT_SHA1_HASH, sha1v, sizeof (sha1v) }; + + CK_ATTRIBUTE step_up_approved = { CKA_TRUST_STEP_UP_APPROVED, &falsev, sizeof (falsev) }; + + CK_ATTRIBUTE_PTR label; + CK_ATTRIBUTE_PTR id; + CK_ATTRIBUTE_PTR der; + CK_ATTRIBUTE_PTR subject; + CK_ATTRIBUTE_PTR issuer; + CK_ATTRIBUTE_PTR serial_number; + + CK_ATTRIBUTE match[] = { + { CKA_CERT_SHA1_HASH, sha1v, sizeof (sha1v) }, + { CKA_CLASS, &klassv, sizeof (klassv) }, + { CKA_X_GENERATED, &generated, sizeof (generated) }, + { CKA_INVALID } + }; + + /* Setup the hashes of the DER certificate value */ + der = p11_attrs_find (cert, CKA_VALUE); + return_if_fail (der != NULL); + p11_checksum_md5 (md5v, der->pValue, der->ulValueLen, NULL); + p11_checksum_sha1 (sha1v, der->pValue, der->ulValueLen, NULL); + + /* If there is a non-auto-generated NSS trust object, then step away */ + generated = CK_FALSE; + if (p11_index_find (index, match)) + return; + + /* Copy all of the following attributes from certificate */ + id = p11_attrs_find (cert, CKA_ID); + return_if_fail (id != NULL); + subject = p11_attrs_find (cert, CKA_SUBJECT); + if (subject == NULL) + subject = &invalid; + issuer = p11_attrs_find (cert, CKA_ISSUER); + if (issuer == NULL) + issuer = &invalid; + serial_number = p11_attrs_find (cert, CKA_SERIAL_NUMBER); + if (serial_number == NULL) + serial_number = &invalid; + + /* Try to use the same label */ + label = p11_attrs_find (cert, CKA_LABEL); + if (label == NULL) + label = &invalid; + + attrs = p11_attrs_build (NULL, &klass, &modifiable, id, label, + subject, issuer, serial_number, &md5_hash, &sha1_hash, + &step_up_approved, &autogen, NULL); + return_if_fail (attrs != NULL); + + /* Calculate the default allow trust */ + if (distrust) + allow = CKT_NSS_NOT_TRUSTED; + else if (trust && authority) + allow = CKT_NSS_TRUSTED_DELEGATOR; + else if (trust) + allow = CKT_NSS_TRUSTED; + else + allow = CKT_NSS_TRUST_UNKNOWN; + + attrs = build_trust_object_ku (builder, index, cert, attrs, allow); + return_if_fail (attrs != NULL); + + attrs = build_trust_object_eku (attrs, allow, purposes, rejects); + return_if_fail (attrs != NULL); + + /* Replace related generated objects with this new one */ + generated = CK_TRUE; + rv = p11_index_replace (index, match, CKA_CERT_MD5_HASH, attrs); + return_if_fail (rv == CKR_OK); +} + +static void +build_assertions (p11_array *array, + CK_ATTRIBUTE *cert, + CK_X_ASSERTION_TYPE type, + const char **oids) +{ + CK_OBJECT_CLASS assertion = CKO_X_TRUST_ASSERTION; + CK_BBOOL truev = CK_TRUE; + CK_BBOOL falsev = CK_FALSE; + + CK_ATTRIBUTE klass = { CKA_CLASS, &assertion, sizeof (assertion) }; + CK_ATTRIBUTE private = { CKA_PRIVATE, &falsev, sizeof (falsev) }; + CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &falsev, sizeof (falsev) }; + CK_ATTRIBUTE assertion_type = { CKA_X_ASSERTION_TYPE, &type, sizeof (type) }; + CK_ATTRIBUTE autogen = { CKA_X_GENERATED, &truev, sizeof (truev) }; + CK_ATTRIBUTE purpose = { CKA_X_PURPOSE, }; + CK_ATTRIBUTE invalid = { CKA_INVALID, }; + + CK_ATTRIBUTE *issuer; + CK_ATTRIBUTE *serial; + CK_ATTRIBUTE *value; + CK_ATTRIBUTE *label; + CK_ATTRIBUTE *id; + CK_ATTRIBUTE *attrs; + int i; + + label = p11_attrs_find (cert, CKA_LABEL); + if (label == NULL) + label = &invalid; + + id = p11_attrs_find (cert, CKA_ID); + issuer = p11_attrs_find (cert, CKA_ISSUER); + serial = p11_attrs_find (cert, CKA_SERIAL_NUMBER); + value = p11_attrs_find (cert, CKA_VALUE); + + return_if_fail (id != NULL && issuer != NULL && serial != NULL && value != NULL); + + for (i = 0; oids[i] != NULL; i++) { + purpose.pValue = (void *)oids[i]; + purpose.ulValueLen = strlen (oids[i]); + + attrs = p11_attrs_build (NULL, &klass, &private, &modifiable, + id, label, &assertion_type, &purpose, + issuer, serial, value, &autogen, NULL); + return_if_fail (attrs != NULL); + + if (!p11_array_push (array, attrs)) + return_if_reached (); + } +} + +static void +build_trust_assertions (p11_array *built, + CK_ATTRIBUTE *cert, + CK_BBOOL trust, + CK_BBOOL distrust, + CK_BBOOL authority, + const char **purposes, + const char **rejects) +{ + const char *all_purposes[] = { + P11_OID_SERVER_AUTH_STR, + P11_OID_CLIENT_AUTH_STR, + P11_OID_CODE_SIGNING_STR, + P11_OID_EMAIL_PROTECTION_STR, + P11_OID_IPSEC_END_SYSTEM_STR, + P11_OID_IPSEC_TUNNEL_STR, + P11_OID_IPSEC_USER_STR, + P11_OID_TIME_STAMPING_STR, + NULL, + }; + + /* Build assertions for anything that's explicitly rejected */ + if (rejects) { + build_assertions (built, cert, CKT_X_DISTRUSTED_CERTIFICATE, rejects); + } + + if (distrust) { + /* + * Trust assertions are defficient in that they don't blacklist a certificate + * for any purposes. So we just have to go wild and write out a bunch of + * assertions for all our known purposes. + */ + build_assertions (built, cert, CKT_X_DISTRUSTED_CERTIFICATE, all_purposes); + } + + /* + * TODO: Build pinned certificate assertions. That is, trusted + * certificates where not an authority. + */ + + if (trust && authority) { + if (purposes) { + /* If purposes explicitly set, then anchor for those purposes */ + build_assertions (built, cert, CKT_X_ANCHORED_CERTIFICATE, purposes); + } else { + /* If purposes not-explicitly set, then anchor for all known */ + build_assertions (built, cert, CKT_X_ANCHORED_CERTIFICATE, all_purposes); + } + } +} + +static void +replace_trust_assertions (p11_builder *builder, + p11_index *index, + CK_ATTRIBUTE *cert, + CK_BBOOL trust, + CK_BBOOL distrust, + CK_BBOOL authority, + const char **purposes, + const char **rejects) +{ + CK_OBJECT_CLASS assertion = CKO_X_TRUST_ASSERTION; + CK_BBOOL generated = CK_FALSE; + CK_ATTRIBUTE *value; + p11_array *built; + CK_RV rv; + + CK_ATTRIBUTE match[] = { + { CKA_VALUE, }, + { CKA_CLASS, &assertion, sizeof (assertion) }, + { CKA_X_GENERATED, &generated, sizeof (generated) }, + { CKA_INVALID } + }; + + value = p11_attrs_find (cert, CKA_VALUE); + return_if_fail (value != NULL); + + built = p11_array_new (NULL); + build_trust_assertions (built, cert, trust, distrust, authority, purposes, rejects); + + generated = CK_TRUE; + match[0].pValue = value->pValue; + match[0].ulValueLen = value->ulValueLen; + rv = p11_index_replace_all (index, match, CKA_X_PURPOSE, built); + return_if_fail (rv == CKR_OK); + + p11_array_free (built); +} + +static void +remove_trust_and_assertions (p11_builder *builder, + p11_index *index, + CK_ATTRIBUTE *attrs) +{ + CK_BBOOL truev = CK_TRUE; + CK_ATTRIBUTE *id; + p11_array *array; + CK_RV rv; + + CK_ATTRIBUTE match[] = { + { CKA_ID, }, + { CKA_X_GENERATED, &truev, sizeof (truev) }, + { CKA_INVALID } + }; + + id = p11_attrs_find (attrs, CKA_ID); + return_if_fail (id != NULL); + + /* An empty array of replacements */ + array = p11_array_new (NULL); + + /* Remove all related NSS trust objects */ + match[0].pValue = id->pValue; + match[0].ulValueLen = id->ulValueLen; + rv = p11_index_replace_all (index, match, CKA_INVALID, array); + return_if_fail (rv == CKR_OK); + + p11_array_free (array); +} + +static void +replace_trust_and_assertions (p11_builder *builder, + p11_index *index, + CK_ATTRIBUTE *cert) +{ + CK_BBOOL trust = CK_FALSE; + CK_BBOOL distrust = CK_FALSE; + CK_BBOOL authority = CK_FALSE; + p11_array *purposes = NULL; + p11_array *rejects = NULL; + const char **purposev; + const char **rejectv; + CK_ULONG category; + unsigned char *ext; + size_t ext_len; + + /* + * We look up all this information in advance, since it's used + * by the various adapter objects, and we don't have to parse + * it multiple times. + */ + + if (!p11_attrs_find_bool (cert, CKA_TRUSTED, &trust)) + trust = CK_FALSE; + if (!p11_attrs_find_bool (cert, CKA_X_DISTRUSTED, &distrust)) + distrust = CK_FALSE; + if (p11_attrs_find_ulong (cert, CKA_CERTIFICATE_CATEGORY, &category) && category == 2) + authority = CK_TRUE; + + if (!distrust) { + ext = lookup_extension (builder, index, cert, P11_OID_EXTENDED_KEY_USAGE, &ext_len); + if (ext != NULL) { + purposes = p11_x509_parse_extended_key_usage (builder->asn1_defs, ext, ext_len); + if (purposes == NULL) + p11_message ("invalid extended key usage certificate extension"); + free (ext); + } + + ext = lookup_extension (builder, index, cert, P11_OID_OPENSSL_REJECT, &ext_len); + if (ext != NULL) { + rejects = p11_x509_parse_extended_key_usage (builder->asn1_defs, ext, ext_len); + if (rejects == NULL) + p11_message ("invalid reject key usage certificate extension"); + free (ext); + } + } + + /* null-terminate these arrays and use as strv's */ + purposev = rejectv = NULL; + if (rejects) { + if (!p11_array_push (rejects, NULL)) + return_if_reached (); + rejectv = (const char **)rejects->elem; + } + if (purposes) { + if (!p11_array_push (purposes, NULL)) + return_if_reached (); + purposev = (const char **)purposes->elem; + } + + replace_nss_trust_object (builder, index, cert, trust, distrust, + authority, purposev, rejectv); + replace_trust_assertions (builder, index, cert, trust, distrust, + authority, purposev, rejectv); + + p11_array_free (purposes); + p11_array_free (rejects); +} + +static void +replace_compat_for_cert (p11_builder *builder, + p11_index *index, + CK_OBJECT_HANDLE handle, + CK_ATTRIBUTE *attrs) +{ + static CK_OBJECT_CLASS certificate = CKO_CERTIFICATE; + static CK_CERTIFICATE_TYPE x509 = CKC_X_509; + + CK_ATTRIBUTE *value; + CK_ATTRIBUTE *id; + + CK_ATTRIBUTE match[] = { + { CKA_VALUE, }, + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_INVALID } + }; + + value = p11_attrs_find (attrs, CKA_VALUE); + id = p11_attrs_find (attrs, CKA_ID); + if (value == NULL || id == NULL) + return; + + /* + * If this certificate is going away, then find duplicate. In this + * case all the trust assertions are recalculated with this new + * certificate in mind. + */ + if (handle == 0) { + match[0].pValue = value->pValue; + match[0].ulValueLen = value->ulValueLen; + handle = p11_index_find (index, match); + if (handle != 0) + attrs = p11_index_lookup (index, handle); + } + + if (handle == 0) + remove_trust_and_assertions (builder, index, attrs); + else + replace_trust_and_assertions (builder, index, attrs); +} + +static void +replace_compat_for_ext (p11_builder *builder, + p11_index *index, + CK_OBJECT_HANDLE handle, + CK_ATTRIBUTE *attrs) +{ + + CK_OBJECT_HANDLE *handles; + CK_ATTRIBUTE *id; + int i; + + id = p11_attrs_find (attrs, CKA_ID); + if (id == NULL) + return; + + handles = lookup_related (index, CKO_CERTIFICATE, id); + for (i = 0; handles && handles[i] != 0; i++) { + attrs = p11_index_lookup (index, handles[i]); + replace_trust_and_assertions (builder, index, attrs); + } + free (handles); +} + +static void +update_related_category (p11_builder *builder, + p11_index *index, + CK_OBJECT_HANDLE handle, + CK_ATTRIBUTE *attrs) +{ + CK_OBJECT_HANDLE *handles; + CK_ULONG categoryv = 0UL; + CK_ATTRIBUTE *update; + CK_ATTRIBUTE *cert; + CK_ATTRIBUTE *id; + CK_RV rv; + int i; + + CK_ATTRIBUTE category[] = { + { CKA_CERTIFICATE_CATEGORY, &categoryv, sizeof (categoryv) }, + { CKA_INVALID, }, + }; + + id = p11_attrs_find (attrs, CKA_ID); + if (id == NULL) + return; + + /* Find all other objects with this handle */ + handles = lookup_related (index, CKO_CERTIFICATE, id); + + for (i = 0; handles && handles[i] != 0; i++) { + cert = p11_index_lookup (index, handle); + + if (calc_certificate_category (builder, index, cert, &categoryv)) { + update = p11_attrs_build (NULL, &category, NULL); + rv = p11_index_update (index, handles[i], update); + return_if_fail (rv == CKR_OK); + } + } + + free (handles); +} + +void +p11_builder_changed (void *bilder, + p11_index *index, + CK_OBJECT_HANDLE handle, + CK_ATTRIBUTE *attrs) +{ + static CK_OBJECT_CLASS certificate = CKO_CERTIFICATE; + static CK_OBJECT_CLASS extension = CKO_X_CERTIFICATE_EXTENSION; + static CK_CERTIFICATE_TYPE x509 = CKC_X_509; + + static CK_ATTRIBUTE match_cert[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_INVALID } + }; + + static CK_ATTRIBUTE match_eku[] = { + { CKA_CLASS, &extension, sizeof (extension) }, + { CKA_OBJECT_ID, (void *)P11_OID_EXTENDED_KEY_USAGE, + sizeof (P11_OID_EXTENDED_KEY_USAGE) }, + { CKA_INVALID } + }; + + static CK_ATTRIBUTE match_ku[] = { + { CKA_CLASS, &extension, sizeof (extension) }, + { CKA_OBJECT_ID, (void *)P11_OID_KEY_USAGE, + sizeof (P11_OID_KEY_USAGE) }, + { CKA_INVALID } + }; + + static CK_ATTRIBUTE match_bc[] = { + { CKA_CLASS, &extension, sizeof (extension) }, + { CKA_OBJECT_ID, (void *)P11_OID_BASIC_CONSTRAINTS, + sizeof (P11_OID_BASIC_CONSTRAINTS) }, + { CKA_INVALID } + }; + + p11_builder *builder = bilder; + + return_if_fail (builder != NULL); + return_if_fail (index != NULL); + return_if_fail (attrs != NULL); + + /* + * Treat these operations as loading, not modifying/creating, so we get + * around many of the rules that govern object creation + */ + p11_index_batch (index); + + /* A certificate */ + if (p11_attrs_match (attrs, match_cert)) { + replace_compat_for_cert (builder, index, handle, attrs); + + /* An ExtendedKeyUsage extension */ + } else if (p11_attrs_match (attrs, match_eku) || + p11_attrs_match (attrs, match_ku)) { + replace_compat_for_ext (builder, index, handle, attrs); + + /* A BasicConstraints extension */ + } else if (p11_attrs_match (attrs, match_bc)) { + update_related_category (builder, index, handle, attrs); + } + + p11_index_finish (index); +} diff --git a/trust/adapter.h b/trust/builder.h index fb4ad4e..c837514 100644 --- a/trust/adapter.h +++ b/trust/builder.h @@ -32,13 +32,35 @@ * Author: Stef Walter <stefw@redhat.com> */ -#include "array.h" -#include "parser.h" +#ifndef P11_BUILDER_H_ +#define P11_BUILDER_H_ -#ifndef P11_ADAPTER_H_ -#define P11_ADAPTER_H_ +#include "asn1.h" +#include "dict.h" +#include "index.h" +#include "pkcs11.h" -void p11_adapter_build_objects (p11_parser *parser, - p11_array *parsing); +enum { + P11_BUILDER_FLAG_NONE = 0, + P11_BUILDER_FLAG_TOKEN = 1 << 1, +}; -#endif /* P11_ADAPTER_H_ */ +typedef struct _p11_builder p11_builder; + +p11_builder * p11_builder_new (int flags); + +void p11_builder_free (p11_builder *builder); + +CK_RV p11_builder_build (void *builder, + p11_index *index, + CK_ATTRIBUTE **attrs, + CK_ATTRIBUTE *merge); + +void p11_builder_changed (void *builder, + p11_index *index, + CK_OBJECT_HANDLE handle, + CK_ATTRIBUTE *attrs); + +p11_asn1_cache * p11_builder_get_cache (p11_builder *builder); + +#endif /* P11_BUILDER_H_ */ 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; -} diff --git a/trust/parser.h b/trust/parser.h index 201c2c3..ca41d26 100644 --- a/trust/parser.h +++ b/trust/parser.h @@ -32,63 +32,42 @@ * Author: Stef Walter <stefw@redhat.com> */ +#include "asn1.h" #include "array.h" #include "dict.h" +#include "index.h" #include "pkcs11.h" #ifndef P11_PARSER_H_ #define P11_PARSER_H_ enum { - P11_PARSE_FAILURE = -1, - P11_PARSE_UNRECOGNIZED = 0, - P11_PARSE_SUCCESS = 1, -}; - -enum { P11_PARSE_FLAG_NONE = 0, P11_PARSE_FLAG_ANCHOR = 1 << 0, - P11_PARSE_FLAG_BLACKLIST = 1 << 1 + P11_PARSE_FLAG_BLACKLIST = 1 << 1, }; -#define P11_PARSER_FIRST_HANDLE 0xA0000000UL +enum { + P11_PARSE_FAILURE = -1, + P11_PARSE_UNRECOGNIZED = 0, + P11_PARSE_SUCCESS = 1, +}; typedef struct _p11_parser p11_parser; -p11_parser * p11_parser_new (void); +p11_parser * p11_parser_new (p11_index *index, + p11_asn1_cache *asn1_cache); void p11_parser_free (p11_parser *parser); -typedef void (* p11_parser_sink) (CK_ATTRIBUTE *attrs, - void *user_data); - int 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 p11_parse_file (p11_parser *parser, const char *filename, - int flags, - p11_parser_sink sink, - void *sink_data); - -p11_dict * p11_parser_get_asn1_defs (p11_parser *parser); - -/* Functions used for retrieving parsing information */ - -CK_ATTRIBUTE * p11_parsing_get_certificate (p11_parser *parser, - p11_array *parsing); - -unsigned char * p11_parsing_get_extension (p11_parser *parser, - p11_array *parsing, - const unsigned char *oid, - size_t *length); - -void p11_parsing_update_certificate (p11_parser *parser, - p11_array *parsing); + int flags); #endif diff --git a/trust/session.c b/trust/session.c index 30928ed..19434ff 100644 --- a/trust/session.c +++ b/trust/session.c @@ -58,7 +58,12 @@ p11_session_new (p11_token *token) session->handle = p11_module_next_id (); - session->index = p11_index_new (NULL, NULL, NULL); + session->builder = p11_builder_new (P11_BUILDER_FLAG_NONE); + return_val_if_fail (session->builder, NULL); + + session->index = p11_index_new (p11_builder_build, + p11_builder_changed, + session->builder); return_val_if_fail (session->index != NULL, NULL); session->token = token; diff --git a/trust/session.h b/trust/session.h index c2626d0..b820770 100644 --- a/trust/session.h +++ b/trust/session.h @@ -32,6 +32,7 @@ * Author: Stef Walter <stefw@redhat.com> */ +#include "builder.h" #include "index.h" #include "pkcs11.h" #include "token.h" @@ -44,6 +45,7 @@ typedef void (* p11_session_cleanup) (void *data); typedef struct { CK_SESSION_HANDLE handle; p11_index *index; + p11_builder *builder; p11_token *token; CK_BBOOL loaded; diff --git a/trust/tests/Makefile.am b/trust/tests/Makefile.am index cdab991..a675a56 100644 --- a/trust/tests/Makefile.am +++ b/trust/tests/Makefile.am @@ -28,6 +28,7 @@ LDADD = \ CHECK_PROGS = \ test-parser \ test-index \ + test-builder \ test-token \ test-module \ $(NULL) diff --git a/trust/tests/test-builder.c b/trust/tests/test-builder.c new file mode 100644 index 0000000..8ffab88 --- /dev/null +++ b/trust/tests/test-builder.c @@ -0,0 +1,1611 @@ +/* + * Copyright (c) 2013 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@gnome.org> + */ + +#include "config.h" +#include "CuTest.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "attrs.h" +#include "builder.h" +#include "checksum.h" +#include "debug.h" +#include "index.h" +#include "library.h" +#include "oid.h" +#include "pkcs11x.h" + +#include "test-data.h" + +struct { + p11_builder *builder; + p11_index *index; +} test; + +static CK_TRUST trusted = CKT_NSS_TRUSTED; +static CK_TRUST trusted_delegator = CKT_NSS_TRUSTED_DELEGATOR; +static CK_TRUST not_trusted = CKT_NSS_NOT_TRUSTED; +static CK_TRUST trust_unknown = CKT_NSS_TRUST_UNKNOWN; +static CK_OBJECT_CLASS certificate = CKO_CERTIFICATE; +static CK_OBJECT_CLASS data = CKO_DATA; +static CK_OBJECT_CLASS certificate_extension = CKO_X_CERTIFICATE_EXTENSION; +static CK_OBJECT_CLASS nss_trust = CKO_NSS_TRUST; +static CK_OBJECT_CLASS trust_assertion = CKO_X_TRUST_ASSERTION; +static CK_X_ASSERTION_TYPE anchored_certificate = CKT_X_ANCHORED_CERTIFICATE; +static CK_X_ASSERTION_TYPE distrusted_certificate = CKT_X_DISTRUSTED_CERTIFICATE; +static CK_CERTIFICATE_TYPE x509 = CKC_X_509; +static CK_ULONG certificate_authority = 2; +static CK_ULONG other_entity = 3; +static CK_BBOOL truev = CK_TRUE; +static CK_BBOOL falsev = CK_FALSE; + +static void +setup (CuTest *cu) +{ + test.builder = p11_builder_new (P11_BUILDER_FLAG_TOKEN); + CuAssertPtrNotNull (cu, test.builder); + + test.index = p11_index_new (p11_builder_build, p11_builder_changed, test.builder); + CuAssertPtrNotNull (cu, test.index); +} + +static void +teardown (CuTest *cu) +{ + p11_builder_free (test.builder); + p11_index_free (test.index); + memset (&test, 0, sizeof (test)); +} + +static void +test_get_cache (CuTest *cu) +{ + p11_asn1_cache *cache; + + setup (cu); + + cache = p11_builder_get_cache (test.builder); + CuAssertPtrEquals (cu, NULL, p11_asn1_cache_get (cache, "blah", (unsigned char *)"blah", 4)); + + teardown (cu); +} + +static void +test_build_data (CuTest *cu) +{ + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &data, sizeof (data) }, + { CKA_VALUE, "the value", 9 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE check[] = { + { CKA_CLASS, &data, sizeof (data) }, + { CKA_TOKEN, &truev, sizeof (truev) }, + { CKA_MODIFIABLE, &falsev, sizeof (falsev) }, + { CKA_PRIVATE, &falsev, sizeof (falsev) }, + { CKA_LABEL, "", 0 }, + { CKA_VALUE, "the value", 9 }, + { CKA_APPLICATION, "", 0 }, + { CKA_OBJECT_ID, "", 0 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_ATTRIBUTE *merge; + CK_RV rv; + + setup (cu); + + attrs = NULL; + merge = p11_attrs_dup (input); + rv = p11_builder_build (test.builder, test.index, &attrs, merge); + CuAssertIntEquals (cu, CKR_OK, rv); + + test_check_attrs (cu, check, attrs); + p11_attrs_free (attrs); + + teardown (cu); +} + +static void +test_build_certificate (CuTest *cu) +{ + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_LABEL, "the label", 9 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_ATTRIBUTE *merge; + CK_RV rv; + + setup (cu); + + attrs = NULL; + merge = p11_attrs_dup (input); + rv = p11_builder_build (test.builder, test.index, &attrs, merge); + CuAssertIntEquals (cu, CKR_OK, rv); + + test_check_cacert3_ca (cu, attrs, "the label"); + p11_attrs_free (attrs); + + teardown (cu); +} + +static void +test_build_certificate_empty (CuTest *cu) +{ + unsigned char checksum[P11_CHECKSUM_SHA1_LENGTH]; + CK_ULONG domain = 0; + CK_ULONG category = 0; + + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_URL, "http://blah", 11 }, + { CKA_HASH_OF_ISSUER_PUBLIC_KEY, checksum, sizeof (checksum) }, + { CKA_HASH_OF_SUBJECT_PUBLIC_KEY, checksum, sizeof (checksum) }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_LABEL, "the label", 9 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE expected[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_CERTIFICATE_CATEGORY, &category, sizeof (category) }, + { CKA_VALUE, "", 0 }, + { CKA_START_DATE, "", 0 }, + { CKA_END_DATE, "", 0, }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_ISSUER, "", 0 }, + { CKA_SERIAL_NUMBER, "", 0 }, + { CKA_HASH_OF_ISSUER_PUBLIC_KEY, checksum, sizeof (checksum) }, + { CKA_HASH_OF_SUBJECT_PUBLIC_KEY, checksum, sizeof (checksum) }, + { CKA_LABEL, "the label", 9 }, + { CKA_JAVA_MIDP_SECURITY_DOMAIN, &domain, sizeof (domain) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_ATTRIBUTE *merge; + CK_RV rv; + + setup (cu); + + p11_checksum_sha1 (checksum, test_cacert3_ca_der, sizeof (test_cacert3_ca_der), NULL); + + attrs = NULL; + merge = p11_attrs_dup (input); + rv = p11_builder_build (test.builder, test.index, &attrs, merge); + CuAssertIntEquals (cu, CKR_OK, rv); + + test_check_attrs (cu, expected, attrs); + p11_attrs_free (attrs); + + teardown (cu); +} + +static const unsigned char entrust_pretend_ca[] = { + 0x30, 0x82, 0x04, 0x5c, 0x30, 0x82, 0x03, 0x44, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x04, 0x38, + 0x63, 0xb9, 0x66, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, + 0x05, 0x00, 0x30, 0x81, 0xb4, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, + 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x31, 0x40, 0x30, 0x3e, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x14, 0x37, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, + 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x43, 0x50, 0x53, 0x5f, 0x32, 0x30, 0x34, 0x38, 0x20, 0x69, + 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x20, 0x62, 0x79, 0x20, 0x72, 0x65, 0x66, 0x2e, 0x20, 0x28, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x20, 0x6c, 0x69, 0x61, 0x62, 0x2e, 0x29, 0x31, 0x25, 0x30, + 0x23, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1c, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39, 0x39, 0x39, + 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x65, 0x64, 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2a, 0x45, + 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x20, 0x28, 0x32, 0x30, 0x34, 0x38, 0x29, 0x30, 0x1e, 0x17, 0x0d, 0x39, 0x39, 0x31, + 0x32, 0x32, 0x34, 0x31, 0x37, 0x35, 0x30, 0x35, 0x31, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x32, + 0x32, 0x34, 0x31, 0x38, 0x32, 0x30, 0x35, 0x31, 0x5a, 0x30, 0x81, 0xb4, 0x31, 0x14, 0x30, 0x12, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, + 0x65, 0x74, 0x31, 0x40, 0x30, 0x3e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x14, 0x37, 0x77, 0x77, 0x77, + 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x43, 0x50, 0x53, + 0x5f, 0x32, 0x30, 0x34, 0x38, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x20, 0x62, 0x79, + 0x20, 0x72, 0x65, 0x66, 0x2e, 0x20, 0x28, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x20, 0x6c, 0x69, + 0x61, 0x62, 0x2e, 0x29, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1c, 0x28, + 0x63, 0x29, 0x20, 0x31, 0x39, 0x39, 0x39, 0x20, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, + 0x6e, 0x65, 0x74, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x33, 0x30, 0x31, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x2a, 0x45, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x6e, 0x65, + 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x28, 0x32, 0x30, 0x34, 0x38, 0x29, + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, + 0x00, 0xad, 0x4d, 0x4b, 0xa9, 0x12, 0x86, 0xb2, 0xea, 0xa3, 0x20, 0x07, 0x15, 0x16, 0x64, 0x2a, + 0x2b, 0x4b, 0xd1, 0xbf, 0x0b, 0x4a, 0x4d, 0x8e, 0xed, 0x80, 0x76, 0xa5, 0x67, 0xb7, 0x78, 0x40, + 0xc0, 0x73, 0x42, 0xc8, 0x68, 0xc0, 0xdb, 0x53, 0x2b, 0xdd, 0x5e, 0xb8, 0x76, 0x98, 0x35, 0x93, + 0x8b, 0x1a, 0x9d, 0x7c, 0x13, 0x3a, 0x0e, 0x1f, 0x5b, 0xb7, 0x1e, 0xcf, 0xe5, 0x24, 0x14, 0x1e, + 0xb1, 0x81, 0xa9, 0x8d, 0x7d, 0xb8, 0xcc, 0x6b, 0x4b, 0x03, 0xf1, 0x02, 0x0c, 0xdc, 0xab, 0xa5, + 0x40, 0x24, 0x00, 0x7f, 0x74, 0x94, 0xa1, 0x9d, 0x08, 0x29, 0xb3, 0x88, 0x0b, 0xf5, 0x87, 0x77, + 0x9d, 0x55, 0xcd, 0xe4, 0xc3, 0x7e, 0xd7, 0x6a, 0x64, 0xab, 0x85, 0x14, 0x86, 0x95, 0x5b, 0x97, + 0x32, 0x50, 0x6f, 0x3d, 0xc8, 0xba, 0x66, 0x0c, 0xe3, 0xfc, 0xbd, 0xb8, 0x49, 0xc1, 0x76, 0x89, + 0x49, 0x19, 0xfd, 0xc0, 0xa8, 0xbd, 0x89, 0xa3, 0x67, 0x2f, 0xc6, 0x9f, 0xbc, 0x71, 0x19, 0x60, + 0xb8, 0x2d, 0xe9, 0x2c, 0xc9, 0x90, 0x76, 0x66, 0x7b, 0x94, 0xe2, 0xaf, 0x78, 0xd6, 0x65, 0x53, + 0x5d, 0x3c, 0xd6, 0x9c, 0xb2, 0xcf, 0x29, 0x03, 0xf9, 0x2f, 0xa4, 0x50, 0xb2, 0xd4, 0x48, 0xce, + 0x05, 0x32, 0x55, 0x8a, 0xfd, 0xb2, 0x64, 0x4c, 0x0e, 0xe4, 0x98, 0x07, 0x75, 0xdb, 0x7f, 0xdf, + 0xb9, 0x08, 0x55, 0x60, 0x85, 0x30, 0x29, 0xf9, 0x7b, 0x48, 0xa4, 0x69, 0x86, 0xe3, 0x35, 0x3f, + 0x1e, 0x86, 0x5d, 0x7a, 0x7a, 0x15, 0xbd, 0xef, 0x00, 0x8e, 0x15, 0x22, 0x54, 0x17, 0x00, 0x90, + 0x26, 0x93, 0xbc, 0x0e, 0x49, 0x68, 0x91, 0xbf, 0xf8, 0x47, 0xd3, 0x9d, 0x95, 0x42, 0xc1, 0x0e, + 0x4d, 0xdf, 0x6f, 0x26, 0xcf, 0xc3, 0x18, 0x21, 0x62, 0x66, 0x43, 0x70, 0xd6, 0xd5, 0xc0, 0x07, + 0xe1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x74, 0x30, 0x72, 0x30, 0x11, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, 0x00, 0x07, 0x30, 0x1f, 0x06, + 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x55, 0xe4, 0x81, 0xd1, 0x11, 0x80, + 0xbe, 0xd8, 0x89, 0xb9, 0x08, 0xa3, 0x31, 0xf9, 0xa1, 0x24, 0x09, 0x16, 0xb9, 0x70, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x55, 0xe4, 0x81, 0xd1, 0x11, 0x80, 0xbe, + 0xd8, 0x89, 0xb9, 0x08, 0xa3, 0x31, 0xf9, 0xa1, 0x24, 0x09, 0x16, 0xb9, 0x70, 0x30, 0x1d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf6, 0x7d, 0x07, 0x41, 0x00, 0x04, 0x10, 0x30, 0x0e, 0x1b, 0x08, + 0x56, 0x35, 0x2e, 0x30, 0x3a, 0x34, 0x2e, 0x30, 0x03, 0x02, 0x04, 0x90, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, + 0x59, 0x47, 0xac, 0x21, 0x84, 0x8a, 0x17, 0xc9, 0x9c, 0x89, 0x53, 0x1e, 0xba, 0x80, 0x85, 0x1a, + 0xc6, 0x3c, 0x4e, 0x3e, 0xb1, 0x9c, 0xb6, 0x7c, 0xc6, 0x92, 0x5d, 0x18, 0x64, 0x02, 0xe3, 0xd3, + 0x06, 0x08, 0x11, 0x61, 0x7c, 0x63, 0xe3, 0x2b, 0x9d, 0x31, 0x03, 0x70, 0x76, 0xd2, 0xa3, 0x28, + 0xa0, 0xf4, 0xbb, 0x9a, 0x63, 0x73, 0xed, 0x6d, 0xe5, 0x2a, 0xdb, 0xed, 0x14, 0xa9, 0x2b, 0xc6, + 0x36, 0x11, 0xd0, 0x2b, 0xeb, 0x07, 0x8b, 0xa5, 0xda, 0x9e, 0x5c, 0x19, 0x9d, 0x56, 0x12, 0xf5, + 0x54, 0x29, 0xc8, 0x05, 0xed, 0xb2, 0x12, 0x2a, 0x8d, 0xf4, 0x03, 0x1b, 0xff, 0xe7, 0x92, 0x10, + 0x87, 0xb0, 0x3a, 0xb5, 0xc3, 0x9d, 0x05, 0x37, 0x12, 0xa3, 0xc7, 0xf4, 0x15, 0xb9, 0xd5, 0xa4, + 0x39, 0x16, 0x9b, 0x53, 0x3a, 0x23, 0x91, 0xf1, 0xa8, 0x82, 0xa2, 0x6a, 0x88, 0x68, 0xc1, 0x79, + 0x02, 0x22, 0xbc, 0xaa, 0xa6, 0xd6, 0xae, 0xdf, 0xb0, 0x14, 0x5f, 0xb8, 0x87, 0xd0, 0xdd, 0x7c, + 0x7f, 0x7b, 0xff, 0xaf, 0x1c, 0xcf, 0xe6, 0xdb, 0x07, 0xad, 0x5e, 0xdb, 0x85, 0x9d, 0xd0, 0x2b, + 0x0d, 0x33, 0xdb, 0x04, 0xd1, 0xe6, 0x49, 0x40, 0x13, 0x2b, 0x76, 0xfb, 0x3e, 0xe9, 0x9c, 0x89, + 0x0f, 0x15, 0xce, 0x18, 0xb0, 0x85, 0x78, 0x21, 0x4f, 0x6b, 0x4f, 0x0e, 0xfa, 0x36, 0x67, 0xcd, + 0x07, 0xf2, 0xff, 0x08, 0xd0, 0xe2, 0xde, 0xd9, 0xbf, 0x2a, 0xaf, 0xb8, 0x87, 0x86, 0x21, 0x3c, + 0x04, 0xca, 0xb7, 0x94, 0x68, 0x7f, 0xcf, 0x3c, 0xe9, 0x98, 0xd7, 0x38, 0xff, 0xec, 0xc0, 0xd9, + 0x50, 0xf0, 0x2e, 0x4b, 0x58, 0xae, 0x46, 0x6f, 0xd0, 0x2e, 0xc3, 0x60, 0xda, 0x72, 0x55, 0x72, + 0xbd, 0x4c, 0x45, 0x9e, 0x61, 0xba, 0xbf, 0x84, 0x81, 0x92, 0x03, 0xd1, 0xd2, 0x69, 0x7c, 0xc5, +}; + +static void +test_build_certificate_non_ca (CuTest *cu) +{ + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_VALUE, (void *)entrust_pretend_ca, sizeof (entrust_pretend_ca) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE expected[] = { + { CKA_CERTIFICATE_CATEGORY, &other_entity, sizeof (other_entity) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + attrs = NULL; + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input)); + CuAssertIntEquals (cu, CKR_OK, rv); + + test_check_attrs (cu, expected, attrs); + p11_attrs_free (attrs); + + teardown (cu); +} + +static const unsigned char verisign_v1_ca[] = { + 0x30, 0x82, 0x02, 0x3c, 0x30, 0x82, 0x01, 0xa5, 0x02, 0x10, 0x3f, 0x69, 0x1e, 0x81, 0x9c, 0xf0, + 0x9a, 0x4a, 0xf3, 0x73, 0xff, 0xb9, 0x48, 0xa2, 0xe4, 0xdd, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x5f, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, + 0x2e, 0x31, 0x37, 0x30, 0x35, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2e, 0x43, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x31, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, + 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x39, 0x36, + 0x30, 0x31, 0x32, 0x39, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x30, + 0x38, 0x30, 0x32, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x5f, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, + 0x63, 0x2e, 0x31, 0x37, 0x30, 0x35, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2e, 0x43, 0x6c, 0x61, + 0x73, 0x73, 0x20, 0x31, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, + 0x61, 0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x81, 0x9f, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, + 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xe5, 0x19, 0xbf, 0x6d, 0xa3, 0x56, 0x61, 0x2d, + 0x99, 0x48, 0x71, 0xf6, 0x67, 0xde, 0xb9, 0x8d, 0xeb, 0xb7, 0x9e, 0x86, 0x80, 0x0a, 0x91, 0x0e, + 0xfa, 0x38, 0x25, 0xaf, 0x46, 0x88, 0x82, 0xe5, 0x73, 0xa8, 0xa0, 0x9b, 0x24, 0x5d, 0x0d, 0x1f, + 0xcc, 0x65, 0x6e, 0x0c, 0xb0, 0xd0, 0x56, 0x84, 0x18, 0x87, 0x9a, 0x06, 0x9b, 0x10, 0xa1, 0x73, + 0xdf, 0xb4, 0x58, 0x39, 0x6b, 0x6e, 0xc1, 0xf6, 0x15, 0xd5, 0xa8, 0xa8, 0x3f, 0xaa, 0x12, 0x06, + 0x8d, 0x31, 0xac, 0x7f, 0xb0, 0x34, 0xd7, 0x8f, 0x34, 0x67, 0x88, 0x09, 0xcd, 0x14, 0x11, 0xe2, + 0x4e, 0x45, 0x56, 0x69, 0x1f, 0x78, 0x02, 0x80, 0xda, 0xdc, 0x47, 0x91, 0x29, 0xbb, 0x36, 0xc9, + 0x63, 0x5c, 0xc5, 0xe0, 0xd7, 0x2d, 0x87, 0x7b, 0xa1, 0xb7, 0x32, 0xb0, 0x7b, 0x30, 0xba, 0x2a, + 0x2f, 0x31, 0xaa, 0xee, 0xa3, 0x67, 0xda, 0xdb, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, + 0x58, 0x15, 0x29, 0x39, 0x3c, 0x77, 0xa3, 0xda, 0x5c, 0x25, 0x03, 0x7c, 0x60, 0xfa, 0xee, 0x09, + 0x99, 0x3c, 0x27, 0x10, 0x70, 0xc8, 0x0c, 0x09, 0xe6, 0xb3, 0x87, 0xcf, 0x0a, 0xe2, 0x18, 0x96, + 0x35, 0x62, 0xcc, 0xbf, 0x9b, 0x27, 0x79, 0x89, 0x5f, 0xc9, 0xc4, 0x09, 0xf4, 0xce, 0xb5, 0x1d, + 0xdf, 0x2a, 0xbd, 0xe5, 0xdb, 0x86, 0x9c, 0x68, 0x25, 0xe5, 0x30, 0x7c, 0xb6, 0x89, 0x15, 0xfe, + 0x67, 0xd1, 0xad, 0xe1, 0x50, 0xac, 0x3c, 0x7c, 0x62, 0x4b, 0x8f, 0xba, 0x84, 0xd7, 0x12, 0x15, + 0x1b, 0x1f, 0xca, 0x5d, 0x0f, 0xc1, 0x52, 0x94, 0x2a, 0x11, 0x99, 0xda, 0x7b, 0xcf, 0x0c, 0x36, + 0x13, 0xd5, 0x35, 0xdc, 0x10, 0x19, 0x59, 0xea, 0x94, 0xc1, 0x00, 0xbf, 0x75, 0x8f, 0xd9, 0xfa, + 0xfd, 0x76, 0x04, 0xdb, 0x62, 0xbb, 0x90, 0x6a, 0x03, 0xd9, 0x46, 0x35, 0xd9, 0xf8, 0x7c, 0x5b, +}; + +static void +test_build_certificate_v1_ca (CuTest *cu) +{ + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_VALUE, (void *)verisign_v1_ca, sizeof (verisign_v1_ca) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE expected[] = { + { CKA_CERTIFICATE_CATEGORY, &certificate_authority, sizeof (certificate_authority) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + attrs = NULL; + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input)); + CuAssertIntEquals (cu, CKR_OK, rv); + + test_check_attrs (cu, expected, attrs); + p11_attrs_free (attrs); + + teardown (cu); +} + +static void +test_build_certificate_staple_ca (CuTest *cu) +{ + CK_ULONG category = 2; /* CA */ + + CK_ATTRIBUTE stapled[] = { + { CKA_CLASS, &certificate_extension, sizeof (certificate_extension) }, + { CKA_OBJECT_ID, (void *)P11_OID_BASIC_CONSTRAINTS, sizeof (P11_OID_BASIC_CONSTRAINTS) }, + { CKA_VALUE, "\x30\x03\x01\x01\xFF", 5 }, + { CKA_ID, "the id", 6 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_VALUE, (void *)entrust_pretend_ca, sizeof (entrust_pretend_ca) }, + { CKA_ID, "the id", 6 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE expected[] = { + { CKA_CERTIFICATE_CATEGORY, &category, sizeof (category) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + /* Add a stapled certificate */ + rv = p11_index_add (test.index, stapled, 4, NULL); + CuAssertIntEquals (cu, CKR_OK, rv); + + attrs = NULL; + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input)); + CuAssertIntEquals (cu, CKR_OK, rv); + + /* + * Even though the certificate is not a valid CA, the presence of the + * stapled certificate extension transforms it into a CA. + */ + test_check_attrs (cu, expected, attrs); + p11_attrs_free (attrs); + + teardown (cu); +} + +static void +test_build_certificate_no_type (CuTest *cu) +{ + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + p11_message_quiet (); + + attrs = NULL; + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input)); + CuAssertIntEquals (cu, CKR_TEMPLATE_INCOMPLETE, rv); + + p11_message_loud (); + + teardown (cu); +} + +static void +test_build_certificate_bad_type (CuTest *cu) +{ + CK_CERTIFICATE_TYPE type = CKC_WTLS; + + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_CERTIFICATE_TYPE, &type, sizeof (type) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + p11_message_quiet (); + + attrs = NULL; + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input)); + CuAssertIntEquals (cu, CKR_TEMPLATE_INCONSISTENT, rv); + + p11_message_loud (); + + teardown (cu); +} + +static void +test_build_extension (CuTest *cu) +{ + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &certificate_extension, sizeof (certificate_extension) }, + { CKA_OBJECT_ID, "\x06\x03\x55\x1d\x50", 5 }, + { CKA_VALUE, "the value", 9 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE check[] = { + { CKA_CLASS, &certificate_extension, sizeof (certificate_extension) }, + { CKA_TOKEN, &truev, sizeof (truev) }, + { CKA_MODIFIABLE, &falsev, sizeof (falsev) }, + { CKA_PRIVATE, &falsev, sizeof (falsev) }, + { CKA_OBJECT_ID, "\x06\x03\x55\x1d\x50", 5 }, + { CKA_VALUE, "the value", 9 }, + { CKA_LABEL, "", 0 }, + { CKA_X_CRITICAL, &falsev, sizeof (falsev) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + attrs = NULL; + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input)); + CuAssertIntEquals (cu, CKR_OK, rv); + + test_check_attrs (cu, check, attrs); + p11_attrs_free (attrs); + + teardown (cu); +} + +static void +test_create_not_settable (CuTest *cu) +{ + /* + * CKA_TRUSTED cannot be set by the normal user according to spec + */ + + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_TRUSTED, &falsev, sizeof (falsev) }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + p11_message_quiet (); + + attrs = NULL; + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input)); + CuAssertIntEquals (cu, CKR_ATTRIBUTE_READ_ONLY, rv); + + p11_message_loud (); + + p11_attrs_free (attrs); + + teardown (cu); +} + +static void +test_create_but_loadable (CuTest *cu) +{ + /* + * CKA_TRUSTED cannot be set on creation, but can be set if we're + * loading from our store. This is signified by batching. + */ + + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_TRUSTED, &falsev, sizeof (falsev) }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + p11_index_batch (test.index); + + attrs = NULL; + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input)); + CuAssertIntEquals (cu, CKR_OK, rv); + + p11_index_finish (test.index); + + test_check_attrs (cu, input, attrs); + p11_attrs_free (attrs); + + teardown (cu); +} + +static void +test_create_unsupported (CuTest *cu) +{ + CK_OBJECT_CLASS klass = CKO_PRIVATE_KEY; + + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &klass, sizeof (klass) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + p11_message_quiet (); + + attrs = NULL; + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input)); + CuAssertIntEquals (cu, CKR_TEMPLATE_INCONSISTENT, rv); + + p11_message_loud (); + + teardown (cu); +} + +static void +test_create_generated (CuTest *cu) +{ + CK_OBJECT_CLASS klass = CKO_NSS_TRUST; + + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &klass, sizeof (klass) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + p11_message_quiet (); + + attrs = NULL; + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input)); + CuAssertIntEquals (cu, CKR_TEMPLATE_INCONSISTENT, rv); + + p11_message_loud (); + + teardown (cu); +} + +static void +test_create_bad_attribute (CuTest *cu) +{ + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &data, sizeof (data) }, + { CKA_VALUE, "the value", 9 }, + { CKA_COLOR, "blue", 4 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + p11_message_quiet (); + + attrs = NULL; + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input)); + CuAssertIntEquals (cu, CKR_TEMPLATE_INCONSISTENT, rv); + + p11_message_loud (); + + teardown (cu); +} + +static void +test_create_missing_attribute (CuTest *cu) +{ + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &certificate_extension, sizeof (certificate_extension) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + p11_message_quiet (); + + attrs = NULL; + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input)); + CuAssertIntEquals (cu, CKR_TEMPLATE_INCOMPLETE, rv); + + p11_message_loud (); + + teardown (cu); +} + +static void +test_create_no_class (CuTest *cu) +{ + CK_ATTRIBUTE input[] = { + { CKA_VALUE, "the value", 9 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + p11_message_quiet (); + + attrs = NULL; + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input)); + CuAssertIntEquals (cu, CKR_TEMPLATE_INCOMPLETE, rv); + + p11_message_loud (); + + teardown (cu); +} + +static void +test_create_token_mismatch (CuTest *cu) +{ + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &data, sizeof (data) }, + { CKA_TOKEN, &falsev, sizeof (falsev) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + p11_message_quiet (); + + attrs = NULL; + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input)); + CuAssertIntEquals (cu, CKR_TEMPLATE_INCONSISTENT, rv); + + p11_message_loud (); + + teardown (cu); +} + +static void +test_modify_success (CuTest *cu) +{ + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &data, sizeof (data) }, + { CKA_MODIFIABLE, &truev, sizeof (truev) }, + { CKA_VALUE, "the value", 9 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE modify[] = { + { CKA_VALUE, "new value long", 14 }, + { CKA_LABEL, "new label", 9 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE expected[] = { + { CKA_CLASS, &data, sizeof (data) }, + { CKA_MODIFIABLE, &truev, sizeof (truev) }, + { CKA_VALUE, "new value long", 14 }, + { CKA_LABEL, "new label", 9 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + attrs = NULL; + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input)); + CuAssertIntEquals (cu, CKR_OK, rv); + + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (modify)); + CuAssertIntEquals (cu, CKR_OK, rv); + + test_check_attrs (cu, expected, attrs); + p11_attrs_free (attrs); + + teardown (cu); +} + +static void +test_modify_read_only (CuTest *cu) +{ + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &data, sizeof (data) }, + { CKA_MODIFIABLE, &truev, sizeof (truev) }, + { CKA_VALUE, "the value", 9 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE modify[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_ATTRIBUTE *merge; + CK_RV rv; + + setup (cu); + + attrs = NULL; + merge = p11_attrs_dup (input); + rv = p11_builder_build (test.builder, test.index, &attrs, merge); + CuAssertIntEquals (cu, CKR_OK, rv); + + p11_message_quiet (); + + merge = p11_attrs_dup (modify); + rv = p11_builder_build (test.builder, test.index, &attrs, merge); + CuAssertIntEquals (cu, CKR_ATTRIBUTE_READ_ONLY, rv); + + p11_message_loud (); + + p11_attrs_free (attrs); + + teardown (cu); +} + +static void +test_modify_unchanged (CuTest *cu) +{ + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &data, sizeof (data) }, + { CKA_MODIFIABLE, &truev, sizeof (truev) }, + { CKA_VALUE, "the value", 9 }, + { CKA_INVALID }, + }; + + /* + * Although CKA_CLASS is read-only, changing to same value + * shouldn't fail + */ + + CK_ATTRIBUTE modify[] = { + { CKA_CLASS, &data, sizeof (data) }, + { CKA_VALUE, "the other", 9 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE expected[] = { + { CKA_CLASS, &data, sizeof (data) }, + { CKA_VALUE, "the other", 9 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + attrs = NULL; + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input)); + CuAssertIntEquals (cu, CKR_OK, rv); + + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (modify)); + CuAssertIntEquals (cu, CKR_OK, rv); + + test_check_attrs (cu, expected, attrs); + p11_attrs_free (attrs); + + teardown (cu); +} + +static void +test_modify_not_modifiable (CuTest *cu) +{ + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &data, sizeof (data) }, + { CKA_MODIFIABLE, &falsev, sizeof (falsev) }, + { CKA_VALUE, "the value", 9 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE modify[] = { + { CKA_VALUE, "the value", 9 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + attrs = NULL; + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input)); + CuAssertIntEquals (cu, CKR_OK, rv); + + p11_message_quiet (); + + rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (modify)); + CuAssertIntEquals (cu, CKR_ATTRIBUTE_READ_ONLY, rv); + + p11_message_loud (); + + p11_attrs_free (attrs); + + teardown (cu); +} + +static void +test_changed_trusted_certificate (CuTest *cu) +{ + static CK_ATTRIBUTE cacert3_trusted_certificate[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_CERTIFICATE_CATEGORY, &certificate_authority, sizeof (certificate_authority) }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_CHECK_VALUE, "\xad\x7c\x3f", 3 }, + { CKA_START_DATE, "20110523", 8 }, + { CKA_END_DATE, "20210520", 8, }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_ISSUER, (void *)test_cacert3_ca_issuer, sizeof (test_cacert3_ca_issuer) }, + { CKA_SERIAL_NUMBER, (void *)test_cacert3_ca_serial, sizeof (test_cacert3_ca_serial) }, + { CKA_TRUSTED, &truev, sizeof (truev) }, + { CKA_ID, "cacert3", 7 }, + { CKA_LABEL, "Custom Label", 12 }, + { CKA_INVALID }, + }; + + static unsigned char eku_server_and_client[] = { + 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, + }; + + CK_ATTRIBUTE eku_extension_server_and_client[] = { + { CKA_CLASS, &certificate_extension, sizeof (certificate_extension), }, + { CKA_OBJECT_ID, (void *)P11_OID_EXTENDED_KEY_USAGE, sizeof (P11_OID_EXTENDED_KEY_USAGE) }, + { CKA_LABEL, "Custom Label", 12 }, + { CKA_X_CRITICAL, &truev, sizeof (truev) }, + { CKA_VALUE, eku_server_and_client, sizeof (eku_server_and_client) }, + { CKA_ID, "cacert3", 7 }, + { CKA_INVALID }, + }; + + static char eku_client_email[] = { + 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x04, + }; + + static CK_ATTRIBUTE reject_extension_email[] = { + { CKA_CLASS, &certificate_extension, sizeof (certificate_extension), }, + { CKA_OBJECT_ID, (void *)P11_OID_OPENSSL_REJECT, sizeof (P11_OID_OPENSSL_REJECT) }, + { CKA_LABEL, "Custom Label", 12 }, + { CKA_X_CRITICAL, &falsev, sizeof (falsev) }, + { CKA_VALUE, eku_client_email, sizeof (eku_client_email) }, + { CKA_ID, "cacert3", 7 }, + { CKA_INVALID }, + }; + + static CK_ATTRIBUTE nss_trust_server_and_client_distrust_email[] = { + { CKA_CLASS, &nss_trust, sizeof (nss_trust), }, + { CKA_ID, "cacert3", 7 }, + { CKA_CERT_SHA1_HASH, "\xad\x7c\x3f\x64\xfc\x44\x39\xfe\xf4\xe9\x0b\xe8\xf4\x7c\x6c\xfa\x8a\xad\xfd\xce", 20 }, + { CKA_CERT_MD5_HASH, "\xf7\x25\x12\x82\x4e\x67\xb5\xd0\x8d\x92\xb7\x7c\x0b\x86\x7a\x42", 16 }, + { CKA_LABEL, "Custom Label", 12 }, + { CKA_ISSUER, (void *)test_cacert3_ca_issuer, sizeof (test_cacert3_ca_issuer) }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_SERIAL_NUMBER, (void *)test_cacert3_ca_serial, sizeof (test_cacert3_ca_serial) }, + { CKA_TRUST_SERVER_AUTH, &trusted_delegator, sizeof (trusted_delegator) }, + { CKA_TRUST_CLIENT_AUTH, &trusted_delegator, sizeof (trusted_delegator) }, + { CKA_TRUST_EMAIL_PROTECTION, ¬_trusted, sizeof (not_trusted) }, + { CKA_TRUST_CODE_SIGNING, &trust_unknown, sizeof (trust_unknown) }, + { CKA_TRUST_IPSEC_END_SYSTEM, &trust_unknown, sizeof (trust_unknown) }, + { CKA_TRUST_IPSEC_TUNNEL, &trust_unknown, sizeof (trust_unknown) }, + { CKA_TRUST_IPSEC_USER, &trust_unknown, sizeof (trust_unknown) }, + { CKA_TRUST_TIME_STAMPING, &trust_unknown, sizeof (trust_unknown) }, + { CKA_TRUST_DIGITAL_SIGNATURE, &trusted_delegator, sizeof (trusted_delegator) }, + { CKA_TRUST_NON_REPUDIATION, &trusted_delegator, sizeof (trusted_delegator) }, + { CKA_TRUST_KEY_ENCIPHERMENT, &trusted_delegator, sizeof (trusted_delegator) }, + { CKA_TRUST_DATA_ENCIPHERMENT, &trusted_delegator, sizeof (trusted_delegator) }, + { CKA_TRUST_KEY_AGREEMENT, &trusted_delegator, sizeof (trusted_delegator) }, + { CKA_TRUST_KEY_CERT_SIGN, &trusted_delegator, sizeof (trusted_delegator) }, + { CKA_TRUST_CRL_SIGN, &trusted_delegator, sizeof (trusted_delegator) }, + { CKA_INVALID, } + }; + + static CK_ATTRIBUTE server_anchor_assertion[] = { + { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, + { CKA_X_PURPOSE, (void *)P11_OID_SERVER_AUTH_STR, sizeof (P11_OID_SERVER_AUTH_STR) - 1 }, + { CKA_LABEL, "Custom Label", 12 }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_X_ASSERTION_TYPE, &anchored_certificate, sizeof (anchored_certificate) }, + { CKA_ID, "cacert3", 7 }, + { CKA_INVALID }, + }; + + static CK_ATTRIBUTE client_anchor_assertion[] = { + { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, + { CKA_X_PURPOSE, (void *)P11_OID_CLIENT_AUTH_STR, sizeof (P11_OID_CLIENT_AUTH_STR) - 1 }, + { CKA_LABEL, "Custom Label", 12 }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_X_ASSERTION_TYPE, &anchored_certificate, sizeof (anchored_certificate) }, + { CKA_ID, "cacert3", 7 }, + { CKA_INVALID }, + }; + + static CK_ATTRIBUTE email_distrust_assertion[] = { + { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, + { CKA_X_PURPOSE, (void *)P11_OID_EMAIL_PROTECTION_STR, sizeof (P11_OID_EMAIL_PROTECTION_STR) - 1 }, + { CKA_LABEL, "Custom Label", 12 }, + { CKA_ISSUER, (void *)test_cacert3_ca_issuer, sizeof (test_cacert3_ca_issuer) }, + { CKA_SERIAL_NUMBER, (void *)test_cacert3_ca_serial, sizeof (test_cacert3_ca_serial) }, + { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, + { CKA_ID, "cacert3", 7 }, + { CKA_INVALID }, + }; + + /* + * We should get an NSS trust object and various assertions here. + * The first two attributes of each object are enough to look it up, + * and then we check the rest of the attributes match. + */ + + CK_ATTRIBUTE *expected[] = { + nss_trust_server_and_client_distrust_email, + email_distrust_assertion, + server_anchor_assertion, + client_anchor_assertion, + NULL, + }; + + CK_OBJECT_HANDLE handle; + CK_ATTRIBUTE *attrs; + CK_RV rv; + int i; + + setup (cu); + + /* + * A trusted cetrificate, trusted for server and client purposes, + * and explicitly rejects the email and timestamping purposes. + */ + p11_index_batch (test.index); + rv = p11_index_take (test.index, p11_attrs_dup (cacert3_trusted_certificate), NULL); + CuAssertIntEquals (cu, CKR_OK, rv); + rv = p11_index_take (test.index, p11_attrs_dup (eku_extension_server_and_client), NULL); + CuAssertIntEquals (cu, CKR_OK, rv); + rv = p11_index_take (test.index, p11_attrs_dup (reject_extension_email), NULL); + CuAssertIntEquals (cu, CKR_OK, rv); + p11_index_finish (test.index); + + + /* The other objects */ + for (i = 0; expected[i]; i++) { + handle = p11_index_findn (test.index, expected[i], 2); + CuAssertTrue (cu, handle != 0); + + attrs = p11_index_lookup (test.index, handle); + CuAssertPtrNotNull (cu, attrs); + + test_check_attrs (cu, expected[i], attrs); + } + + teardown (cu); +} + +static void +test_changed_distrusted (CuTest *cu) +{ + CK_ATTRIBUTE distrust_cert[] = { + { CKA_CLASS, &certificate, sizeof (certificate), }, + { CKA_CERTIFICATE_CATEGORY, &certificate_authority, sizeof (certificate_authority) }, + { CKA_PRIVATE, &falsev, sizeof (falsev) }, + { CKA_MODIFIABLE, &falsev, sizeof (falsev) }, + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_TRUSTED, &falsev, sizeof (falsev) }, + { CKA_X_DISTRUSTED, &truev, sizeof (truev) }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_ID, "the id", 6 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE eku_extension[] = { + { CKA_CLASS, &certificate_extension, sizeof (certificate_extension), }, + { CKA_OBJECT_ID, (void *)P11_OID_EXTENDED_KEY_USAGE, sizeof (P11_OID_EXTENDED_KEY_USAGE) }, + { CKA_X_CRITICAL, &truev, sizeof (truev) }, + { CKA_VALUE, "\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x99\x77\x06\x0a\x10", 14 }, + { CKA_ID, "the id", 6 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE reject_extension[] = { + { CKA_CLASS, &certificate_extension, sizeof (certificate_extension), }, + { CKA_OBJECT_ID, (void *)P11_OID_OPENSSL_REJECT, sizeof (P11_OID_OPENSSL_REJECT) }, + { CKA_X_CRITICAL, &falsev, sizeof (falsev) }, + { CKA_VALUE, "\x30\x0a\x06\x08\x2b\x06\x01\x05\x05\x07\x03\x02", 12 }, + { CKA_ID, "the id", 6 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE nss_trust_nothing[] = { + { CKA_CLASS, &nss_trust, sizeof (nss_trust), }, + { CKA_ID, "the id", 6 }, + { CKA_CERT_SHA1_HASH, "\xad\x7c\x3f\x64\xfc\x44\x39\xfe\xf4\xe9\x0b\xe8\xf4\x7c\x6c\xfa\x8a\xad\xfd\xce", 20 }, + { CKA_CERT_MD5_HASH, "\xf7\x25\x12\x82\x4e\x67\xb5\xd0\x8d\x92\xb7\x7c\x0b\x86\x7a\x42", 16 }, + { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, + { CKA_ISSUER, (void *)test_cacert3_ca_issuer, sizeof (test_cacert3_ca_issuer) }, + { CKA_SERIAL_NUMBER, (void *)test_cacert3_ca_serial, sizeof (test_cacert3_ca_serial) }, + { CKA_TRUST_SERVER_AUTH, ¬_trusted, sizeof (not_trusted) }, + { CKA_TRUST_CLIENT_AUTH, ¬_trusted, sizeof (not_trusted) }, + { CKA_TRUST_EMAIL_PROTECTION, ¬_trusted, sizeof (not_trusted) }, + { CKA_TRUST_CODE_SIGNING, ¬_trusted, sizeof (not_trusted) }, + { CKA_TRUST_IPSEC_END_SYSTEM, ¬_trusted, sizeof (not_trusted) }, + { CKA_TRUST_IPSEC_TUNNEL, ¬_trusted, sizeof (not_trusted) }, + { CKA_TRUST_IPSEC_USER, ¬_trusted, sizeof (not_trusted) }, + { CKA_TRUST_TIME_STAMPING, ¬_trusted, sizeof (not_trusted) }, + { CKA_TRUST_DIGITAL_SIGNATURE, ¬_trusted, sizeof (not_trusted) }, + { CKA_TRUST_NON_REPUDIATION, ¬_trusted, sizeof (not_trusted) }, + { CKA_TRUST_KEY_ENCIPHERMENT, ¬_trusted, sizeof (not_trusted) }, + { CKA_TRUST_DATA_ENCIPHERMENT, ¬_trusted, sizeof (not_trusted) }, + { CKA_TRUST_KEY_AGREEMENT, ¬_trusted, sizeof (not_trusted) }, + { CKA_TRUST_KEY_CERT_SIGN, ¬_trusted, sizeof (not_trusted) }, + { CKA_TRUST_CRL_SIGN, ¬_trusted, sizeof (not_trusted) }, + { CKA_INVALID, } + }; + + CK_ATTRIBUTE server_distrust[] = { + { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, + { CKA_X_PURPOSE, (void *)P11_OID_SERVER_AUTH_STR, strlen (P11_OID_SERVER_AUTH_STR) }, + { CKA_ISSUER, (void *)test_cacert3_ca_issuer, sizeof (test_cacert3_ca_issuer) }, + { CKA_SERIAL_NUMBER, (void *)test_cacert3_ca_serial, sizeof (test_cacert3_ca_serial) }, + { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, + { CKA_ID, "the id", 6 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE client_distrust[] = { + { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, + { CKA_X_PURPOSE, (void *)P11_OID_CLIENT_AUTH_STR, strlen (P11_OID_CLIENT_AUTH_STR) }, + { CKA_ISSUER, (void *)test_cacert3_ca_issuer, sizeof (test_cacert3_ca_issuer) }, + { CKA_SERIAL_NUMBER, (void *)test_cacert3_ca_serial, sizeof (test_cacert3_ca_serial) }, + { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, + { CKA_ID, "the id", 6 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE code_distrust[] = { + { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, + { CKA_X_PURPOSE, (void *)P11_OID_CODE_SIGNING_STR, strlen (P11_OID_CODE_SIGNING_STR) }, + { CKA_ISSUER, (void *)test_cacert3_ca_issuer, sizeof (test_cacert3_ca_issuer) }, + { CKA_SERIAL_NUMBER, (void *)test_cacert3_ca_serial, sizeof (test_cacert3_ca_serial) }, + { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, + { CKA_ID, "the id", 6 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE email_distrust[] = { + { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, + { CKA_X_PURPOSE, (void *)P11_OID_EMAIL_PROTECTION_STR, strlen (P11_OID_EMAIL_PROTECTION_STR) }, + { CKA_ISSUER, (void *)test_cacert3_ca_issuer, sizeof (test_cacert3_ca_issuer) }, + { CKA_SERIAL_NUMBER, (void *)test_cacert3_ca_serial, sizeof (test_cacert3_ca_serial) }, + { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, + { CKA_ID, "the id", 6 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE ipsec_system_distrust[] = { + { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, + { CKA_X_PURPOSE, (void *)P11_OID_IPSEC_END_SYSTEM_STR, strlen (P11_OID_IPSEC_END_SYSTEM_STR) }, + { CKA_ISSUER, (void *)test_cacert3_ca_issuer, sizeof (test_cacert3_ca_issuer) }, + { CKA_SERIAL_NUMBER, (void *)test_cacert3_ca_serial, sizeof (test_cacert3_ca_serial) }, + { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, + { CKA_ID, "the id", 6 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE ipsec_tunnel_distrust[] = { + { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, + { CKA_X_PURPOSE, (void *)P11_OID_IPSEC_TUNNEL_STR, strlen (P11_OID_IPSEC_TUNNEL_STR) }, + { CKA_ISSUER, (void *)test_cacert3_ca_issuer, sizeof (test_cacert3_ca_issuer) }, + { CKA_SERIAL_NUMBER, (void *)test_cacert3_ca_serial, sizeof (test_cacert3_ca_serial) }, + { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, + { CKA_ID, "the id", 6 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE ipsec_user_distrust[] = { + { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, + { CKA_X_PURPOSE, (void *)P11_OID_IPSEC_USER_STR, strlen (P11_OID_IPSEC_USER_STR) }, + { CKA_ISSUER, (void *)test_cacert3_ca_issuer, sizeof (test_cacert3_ca_issuer) }, + { CKA_SERIAL_NUMBER, (void *)test_cacert3_ca_serial, sizeof (test_cacert3_ca_serial) }, + { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, + { CKA_ID, "the id", 6 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE stamping_distrust[] = { + { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, + { CKA_X_PURPOSE, (void *)P11_OID_TIME_STAMPING_STR, strlen (P11_OID_TIME_STAMPING_STR) }, + { CKA_ISSUER, (void *)test_cacert3_ca_issuer, sizeof (test_cacert3_ca_issuer) }, + { CKA_SERIAL_NUMBER, (void *)test_cacert3_ca_serial, sizeof (test_cacert3_ca_serial) }, + { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, + { CKA_ID, "the id", 6 }, + { CKA_INVALID }, + }; + + /* + * We should get an NSS trust object and various assertions here. + * The first two attributes of each object are enough to look it up, + * and then we check the rest of the attributes match. + */ + + CK_ATTRIBUTE *expected[] = { + nss_trust_nothing, + server_distrust, + client_distrust, + code_distrust, + email_distrust, + ipsec_system_distrust, + ipsec_tunnel_distrust, + ipsec_user_distrust, + stamping_distrust, + NULL + }; + + CK_OBJECT_HANDLE handle; + CK_ATTRIBUTE *attrs; + CK_RV rv; + int i; + + setup (cu); + + /* + * A trusted cetrificate, trusted for server and client purposes, + * and explicitly rejects the email and timestamping purposes. + */ + p11_index_batch (test.index); + rv = p11_index_take (test.index, p11_attrs_dup (distrust_cert), NULL); + CuAssertIntEquals (cu, CKR_OK, rv); + rv = p11_index_take (test.index, p11_attrs_dup (eku_extension), NULL); + CuAssertIntEquals (cu, CKR_OK, rv); + rv = p11_index_take (test.index, p11_attrs_dup (reject_extension), NULL); + CuAssertIntEquals (cu, CKR_OK, rv); + p11_index_finish (test.index); + + /* The other objects */ + for (i = 0; expected[i]; i++) { + handle = p11_index_findn (test.index, expected[i], 2); + CuAssertTrue (cu, handle != 0); + + attrs = p11_index_lookup (test.index, handle); + CuAssertPtrNotNull (cu, attrs); + + test_check_attrs (cu, expected[i], attrs); + } + + teardown (cu); +} + +static void +test_changed_dup_certificates (CuTest *cu) +{ + static CK_ATTRIBUTE trusted_cert[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_CERTIFICATE_CATEGORY, &certificate_authority, sizeof (certificate_authority) }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_TRUSTED, &truev, sizeof (truev) }, + { CKA_ID, "cacert3", 7 }, + { CKA_INVALID }, + }; + + static CK_ATTRIBUTE distrust_cert[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_CERTIFICATE_CATEGORY, &certificate_authority, sizeof (certificate_authority) }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_X_DISTRUSTED, &truev, sizeof (truev) }, + { CKA_ID, "cacert3", 7 }, + { CKA_INVALID }, + }; + + static CK_ATTRIBUTE trusted_nss[] = { + { CKA_CLASS, &nss_trust, sizeof (nss_trust), }, + { CKA_CERT_SHA1_HASH, "\xad\x7c\x3f\x64\xfc\x44\x39\xfe\xf4\xe9\x0b\xe8\xf4\x7c\x6c\xfa\x8a\xad\xfd\xce", 20 }, + { CKA_TRUST_SERVER_AUTH, &trusted_delegator, sizeof (trusted_delegator) }, + { CKA_ID, "cacert3", 7 }, + { CKA_INVALID, } + }; + + static CK_ATTRIBUTE distrust_nss[] = { + { CKA_CLASS, &nss_trust, sizeof (nss_trust), }, + { CKA_CERT_SHA1_HASH, "\xad\x7c\x3f\x64\xfc\x44\x39\xfe\xf4\xe9\x0b\xe8\xf4\x7c\x6c\xfa\x8a\xad\xfd\xce", 20 }, + { CKA_TRUST_SERVER_AUTH, ¬_trusted, sizeof (not_trusted) }, + { CKA_ID, "cacert3", 7 }, + { CKA_INVALID, } + }; + + static CK_ATTRIBUTE match_nss[] = { + { CKA_CLASS, &nss_trust, sizeof (nss_trust), }, + { CKA_ID, "cacert3", 7 }, + { CKA_INVALID, } + }; + + static CK_ATTRIBUTE anchor_assertion[] = { + { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, + { CKA_X_PURPOSE, (void *)P11_OID_SERVER_AUTH_STR, sizeof (P11_OID_SERVER_AUTH_STR) - 1 }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_X_ASSERTION_TYPE, &anchored_certificate, sizeof (anchored_certificate) }, + { CKA_ID, "cacert3", 7 }, + { CKA_INVALID }, + }; + + static CK_ATTRIBUTE distrust_assertion[] = { + { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, + { CKA_X_PURPOSE, (void *)P11_OID_SERVER_AUTH_STR, sizeof (P11_OID_SERVER_AUTH_STR) - 1 }, + { CKA_ISSUER, (void *)test_cacert3_ca_issuer, sizeof (test_cacert3_ca_issuer) }, + { CKA_SERIAL_NUMBER, (void *)test_cacert3_ca_serial, sizeof (test_cacert3_ca_serial) }, + { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, + { CKA_ID, "cacert3", 7 }, + { CKA_INVALID }, + }; + + static CK_ATTRIBUTE match_assertion[] = { + { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, + { CKA_ID, "cacert3", 7 }, + { CKA_INVALID, } + }; + + CK_OBJECT_HANDLE handle1; + CK_OBJECT_HANDLE handle2; + CK_OBJECT_HANDLE handle; + CK_RV rv; + + setup (cu); + + /* + * A trusted certificate, should create trutsed nss trust + * and anchor assertions + */ + p11_index_batch (test.index); + rv = p11_index_take (test.index, p11_attrs_dup (trusted_cert), &handle1); + CuAssertIntEquals (cu, CKR_OK, rv); + p11_index_finish (test.index); + + handle = p11_index_find (test.index, match_nss); + CuAssertTrue (cu, handle != 0); + handle = p11_index_find (test.index, match_assertion); + CuAssertTrue (cu, handle != 0); + handle = p11_index_find (test.index, trusted_nss); + CuAssertTrue (cu, handle != 0); + handle = p11_index_find (test.index, anchor_assertion); + CuAssertTrue (cu, handle != 0); + + /* Now we add a distrusted certificate, should update the objects */ + p11_index_batch (test.index); + rv = p11_index_take (test.index, p11_attrs_dup (distrust_cert), &handle2); + CuAssertIntEquals (cu, CKR_OK, rv); + p11_index_finish (test.index); + + handle = p11_index_find (test.index, trusted_nss); + CuAssertTrue (cu, handle == 0); + handle = p11_index_find (test.index, distrust_nss); + CuAssertTrue (cu, handle != 0); + handle = p11_index_find (test.index, anchor_assertion); + CuAssertTrue (cu, handle == 0); + handle = p11_index_find (test.index, distrust_assertion); + CuAssertTrue (cu, handle != 0); + + /* Now remove the trusted cetrificate, should update again */ + rv = p11_index_remove (test.index, handle2); + CuAssertIntEquals (cu, CKR_OK, rv); + + handle = p11_index_find (test.index, trusted_nss); + CuAssertTrue (cu, handle != 0); + handle = p11_index_find (test.index, distrust_nss); + CuAssertTrue (cu, handle == 0); + handle = p11_index_find (test.index, anchor_assertion); + CuAssertTrue (cu, handle != 0); + handle = p11_index_find (test.index, distrust_assertion); + CuAssertTrue (cu, handle == 0); + + /* Now remove the original certificate, no more nss/assertions */ + rv = p11_index_remove (test.index, handle1); + CuAssertIntEquals (cu, CKR_OK, rv); + + handle = p11_index_find (test.index, match_nss); + CuAssertTrue (cu, handle == 0); + handle = p11_index_find (test.index, match_assertion); + CuAssertTrue (cu, handle == 0); + + teardown (cu); +} + +static void +test_changed_without_id (CuTest *cu) +{ + static CK_ATTRIBUTE trusted_without_id[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_CERTIFICATE_CATEGORY, &certificate_authority, sizeof (certificate_authority) }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_TRUSTED, &truev, sizeof (truev) }, + { CKA_INVALID }, + }; + + CK_OBJECT_CLASS klass = 0; + CK_ATTRIBUTE match[] = { + { CKA_CLASS, &klass, sizeof (klass) }, + { CKA_INVALID }, + }; + + /* + * A cetrificate without a CKA_ID that's created should not + * automatically create any compat objects. + */ + + CK_OBJECT_HANDLE handle; + CK_RV rv; + + setup (cu); + + p11_index_batch (test.index); + rv = p11_index_take (test.index, p11_attrs_dup (trusted_without_id), NULL); + CuAssertIntEquals (cu, CKR_OK, rv); + p11_index_finish (test.index); + + klass = CKO_NSS_TRUST; + handle = p11_index_find (test.index, match); + CuAssertIntEquals (cu, 0, handle); + + klass = CKO_X_TRUST_ASSERTION; + handle = p11_index_find (test.index, match); + CuAssertIntEquals (cu, 0, handle); + + teardown (cu); +} + +static void +test_changed_staple_ca (CuTest *cu) +{ + CK_ULONG category = 0; + + CK_ATTRIBUTE stapled[] = { + { CKA_CLASS, &certificate_extension, sizeof (certificate_extension) }, + { CKA_OBJECT_ID, (void *)P11_OID_BASIC_CONSTRAINTS, sizeof (P11_OID_BASIC_CONSTRAINTS) }, + { CKA_VALUE, "\x30\x03\x01\x01\xFF", 5 }, + { CKA_ID, "the id", 6 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_VALUE, (void *)entrust_pretend_ca, sizeof (entrust_pretend_ca) }, + { CKA_ID, "the id", 6 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE match[] = { + { CKA_VALUE, (void *)entrust_pretend_ca, sizeof (entrust_pretend_ca) }, + { CKA_CERTIFICATE_CATEGORY, &category, sizeof (category) }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + attrs = NULL; + rv = p11_index_take (test.index, p11_attrs_dup (input), NULL); + CuAssertIntEquals (cu, CKR_OK, rv); + + /* Not a CA at this point, until we staple */ + category = 0; + CuAssertTrue (cu, p11_index_find (test.index, match) == 0); + + /* Add a stapled basic constraint */ + rv = p11_index_add (test.index, stapled, 4, NULL); + CuAssertIntEquals (cu, CKR_OK, rv); + + /* Now should be a CA */ + category = 2; + CuAssertTrue (cu, p11_index_find (test.index, match) != 0); + + p11_attrs_free (attrs); + + teardown (cu); +} + +static void +test_changed_staple_ku (CuTest *cu) +{ + CK_ATTRIBUTE stapled_ds_and_np[] = { + { CKA_CLASS, &certificate_extension, sizeof (certificate_extension) }, + { CKA_OBJECT_ID, (void *)P11_OID_KEY_USAGE, sizeof (P11_OID_KEY_USAGE) }, + { CKA_VALUE, "\x03\x03\x07\xc0\x00", 5 }, + { CKA_ID, "the id", 6 }, + { CKA_INVALID }, + }; + + CK_ATTRIBUTE input[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_VALUE, (void *)entrust_pretend_ca, sizeof (entrust_pretend_ca) }, + { CKA_TRUSTED, &truev, sizeof (truev) }, + { CKA_ID, "the id", 6 }, + { CKA_INVALID }, + }; + + static CK_ATTRIBUTE nss_trust_ds_and_np[] = { + { CKA_CLASS, &nss_trust, sizeof (nss_trust), }, + { CKA_ID, "the id", 6 }, + { CKA_TRUST_SERVER_AUTH, &trusted, sizeof (trusted) }, + { CKA_TRUST_CLIENT_AUTH, &trusted, sizeof (trusted) }, + { CKA_TRUST_EMAIL_PROTECTION, &trusted, sizeof (trusted) }, + { CKA_TRUST_CODE_SIGNING, &trusted, sizeof (trusted) }, + { CKA_TRUST_IPSEC_END_SYSTEM, &trusted, sizeof (trusted) }, + { CKA_TRUST_IPSEC_TUNNEL, &trusted, sizeof (trusted) }, + { CKA_TRUST_IPSEC_USER, &trusted, sizeof (trusted) }, + { CKA_TRUST_TIME_STAMPING, &trusted, sizeof (trusted) }, + { CKA_TRUST_DIGITAL_SIGNATURE, &trusted, sizeof (trusted) }, + { CKA_TRUST_NON_REPUDIATION, &trusted, sizeof (trusted) }, + { CKA_TRUST_KEY_ENCIPHERMENT, &trust_unknown, sizeof (trust_unknown) }, + { CKA_TRUST_DATA_ENCIPHERMENT, &trust_unknown, sizeof (trust_unknown) }, + { CKA_TRUST_KEY_AGREEMENT, &trust_unknown, sizeof (trust_unknown) }, + { CKA_TRUST_KEY_CERT_SIGN, &trust_unknown, sizeof (trust_unknown) }, + { CKA_TRUST_CRL_SIGN, &trust_unknown, sizeof (trust_unknown) }, + { CKA_INVALID, } + }; + + CK_OBJECT_HANDLE handle; + CK_ATTRIBUTE *attrs; + CK_RV rv; + + setup (cu); + + p11_index_batch (test.index); + rv = p11_index_take (test.index, p11_attrs_dup (input), NULL); + CuAssertIntEquals (cu, CKR_OK, rv); + rv = p11_index_take (test.index, p11_attrs_dup (stapled_ds_and_np), NULL); + CuAssertIntEquals (cu, CKR_OK, rv); + p11_index_finish (test.index); + + handle = p11_index_findn (test.index, nss_trust_ds_and_np, 2); + CuAssertTrue (cu, handle != 0); + + attrs = p11_index_lookup (test.index, handle); + test_check_attrs (cu, nss_trust_ds_and_np, attrs); + + teardown (cu); +} + +int +main (void) +{ + CuString *output = CuStringNew (); + CuSuite* suite = CuSuiteNew (); + int ret; + + putenv ("P11_KIT_STRICT=1"); + p11_library_init (); + p11_debug_init (); + /* p11_message_quiet (); */ + + SUITE_ADD_TEST (suite, test_get_cache); + SUITE_ADD_TEST (suite, test_build_data); + SUITE_ADD_TEST (suite, test_build_certificate); + SUITE_ADD_TEST (suite, test_build_certificate_empty); + SUITE_ADD_TEST (suite, test_build_certificate_non_ca); + SUITE_ADD_TEST (suite, test_build_certificate_v1_ca); + SUITE_ADD_TEST (suite, test_build_certificate_staple_ca); + SUITE_ADD_TEST (suite, test_build_certificate_no_type); + SUITE_ADD_TEST (suite, test_build_certificate_bad_type); + SUITE_ADD_TEST (suite, test_build_extension); + SUITE_ADD_TEST (suite, test_create_not_settable); + SUITE_ADD_TEST (suite, test_create_but_loadable); + SUITE_ADD_TEST (suite, test_create_unsupported); + SUITE_ADD_TEST (suite, test_create_generated); + SUITE_ADD_TEST (suite, test_create_bad_attribute); + SUITE_ADD_TEST (suite, test_create_missing_attribute); + SUITE_ADD_TEST (suite, test_create_no_class); + SUITE_ADD_TEST (suite, test_create_token_mismatch); + SUITE_ADD_TEST (suite, test_modify_success); + SUITE_ADD_TEST (suite, test_modify_read_only); + SUITE_ADD_TEST (suite, test_modify_unchanged); + SUITE_ADD_TEST (suite, test_modify_not_modifiable); + + SUITE_ADD_TEST (suite, test_changed_trusted_certificate); + SUITE_ADD_TEST (suite, test_changed_distrusted); + SUITE_ADD_TEST (suite, test_changed_without_id); + SUITE_ADD_TEST (suite, test_changed_staple_ca); + SUITE_ADD_TEST (suite, test_changed_staple_ku); + SUITE_ADD_TEST (suite, test_changed_dup_certificates); + + CuSuiteRun (suite); + CuSuiteSummary (suite, output); + CuSuiteDetails (suite, output); + printf ("%s\n", output->buffer); + ret = suite->failCount; + CuSuiteDelete (suite); + CuStringDelete (output); + + return ret; +} diff --git a/trust/tests/test-data.c b/trust/tests/test-data.c index f159926..0ddc4c6 100644 --- a/trust/tests/test-data.c +++ b/trust/tests/test-data.c @@ -51,11 +51,9 @@ test_check_object_msg (CuTest *cu, CK_OBJECT_CLASS klass, const char *label) { - CK_BBOOL vtrue = CK_TRUE; CK_BBOOL vfalse = CK_FALSE; CK_ATTRIBUTE expected[] = { - { CKA_TOKEN, &vtrue, sizeof (vtrue) }, { CKA_PRIVATE, &vfalse, sizeof (vfalse) }, { CKA_MODIFIABLE, &vfalse, sizeof (vfalse) }, { CKA_CLASS, &klass, sizeof (klass) }, diff --git a/trust/tests/test-module.c b/trust/tests/test-module.c index ddc31df..9c633f0 100644 --- a/trust/tests/test-module.c +++ b/trust/tests/test-module.c @@ -59,6 +59,8 @@ */ #define NUM_SLOTS 3 +static CK_OBJECT_CLASS data = CKO_DATA; + struct { CK_FUNCTION_LIST *module; CK_SLOT_ID slots[NUM_SLOTS]; @@ -357,7 +359,7 @@ check_trust_object_equiv (CuTest *cu, }; rv = test.module->C_GetAttributeValue (session, trust, equiv, 6); - CuAssertTrue (cu, rv == CKR_OK); + CuAssertIntEquals (cu, CKR_OK, rv); test_check_attrs (cu, equiv, cert); } @@ -551,6 +553,7 @@ static void test_session_object (CuTest *cu) { CK_ATTRIBUTE original[] = { + { CKA_CLASS, &data, sizeof (data) }, { CKA_LABEL, "yay", 3 }, { CKA_VALUE, "eight", 5 }, { CKA_INVALID } @@ -579,6 +582,7 @@ static void test_session_find (CuTest *cu) { CK_ATTRIBUTE original[] = { + { CKA_CLASS, &data, sizeof (data) }, { CKA_LABEL, "yay", 3 }, { CKA_VALUE, "eight", 5 }, { CKA_INVALID } @@ -593,21 +597,21 @@ test_session_find (CuTest *cu) setup (cu); rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION, NULL, NULL, &session); - CuAssertTrue (cu, rv == CKR_OK); + CuAssertIntEquals (cu, CKR_OK, rv); rv = test.module->C_CreateObject (session, original, 2, &handle); - CuAssertTrue (cu, rv == CKR_OK); + CuAssertIntEquals (cu, CKR_OK, rv); rv = test.module->C_FindObjectsInit (session, original, 2); - CuAssertTrue (cu, rv == CKR_OK); + CuAssertIntEquals (cu, CKR_OK, rv); rv = test.module->C_FindObjects (session, &check, 1, &count); - CuAssertTrue (cu, rv == CKR_OK); + CuAssertIntEquals (cu, CKR_OK, rv); CuAssertIntEquals (cu, 1, count); CuAssertIntEquals (cu, handle, check); rv = test.module->C_FindObjectsFinal (session); - CuAssertTrue (cu, rv == CKR_OK); + CuAssertIntEquals (cu, CKR_OK, rv); teardown (cu); } @@ -660,6 +664,7 @@ static void test_setattr_token (CuTest *cu) { CK_ATTRIBUTE original[] = { + { CKA_CLASS, &data, sizeof (data) }, { CKA_LABEL, "yay", 3 }, { CKA_VALUE, "eight", 5 }, { CKA_INVALID } @@ -692,6 +697,7 @@ static void test_session_copy (CuTest *cu) { CK_ATTRIBUTE original[] = { + { CKA_CLASS, &data, sizeof (data) }, { CKA_LABEL, "yay", 3 }, { CKA_VALUE, "eight", 5 }, { CKA_INVALID } @@ -706,16 +712,16 @@ test_session_copy (CuTest *cu) setup (cu); rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION, NULL, NULL, &session); - CuAssertTrue (cu, rv == CKR_OK); + CuAssertIntEquals (cu, CKR_OK, rv); rv = test.module->C_CreateObject (session, original, 2, &handle); - CuAssertTrue (cu, rv == CKR_OK); + CuAssertIntEquals (cu, CKR_OK, rv); rv = test.module->C_CopyObject (session, handle, original, 2, ©); - CuAssertTrue (cu, rv == CKR_OK); + CuAssertIntEquals (cu, CKR_OK, rv); rv = test.module->C_GetObjectSize (session, copy, &size); - CuAssertTrue (cu, rv == CKR_OK); + CuAssertIntEquals (cu, CKR_OK, rv); teardown (cu); } @@ -724,6 +730,7 @@ static void test_session_setattr (CuTest *cu) { CK_ATTRIBUTE original[] = { + { CKA_CLASS, &data, sizeof (data) }, { CKA_LABEL, "yay", 3 }, { CKA_VALUE, "eight", 5 }, { CKA_INVALID } @@ -751,6 +758,7 @@ static void test_session_remove (CuTest *cu) { CK_ATTRIBUTE original[] = { + { CKA_CLASS, &data, sizeof (data) }, { CKA_LABEL, "yay", 3 }, { CKA_VALUE, "eight", 5 }, { CKA_INVALID } diff --git a/trust/tests/test-parser.c b/trust/tests/test-parser.c index 0f40748..3ad89da 100644 --- a/trust/tests/test-parser.c +++ b/trust/tests/test-parser.c @@ -41,6 +41,7 @@ #include "array.h" #include "attrs.h" +#include "builder.h" #include "debug.h" #include "library.h" #include "oid.h" @@ -50,69 +51,75 @@ struct { p11_parser *parser; - p11_array *objects; + p11_asn1_cache *cache; + p11_index *index; } test; static void setup (CuTest *cu) { - test.parser = p11_parser_new (); + test.index = p11_index_new (NULL, NULL, NULL); + test.cache = p11_asn1_cache_new (); + test.parser = p11_parser_new (test.index, test.cache); CuAssertPtrNotNull (cu, test.parser); - - test.objects = p11_array_new (p11_attrs_free); - CuAssertPtrNotNull (cu, test.objects); } static void teardown (CuTest *cu) { p11_parser_free (test.parser); - p11_array_free (test.objects); + p11_index_free (test.index); + p11_asn1_cache_free (test.cache); memset (&test, 0, sizeof (test)); } -static void -on_parse_object (CK_ATTRIBUTE *attrs, - void *data) -{ - CuTest *cu = data; +static CK_OBJECT_CLASS certificate = CKO_CERTIFICATE; +static CK_OBJECT_CLASS certificate_extension = CKO_X_CERTIFICATE_EXTENSION; +static CK_BBOOL falsev = CK_FALSE; +static CK_BBOOL truev = CK_TRUE; +static CK_CERTIFICATE_TYPE x509 = CKC_X_509; - CuAssertPtrNotNull (cu, attrs); - CuAssertTrue (cu, p11_attrs_count (attrs) > 0); +static CK_ATTRIBUTE certificate_match[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_INVALID, }, +}; + +static CK_ATTRIBUTE * +parsed_attrs (CK_ATTRIBUTE *match) +{ + CK_OBJECT_HANDLE handle; + handle = p11_index_find (test.index, certificate_match); + return p11_index_lookup (test.index, handle); - p11_array_push (test.objects, attrs); } static void test_parse_der_certificate (CuTest *cu) { CK_ATTRIBUTE *cert; - CK_ATTRIBUTE *object; - CK_BBOOL bval; int ret; + CK_ATTRIBUTE expected[] = { + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_MODIFIABLE, &falsev, sizeof (falsev) }, + { CKA_TRUSTED, &falsev, sizeof (falsev) }, + { CKA_X_DISTRUSTED, &falsev, sizeof (falsev) }, + { CKA_INVALID }, + }; + setup (cu); ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der", - 0, on_parse_object, cu); + P11_PARSE_FLAG_NONE); CuAssertIntEquals (cu, P11_PARSE_SUCCESS, ret); - /* Should have gotten certificate and a trust object */ - CuAssertIntEquals (cu, 2, test.objects->num); - - cert = test.objects->elem[0]; - test_check_cacert3_ca (cu, cert, NULL); - - if (!p11_attrs_find_bool (cert, CKA_TRUSTED, &bval)) - CuFail (cu, "missing CKA_TRUSTED"); - CuAssertIntEquals (cu, CK_FALSE, bval); + /* Should have gotten certificate */ + CuAssertIntEquals (cu, 1, p11_index_size (test.index)); - if (!p11_attrs_find_bool (cert, CKA_X_DISTRUSTED, &bval)) - CuFail (cu, "missing CKA_X_DISTRUSTED"); - CuAssertIntEquals (cu, CK_FALSE, bval); - - object = test.objects->elem[1]; - test_check_id (cu, cert, object); + cert = parsed_attrs (certificate_match); + test_check_attrs (cu, expected, cert); teardown (cu); } @@ -121,32 +128,29 @@ static void test_parse_pem_certificate (CuTest *cu) { CK_ATTRIBUTE *cert; - CK_ATTRIBUTE *object; - CK_BBOOL bval; int ret; + CK_ATTRIBUTE expected[] = { + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_MODIFIABLE, &falsev, sizeof (falsev) }, + { CKA_TRUSTED, &falsev, sizeof (falsev) }, + { CKA_X_DISTRUSTED, &falsev, sizeof (falsev) }, + { CKA_INVALID }, + }; + setup (cu); ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.pem", - 0, on_parse_object, cu); + P11_PARSE_FLAG_NONE); CuAssertIntEquals (cu, P11_PARSE_SUCCESS, ret); - /* Should have gotten certificate and a trust object */ - CuAssertIntEquals (cu, 2, test.objects->num); + /* Should have gotten certificate */ + CuAssertIntEquals (cu, 1, p11_index_size (test.index)); - cert = test.objects->elem[0]; - test_check_cacert3_ca (cu, cert, NULL); - - if (!p11_attrs_find_bool (cert, CKA_TRUSTED, &bval)) - CuFail (cu, "missing CKA_TRUSTED"); - CuAssertIntEquals (cu, CK_FALSE, bval); - - if (!p11_attrs_find_bool (cert, CKA_X_DISTRUSTED, &bval)) - CuFail (cu, "missing CKA_X_DISTRUSTED"); - CuAssertIntEquals (cu, CK_FALSE, bval); - - object = test.objects->elem[1]; - test_check_id (cu, cert, object); + cert = parsed_attrs (certificate_match); + test_check_attrs (cu, expected, cert); teardown (cu); } @@ -154,136 +158,71 @@ test_parse_pem_certificate (CuTest *cu) static void test_parse_openssl_trusted (CuTest *cu) { - CK_TRUST trusted = CKT_NSS_TRUSTED_DELEGATOR; - CK_TRUST distrusted = CKT_NSS_NOT_TRUSTED; - CK_TRUST unknown = CKT_NSS_TRUST_UNKNOWN; - CK_OBJECT_CLASS certificate_extension = CKO_X_CERTIFICATE_EXTENSION; - CK_OBJECT_CLASS trust_object = CKO_NSS_TRUST; - CK_OBJECT_CLASS trust_assertion = CKO_X_TRUST_ASSERTION; - CK_X_ASSERTION_TYPE anchored_certificate = CKT_X_ANCHORED_CERTIFICATE; - CK_X_ASSERTION_TYPE distrusted_certificate = CKT_X_DISTRUSTED_CERTIFICATE; - CK_BBOOL vtrue = CK_TRUE; - CK_BBOOL vfalse = CK_FALSE; + CK_ATTRIBUTE cacert3[] = { + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_CLASS, &certificate, sizeof (certificate) }, + { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, + { CKA_MODIFIABLE, &falsev, sizeof (falsev) }, + { CKA_TRUSTED, &truev, sizeof (truev) }, + { CKA_X_DISTRUSTED, &falsev, sizeof (falsev) }, + { CKA_INVALID }, + }; CK_ATTRIBUTE eku_extension[] = { - { CKA_LABEL, "Custom Label", 12 }, { CKA_CLASS, &certificate_extension, sizeof (certificate_extension), }, { CKA_OBJECT_ID, (void *)P11_OID_EXTENDED_KEY_USAGE, sizeof (P11_OID_EXTENDED_KEY_USAGE) }, - { CKA_X_CRITICAL, &vtrue, sizeof (vtrue) }, + { CKA_X_CRITICAL, &truev, sizeof (truev) }, { CKA_VALUE, "\x30\x14\x06\x08\x2b\x06\x01\x05\x05\x07\x03\x01\x06\x08\x2b\x06" "\x01\x05\x05\x07\x03\x02", 22 }, { CKA_INVALID }, }; CK_ATTRIBUTE reject_extension[] = { - { CKA_LABEL, "Custom Label", 12 }, { CKA_CLASS, &certificate_extension, sizeof (certificate_extension), }, { CKA_OBJECT_ID, (void *)P11_OID_OPENSSL_REJECT, sizeof (P11_OID_OPENSSL_REJECT) }, - { CKA_X_CRITICAL, &vfalse, sizeof (vfalse) }, + { CKA_X_CRITICAL, &falsev, sizeof (falsev) }, { CKA_VALUE, "\x30\x0a\x06\x08\x2b\x06\x01\x05\x05\x07\x03\x04", 12 }, { CKA_INVALID }, }; - CK_ATTRIBUTE nss_trust[] = { - { CKA_LABEL, "Custom Label", 12 }, - { CKA_CLASS, &trust_object, sizeof (trust_object), }, - { CKA_CERT_SHA1_HASH, "\xad\x7c\x3f\x64\xfc\x44\x39\xfe\xf4\xe9\x0b\xe8\xf4\x7c\x6c\xfa\x8a\xad\xfd\xce", 20 }, - { CKA_CERT_MD5_HASH, "\xf7\x25\x12\x82\x4e\x67\xb5\xd0\x8d\x92\xb7\x7c\x0b\x86\x7a\x42", 16 }, - { CKA_ISSUER, (void *)test_cacert3_ca_issuer, sizeof (test_cacert3_ca_issuer) }, - { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, - { CKA_SERIAL_NUMBER, (void *)test_cacert3_ca_serial, sizeof (test_cacert3_ca_serial) }, - { CKA_TRUST_SERVER_AUTH, &trusted, sizeof (trusted) }, - { CKA_TRUST_CLIENT_AUTH, &trusted, sizeof (trusted) }, - { CKA_TRUST_EMAIL_PROTECTION, &distrusted, sizeof (distrusted) }, - { CKA_TRUST_CODE_SIGNING, &unknown, sizeof (unknown) }, - { CKA_TRUST_IPSEC_END_SYSTEM, &unknown, sizeof (unknown) }, - { CKA_TRUST_IPSEC_TUNNEL, &unknown, sizeof (unknown) }, - { CKA_TRUST_IPSEC_USER, &unknown, sizeof (unknown) }, - { CKA_TRUST_TIME_STAMPING, &unknown, sizeof (unknown) }, - { CKA_TRUST_DIGITAL_SIGNATURE, &trusted, sizeof (trusted) }, - { CKA_TRUST_NON_REPUDIATION, &trusted, sizeof (trusted) }, - { CKA_TRUST_KEY_ENCIPHERMENT, &trusted, sizeof (trusted) }, - { CKA_TRUST_DATA_ENCIPHERMENT, &trusted, sizeof (trusted) }, - { CKA_TRUST_KEY_AGREEMENT, &trusted, sizeof (trusted) }, - { CKA_TRUST_KEY_CERT_SIGN, &trusted, sizeof (trusted) }, - { CKA_TRUST_CRL_SIGN, &trusted, sizeof (trusted) }, - { CKA_INVALID, } - }; - - CK_ATTRIBUTE server_anchor[] = { - { CKA_LABEL, "Custom Label", 12 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, - { CKA_X_ASSERTION_TYPE, &anchored_certificate, sizeof (anchored_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_SERVER_AUTH_STR, strlen (P11_OID_SERVER_AUTH_STR) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE client_anchor[] = { - { CKA_LABEL, "Custom Label", 12 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, - { CKA_X_ASSERTION_TYPE, &anchored_certificate, sizeof (anchored_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_CLIENT_AUTH_STR, strlen (P11_OID_CLIENT_AUTH_STR) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE email_distrust[] = { - { CKA_LABEL, "Custom Label", 12 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_ISSUER, (void *)test_cacert3_ca_issuer, sizeof (test_cacert3_ca_issuer) }, - { CKA_SERIAL_NUMBER, (void *)test_cacert3_ca_serial, sizeof (test_cacert3_ca_serial) }, - { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_EMAIL_PROTECTION_STR, strlen (P11_OID_EMAIL_PROTECTION_STR) }, - { CKA_INVALID }, - }; - CK_ATTRIBUTE *expected[] = { - NULL, + cacert3, eku_extension, reject_extension, - nss_trust, - email_distrust, - server_anchor, - client_anchor + NULL }; CK_ATTRIBUTE *cert; CK_ATTRIBUTE *object; - CK_BBOOL bval; + CK_OBJECT_HANDLE handle; int ret; int i; setup (cu); ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3-trusted.pem", - P11_PARSE_FLAG_ANCHOR, on_parse_object, cu); + P11_PARSE_FLAG_ANCHOR); CuAssertIntEquals (cu, P11_PARSE_SUCCESS, ret); /* * Should have gotten: * - 1 certificate * - 2 stapled extensions - * - 1 trust object - * - 3 trust assertions */ - CuAssertIntEquals (cu, 7, test.objects->num); + CuAssertIntEquals (cu, 3, p11_index_size (test.index)); /* The certificate */ - cert = test.objects->elem[0]; - test_check_cacert3_ca (cu, cert, NULL); + cert = parsed_attrs (certificate_match); + test_check_attrs (cu, expected[0], cert); - if (!p11_attrs_find_bool (cert, CKA_TRUSTED, &bval)) - CuFail (cu, "missing CKA_TRUSTED"); - CuAssertIntEquals (cu, CK_TRUE, bval); + /* The other objects */ + for (i = 1; expected[i]; i++) { + handle = p11_index_findn (test.index, expected[i], 2); + CuAssertTrue (cu, handle != 0); - if (!p11_attrs_find_bool (cert, CKA_X_DISTRUSTED, &bval)) - CuFail (cu, "missing CKA_X_DISTRUSTED"); - CuAssertIntEquals (cu, CK_FALSE, bval); + object = p11_index_lookup (test.index, handle); + CuAssertPtrNotNull (cu, object); - /* The other objects */ - for (i = 1; i < 7; i++) { - object = test.objects->elem[i]; test_check_attrs (cu, expected[i], object); test_check_id (cu, cert, object); } @@ -294,191 +233,41 @@ test_parse_openssl_trusted (CuTest *cu) static void test_parse_openssl_distrusted (CuTest *cu) { - CK_TRUST distrusted = CKT_NSS_NOT_TRUSTED; - CK_OBJECT_CLASS certificate_extension = CKO_X_CERTIFICATE_EXTENSION; - CK_OBJECT_CLASS trust_object = CKO_NSS_TRUST; - CK_OBJECT_CLASS klass = CKO_CERTIFICATE; - CK_OBJECT_CLASS trust_assertion = CKO_X_TRUST_ASSERTION; - CK_X_ASSERTION_TYPE distrusted_certificate = CKT_X_DISTRUSTED_CERTIFICATE; - CK_CERTIFICATE_TYPE x509 = CKC_X_509; - CK_ULONG category = 2; /* authority */ - CK_BBOOL vtrue = CK_TRUE; - CK_BBOOL vfalse = CK_FALSE; - - CK_ATTRIBUTE certificate[] = { - { CKA_CLASS, &klass, sizeof (klass), }, - { CKA_TOKEN, &vtrue, sizeof (vtrue) }, - { CKA_PRIVATE, &vfalse, sizeof (vfalse) }, - { CKA_MODIFIABLE, &vfalse, sizeof (vfalse) }, - { CKA_CLASS, &klass, sizeof (klass) }, - { CKA_LABEL, "Red Hat Is the CA", 17 }, + CK_ATTRIBUTE distrust_cert[] = { + { CKA_CLASS, &certificate, sizeof (certificate), }, + { CKA_MODIFIABLE, &falsev, sizeof (falsev) }, { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, - { CKA_CERTIFICATE_CATEGORY, &category, sizeof (category) }, - { CKA_CHECK_VALUE, "\xe9z}", 3 }, - { CKA_START_DATE, "20090916", 8 }, - { CKA_END_DATE, "20190914", 8, }, - { CKA_SERIAL_NUMBER, "\x02\x01\x01", 3 }, - { CKA_TRUSTED, &vfalse, sizeof (vfalse) }, - { CKA_X_DISTRUSTED, &vtrue, sizeof (vtrue) }, + { CKA_TRUSTED, &falsev, sizeof (falsev) }, + { CKA_X_DISTRUSTED, &truev, sizeof (truev) }, { CKA_INVALID }, }; CK_ATTRIBUTE eku_extension[] = { - { CKA_LABEL, "Red Hat Is the CA", 17 }, { CKA_CLASS, &certificate_extension, sizeof (certificate_extension), }, { CKA_OBJECT_ID, (void *)P11_OID_EXTENDED_KEY_USAGE, sizeof (P11_OID_EXTENDED_KEY_USAGE) }, - { CKA_X_CRITICAL, &vtrue, sizeof (vtrue) }, + { CKA_X_CRITICAL, &truev, sizeof (truev) }, { CKA_VALUE, "\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x99\x77\x06\x0a\x10", 14 }, { CKA_INVALID }, }; CK_ATTRIBUTE reject_extension[] = { - { CKA_LABEL, "Red Hat Is the CA", 17 }, { CKA_CLASS, &certificate_extension, sizeof (certificate_extension), }, { CKA_OBJECT_ID, (void *)P11_OID_OPENSSL_REJECT, sizeof (P11_OID_OPENSSL_REJECT) }, - { CKA_X_CRITICAL, &vfalse, sizeof (vfalse) }, + { CKA_X_CRITICAL, &falsev, sizeof (falsev) }, { CKA_VALUE, "\x30\x0a\x06\x08\x2b\x06\x01\x05\x05\x07\x03\x02", 12 }, { CKA_INVALID }, }; - CK_ATTRIBUTE nss_trust[] = { - { CKA_LABEL, "Red Hat Is the CA", 17 }, - { CKA_CLASS, &trust_object, sizeof (trust_object), }, - { CKA_CERT_SHA1_HASH, "\xe9z}\xe3\x82""7\xa0U\xb1k\xfe\xffo.\x03\x15*\xba\xb9\x90", 20 }, - { CKA_CERT_MD5_HASH, "\xda\xb4<\xe7;QK\x1a\xe5\xeau\xa1\xc9 \xdf""B", 16 }, - { CKA_SERIAL_NUMBER, "\x02\x01\x01", 3 }, - { CKA_TRUST_SERVER_AUTH, &distrusted, sizeof (distrusted) }, - { CKA_TRUST_CLIENT_AUTH, &distrusted, sizeof (distrusted) }, - { CKA_TRUST_EMAIL_PROTECTION, &distrusted, sizeof (distrusted) }, - { CKA_TRUST_CODE_SIGNING, &distrusted, sizeof (distrusted) }, - { CKA_TRUST_IPSEC_END_SYSTEM, &distrusted, sizeof (distrusted) }, - { CKA_TRUST_IPSEC_TUNNEL, &distrusted, sizeof (distrusted) }, - { CKA_TRUST_IPSEC_USER, &distrusted, sizeof (distrusted) }, - { CKA_TRUST_TIME_STAMPING, &distrusted, sizeof (distrusted) }, - { CKA_TRUST_DIGITAL_SIGNATURE, &distrusted, sizeof (distrusted) }, - { CKA_TRUST_NON_REPUDIATION, &distrusted, sizeof (distrusted) }, - { CKA_TRUST_KEY_ENCIPHERMENT, &distrusted, sizeof (distrusted) }, - { CKA_TRUST_DATA_ENCIPHERMENT, &distrusted, sizeof (distrusted) }, - { CKA_TRUST_KEY_AGREEMENT, &distrusted, sizeof (distrusted) }, - { CKA_TRUST_KEY_CERT_SIGN, &distrusted, sizeof (distrusted) }, - { CKA_TRUST_CRL_SIGN, &distrusted, sizeof (distrusted) }, - { CKA_INVALID, } - }; - - unsigned char red_hat_issuer[] = { - 0x30, 0x81, 0x9d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, - 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0e, 0x4e, 0x6f, 0x72, 0x74, 0x68, - 0x20, 0x43, 0x61, 0x72, 0x6f, 0x6c, 0x69, 0x6e, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, - 0x04, 0x07, 0x13, 0x07, 0x52, 0x61, 0x6c, 0x65, 0x69, 0x67, 0x68, 0x31, 0x16, 0x30, 0x14, 0x06, - 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x2c, 0x20, 0x49, - 0x6e, 0x63, 0x2e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x02, 0x49, 0x53, - 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0d, 0x52, 0x65, 0x64, 0x20, 0x48, - 0x61, 0x74, 0x20, 0x49, 0x53, 0x20, 0x43, 0x41, 0x31, 0x26, 0x30, 0x24, 0x06, 0x09, 0x2a, 0x86, - 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x17, 0x73, 0x79, 0x73, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2d, 0x72, 0x64, 0x75, 0x40, 0x72, 0x65, 0x64, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, - }; - - unsigned char red_hat_serial[] = { - 0x02, 0x01, 0x01, - }; - - CK_ATTRIBUTE server_distrust[] = { - { CKA_LABEL, "Red Hat Is the CA", 17 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_ISSUER, (void *)red_hat_issuer, sizeof (red_hat_issuer) }, - { CKA_SERIAL_NUMBER, (void *)red_hat_serial, sizeof (red_hat_serial) }, - { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_SERVER_AUTH_STR, strlen (P11_OID_SERVER_AUTH_STR) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE client_distrust[] = { - { CKA_LABEL, "Red Hat Is the CA", 17 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_ISSUER, (void *)red_hat_issuer, sizeof (red_hat_issuer) }, - { CKA_SERIAL_NUMBER, (void *)red_hat_serial, sizeof (red_hat_serial) }, - { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_CLIENT_AUTH_STR, strlen (P11_OID_CLIENT_AUTH_STR) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE code_distrust[] = { - { CKA_LABEL, "Red Hat Is the CA", 17 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_ISSUER, (void *)red_hat_issuer, sizeof (red_hat_issuer) }, - { CKA_SERIAL_NUMBER, (void *)red_hat_serial, sizeof (red_hat_serial) }, - { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_CODE_SIGNING_STR, strlen (P11_OID_CODE_SIGNING_STR) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE email_distrust[] = { - { CKA_LABEL, "Red Hat Is the CA", 17 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_ISSUER, (void *)red_hat_issuer, sizeof (red_hat_issuer) }, - { CKA_SERIAL_NUMBER, (void *)red_hat_serial, sizeof (red_hat_serial) }, - { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_EMAIL_PROTECTION_STR, strlen (P11_OID_EMAIL_PROTECTION_STR) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE ipsec_system_distrust[] = { - { CKA_LABEL, "Red Hat Is the CA", 17 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_ISSUER, (void *)red_hat_issuer, sizeof (red_hat_issuer) }, - { CKA_SERIAL_NUMBER, (void *)red_hat_serial, sizeof (red_hat_serial) }, - { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_IPSEC_END_SYSTEM_STR, strlen (P11_OID_IPSEC_END_SYSTEM_STR) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE ipsec_tunnel_distrust[] = { - { CKA_LABEL, "Red Hat Is the CA", 17 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_ISSUER, (void *)red_hat_issuer, sizeof (red_hat_issuer) }, - { CKA_SERIAL_NUMBER, (void *)red_hat_serial, sizeof (red_hat_serial) }, - { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_IPSEC_TUNNEL_STR, strlen (P11_OID_IPSEC_TUNNEL_STR) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE ipsec_user_distrust[] = { - { CKA_LABEL, "Red Hat Is the CA", 17 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_ISSUER, (void *)red_hat_issuer, sizeof (red_hat_issuer) }, - { CKA_SERIAL_NUMBER, (void *)red_hat_serial, sizeof (red_hat_serial) }, - { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_IPSEC_USER_STR, strlen (P11_OID_IPSEC_USER_STR) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE stamping_distrust[] = { - { CKA_LABEL, "Red Hat Is the CA", 17 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_ISSUER, (void *)red_hat_issuer, sizeof (red_hat_issuer) }, - { CKA_SERIAL_NUMBER, (void *)red_hat_serial, sizeof (red_hat_serial) }, - { CKA_X_ASSERTION_TYPE, &distrusted_certificate, sizeof (distrusted_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_TIME_STAMPING_STR, strlen (P11_OID_TIME_STAMPING_STR) }, - { CKA_INVALID }, - }; - CK_ATTRIBUTE *expected[] = { - certificate, + distrust_cert, eku_extension, reject_extension, - nss_trust, - server_distrust, - client_distrust, - code_distrust, - email_distrust, - ipsec_system_distrust, - ipsec_tunnel_distrust, - ipsec_user_distrust, - stamping_distrust, + NULL }; CK_ATTRIBUTE *cert; CK_ATTRIBUTE *object; + CK_OBJECT_HANDLE handle; int ret; int i; @@ -489,22 +278,26 @@ test_parse_openssl_distrusted (CuTest *cu) * so we parse this as an anchor, but expect it to be blacklisted */ ret = p11_parse_file (test.parser, SRCDIR "/files/distrusted.pem", - P11_PARSE_FLAG_ANCHOR, on_parse_object, cu); + P11_PARSE_FLAG_ANCHOR); CuAssertIntEquals (cu, P11_PARSE_SUCCESS, ret); /* * Should have gotten: * - 1 certificate * - 2 stapled extensions - * - 1 trust object - * - 8 trust assertions */ - CuAssertIntEquals (cu, 12, test.objects->num); - cert = test.objects->elem[0]; + CuAssertIntEquals (cu, 3, p11_index_size (test.index)); + cert = parsed_attrs (certificate_match); + test_check_attrs (cu, expected[0], cert); /* The other objects */ - for (i = 0; i < 12; i++) { - object = test.objects->elem[i]; + for (i = 1; expected[i]; i++) { + handle = p11_index_findn (test.index, expected[i], 2); + CuAssertTrue (cu, handle != 0); + + object = p11_index_lookup (test.index, handle); + CuAssertPtrNotNull (cu, object); + test_check_attrs (cu, expected[i], object); test_check_id (cu, cert, object); } @@ -513,246 +306,35 @@ test_parse_openssl_distrusted (CuTest *cu) } static void -test_parse_with_key_usage (CuTest *cu) -{ - CK_TRUST trusted = CKT_NSS_TRUSTED; - CK_TRUST unknown = CKT_NSS_TRUST_UNKNOWN; - CK_OBJECT_CLASS klass = CKO_CERTIFICATE; - CK_OBJECT_CLASS trust_object = CKO_NSS_TRUST; - CK_BBOOL vtrue = CK_TRUE; - CK_BBOOL vfalse = CK_FALSE; - CK_CERTIFICATE_TYPE x509 = CKC_X_509; - CK_ULONG category = 3; /* other entity */ - - CK_ATTRIBUTE certificate[] = { - { CKA_CLASS, &klass, sizeof (klass), }, - { CKA_TOKEN, &vtrue, sizeof (vtrue) }, - { CKA_PRIVATE, &vfalse, sizeof (vfalse) }, - { CKA_MODIFIABLE, &vfalse, sizeof (vfalse) }, - { CKA_CLASS, &klass, sizeof (klass) }, - { CKA_LABEL, "self-signed-with-ku.example.com", 31 }, - { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, - { CKA_CERTIFICATE_CATEGORY, &category, sizeof (category) }, - { CKA_CHECK_VALUE, "d/\x9c", 3 }, - { CKA_START_DATE, "20121211", 8 }, - { CKA_END_DATE, "20130110", 8, }, - { CKA_ISSUER, "0*1(0&\x06\x03U\x04\x03\x13\x1f""self-signed-with-ku.example.com", 44 }, - { CKA_SUBJECT, "0*1(0&\x06\x03U\x04\x03\x13\x1f""self-signed-with-ku.example.com", 44 }, - { CKA_SERIAL_NUMBER, "\x02\x02\x03x", 4 }, - { CKA_TRUSTED, &vtrue, sizeof (vtrue) }, - { CKA_X_DISTRUSTED, &vfalse, sizeof (vfalse) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE nss_trust[] = { - { CKA_LABEL, "self-signed-with-ku.example.com", 31 }, - { CKA_CLASS, &trust_object, sizeof (trust_object), }, - { CKA_CERT_SHA1_HASH, "d/\x9c=\xbc\x9a\x7f\x91\xc7wT\t`\x86\xe2\x8e\x8f\xa8J\x12", 20 }, - { CKA_CERT_MD5_HASH, "\xb1N=\x16\x12?dz\x97\x81""By/\xcc\x97\x82", 16 }, - { CKA_ISSUER, "0*1(0&\x06\x03U\x04\x03\x13\x1f""self-signed-with-ku.example.com", 44 }, - { CKA_SUBJECT, "0*1(0&\x06\x03U\x04\x03\x13\x1f""self-signed-with-ku.example.com", 44 }, - { CKA_SERIAL_NUMBER, "\x02\x02\x03x", 4 }, - { CKA_TRUST_SERVER_AUTH, &trusted, sizeof (trusted) }, - { CKA_TRUST_CLIENT_AUTH, &trusted, sizeof (trusted) }, - { CKA_TRUST_EMAIL_PROTECTION, &trusted, sizeof (trusted) }, - { CKA_TRUST_CODE_SIGNING, &trusted, sizeof (trusted) }, - { CKA_TRUST_IPSEC_END_SYSTEM, &trusted, sizeof (trusted) }, - { CKA_TRUST_IPSEC_TUNNEL, &trusted, sizeof (trusted) }, - { CKA_TRUST_IPSEC_USER, &trusted, sizeof (trusted) }, - { CKA_TRUST_TIME_STAMPING, &trusted, sizeof (trusted) }, - { CKA_TRUST_DIGITAL_SIGNATURE, &trusted, sizeof (trusted) }, - { CKA_TRUST_NON_REPUDIATION, &unknown, sizeof (unknown) }, - { CKA_TRUST_KEY_ENCIPHERMENT, &unknown, sizeof (unknown) }, - { CKA_TRUST_DATA_ENCIPHERMENT, &unknown, sizeof (unknown) }, - { CKA_TRUST_KEY_AGREEMENT, &unknown, sizeof (unknown) }, - { CKA_TRUST_KEY_CERT_SIGN, &trusted, sizeof (trusted) }, - { CKA_TRUST_CRL_SIGN, &unknown, sizeof (unknown) }, - { CKA_INVALID, } - }; - - CK_ATTRIBUTE *cert; - CK_ATTRIBUTE *object; - CK_BBOOL bval; - int ret; - - setup (cu); - - ret = p11_parse_file (test.parser, SRCDIR "/files/self-signed-with-ku.der", - P11_PARSE_FLAG_ANCHOR, on_parse_object, cu); - CuAssertIntEquals (cu, P11_PARSE_SUCCESS, ret); - - /* Should have gotten certificate, and a trust object */ - CuAssertIntEquals (cu, 2, test.objects->num); - - cert = test.objects->elem[0]; - test_check_attrs (cu, certificate, cert); - - if (!p11_attrs_find_bool (cert, CKA_TRUSTED, &bval)) - CuFail (cu, "missing CKA_TRUSTED"); - CuAssertIntEquals (cu, CK_TRUE, bval); - - if (!p11_attrs_find_bool (cert, CKA_X_DISTRUSTED, &bval)) - CuFail (cu, "missing CKA_X_DISTRUSTED"); - CuAssertIntEquals (cu, CK_FALSE, bval); - - object = test.objects->elem[1]; - test_check_attrs (cu, nss_trust, object); - test_check_id (cu, cert, object); - - teardown (cu); -} - -static void test_parse_anchor (CuTest *cu) { - CK_BBOOL vtrue = CK_TRUE; - CK_OBJECT_CLASS trust_object = CKO_NSS_TRUST; - CK_ATTRIBUTE trusted = { CKA_TRUSTED, &vtrue, sizeof (vtrue) }; - CK_TRUST delegator = CKT_NSS_TRUSTED_DELEGATOR; - CK_OBJECT_CLASS trust_assertion = CKO_X_TRUST_ASSERTION; - CK_X_ASSERTION_TYPE anchored_certificate = CKT_X_ANCHORED_CERTIFICATE; - - CK_ATTRIBUTE nss_trust[] = { - { CKA_LABEL, "CAcert Class 3 Root", 19 }, - { CKA_CLASS, &trust_object, sizeof (trust_object), }, - { CKA_CERT_SHA1_HASH, "\xad\x7c\x3f\x64\xfc\x44\x39\xfe\xf4\xe9\x0b\xe8\xf4\x7c\x6c\xfa\x8a\xad\xfd\xce", 20 }, - { CKA_CERT_MD5_HASH, "\xf7\x25\x12\x82\x4e\x67\xb5\xd0\x8d\x92\xb7\x7c\x0b\x86\x7a\x42", 16 }, - { CKA_ISSUER, (void *)test_cacert3_ca_issuer, sizeof (test_cacert3_ca_issuer) }, - { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, - { CKA_SERIAL_NUMBER, (void *)test_cacert3_ca_serial, sizeof (test_cacert3_ca_serial) }, - { CKA_TRUST_SERVER_AUTH, &delegator, sizeof (delegator) }, - { CKA_TRUST_CLIENT_AUTH, &delegator, sizeof (delegator) }, - { CKA_TRUST_EMAIL_PROTECTION, &delegator, sizeof (delegator) }, - { CKA_TRUST_CODE_SIGNING, &delegator, sizeof (delegator) }, - { CKA_TRUST_IPSEC_END_SYSTEM, &delegator, sizeof (delegator) }, - { CKA_TRUST_IPSEC_TUNNEL, &delegator, sizeof (delegator) }, - { CKA_TRUST_IPSEC_USER, &delegator, sizeof (delegator) }, - { CKA_TRUST_TIME_STAMPING, &delegator, sizeof (delegator) }, - { CKA_TRUST_DIGITAL_SIGNATURE, &delegator, sizeof (delegator) }, - { CKA_TRUST_NON_REPUDIATION, &delegator, sizeof (delegator) }, - { CKA_TRUST_KEY_ENCIPHERMENT, &delegator, sizeof (delegator) }, - { CKA_TRUST_DATA_ENCIPHERMENT, &delegator, sizeof (delegator) }, - { CKA_TRUST_KEY_AGREEMENT, &delegator, sizeof (delegator) }, - { CKA_TRUST_KEY_CERT_SIGN, &delegator, sizeof (delegator) }, - { CKA_TRUST_CRL_SIGN, &delegator, sizeof (delegator) }, - { CKA_INVALID, } - }; - - CK_ATTRIBUTE server_anchor[] = { - { CKA_LABEL, "CAcert Class 3 Root", 19 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, - { CKA_X_ASSERTION_TYPE, &anchored_certificate, sizeof (anchored_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_SERVER_AUTH_STR, strlen (P11_OID_SERVER_AUTH_STR) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE client_anchor[] = { - { CKA_LABEL, "CAcert Class 3 Root", 19 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, - { CKA_X_ASSERTION_TYPE, &anchored_certificate, sizeof (anchored_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_CLIENT_AUTH_STR, strlen (P11_OID_CLIENT_AUTH_STR) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE code_anchor[] = { - { CKA_LABEL, "CAcert Class 3 Root", 19 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, - { CKA_X_ASSERTION_TYPE, &anchored_certificate, sizeof (anchored_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_CODE_SIGNING_STR, strlen (P11_OID_CODE_SIGNING_STR) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE email_anchor[] = { - { CKA_LABEL, "CAcert Class 3 Root", 19 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, - { CKA_X_ASSERTION_TYPE, &anchored_certificate, sizeof (anchored_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_EMAIL_PROTECTION_STR, strlen (P11_OID_EMAIL_PROTECTION_STR) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE ipsec_system_anchor[] = { - { CKA_LABEL, "CAcert Class 3 Root", 19 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, - { CKA_X_ASSERTION_TYPE, &anchored_certificate, sizeof (anchored_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_IPSEC_END_SYSTEM_STR, strlen (P11_OID_IPSEC_END_SYSTEM_STR) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE ipsec_tunnel_anchor[] = { - { CKA_LABEL, "CAcert Class 3 Root", 19 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, - { CKA_X_ASSERTION_TYPE, &anchored_certificate, sizeof (anchored_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_IPSEC_TUNNEL_STR, strlen (P11_OID_IPSEC_TUNNEL_STR) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE ipsec_user_anchor[] = { - { CKA_LABEL, "CAcert Class 3 Root", 19 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, - { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, - { CKA_X_ASSERTION_TYPE, &anchored_certificate, sizeof (anchored_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_IPSEC_USER_STR, strlen (P11_OID_IPSEC_USER_STR) }, - { CKA_INVALID }, - }; - - CK_ATTRIBUTE stamping_anchor[] = { - { CKA_LABEL, "CAcert Class 3 Root", 19 }, - { CKA_CLASS, &trust_assertion, sizeof (trust_assertion) }, + CK_ATTRIBUTE cacert3[] = { + { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) }, + { CKA_CLASS, &certificate, sizeof (certificate) }, { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) }, - { CKA_X_ASSERTION_TYPE, &anchored_certificate, sizeof (anchored_certificate) }, - { CKA_X_PURPOSE, (void *)P11_OID_TIME_STAMPING_STR, strlen (P11_OID_TIME_STAMPING_STR) }, + { CKA_MODIFIABLE, &falsev, sizeof (falsev) }, + { CKA_TRUSTED, &truev, sizeof (truev) }, + { CKA_X_DISTRUSTED, &falsev, sizeof (falsev) }, { CKA_INVALID }, }; - CK_ATTRIBUTE *expected[] = { - NULL, - nss_trust, - server_anchor, - client_anchor, - code_anchor, - email_anchor, - ipsec_system_anchor, - ipsec_tunnel_anchor, - ipsec_user_anchor, - stamping_anchor, - }; - CK_ATTRIBUTE *cert; - CK_ATTRIBUTE *object; - CK_ATTRIBUTE *attr; int ret; - int i; setup (cu); ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der", - P11_PARSE_FLAG_ANCHOR, on_parse_object, cu); + P11_PARSE_FLAG_ANCHOR); CuAssertIntEquals (cu, P11_PARSE_SUCCESS, ret); /* * Should have gotten: * - 1 certificate - * - 1 trust object - * - 8 trust assertions */ - CuAssertIntEquals (cu, 10, test.objects->num); - - cert = test.objects->elem[0]; - test_check_cacert3_ca (cu, cert, NULL); - attr = p11_attrs_find (cert, CKA_TRUSTED); - test_check_attr (cu, &trusted, attr); + CuAssertIntEquals (cu, 1, p11_index_size (test.index)); - for (i = 1; i < 10; i++) { - object = test.objects->elem[i]; - test_check_attrs (cu, expected[i], object); - test_check_id (cu, cert, object); - } + cert = parsed_attrs (certificate_match); + test_check_attrs (cu, cacert3, cert); teardown (cu); } @@ -760,29 +342,20 @@ test_parse_anchor (CuTest *cu) /* TODO: A certificate that uses generalTime needs testing */ static void -test_parse_no_sink (CuTest *cu) -{ - int ret; - - setup (cu); - - ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der", - 0, NULL, NULL); - CuAssertIntEquals (cu, P11_PARSE_SUCCESS, ret); - - teardown (cu); -} - -static void test_parse_invalid_file (CuTest *cu) { int ret; setup (cu); - ret = p11_parse_file (test.parser, "/nonexistant", 0, on_parse_object, cu); + p11_message_quiet (); + + ret = p11_parse_file (test.parser, "/nonexistant", + P11_PARSE_FLAG_NONE); CuAssertIntEquals (cu, P11_PARSE_FAILURE, ret); + p11_message_loud (); + teardown (cu); } @@ -793,10 +366,14 @@ test_parse_unrecognized (CuTest *cu) setup (cu); + p11_message_quiet (); + ret = p11_parse_file (test.parser, SRCDIR "/files/unrecognized-file.txt", - 0, on_parse_object, cu); + P11_PARSE_FLAG_NONE); CuAssertIntEquals (cu, P11_PARSE_UNRECOGNIZED, ret); + p11_message_loud (); + teardown (cu); } @@ -810,15 +387,12 @@ main (void) putenv ("P11_KIT_STRICT=1"); p11_library_init (); p11_debug_init (); - p11_message_quiet (); SUITE_ADD_TEST (suite, test_parse_der_certificate); SUITE_ADD_TEST (suite, test_parse_pem_certificate); SUITE_ADD_TEST (suite, test_parse_openssl_trusted); SUITE_ADD_TEST (suite, test_parse_openssl_distrusted); - SUITE_ADD_TEST (suite, test_parse_with_key_usage); SUITE_ADD_TEST (suite, test_parse_anchor); - SUITE_ADD_TEST (suite, test_parse_no_sink); SUITE_ADD_TEST (suite, test_parse_invalid_file); SUITE_ADD_TEST (suite, test_parse_unrecognized); diff --git a/trust/tests/test-token.c b/trust/tests/test-token.c index ad25da0..5cca233 100644 --- a/trust/tests/test-token.c +++ b/trust/tests/test-token.c @@ -83,33 +83,10 @@ test_token_load (CuTest *cu) teardown (cu); } -static bool -check_object (CK_ATTRIBUTE *match) -{ - CK_OBJECT_HANDLE *handles; - CK_ATTRIBUTE *attrs; - p11_index *index; - bool ret = false; - int i; - - index = p11_token_index (test.token); - handles = p11_index_snapshot (index, NULL, match, p11_attrs_count (match)); - - for (i = 0; handles[i] != 0; i++) { - attrs = p11_index_lookup (index, handles[i]); - if (p11_attrs_match (attrs, match)) { - ret = true; - break; - } - } - - free (handles); - return ret; -} - static void test_token_flags (CuTest *cu) { + CK_OBJECT_CLASS certificate = CKO_CERTIFICATE; CK_BBOOL falsev = CK_FALSE; CK_BBOOL truev = CK_TRUE; @@ -120,6 +97,7 @@ test_token_flags (CuTest *cu) */ CK_ATTRIBUTE blacklist[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, { CKA_LABEL, "Red Hat Is the CA", 17 }, { CKA_SERIAL_NUMBER, "\x02\x01\x01", 3 }, { CKA_TRUSTED, &falsev, sizeof (falsev) }, @@ -142,6 +120,7 @@ test_token_flags (CuTest *cu) }; CK_ATTRIBUTE blacklist2[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, { CKA_SUBJECT, (void *)self_server_subject, sizeof (self_server_subject) }, { CKA_TRUSTED, &falsev, sizeof (falsev) }, { CKA_X_DISTRUSTED, &truev, sizeof (truev) }, @@ -155,6 +134,7 @@ test_token_flags (CuTest *cu) */ CK_ATTRIBUTE anchor[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) }, { CKA_TRUSTED, &truev, sizeof (truev) }, { CKA_X_DISTRUSTED, &falsev, sizeof (falsev) }, @@ -179,27 +159,40 @@ test_token_flags (CuTest *cu) */ CK_ATTRIBUTE notrust[] = { + { CKA_CLASS, &certificate, sizeof (certificate) }, { CKA_SUBJECT, (void *)cacert_root_subject, sizeof (cacert_root_subject) }, { CKA_TRUSTED, &falsev, sizeof (falsev) }, { CKA_X_DISTRUSTED, &falsev, sizeof (falsev) }, { CKA_INVALID }, }; - CK_ATTRIBUTE invalid[] = { - { CKA_LABEL, "Waonec9aoe9", 8 }, - { CKA_INVALID }, + CK_ATTRIBUTE *expected[] = { + anchor, + blacklist, + blacklist2, + notrust, + NULL, }; + CK_OBJECT_HANDLE handle; + CK_ATTRIBUTE *object; + int i; + setup (cu, SRCDIR "/input"); if (p11_token_load (test.token) < 0) CuFail (cu, "should not be reached"); - CuAssertTrue (cu, !check_object (invalid)); - CuAssertTrue (cu, check_object (anchor)); - CuAssertTrue (cu, check_object (blacklist)); - CuAssertTrue (cu, check_object (blacklist2)); - CuAssertTrue (cu, check_object (notrust)); + /* The other objects */ + for (i = 0; expected[i]; i++) { + handle = p11_index_findn (p11_token_index (test.token), expected[i], 2); + CuAssertTrue (cu, handle != 0); + + object = p11_index_lookup (p11_token_index (test.token), handle); + CuAssertPtrNotNull (cu, object); + + test_check_attrs (cu, expected[i], object); + } teardown (cu); } @@ -234,7 +227,6 @@ main (void) putenv ("P11_KIT_STRICT=1"); p11_library_init (); p11_debug_init (); - p11_message_quiet (); SUITE_ADD_TEST (suite, test_token_load); SUITE_ADD_TEST (suite, test_token_flags); diff --git a/trust/token.c b/trust/token.c index 558f374..ae140c7 100644 --- a/trust/token.c +++ b/trust/token.c @@ -34,7 +34,9 @@ #include "config.h" +#include "asn1.h" #include "attrs.h" +#include "builder.h" #include "compat.h" #define P11_DEBUG_FLAG P11_DEBUG_TRUST #include "debug.h" @@ -59,6 +61,7 @@ struct _p11_token { p11_parser *parser; p11_index *index; + p11_builder *builder; const char *path; CK_SLOT_ID slot; int loaded; @@ -84,8 +87,7 @@ loader_load_file (p11_token *token, { int ret; - ret = p11_parse_file (token->parser, filename, flags, - on_parser_object, token); + ret = p11_parse_file (token->parser, filename, flags); switch (ret) { case P11_PARSE_SUCCESS: @@ -361,12 +363,14 @@ load_builtin_objects (p11_token *token) { CKA_TRUST_STEP_UP_APPROVED, &vfalse, sizeof (vfalse) }, }; + p11_index_batch (token->index); on_parser_object (p11_attrs_buildn (NULL, builtin_root_list, ELEMS (builtin_root_list)), token); on_parser_object (p11_attrs_buildn (NULL, distrust_trustwave1, ELEMS (distrust_trustwave1)), token); on_parser_object (p11_attrs_buildn (NULL, distrust_trustwave2, ELEMS (distrust_trustwave2)), token); on_parser_object (p11_attrs_buildn (NULL, distrust_turktrust1, ELEMS (distrust_turktrust1)), token); on_parser_object (p11_attrs_buildn (NULL, distrust_turktrust2, ELEMS (distrust_turktrust2)), token); on_parser_object (p11_attrs_buildn (NULL, distrust_p11subca, ELEMS (distrust_p11subca)), token); + p11_index_finish (token->index); return 1; } @@ -396,6 +400,7 @@ p11_token_free (p11_token *token) p11_index_free (token->index); p11_parser_free (token->parser); + p11_builder_free (token->builder); free (token); } @@ -408,12 +413,18 @@ p11_token_new (CK_SLOT_ID slot, token = calloc (1, sizeof (p11_token)); return_val_if_fail (token != NULL, NULL); - token->parser = p11_parser_new (); - return_val_if_fail (token->parser != NULL, NULL); + token->builder = p11_builder_new (P11_BUILDER_FLAG_TOKEN); + return_val_if_fail (token->builder != NULL, NULL); - token->index = p11_index_new (NULL, NULL, NULL); + token->index = p11_index_new (p11_builder_build, + p11_builder_changed, + token->builder); return_val_if_fail (token->index != NULL, NULL); + token->parser = p11_parser_new (token->index, + p11_builder_get_cache (token->builder)); + return_val_if_fail (token->parser != NULL, NULL); + token->path = strdup (path); return_val_if_fail (token->path != NULL, NULL); |