]> granicus.if.org Git - p11-kit/commitdiff
trust: Fix various issues writing objects in trust token
authorStef Walter <stef@thewalter.net>
Mon, 8 Jul 2013 16:38:38 +0000 (18:38 +0200)
committerStef Walter <stef@thewalter.net>
Mon, 8 Jul 2013 16:38:38 +0000 (18:38 +0200)
 * Create directory before trying to write files to it
 * Handle write failures appropriately

Refactor how we build and store objects in the index to handle
the above cases properly.

trust/builder.c
trust/builder.h
trust/index.c
trust/index.h
trust/session.c
trust/tests/test-builder.c
trust/tests/test-index.c
trust/token.c

index 106968ce482a2df843eade0dba4deb37f99a55de..d39890d81996094505880a97b5a6f1905c022b59 100644 (file)
@@ -81,7 +81,7 @@ typedef struct {
                bool (*validate) (p11_builder *, CK_ATTRIBUTE *);
        } attrs[32];
        CK_ATTRIBUTE * (*populate) (p11_builder *, p11_index *, CK_ATTRIBUTE *);
-       CK_RV (*validate) (p11_builder *, CK_ATTRIBUTE *);
+       CK_RV (*validate) (p11_builder *, CK_ATTRIBUTE *, CK_ATTRIBUTE *);
 } builder_schema;
 
 static node_asn *
@@ -711,12 +711,24 @@ certificate_populate (p11_builder *builder,
        return p11_attrs_build (attrs, &category, &empty_value, NULL);
 }
 
