diff options
-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); |