-static CK_RV
-certificate_validate (p11_builder *builder,
-                      CK_ATTRIBUTE *attrs)
+static bool
+have_attribute (CK_ATTRIBUTE *attrs1,
+                CK_ATTRIBUTE *attrs2,
+                CK_ATTRIBUTE_TYPE type)
 {
        CK_ATTRIBUTE *attr;
 
+       attr = p11_attrs_find (attrs1, type);
+       if (attr == NULL)
+               attr = p11_attrs_find (attrs2, type);
+       return attr != NULL && attr->ulValueLen > 0;
+}
+
+static CK_RV
+certificate_validate (p11_builder *builder,
+                      CK_ATTRIBUTE *attrs,
+                      CK_ATTRIBUTE *merge)
+{
        /*
         * In theory we should be validating that in the absence of CKA_VALUE
         * various other fields must be set. However we do not enforce this
@@ -724,16 +736,13 @@ certificate_validate (p11_builder *builder,
         * but issuer and serial number, for blacklisting purposes.
         */
 
-       attr = p11_attrs_find (attrs, CKA_URL);
-       if (attr != NULL && attr->ulValueLen > 0) {
-               attr = p11_attrs_find (attrs, CKA_HASH_OF_SUBJECT_PUBLIC_KEY);
-               if (attr == NULL || attr->ulValueLen == 0) {
+       if (have_attribute (attrs, merge, CKA_URL)) {
+               if (!have_attribute (attrs, merge, CKA_HASH_OF_SUBJECT_PUBLIC_KEY)) {
                        p11_message ("missing the CKA_HASH_OF_SUBJECT_PUBLIC_KEY attribute");
                        return CKR_TEMPLATE_INCONSISTENT;
                }
 
-               attr = p11_attrs_find (attrs, CKA_HASH_OF_ISSUER_PUBLIC_KEY);
-               if (attr == NULL || attr->ulValueLen == 0) {
+               if (!have_attribute (attrs, merge, CKA_HASH_OF_SUBJECT_PUBLIC_KEY)) {
                        p11_message ("missing the CKA_HASH_OF_ISSUER_PUBLIC_KEY attribute");
                        return CKR_TEMPLATE_INCONSISTENT;
                }
@@ -746,8 +755,8 @@ const static builder_schema certificate_schema = {
        NORMAL_BUILD,
        { COMMON_ATTRS,
          { CKA_CERTIFICATE_TYPE, REQUIRE | CREATE, type_ulong },
-         { CKA_TRUSTED, NONE, type_bool },
-         { CKA_X_DISTRUSTED, NONE, type_bool },
+         { CKA_TRUSTED, CREATE | WANT, type_bool },
+         { CKA_X_DISTRUSTED, CREATE | WANT, type_bool },
          { CKA_CERTIFICATE_CATEGORY, CREATE | WANT, type_ulong },
          { CKA_CHECK_VALUE, CREATE | WANT, },
          { CKA_START_DATE, CREATE | MODIFY | WANT, type_date },
@@ -761,7 +770,7 @@ const static builder_schema certificate_schema = {
          { CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CREATE },
          { CKA_HASH_OF_ISSUER_PUBLIC_KEY, CREATE },
          { CKA_JAVA_MIDP_SECURITY_DOMAIN, CREATE, type_ulong },
-         { CKA_X_PUBLIC_KEY_INFO, CREATE | WANT, type_der_key },
+         { CKA_X_PUBLIC_KEY_INFO, WANT, type_der_key },
          { CKA_INVALID },
        }, certificate_populate, certificate_validate,
 };
@@ -884,33 +893,6 @@ const static builder_schema builtin_schema = {
        }, 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_terminator (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_terminator (merge + out));
-}
-
 static const char *
 value_name (const p11_constant *info,
             CK_ATTRIBUTE_TYPE type)
@@ -925,50 +907,16 @@ type_name (CK_ATTRIBUTE_TYPE type)
        return value_name (p11_constant_types, type);
 }
 
-static CK_RV
-validate_for_schema (p11_builder *builder,
-                     const builder_schema *schema,
-                     CK_ATTRIBUTE *attrs,
-                     CK_ATTRIBUTE *merge)
-{
-       CK_ATTRIBUTE *shallow;
-       CK_ULONG nattrs;
-       CK_ULONG nmerge;
-       CK_RV rv;
-
-       if (!schema->validate)
-               return CKR_OK;
-
-       nattrs = p11_attrs_count (attrs);
-       nmerge = p11_attrs_count (merge);
-
-       /* Make a shallow copy of the combined attributes for validation */
-       shallow = calloc (nmerge + nattrs + 1, sizeof (CK_ATTRIBUTE));
-       return_val_if_fail (shallow != NULL, CKR_GENERAL_ERROR);
-
-       memcpy (shallow, merge, sizeof (CK_ATTRIBUTE) * nmerge);
-       memcpy (shallow + nmerge, attrs, sizeof (CK_ATTRIBUTE) * nattrs);
-
-       /* The terminator attribute */
-       shallow[nmerge + nattrs].type = CKA_INVALID;
-       assert(p11_attrs_terminator (shallow + nmerge + nattrs));
-
-       rv = (schema->validate) (builder, shallow);
-       free (shallow);
-
-       return rv;
-}
-
 static CK_RV
 build_for_schema (p11_builder *builder,
                   p11_index *index,
                   const builder_schema *schema,
-                  CK_ATTRIBUTE **object,
-                  CK_ATTRIBUTE *merge)
+                  CK_ATTRIBUTE *attrs,
+                  CK_ATTRIBUTE *merge,
+                  CK_ATTRIBUTE **extra)
 {
-       CK_ATTRIBUTE *extra;
-       CK_ATTRIBUTE *attrs;
        CK_BBOOL modifiable;
+       CK_ATTRIBUTE *attr;
        bool modifying;
        bool creating;
        bool populate;
@@ -978,7 +926,6 @@ build_for_schema (p11_builder *builder,
        int i, j;
        CK_RV rv;
 
-       attrs = *object;
        populate = false;
 
        /* Signifies that data is being loaded */
@@ -998,9 +945,6 @@ build_for_schema (p11_builder *builder,
                }
        }
 
-       if (attrs != NULL)
-               attrs_filter_if_unchanged (attrs, merge);
-
        if (creating && (builder->flags & P11_BUILDER_FLAG_TOKEN)) {
                if (schema->build_flags & GENERATED_CLASS) {
                        p11_message ("objects of this type cannot be created");
@@ -1009,6 +953,12 @@ build_for_schema (p11_builder *builder,
        }
 
        for (i = 0; merge[i].type != CKA_INVALID; i++) {
+
+               /* Don't validate attribute if not changed */
+               attr = p11_attrs_find (attrs, merge[i].type);
+               if (attr && p11_attr_equal (attr, merge + i))
+                       continue;
+
                found = false;
                for (j = 0; schema->attrs[j].type != CKA_INVALID; j++) {
                        if (schema->attrs[j].type != merge[i].type)
@@ -1068,35 +1018,27 @@ build_for_schema (p11_builder *builder,
                }
        }
 
-       if (populate && schema->populate) {
-               extra = schema->populate (builder, index, merge);
-               if (extra != NULL)
-                       merge = p11_attrs_merge (merge, extra, false);
-       }
+       if (populate && schema->populate)
+               *extra = schema->populate (builder, index, merge);
 
        /* Validate the result, before committing to the change. */
-       if (!loading) {
-               rv = validate_for_schema (builder, schema, attrs, merge);
-               if (rv != CKR_OK) {
-                       p11_attrs_free (merge);
+       if (!loading && schema->validate) {
+               rv = (schema->validate) (builder, attrs, merge);
+               if (rv != CKR_OK)
                        return rv;
-               }
        }
 
-       *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)
+                   CK_ATTRIBUTE *attrs,
+                   CK_ATTRIBUTE *merge,
+                   CK_ATTRIBUTE **populate)
 {
        p11_builder *builder = bilder;
-       CK_ATTRIBUTE *attrs;
        CK_OBJECT_CLASS klass;
        CK_CERTIFICATE_TYPE type;
        CK_BBOOL token;
@@ -1105,8 +1047,6 @@ p11_builder_build (void *bilder,
        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;
@@ -1125,7 +1065,7 @@ p11_builder_build (void *bilder,
                        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);
+                       return build_for_schema (builder, index, &certificate_schema, attrs, merge, populate);
                } else {
                        p11_message ("%s unsupported %s", value_name (p11_constant_certs, type),
                                     type_name (CKA_CERTIFICATE_TYPE));
@@ -1133,19 +1073,19 @@ p11_builder_build (void *bilder,
                }
 
        case CKO_X_CERTIFICATE_EXTENSION:
-               return build_for_schema (builder, index, &extension_schema, object, merge);
+               return build_for_schema (builder, index, &extension_schema, attrs, merge, populate);
 
        case CKO_DATA:
-               return build_for_schema (builder, index, &data_schema, object, merge);
+               return build_for_schema (builder, index, &data_schema, attrs, merge, populate);
 
        case CKO_NSS_TRUST:
-               return build_for_schema (builder, index, &trust_schema, object, merge);
+               return build_for_schema (builder, index, &trust_schema, attrs, merge, populate);
 
        case CKO_NSS_BUILTIN_ROOT_LIST:
-               return build_for_schema (builder, index, &builtin_schema, object, merge);
+               return build_for_schema (builder, index, &builtin_schema, attrs, merge, populate);
 
        case CKO_X_TRUST_ASSERTION:
-               return build_for_schema (builder, index, &assertion_schema, object, merge);
+               return build_for_schema (builder, index, &assertion_schema, attrs, merge, populate);
 
        default:
                p11_message ("%s unsupported object class",
index c8375140e4bda87dc881c67878221dd46c2d12fe..ba130e147cc9c00edb4259f4175e105af1f53019 100644 (file)
@@ -53,8 +53,9 @@ void                  p11_builder_free        (p11_builder *builder);
 
 CK_RV                 p11_builder_build       (void *builder,
                                                p11_index *index,
-                                               CK_ATTRIBUTE **attrs,
-                                               CK_ATTRIBUTE *merge);
+                                               CK_ATTRIBUTE *attrs,
+                                               CK_ATTRIBUTE *merge,
+                                               CK_ATTRIBUTE **populate);
 
 void                  p11_builder_changed     (void *builder,
                                                p11_index *index,
index 47433971d93e52679e0a48cb28560bcec54e6520..b84142f7762f7f4d127c53ef576ffe0acc5f9ff4 100644 (file)
@@ -77,6 +77,9 @@ struct _p11_index {
        /* Called to build an new/modified object */
        p11_index_build_cb build;
 
+       /* Called after each object ready to be stored */
+       p11_index_store_cb store;
+
        /* Called after objects change */
        p11_index_notify_cb notify;
 
@@ -98,8 +101,37 @@ free_object (void *data)
        free (obj);
 }
 
+static CK_RV
+default_build (void *data,
+               p11_index *index,
+               CK_ATTRIBUTE *attrs,
+               CK_ATTRIBUTE *merge,
+               CK_ATTRIBUTE **populate)
+{
+       return CKR_OK;
+}
+
+static CK_RV
+default_store (void *data,
+               p11_index *index,
+               CK_OBJECT_HANDLE handle,
+               CK_ATTRIBUTE **attrs)
+{
+       return CKR_OK;
+}
+
+static void
+default_notify (void *data,
+                p11_index *index,
+                CK_OBJECT_HANDLE handle,
+                CK_ATTRIBUTE *attrs)
+{
+
+}
+
 p11_index *
 p11_index_new (p11_index_build_cb build,
+               p11_index_store_cb store,
                p11_index_notify_cb notify,
                void *data)
 {
@@ -108,7 +140,15 @@ p11_index_new (p11_index_build_cb build,
        index = calloc (1, sizeof (p11_index));
        return_val_if_fail (index != NULL, NULL);
 
+       if (build == NULL)
+               build = default_build;
+       if (store == NULL)
+               store = default_store;
+       if (notify == NULL)
+               notify = default_notify;
+
        index->build = build;
+       index->store = store;
        index->notify = notify;
        index->data = data;
 
@@ -251,17 +291,89 @@ index_hash (p11_index *index,
        }
 }
 
+static void
+merge_attrs (CK_ATTRIBUTE *output,
+             CK_ULONG *noutput,
+             CK_ATTRIBUTE *merge,
+             CK_ULONG nmerge,
+             p11_array *to_free)
+{
+       CK_ULONG i;
+
+       for (i = 0; i < nmerge; i++) {
+               /* Already have this attribute? */
+               if (p11_attrs_findn (output, *noutput, merge[i].type)) {
+                       p11_array_push (to_free, merge[i].pValue);
+
+               } else {
+                       memcpy (output + *noutput, merge + i, sizeof (CK_ATTRIBUTE));
+                       (*noutput)++;
+               }
+       }
+
+       /* Freeing the array itself */
+       p11_array_push (to_free, merge);
+}
+
 static CK_RV
 index_build (p11_index *index,
+             CK_OBJECT_HANDLE handle,
              CK_ATTRIBUTE **attrs,
              CK_ATTRIBUTE *merge)
 {
-       if (index->build) {
-               return index->build (index->data, index, attrs, merge);
+       CK_ATTRIBUTE *extra = NULL;
+       CK_ATTRIBUTE *built;
+       p11_array *stack = NULL;
+       CK_ULONG count;
+       CK_ULONG nattrs;
+       CK_ULONG nmerge;
+       CK_ULONG nextra;
+       CK_RV rv;
+       int i;
+
+       rv = index->build (index->data, index, *attrs, merge, &extra);
+       if (rv != CKR_OK)
+               return rv;
+
+       /* Short circuit when nothing to merge */
+       if (*attrs == NULL && extra == NULL) {
+               built = merge;
+               stack = NULL;
+
        } else {
-               *attrs = p11_attrs_merge (*attrs, merge, true);
-               return CKR_OK;
+               stack = p11_array_new (NULL);
+               nattrs = p11_attrs_count (*attrs);
+               nmerge = p11_attrs_count (merge);
+               nextra = p11_attrs_count (extra);
+
+               /* Make a shallow copy of the combined attributes for validation */
+               built = calloc (nmerge + nattrs + nextra + 1, sizeof (CK_ATTRIBUTE));
+               return_val_if_fail (built != NULL, CKR_GENERAL_ERROR);
+
+               count = nmerge;
+               memcpy (built, merge, sizeof (CK_ATTRIBUTE) * nmerge);
+               merge_attrs (built, &count, *attrs, nattrs, stack);
+               merge_attrs (built, &count, extra, nextra, stack);
+
+               /* The terminator attribute */
+               built[count].type = CKA_INVALID;
+               assert (p11_attrs_terminator (built + count));
        }
+
+       rv = index->store (index->data, index, handle, &built);
+
+       if (rv == CKR_OK) {
+               for (i = 0; stack && i < stack->num; i++)
+                       free (stack->elem[i]);
+               *attrs = built;
+       } else {
+               p11_attrs_free (merge);
+               p11_attrs_free (extra);
+               free (built);
+       }
+
+       p11_array_free (stack);
+       return rv;
 }
 
 static void
@@ -371,7 +483,9 @@ p11_index_take (p11_index *index,
        obj = calloc (1, sizeof (index_object));
        return_val_if_fail (obj != NULL, CKR_HOST_MEMORY);
 
-       rv = index_build (index, &obj->attrs, attrs);
+       obj->handle = p11_module_next_id ();
+
+       rv = index_build (index, obj->handle, &obj->attrs, attrs);
        if (rv != CKR_OK) {
                p11_attrs_free (attrs);
                free (obj);
@@ -379,7 +493,6 @@ p11_index_take (p11_index *index,
        }
 
        return_val_if_fail (obj->attrs != NULL, CKR_GENERAL_ERROR);
-       obj->handle = p11_module_next_id ();
 
        if (!p11_dict_set (index->objects, &obj->handle, obj))
                return_val_if_reached (CKR_HOST_MEMORY);
@@ -427,7 +540,7 @@ p11_index_update (p11_index *index,
                return CKR_OBJECT_HANDLE_INVALID;
        }
 
-       rv = index_build (index, &obj->attrs, update);
+       rv = index_build (index, obj->handle, &obj->attrs, update);
        if (rv != CKR_OK) {
                p11_attrs_free (update);
                return rv;
@@ -508,7 +621,7 @@ index_replacev (p11_index *index,
                                        continue;
                                if (p11_attrs_matchn (replace[j], attr, 1)) {
                                        attrs = NULL;
-                                       rv = index_build (index, &attrs, replace[j]);
+                                       rv = index_build (index, obj->handle, &attrs, replace[j]);
                                        if (rv != CKR_OK)
                                                return rv;
                                        p11_attrs_free (obj->attrs);
index 6603092cacdba67f22980ddf02111513397b6b2f..192bfcdb9f3438f1a2e7873cecd3127cc1583ee0 100644 (file)
@@ -44,8 +44,14 @@ typedef struct _p11_index p11_index;
 
 typedef CK_RV   (* p11_index_build_cb)   (void *data,
                                           p11_index *index,
-                                          CK_ATTRIBUTE **attrs,
-                                          CK_ATTRIBUTE *merge);
+                                          CK_ATTRIBUTE *attrs,
+                                          CK_ATTRIBUTE *merge,
+                                          CK_ATTRIBUTE **populate);
+
+typedef CK_RV   (* p11_index_store_cb)   (void *data,
+                                          p11_index *index,
+                                          CK_OBJECT_HANDLE handle,
+                                          CK_ATTRIBUTE **attrs);
 
 typedef void    (* p11_index_notify_cb)  (void *data,
                                           p11_index *index,
@@ -53,6 +59,7 @@ typedef void    (* p11_index_notify_cb)  (void *data,
                                           CK_ATTRIBUTE *attrs);
 
 p11_index *        p11_index_new         (p11_index_build_cb build,
+                                          p11_index_store_cb store,
                                           p11_index_notify_cb notify,
                                           void *data);
 
index b04b8bf1b9c16e6ac886afb9dc81f1c4e0c281c1..76a9acf0052206075135577016c5ed45f2b63844 100644 (file)
@@ -61,7 +61,7 @@ p11_session_new (p11_token *token)
        session->builder = p11_builder_new (P11_BUILDER_FLAG_NONE);
        return_val_if_fail (session->builder, NULL);
 
-       session->index = p11_index_new (p11_builder_build,
+       session->index = p11_index_new (p11_builder_build, NULL,
                                        p11_builder_changed,
                                        session->builder);
        return_val_if_fail (session->index != NULL, NULL);
index 72ee15167bb18c53c0e4d8064236515472c62729..3f71b140ce85f600489226670e118b5eaddc5803 100644 (file)
@@ -77,7 +77,7 @@ setup (void *unused)
        test.builder = p11_builder_new (P11_BUILDER_FLAG_TOKEN);
        assert_ptr_not_null (test.builder);
 
-       test.index = p11_index_new (p11_builder_build, p11_builder_changed, test.builder);
+       test.index = p11_index_new (p11_builder_build, NULL, p11_builder_changed, test.builder);
        assert_ptr_not_null (test.index);
 }
 
@@ -121,13 +121,18 @@ test_build_data (void)
 
        CK_ATTRIBUTE *attrs;
        CK_ATTRIBUTE *merge;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        attrs = NULL;
+       extra = NULL;
        merge = p11_attrs_dup (input);
-       rv = p11_builder_build (test.builder, test.index, &attrs, merge);
+       rv = p11_builder_build (test.builder, test.index, attrs, merge, &extra);
        assert_num_eq (CKR_OK, rv);
 
+       attrs = p11_attrs_merge (attrs, merge, true);
+       attrs = p11_attrs_merge (attrs, extra, false);
+
        test_check_attrs (check, attrs);
        p11_attrs_free (attrs);
 }
@@ -160,13 +165,18 @@ test_build_certificate (void)
 
        CK_ATTRIBUTE *attrs;
        CK_ATTRIBUTE *merge;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        attrs = NULL;
+       extra = NULL;
        merge = p11_attrs_dup (input);
-       rv = p11_builder_build (test.builder, test.index, &attrs, merge);
+       rv = p11_builder_build (test.builder, test.index, attrs, merge, &extra);
        assert_num_eq (CKR_OK, rv);
 
+       attrs = p11_attrs_merge (attrs, merge, true);
+       attrs = p11_attrs_merge (attrs, extra, false);
+
        test_check_attrs (expected, attrs);
        p11_attrs_free (attrs);
 }
@@ -208,15 +218,20 @@ test_build_certificate_empty (void)
 
        CK_ATTRIBUTE *attrs;
        CK_ATTRIBUTE *merge;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        p11_hash_sha1 (checksum, test_cacert3_ca_der, sizeof (test_cacert3_ca_der), NULL);
 
        attrs = NULL;
+       extra = NULL;
        merge = p11_attrs_dup (input);
-       rv = p11_builder_build (test.builder, test.index, &attrs, merge);
+       rv = p11_builder_build (test.builder, test.index, attrs, merge, &extra);
        assert_num_eq (CKR_OK, rv);
 
+       attrs = p11_attrs_merge (attrs, merge, true);
+       attrs = p11_attrs_merge (attrs, extra, false);
+
        test_check_attrs (expected, attrs);
        p11_attrs_free (attrs);
 }
@@ -332,12 +347,17 @@ test_build_certificate_non_ca (void)
        };
 
        CK_ATTRIBUTE *attrs;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        attrs = NULL;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       extra = NULL;
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
+       attrs = p11_attrs_merge (attrs, p11_attrs_dup (input), true);
+       attrs = p11_attrs_merge (attrs, extra, false);
+
        test_check_attrs (expected, attrs);
        p11_attrs_free (attrs);
 }
@@ -358,12 +378,17 @@ test_build_certificate_v1_ca (void)
        };
 
        CK_ATTRIBUTE *attrs;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        attrs = NULL;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       extra = NULL;
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
+       attrs = p11_attrs_merge (attrs, p11_attrs_dup (input), true);
+       attrs = p11_attrs_merge (attrs, extra, false);
+
        test_check_attrs (expected, attrs);
        p11_attrs_free (attrs);
 }
@@ -394,6 +419,7 @@ test_build_certificate_staple_ca (void)
        };
 
        CK_ATTRIBUTE *attrs;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        /* Add a stapled certificate */
@@ -401,9 +427,13 @@ test_build_certificate_staple_ca (void)
        assert_num_eq (CKR_OK, rv);
 
        attrs = NULL;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       extra = NULL;
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
+       attrs = p11_attrs_merge (attrs, p11_attrs_dup (input), true);
+       attrs = p11_attrs_merge (attrs, extra, false);
+
        /*
         * Even though the certificate is not a valid CA, the presence of the
         * stapled certificate extension transforms it into a CA.
@@ -422,13 +452,15 @@ test_build_certificate_no_type (void)
 
        CK_ATTRIBUTE *attrs;
        CK_ATTRIBUTE *merge;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        p11_message_quiet ();
 
        attrs = NULL;
+       extra = NULL;
        merge = p11_attrs_dup (input);
-       rv = p11_builder_build (test.builder, test.index, &attrs, merge);
+       rv = p11_builder_build (test.builder, test.index, attrs, merge, &extra);
        assert_num_eq (CKR_TEMPLATE_INCOMPLETE, rv);
        p11_attrs_free (merge);
 
@@ -448,13 +480,14 @@ test_build_certificate_bad_type (void)
 
        CK_ATTRIBUTE *attrs;
        CK_ATTRIBUTE *merge;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        p11_message_quiet ();
 
        attrs = NULL;
        merge = p11_attrs_dup (input);
-       rv = p11_builder_build (test.builder, test.index, &attrs, merge);
+       rv = p11_builder_build (test.builder, test.index, attrs, merge, &extra);
        assert_num_eq (CKR_TEMPLATE_INCONSISTENT, rv);
        p11_attrs_free (merge);
 
@@ -484,12 +517,17 @@ test_build_extension (void)
        };
 
        CK_ATTRIBUTE *attrs;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        attrs = NULL;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       extra = NULL;
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
+       attrs = p11_attrs_merge (attrs, p11_attrs_dup (input), true);
+       attrs = p11_attrs_merge (attrs, extra, false);
+
        test_check_attrs (check, attrs);
        p11_attrs_free (attrs);
 }
@@ -538,12 +576,17 @@ test_build_distant_end_date (void)
        };
 
        CK_ATTRIBUTE *attrs;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        attrs = NULL;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       extra = NULL;
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
+       attrs = p11_attrs_merge (attrs, p11_attrs_dup (input), true);
+       attrs = p11_attrs_merge (attrs, extra, false);
+
        test_check_attrs (expected, attrs);
        p11_attrs_free (attrs);
 }
@@ -552,6 +595,7 @@ static void
 test_valid_bool (void)
 {
        CK_ATTRIBUTE *attrs = NULL;
+       CK_ATTRIBUTE *extra = NULL;
        CK_BBOOL value = CK_TRUE;
        CK_RV rv;
 
@@ -562,16 +606,17 @@ test_valid_bool (void)
                { CKA_INVALID },
        };
 
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
-       p11_attrs_free (attrs);
+       p11_attrs_free (extra);
 }
 
 static void
 test_invalid_bool (void)
 {
        CK_ATTRIBUTE *attrs = NULL;
+       CK_ATTRIBUTE *extra = NULL;
        CK_RV rv;
 
        CK_ATTRIBUTE input[] = {
@@ -585,13 +630,13 @@ test_invalid_bool (void)
 
        input[0].pValue = "123";
        input[0].ulValueLen = 3;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_ATTRIBUTE_VALUE_INVALID, rv);
 
 
        input[0].pValue = NULL;
        input[0].ulValueLen = sizeof (CK_BBOOL);
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_ATTRIBUTE_VALUE_INVALID, rv);
 
        p11_message_loud ();
@@ -601,6 +646,7 @@ static void
 test_valid_ulong (void)
 {
        CK_ATTRIBUTE *attrs = NULL;
+       CK_ATTRIBUTE *extra = NULL;
        CK_ULONG value = 2;
        CK_RV rv;
 
@@ -611,16 +657,17 @@ test_valid_ulong (void)
                { CKA_INVALID },
        };
 
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
-       p11_attrs_free (attrs);
+       p11_attrs_free (extra);
 }
 
 static void
 test_invalid_ulong (void)
 {
        CK_ATTRIBUTE *attrs = NULL;
+       CK_ATTRIBUTE *extra = NULL;
        CK_RV rv;
 
        CK_ATTRIBUTE input[] = {
@@ -634,13 +681,13 @@ test_invalid_ulong (void)
 
        input[0].pValue = "123";
        input[0].ulValueLen = 3;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_ATTRIBUTE_VALUE_INVALID, rv);
 
 
        input[0].pValue = NULL;
        input[0].ulValueLen = sizeof (CK_ULONG);
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_ATTRIBUTE_VALUE_INVALID, rv);
 
        p11_message_loud ();
@@ -650,6 +697,7 @@ static void
 test_valid_utf8 (void)
 {
        CK_ATTRIBUTE *attrs = NULL;
+       CK_ATTRIBUTE *extra = NULL;
        CK_RV rv;
 
        CK_ATTRIBUTE input[] = {
@@ -661,16 +709,17 @@ test_valid_utf8 (void)
 
        input[0].pValue = NULL;
        input[0].ulValueLen = 0;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
-       p11_attrs_free (attrs);
+       p11_attrs_free (extra);
 }
 
 static void
 test_invalid_utf8 (void)
 {
        CK_ATTRIBUTE *attrs = NULL;
+       CK_ATTRIBUTE *extra = NULL;
        CK_RV rv;
 
        CK_ATTRIBUTE input[] = {
@@ -684,13 +733,13 @@ test_invalid_utf8 (void)
 
        input[0].pValue = "\xfex23";
        input[0].ulValueLen = 4;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_ATTRIBUTE_VALUE_INVALID, rv);
 
 
        input[0].pValue = NULL;
        input[0].ulValueLen = 4;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_ATTRIBUTE_VALUE_INVALID, rv);
 
        p11_message_loud ();
@@ -700,6 +749,7 @@ static void
 test_valid_dates (void)
 {
        CK_ATTRIBUTE *attrs = NULL;
+       CK_ATTRIBUTE *extra = NULL;
        CK_DATE date;
        CK_RV rv;
 
@@ -711,14 +761,14 @@ test_valid_dates (void)
        };
 
        memcpy (&date, "20001010", sizeof (date));
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
        p11_attrs_free (attrs);
        attrs = NULL;
 
        input[0].ulValueLen = 0;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
        p11_attrs_free (attrs);
@@ -728,6 +778,7 @@ static void
 test_invalid_dates (void)
 {
        CK_ATTRIBUTE *attrs = NULL;
+       CK_ATTRIBUTE *extra = NULL;
        CK_DATE date;
        CK_RV rv;
 
@@ -741,15 +792,15 @@ test_invalid_dates (void)
        p11_message_quiet ();
 
        memcpy (&date, "AAAABBCC", sizeof (date));
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_ATTRIBUTE_VALUE_INVALID, rv);
 
        memcpy (&date, "20001580", sizeof (date));
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_ATTRIBUTE_VALUE_INVALID, rv);
 
        input[0].pValue = NULL;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_ATTRIBUTE_VALUE_INVALID, rv);
 
        p11_message_loud ();
@@ -759,6 +810,7 @@ static void
 test_valid_name (void)
 {
        CK_ATTRIBUTE *attrs = NULL;
+       CK_ATTRIBUTE *extra = NULL;
        CK_RV rv;
 
        CK_ATTRIBUTE input[] = {
@@ -770,7 +822,7 @@ test_valid_name (void)
 
        input[0].pValue = NULL;
        input[0].ulValueLen = 0;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
        p11_attrs_free (attrs);
@@ -778,7 +830,7 @@ test_valid_name (void)
 
        input[0].pValue = (void *)test_cacert3_ca_issuer;
        input[0].ulValueLen = sizeof (test_cacert3_ca_issuer);
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
        p11_attrs_free (attrs);
@@ -788,6 +840,7 @@ static void
 test_invalid_name (void)
 {
        CK_ATTRIBUTE *attrs = NULL;
+       CK_ATTRIBUTE *extra = NULL;
        CK_RV rv;
 
        CK_ATTRIBUTE input[] = {
@@ -801,12 +854,12 @@ test_invalid_name (void)
 
        input[0].pValue = "blah";
        input[0].ulValueLen = 4;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_ATTRIBUTE_VALUE_INVALID, rv);
 
        input[0].pValue = NULL;
        input[0].ulValueLen = 4;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_ATTRIBUTE_VALUE_INVALID, rv);
 
        p11_message_loud ();
@@ -816,6 +869,7 @@ static void
 test_valid_serial (void)
 {
        CK_ATTRIBUTE *attrs = NULL;
+       CK_ATTRIBUTE *extra = NULL;
        CK_RV rv;
 
        CK_ATTRIBUTE input[] = {
@@ -827,24 +881,25 @@ test_valid_serial (void)
 
        input[0].pValue = NULL;
        input[0].ulValueLen = 0;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
-       p11_attrs_free (attrs);
+       p11_attrs_free (extra);
        attrs = NULL;
 
        input[0].pValue = (void *)test_cacert3_ca_serial;
        input[0].ulValueLen = sizeof (test_cacert3_ca_serial);
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
-       p11_attrs_free (attrs);
+       p11_attrs_free (extra);
 }
 
 static void
 test_invalid_serial (void)
 {
        CK_ATTRIBUTE *attrs = NULL;
+       CK_ATTRIBUTE *extra = NULL;
        CK_RV rv;
 
        CK_ATTRIBUTE input[] = {
@@ -858,17 +913,17 @@ test_invalid_serial (void)
 
        input[0].pValue = "blah";
        input[0].ulValueLen = 4;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_ATTRIBUTE_VALUE_INVALID, rv);
 
        input[0].pValue = (void *)test_cacert3_ca_subject;
        input[0].ulValueLen = sizeof (test_cacert3_ca_subject);
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_ATTRIBUTE_VALUE_INVALID, rv);
 
        input[0].pValue = NULL;
        input[0].ulValueLen = 4;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_ATTRIBUTE_VALUE_INVALID, rv);
 
        p11_message_loud ();
@@ -878,6 +933,7 @@ static void
 test_valid_cert (void)
 {
        CK_ATTRIBUTE *attrs = NULL;
+       CK_ATTRIBUTE *extra = NULL;
        CK_RV rv;
 
        CK_ATTRIBUTE input[] = {
@@ -889,24 +945,25 @@ test_valid_cert (void)
 
        input[0].pValue = NULL;
        input[0].ulValueLen = 0;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
-       p11_attrs_free (attrs);
+       p11_attrs_free (extra);
        attrs = NULL;
 
        input[0].pValue = (void *)test_cacert3_ca_der;
        input[0].ulValueLen = sizeof (test_cacert3_ca_der);
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
-       p11_attrs_free (attrs);
+       p11_attrs_free (extra);
 }
 
 static void
 test_invalid_cert (void)
 {
        CK_ATTRIBUTE *attrs = NULL;
+       CK_ATTRIBUTE *extra = NULL;
        CK_RV rv;
 
        CK_ATTRIBUTE input[] = {
@@ -920,17 +977,17 @@ test_invalid_cert (void)
 
        input[0].pValue = "blah";
        input[0].ulValueLen = 4;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_ATTRIBUTE_VALUE_INVALID, rv);
 
        input[0].pValue = (void *)test_cacert3_ca_subject;
        input[0].ulValueLen = sizeof (test_cacert3_ca_subject);
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_ATTRIBUTE_VALUE_INVALID, rv);
 
        input[0].pValue = NULL;
        input[0].ulValueLen = 4;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_ATTRIBUTE_VALUE_INVALID, rv);
 
        p11_message_loud ();
@@ -940,6 +997,7 @@ static void
 test_invalid_schema (void)
 {
        CK_ATTRIBUTE *attrs = NULL;
+       CK_ATTRIBUTE *extra = NULL;
        CK_RV rv;
 
        CK_ATTRIBUTE input[] = {
@@ -952,7 +1010,7 @@ test_invalid_schema (void)
        p11_message_quiet ();
 
        /* Missing CKA_HASH_OF_SUBJECT_PUBLIC_KEY and CKA_HASH_OF_ISSUER_PUBLIC_KEY */
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_TEMPLATE_INCONSISTENT, rv);
 
        p11_message_loud ();
@@ -962,26 +1020,27 @@ static void
 test_create_not_settable (void)
 {
        /*
-        * CKA_TRUSTED cannot be set by the normal user according to spec
+        * CKA_X_PUBLIC_KEY_INFO cannot be created/modified
         */
 
        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_X_PUBLIC_KEY_INFO, (void *)verisign_v1_ca_public_key, sizeof (verisign_v1_ca_public_key) },
                { CKA_INVALID },
        };
 
        CK_ATTRIBUTE *attrs;
        CK_ATTRIBUTE *merge;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        p11_message_quiet ();
 
        attrs = NULL;
        merge = p11_attrs_dup (input);
-       rv = p11_builder_build (test.builder, test.index, &attrs, merge);
+       rv = p11_builder_build (test.builder, test.index, attrs, merge, &extra);
        assert_num_eq (CKR_ATTRIBUTE_READ_ONLY, rv);
        p11_attrs_free (merge);
 
@@ -994,29 +1053,33 @@ static void
 test_create_but_loadable (void)
 {
        /*
-        * CKA_TRUSTED cannot be set on creation, but can be set if we're
+        * CKA_X_PUBLIC_KEY_INFO 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_X_PUBLIC_KEY_INFO, (void *)verisign_v1_ca_public_key, sizeof (verisign_v1_ca_public_key) },
                { CKA_INVALID },
        };
 
        CK_ATTRIBUTE *attrs;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        p11_index_load (test.index);
 
        attrs = NULL;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
        p11_index_finish (test.index);
 
+       attrs = p11_attrs_merge (attrs, p11_attrs_dup (input), true);
+       attrs = p11_attrs_merge (attrs, extra, false);
+
        test_check_attrs (input, attrs);
        p11_attrs_free (attrs);
 }
@@ -1033,13 +1096,15 @@ test_create_unsupported (void)
 
        CK_ATTRIBUTE *attrs;
        CK_ATTRIBUTE *merge;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        p11_message_quiet ();
 
        attrs = NULL;
+       extra = NULL;
        merge = p11_attrs_dup (input);
-       rv = p11_builder_build (test.builder, test.index, &attrs, merge);
+       rv = p11_builder_build (test.builder, test.index, attrs, merge, &extra);
        assert_num_eq (CKR_TEMPLATE_INCONSISTENT, rv);
        p11_attrs_free (merge);
 
@@ -1058,13 +1123,15 @@ test_create_generated (void)
 
        CK_ATTRIBUTE *attrs;
        CK_ATTRIBUTE *merge;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        p11_message_quiet ();
 
        attrs = NULL;
+       extra = NULL;
        merge = p11_attrs_dup (input);
-       rv = p11_builder_build (test.builder, test.index, &attrs, merge);
+       rv = p11_builder_build (test.builder, test.index, attrs, merge, &extra);
        assert_num_eq (CKR_TEMPLATE_INCONSISTENT, rv);
        p11_attrs_free (merge);
 
@@ -1083,13 +1150,15 @@ test_create_bad_attribute (void)
 
        CK_ATTRIBUTE *attrs;
        CK_ATTRIBUTE *merge;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        p11_message_quiet ();
 
        attrs = NULL;
+       extra = NULL;
        merge = p11_attrs_dup (input);
-       rv = p11_builder_build (test.builder, test.index, &attrs, merge);
+       rv = p11_builder_build (test.builder, test.index, attrs, merge, &extra);
        assert_num_eq (CKR_TEMPLATE_INCONSISTENT, rv);
        p11_attrs_free (merge);
 
@@ -1106,13 +1175,15 @@ test_create_missing_attribute (void)
 
        CK_ATTRIBUTE *attrs;
        CK_ATTRIBUTE *merge;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        p11_message_quiet ();
 
        attrs = NULL;
+       extra = NULL;
        merge = p11_attrs_dup (input);
-       rv = p11_builder_build (test.builder, test.index, &attrs, merge);
+       rv = p11_builder_build (test.builder, test.index, attrs, merge, &extra);
        assert_num_eq (CKR_TEMPLATE_INCOMPLETE, rv);
        p11_attrs_free (merge);
 
@@ -1129,13 +1200,15 @@ test_create_no_class (void)
 
        CK_ATTRIBUTE *attrs;
        CK_ATTRIBUTE *merge;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        p11_message_quiet ();
 
        attrs = NULL;
+       extra = NULL;
        merge = p11_attrs_dup (input);
-       rv = p11_builder_build (test.builder, test.index, &attrs, merge);
+       rv = p11_builder_build (test.builder, test.index, attrs, merge, &extra);
        assert_num_eq (CKR_TEMPLATE_INCOMPLETE, rv);
        p11_attrs_free (merge);
 
@@ -1153,13 +1226,15 @@ test_create_token_mismatch (void)
 
        CK_ATTRIBUTE *attrs;
        CK_ATTRIBUTE *merge;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        p11_message_quiet ();
 
        attrs = NULL;
+       extra = NULL;
        merge = p11_attrs_dup (input);
-       rv = p11_builder_build (test.builder, test.index, &attrs, merge);
+       rv = p11_builder_build (test.builder, test.index, attrs, merge, &extra);
        assert_num_eq (CKR_TEMPLATE_INCONSISTENT, rv);
        p11_attrs_free (merge);
 
@@ -1191,15 +1266,24 @@ test_modify_success (void)
        };
 
        CK_ATTRIBUTE *attrs;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        attrs = NULL;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       extra = NULL;
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (modify));
+       attrs = p11_attrs_merge (attrs, p11_attrs_dup (input), true);
+       attrs = p11_attrs_merge (attrs, extra, false);
+
+       extra = NULL;
+       rv = p11_builder_build (test.builder, test.index, attrs, modify, &extra);
        assert_num_eq (CKR_OK, rv);
 
+       attrs = p11_attrs_merge (attrs, p11_attrs_dup (modify), true);
+       attrs = p11_attrs_merge (attrs, extra, false);
+
        test_check_attrs (expected, attrs);
        p11_attrs_free (attrs);
 }
@@ -1221,17 +1305,23 @@ test_modify_read_only (void)
 
        CK_ATTRIBUTE *attrs;
        CK_ATTRIBUTE *merge;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        attrs = NULL;
+       extra = NULL;
        merge = p11_attrs_dup (input);
-       rv = p11_builder_build (test.builder, test.index, &attrs, merge);
+       rv = p11_builder_build (test.builder, test.index, attrs, merge, &extra);
        assert_num_eq (CKR_OK, rv);
 
+       attrs = p11_attrs_merge (attrs, merge, true);
+       attrs = p11_attrs_merge (attrs, extra, false);
+
        p11_message_quiet ();
 
+       extra = NULL;
        merge = p11_attrs_dup (modify);
-       rv = p11_builder_build (test.builder, test.index, &attrs, merge);
+       rv = p11_builder_build (test.builder, test.index, attrs, merge, &extra);
        assert_num_eq (CKR_ATTRIBUTE_READ_ONLY, rv);
        p11_attrs_free (merge);
 
@@ -1268,15 +1358,23 @@ test_modify_unchanged (void)
        };
 
        CK_ATTRIBUTE *attrs;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        attrs = NULL;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (modify));
+       attrs = p11_attrs_merge (attrs, p11_attrs_dup (input), true);
+       attrs = p11_attrs_merge (attrs, extra, false);
+
+       extra = NULL;
+       rv = p11_builder_build (test.builder, test.index, attrs, modify, &extra);
        assert_num_eq (CKR_OK, rv);
 
+       attrs = p11_attrs_merge (attrs, p11_attrs_dup (modify), true);
+       attrs = p11_attrs_merge (attrs, extra, false);
+
        test_check_attrs (expected, attrs);
        p11_attrs_free (attrs);
 }
@@ -1298,16 +1396,22 @@ test_modify_not_modifiable (void)
 
        CK_ATTRIBUTE *attrs;
        CK_ATTRIBUTE *merge;
+       CK_ATTRIBUTE *extra;
        CK_RV rv;
 
        attrs = NULL;
-       rv = p11_builder_build (test.builder, test.index, &attrs, p11_attrs_dup (input));
+       extra = NULL;
+       rv = p11_builder_build (test.builder, test.index, attrs, input, &extra);
        assert_num_eq (CKR_OK, rv);
 
+       attrs = p11_attrs_merge (attrs, p11_attrs_dup (input), true);
+       attrs = p11_attrs_merge (attrs, extra, false);
+
        p11_message_quiet ();
 
+       extra = NULL;
        merge = p11_attrs_dup (modify);
-       rv = p11_builder_build (test.builder, test.index, &attrs, merge);
+       rv = p11_builder_build (test.builder, test.index, attrs, merge, &extra);
        assert_num_eq (CKR_ATTRIBUTE_READ_ONLY, rv);
        p11_attrs_free (merge);
 
index 8932da649008332451a93f895e1ed0bad2b0bdc8..73fc35967e86e159a5d7d93344942e699c8d3010 100644 (file)
@@ -53,7 +53,7 @@ struct {
 static void
 setup (void *unused)
 {
-       test.index = p11_index_new (NULL, NULL, NULL);
+       test.index = p11_index_new (NULL, NULL, NULL, NULL);
        assert_ptr_not_null (test.index);
 }
 
@@ -657,22 +657,20 @@ test_replace_all (void)
 static CK_RV
 on_build_populate (void *data,
                    p11_index *index,
-                   CK_ATTRIBUTE **attrs,
-                   CK_ATTRIBUTE *merge)
+                   CK_ATTRIBUTE *attrs,
+                   CK_ATTRIBUTE *merge,
+                   CK_ATTRIBUTE **populate)
 {
-       CK_ATTRIBUTE override[] = {
+       CK_ATTRIBUTE more[] = {
                { CKA_APPLICATION, "vigorous", 8 },
                { CKA_LABEL, "naay", 4 },
-               { CKA_INVALID },
        };
 
        assert_str_eq (data, "blah");
        assert_ptr_not_null (index);
-       assert_ptr_not_null (attrs);
        assert_ptr_not_null (merge);
 
-       *attrs = p11_attrs_merge (*attrs, merge, true);
-       *attrs = p11_attrs_merge (*attrs, p11_attrs_dup (override), true);
+       *populate = p11_attrs_buildn (*populate, more, 2);
        return CKR_OK;
 }
 
@@ -687,7 +685,7 @@ test_build_populate (void)
        };
 
        CK_ATTRIBUTE after[] = {
-               { CKA_LABEL, "naay", 4 },
+               { CKA_LABEL, "yay", 3 },
                { CKA_VALUE, "eight", 5 },
                { CKA_APPLICATION, "vigorous", 8 },
                { CKA_INVALID }
@@ -698,7 +696,7 @@ test_build_populate (void)
        p11_index *index;
        CK_RV rv;
 
-       index = p11_index_new (on_build_populate, NULL, "blah");
+       index = p11_index_new (on_build_populate, NULL, NULL, "blah");
        assert_ptr_not_null (index);
 
        rv = p11_index_add (index, original, 2, &handle);
@@ -723,8 +721,9 @@ test_build_populate (void)
 static CK_RV
 on_build_fail (void *data,
                p11_index *index,
-               CK_ATTRIBUTE **attrs,
-               CK_ATTRIBUTE *merge)
+               CK_ATTRIBUTE *attrs,
+               CK_ATTRIBUTE *merge,
+               CK_ATTRIBUTE **populate)
 {
        CK_ATTRIBUTE check[] = {
                { CKA_LABEL, "nay", 3 },
@@ -737,7 +736,6 @@ on_build_fail (void *data,
        if (p11_attrs_match (merge, check))
                return CKR_DEVICE_ERROR;
 
-       *attrs = p11_attrs_merge (*attrs, merge, true);
        return CKR_OK;
 }
 
@@ -761,7 +759,7 @@ test_build_fail (void)
        p11_index *index;
        CK_RV rv;
 
-       index = p11_index_new (on_build_fail, NULL, "testo");
+       index = p11_index_new (on_build_fail, NULL, NULL, "testo");
        assert_ptr_not_null (index);
 
        rv = p11_index_add (index, okay, 2, &handle);
@@ -825,7 +823,7 @@ test_change_called (void)
        p11_index *index;
        CK_RV rv;
 
-       index = p11_index_new (NULL, on_change_check, "change-check");
+       index = p11_index_new (NULL, NULL, on_change_check, "change-check");
        assert_ptr_not_null (index);
 
        on_change_removing = false;
@@ -870,7 +868,7 @@ test_change_batch (void)
        p11_index *index;
        CK_RV rv;
 
-       index = p11_index_new (NULL, on_change_check, "change-check");
+       index = p11_index_new (NULL, NULL, on_change_check, "change-check");
        assert_ptr_not_null (index);
 
        on_change_batching = true;
@@ -961,7 +959,7 @@ test_change_nested (void)
        p11_index *index;
        CK_RV rv;
 
-       index = p11_index_new (NULL, on_change_nested, "change-nested");
+       index = p11_index_new (NULL, NULL, on_change_nested, "change-nested");
        assert_ptr_not_null (index);
 
        on_change_called = 0;
index ca24762c582a1735354a2c99e06c7ac3368adf9c..06416199e26916ade5392585d59f573cc881efee 100644 (file)
@@ -73,8 +73,9 @@ struct _p11_token {
        char *label;              /* The token label */
        CK_SLOT_ID slot;          /* The slot id */
 
-       bool checked_writable;
+       bool checked_path;
        bool is_writable;
+       bool make_directory;
 };
 
 static bool
@@ -422,6 +423,60 @@ p11_token_reload (p11_token *token,
        return loader_load_file (token, origin, &sb) > 0;
 }
 
+static bool
+check_directory (const char *path,
+                 bool *make_directory,
+                 bool *is_writable)
+{
+       struct stat sb;
+       char *parent;
+       bool dummy;
+       bool ret;
+
+       /*
+        * This function attempts to determine whether a later write
+        * to this token will succeed so we can setup the appropriate
+        * token flags. Yes, it is racy, but that's inherent to the problem.
+        */
+
+       if (stat (path, &sb) == 0) {
+               *make_directory = false;
+               *is_writable = S_ISDIR (sb.st_mode) && access (path, W_OK) == 0;
+               return true;
+       }
+
+       switch (errno) {
+       case EACCES:
+               *is_writable = false;
+               *make_directory = false;
+               return true;
+       case ENOENT:
+               *make_directory = true;
+               parent = p11_path_parent (path);
+               if (parent == NULL)
+                       ret = false;
+               else
+                       ret = check_directory (parent, &dummy, is_writable);
+               free (parent);
+               return ret;
+       default:
+               p11_message ("couldn't access: %s: %s", path, strerror (errno));
+               return false;
+       }
+}
+
+static bool
+check_token_directory (p11_token *token)
+{
+       if (!token->checked_path) {
+               token->checked_path = check_directory (token->path,
+                                                      &token->make_directory,
+                                                      &token->is_writable);
+       }
+
+       return token->checked_path;
+}
+
 static p11_save_file *
 writer_overwrite_origin (p11_token *token,
                          CK_ATTRIBUTE *origin)
@@ -515,11 +570,50 @@ writer_put_object (p11_save_file *file,
        return CKR_OK;
 }
 
+static bool
+mkdir_with_parents (const char *path)
+{
+       int mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+       char *parent;
+       bool ret;
+
+       if (mkdir (path, mode) == 0)
+               return true;
+
+       switch (errno) {
+       case ENOENT:
+               parent = p11_path_parent (path);
+               if (parent != NULL) {
+                       ret = mkdir_with_parents (parent);
+                       free (parent);
+                       if (ret == true) {
+                               if (mkdir (path, mode) == 0)
+                                       return true;
+                       }
+               }
+               /* fall through */
+       default:
+               p11_message ("couldn't create directory: %s: %s", path, strerror (errno));
+               return false;
+       }
+}
+
 static CK_RV
 on_index_build (void *data,
                 p11_index *index,
-                CK_ATTRIBUTE **attrs,
-                CK_ATTRIBUTE *merge)
+                CK_ATTRIBUTE *attrs,
+                CK_ATTRIBUTE *merge,
+                CK_ATTRIBUTE **extra)
+{
+       p11_token *token = data;
+       return p11_builder_build (token->builder, index, attrs, merge, extra);
+}
+
+static CK_RV
+on_index_store (void *data,
+                p11_index *index,
+                CK_OBJECT_HANDLE handle,
+                CK_ATTRIBUTE **attrs)
 {
        p11_token *token = data;
        CK_OBJECT_HANDLE *other;
@@ -533,14 +627,19 @@ on_index_build (void *data,
        CK_RV rv;
        int i;
 
-       rv = p11_builder_build (token->builder, index, attrs, merge);
-       if (rv != CKR_OK)
-               return rv;
-
        /* Signifies that data is being loaded, don't write out */
        if (p11_index_loading (index))
                return CKR_OK;
 
+       if (!check_token_directory (token))
+               return CKR_FUNCTION_FAILED;
+
+       if (token->make_directory) {
+               if (!mkdir_with_parents (token->path))
+                       return CKR_FUNCTION_FAILED;
+               token->make_directory = false;
+       }
+
        /* Do we already have a filename? */
        origin = p11_attrs_find (*attrs, CKA_X_ORIGIN);
        if (origin == NULL) {
@@ -567,9 +666,11 @@ on_index_build (void *data,
                rv = writer_put_object (file, persist, &buffer, *attrs);
 
        for (i = 0; rv == CKR_OK && other && other[i] != 0; i++) {
-               object = p11_index_lookup (index, other[i]);
-               if (object != NULL && object != *attrs)
-                       rv = writer_put_object (file, persist, &buffer, object);
+               if (other[i] != handle) {
+                       object = p11_index_lookup (index, handle);
+                       if (object != NULL)
+                               rv = writer_put_object (file, persist, &buffer, object);
+               }
        }
 
        p11_buffer_uninit (&buffer);
@@ -632,7 +733,10 @@ p11_token_new (CK_SLOT_ID slot,
        token->builder = p11_builder_new (P11_BUILDER_FLAG_TOKEN);
        return_val_if_fail (token->builder != NULL, NULL);
 
-       token->index = p11_index_new (on_index_build, on_index_notify, token);
+       token->index = p11_index_new (on_index_build,
+                                     on_index_store,
+                                     on_index_notify,
+                                     token);
        return_val_if_fail (token->index != NULL, NULL);
 
        token->parser = p11_parser_new (p11_builder_get_cache (token->builder));
@@ -698,46 +802,10 @@ p11_token_parser (p11_token *token)
        return token->parser;
 }
 
-static bool
-check_writable_directory (const char *path)
-{
-       struct stat sb;
-       char *parent;
-       bool ret;
-
-       if (access (path, W_OK) == 0)
-               return stat (path, &sb) == 0 && S_ISDIR (sb.st_mode);
-
-       switch (errno) {
-       case EACCES:
-               return false;
-       case ENOENT:
-               parent = p11_path_parent (path);
-               if (parent == NULL)
-                       ret = false;
-               else
-                       ret = check_writable_directory (parent);
-               free (parent);
-               return ret;
-       default:
-               p11_message ("couldn't access: %s: %s", path, strerror (errno));
-               return false;
-       }
-}
-
 bool
 p11_token_is_writable (p11_token *token)
 {
-       /*
-        * This function attempts to determine whether a later write
-        * to this token will succeed so we can setup the appropriate
-        * token flags. Yes, it is racy, but that's inherent to the problem.
-        */
-
-       if (!token->checked_writable) {
-               token->is_writable = check_writable_directory (token->path);
-               token->checked_writable = true;
-       }
-
+       if (!check_token_directory (token))
+               return false;
        return token->is_writable;
 }