]> granicus.if.org Git - p11-kit/commitdiff
persist: Support for writing out p11-kit persist files
authorStef Walter <stefw@gnome.org>
Tue, 21 May 2013 19:46:27 +0000 (21:46 +0200)
committerStef Walter <stefw@gnome.org>
Mon, 27 May 2013 08:46:11 +0000 (10:46 +0200)
trust/parser.c
trust/persist.c
trust/persist.h
trust/tests/test-persist.c
trust/tests/test-trust.c

index 7690d6ac47d304cc5529ee96f2fcdb21a4e7541f..21b693b82fef78d2c95eccbcca5ee44e9175d35b 100644 (file)
@@ -675,10 +675,14 @@ parse_p11_kit_persist (p11_parser *parser,
                        const unsigned char *data,
                        size_t length)
 {
+       CK_BBOOL modifiablev = CK_FALSE;
+       CK_ATTRIBUTE *attrs;
        p11_array *objects;
        bool ret;
        int i;
 
+       CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &modifiablev, sizeof (modifiablev) };
+
        if (!p11_persist_magic (data, length))
                return P11_PARSE_UNRECOGNIZED;
 
@@ -692,8 +696,10 @@ parse_p11_kit_persist (p11_parser *parser,
 
        ret = p11_persist_read (parser->persist, parser->basename, data, length, objects);
        if (ret) {
-               for (i = 0; i < objects->num; i++)
-                       sink_object (parser, objects->elem[i]);
+               for (i = 0; i < objects->num; i++) {
+                       attrs = p11_attrs_build (objects->elem[i], &modifiable, NULL);
+                       sink_object (parser, attrs);
+               }
        }
 
        p11_array_free (objects);
index 69af697eb0f6162dab5c2c20389395083d8d8e14..ad80683734daeef2ac25c9a3b35641281aa1fc56 100644 (file)
 #include "lexer.h"
 #include "pem.h"
 #include "persist.h"
+#include "pkcs11.h"
+#include "pkcs11x.h"
 #include "url.h"
 
 #include "basic.asn.h"
 
 #include <libtasn1.h>
 
+#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
 struct _p11_persist {
        p11_dict *constants;
        node_asn *asn1_defs;
-
-       /* Used during parsing */
-       p11_lexer lexer;
-       CK_ATTRIBUTE *attrs;
-       bool result;
-       bool skip;
 };
 
 bool
@@ -127,6 +124,20 @@ parse_string (p11_lexer *lexer,
        return true;
 }
 
+static void
+format_string (CK_ATTRIBUTE *attr,
+               p11_buffer *buf)
+{
+       const unsigned char *value;
+
+       assert (attr->ulValueLen != CK_UNAVAILABLE_INFORMATION);
+
+       p11_buffer_add (buf, "\"", 1);
+       value = attr->pValue;
+       p11_url_encode (value, value + attr->ulValueLen, P11_URL_VERBATIM, buf);
+       p11_buffer_add (buf, "\"", 1);
+}
+
 static bool
 parse_bool (p11_lexer *lexer,
             CK_ATTRIBUTE *attr)
@@ -151,6 +162,56 @@ parse_bool (p11_lexer *lexer,
        return true;
 }
 
+static bool
+format_bool (CK_ATTRIBUTE *attr,
+             p11_buffer *buf)
+{
+       const CK_BBOOL *value;
+
+       if (attr->ulValueLen != sizeof (CK_BBOOL))
+               return false;
+
+       switch (attr->type) {
+       case CKA_TOKEN:
+       case CKA_PRIVATE:
+       case CKA_TRUSTED:
+       case CKA_SENSITIVE:
+       case CKA_ENCRYPT:
+       case CKA_DECRYPT:
+       case CKA_WRAP:
+       case CKA_UNWRAP:
+       case CKA_SIGN:
+       case CKA_SIGN_RECOVER:
+       case CKA_VERIFY:
+       case CKA_VERIFY_RECOVER:
+       case CKA_DERIVE:
+       case CKA_EXTRACTABLE:
+       case CKA_LOCAL:
+       case CKA_NEVER_EXTRACTABLE:
+       case CKA_ALWAYS_SENSITIVE:
+       case CKA_MODIFIABLE:
+       case CKA_SECONDARY_AUTH:
+       case CKA_ALWAYS_AUTHENTICATE:
+       case CKA_WRAP_WITH_TRUSTED:
+       case CKA_RESET_ON_INIT:
+       case CKA_HAS_RESET:
+       case CKA_COLOR:
+               break;
+       default:
+               return false;
+       }
+
+       value = attr->pValue;
+       if (*value == CK_TRUE)
+               p11_buffer_add (buf, "true", -1);
+       else if (*value == CK_FALSE)
+               p11_buffer_add (buf, "false", -1);
+       else
+               return false;
+
+       return true;
+}
+
 static bool
 parse_ulong (p11_lexer *lexer,
              CK_ATTRIBUTE *attr)
@@ -171,6 +232,66 @@ parse_ulong (p11_lexer *lexer,
        return true;
 }
 
+static bool
+format_ulong (CK_ATTRIBUTE *attr,
+              p11_buffer *buf)
+{
+       char string[sizeof (CK_ULONG) * 4];
+       const CK_ULONG *value;
+
+       if (attr->ulValueLen != sizeof (CK_ULONG))
+               return false;
+
+       switch (attr->type) {
+       case CKA_CERTIFICATE_CATEGORY:
+       case CKA_CERTIFICATE_TYPE:
+       case CKA_CLASS:
+       case CKA_JAVA_MIDP_SECURITY_DOMAIN:
+       case CKA_KEY_GEN_MECHANISM:
+       case CKA_KEY_TYPE:
+       case CKA_MECHANISM_TYPE:
+       case CKA_MODULUS_BITS:
+       case CKA_PRIME_BITS:
+       case CKA_SUB_PRIME_BITS:
+       case CKA_VALUE_BITS:
+       case CKA_VALUE_LEN:
+       case CKA_TRUST_DIGITAL_SIGNATURE:
+       case CKA_TRUST_NON_REPUDIATION:
+       case CKA_TRUST_KEY_ENCIPHERMENT:
+       case CKA_TRUST_DATA_ENCIPHERMENT:
+       case CKA_TRUST_KEY_AGREEMENT:
+       case CKA_TRUST_KEY_CERT_SIGN:
+       case CKA_TRUST_CRL_SIGN:
+       case CKA_TRUST_SERVER_AUTH:
+       case CKA_TRUST_CLIENT_AUTH:
+       case CKA_TRUST_CODE_SIGNING:
+       case CKA_TRUST_EMAIL_PROTECTION:
+       case CKA_TRUST_IPSEC_END_SYSTEM:
+       case CKA_TRUST_IPSEC_TUNNEL:
+       case CKA_TRUST_IPSEC_USER:
+       case CKA_TRUST_TIME_STAMPING:
+       case CKA_TRUST_STEP_UP_APPROVED:
+       case CKA_X_ASSERTION_TYPE:
+       case CKA_AUTH_PIN_FLAGS:
+       case CKA_HW_FEATURE_TYPE:
+       case CKA_PIXEL_X:
+       case CKA_PIXEL_Y:
+       case CKA_RESOLUTION:
+       case CKA_CHAR_ROWS:
+       case CKA_CHAR_COLUMNS:
+       case CKA_BITS_PER_PIXEL:
+               break;
+       default:
+               return false;
+       }
+
+       value = attr->pValue;
+       snprintf (string, sizeof (string), "%lu", *value);
+
+       p11_buffer_add (buf, string, -1);
+       return true;
+}
+
 static bool
 parse_constant (p11_persist *persist,
                 p11_lexer *lexer,
@@ -190,6 +311,70 @@ parse_constant (p11_persist *persist,
        return true;
 }
 
+static bool
+format_constant (CK_ATTRIBUTE *attr,
+                 p11_buffer *buf)
+{
+       const p11_constant *table;
+       const CK_ULONG *value;
+       const char *nick;
+
+       if (attr->ulValueLen != sizeof (CK_ULONG))
+               return false;
+
+       switch (attr->type) {
+       case CKA_TRUST_DIGITAL_SIGNATURE:
+       case CKA_TRUST_NON_REPUDIATION:
+       case CKA_TRUST_KEY_ENCIPHERMENT:
+       case CKA_TRUST_DATA_ENCIPHERMENT:
+       case CKA_TRUST_KEY_AGREEMENT:
+       case CKA_TRUST_KEY_CERT_SIGN:
+       case CKA_TRUST_CRL_SIGN:
+       case CKA_TRUST_SERVER_AUTH:
+       case CKA_TRUST_CLIENT_AUTH:
+       case CKA_TRUST_CODE_SIGNING:
+       case CKA_TRUST_EMAIL_PROTECTION:
+       case CKA_TRUST_IPSEC_END_SYSTEM:
+       case CKA_TRUST_IPSEC_TUNNEL:
+       case CKA_TRUST_IPSEC_USER:
+       case CKA_TRUST_TIME_STAMPING:
+               table = p11_constant_trusts;
+               break;
+       case CKA_CLASS:
+               table = p11_constant_classes;
+               break;
+       case CKA_CERTIFICATE_TYPE:
+               table = p11_constant_certs;
+               break;
+       case CKA_KEY_TYPE:
+               table = p11_constant_keys;
+               break;
+       case CKA_X_ASSERTION_TYPE:
+               table = p11_constant_asserts;
+               break;
+       case CKA_CERTIFICATE_CATEGORY:
+               table = p11_constant_categories;
+               break;
+       case CKA_KEY_GEN_MECHANISM:
+       case CKA_MECHANISM_TYPE:
+               table = p11_constant_mechanisms;
+               break;
+       default:
+               table = NULL;
+       };
+
+       if (!table)
+               return false;
+
+       value = attr->pValue;
+       nick = p11_constant_nick (table, *value);
+
+       if (!nick)
+               return false;
+
+       p11_buffer_add (buf, nick, -1);
+       return true;
+}
 
 static bool
 parse_oid (p11_persist *persist,
@@ -248,6 +433,60 @@ parse_oid (p11_persist *persist,
        return true;
 }
 
+static bool
+format_oid (p11_persist *persist,
+            CK_ATTRIBUTE *attr,
+            p11_buffer *buf)
+{
+       char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, };
+       node_asn *asn;
+       char *data;
+       int len;
+       int ret;
+
+       if (attr->type != CKA_OBJECT_ID)
+               return false;
+
+       if (!persist->asn1_defs) {
+               ret = asn1_array2tree (basic_asn1_tab, &persist->asn1_defs, message);
+               if (ret != ASN1_SUCCESS) {
+                       p11_debug_precond ("failed to load BASIC definitions: %s: %s\n",
+                                          asn1_strerror (ret), message);
+                       return false;
+               }
+       }
+
+       ret = asn1_create_element (persist->asn1_defs, "BASIC.ObjectIdentifier", &asn);
+       if (ret != ASN1_SUCCESS) {
+               p11_debug_precond ("failed to create ObjectIdentifier element: %s\n",
+                                  asn1_strerror (ret));
+               return false;
+       }
+
+       ret = asn1_der_decoding (&asn, attr->pValue, attr->ulValueLen, message);
+       if (ret != ASN1_SUCCESS) {
+               p11_debug_precond ("invalid oid value: %s", message);
+               return false;
+       }
+
+       len = 0;
+       ret = asn1_read_value (asn, "", NULL, &len);
+       return_val_if_fail (ret == ASN1_MEM_ERROR, false);
+
+       data = calloc (len + 1, 1);
+       return_val_if_fail (data != NULL, false);
+
+       ret = asn1_read_value (asn, "", data, &len);
+       return_val_if_fail (ret == ASN1_SUCCESS, false);
+
+       asn1_delete_structure (&asn);
+
+       p11_buffer_add (buf, data, len - 1);
+       free (data);
+
+       return true;
+}
+
 static bool
 parse_value (p11_persist *persist,
              p11_lexer *lexer,
@@ -260,16 +499,41 @@ parse_value (p11_persist *persist,
               parse_oid (persist, lexer, attr);
 }
 
+static void
+format_value (p11_persist *persist,
+              CK_ATTRIBUTE *attr,
+              p11_buffer *buf)
+{
+       assert (attr->ulValueLen != CK_UNAVAILABLE_INFORMATION);
+
+       if (format_bool (attr, buf) ||
+           format_constant (attr, buf) ||
+           format_ulong (attr, buf) ||
+           format_oid (persist, attr, buf))
+               return;
+
+       /* Everything else as string */
+       format_string (attr, buf);
+}
+
 static bool
 field_to_attribute (p11_persist *persist,
-                    p11_lexer *lexer)
+                    p11_lexer *lexer,
+                    CK_ATTRIBUTE **attrs)
 {
        CK_ATTRIBUTE attr = { 0, };
+       char *end;
 
-       attr.type = p11_constant_resolve (persist->constants, lexer->tok.field.name);
-       if (attr.type == CKA_INVALID || !p11_constant_name (p11_constant_types, attr.type)) {
-               p11_lexer_msg (lexer, "invalid or unsupported attribute");
-               return false;
+       end = NULL;
+       attr.type = strtoul (lexer->tok.field.name, &end, 10);
+
+       /* Not a valid number value, probably a constant */
+       if (!end || *end != '\0') {
+               attr.type = p11_constant_resolve (persist->constants, lexer->tok.field.name);
+               if (attr.type == CKA_INVALID || !p11_constant_name (p11_constant_types, attr.type)) {
+                       p11_lexer_msg (lexer, "invalid or unsupported attribute");
+                       return false;
+               }
        }
 
        if (!parse_value (persist, lexer, &attr)) {
@@ -277,51 +541,61 @@ field_to_attribute (p11_persist *persist,
                return false;
        }
 
-       persist->attrs = p11_attrs_take (persist->attrs, attr.type,
-                                        attr.pValue, attr.ulValueLen);
+       *attrs = p11_attrs_take (*attrs, attr.type,
+                                attr.pValue, attr.ulValueLen);
        return true;
 }
 
-static void
-on_pem_block (const char *type,
-              const unsigned char *contents,
-              size_t length,
-              void *user_data)
+static CK_ATTRIBUTE *
+certificate_to_attributes (const unsigned char *der,
+                           size_t length)
 {
        CK_OBJECT_CLASS klassv = CKO_CERTIFICATE;
        CK_CERTIFICATE_TYPE x509 = CKC_X_509;
-       CK_BBOOL modifiablev = CK_FALSE;
 
-       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, };
+       CK_ATTRIBUTE value = { CKA_VALUE, (void *)der, length };
+
+       return p11_attrs_build (NULL, &klass, &certificate_type, &value, NULL);
+}
 
-       p11_persist *store = user_data;
+typedef struct {
+       p11_lexer *lexer;
+       CK_ATTRIBUTE *attrs;
+       bool result;
+} parse_block;
+
+static void
+on_pem_block (const char *type,
+              const unsigned char *contents,
+              size_t length,
+              void *user_data)
+{
+       parse_block *pb = user_data;
        CK_ATTRIBUTE *attrs;
 
        if (strcmp (type, "CERTIFICATE") == 0) {
-               value.pValue = (void *)contents;
-               value.ulValueLen = length;
-               attrs = p11_attrs_build (NULL, &klass, &modifiable, &certificate_type, &value, NULL);
-               store->attrs = p11_attrs_merge (store->attrs, attrs, false);
-               store->result = true;
+               attrs = certificate_to_attributes (contents, length);
+               pb->attrs = p11_attrs_merge (pb->attrs, attrs, false);
+               pb->result = true;
 
        } else {
-               p11_lexer_msg (&store->lexer, "unsupported pem block in store");
-               store->result = false;
+               p11_lexer_msg (pb->lexer, "unsupported pem block in store");
+               pb->result = false;
        }
 }
 
 static bool
-pem_to_attributes (p11_persist *store,
-                   p11_lexer *lexer)
+pem_to_attributes (p11_lexer *lexer,
+                   CK_ATTRIBUTE **attrs)
 {
+       parse_block pb = { lexer, *attrs, false };
        unsigned int count;
 
        count = p11_pem_parse (lexer->tok.pem.begin,
                               lexer->tok.pem.length,
-                              on_pem_block, store);
+                              on_pem_block, &pb);
 
        if (count == 0) {
                p11_lexer_msg (lexer, "invalid pem block");
@@ -330,7 +604,8 @@ pem_to_attributes (p11_persist *store,
 
        /* The lexer should have only matched one block */
        return_val_if_fail (count == 1, false);
-       return store->result;
+       *attrs = pb.attrs;
+       return pb.result;
 }
 
 bool
@@ -340,50 +615,53 @@ p11_persist_read (p11_persist *persist,
                   size_t length,
                   p11_array *objects)
 {
-       bool failed = false;
+       p11_lexer lexer;
+       CK_ATTRIBUTE *attrs;
+       bool failed;
+       bool skip;
 
        return_val_if_fail (persist != NULL, false);
        return_val_if_fail (objects != NULL, false);
 
-       persist->skip = false;
-       persist->result = false;
-       persist->attrs = NULL;
+       skip = false;
+       attrs = NULL;
+       failed = false;
 
-       p11_lexer_init (&persist->lexer, filename, (const char *)data, length);
-       while (p11_lexer_next (&persist->lexer, &failed)) {
-               switch (persist->lexer.tok_type) {
+       p11_lexer_init (&lexer, filename, (const char *)data, length);
+       while (p11_lexer_next (&lexer, &failed)) {
+               switch (lexer.tok_type) {
                case TOK_SECTION:
-                       if (persist->attrs && !p11_array_push (objects, persist->attrs))
+                       if (attrs && !p11_array_push (objects, attrs))
                                return_val_if_reached (false);
-                       persist->attrs = NULL;
-                       if (strcmp (persist->lexer.tok.section.name, PERSIST_HEADER) != 0) {
-                               p11_lexer_msg (&persist->lexer, "unrecognized or invalid section header");
-                               persist->skip = true;
+                       attrs = NULL;
+                       if (strcmp (lexer.tok.section.name, PERSIST_HEADER) != 0) {
+                               p11_lexer_msg (&lexer, "unrecognized or invalid section header");
+                               skip = true;
                        } else {
-                               persist->attrs = p11_attrs_build (NULL, NULL);
-                               return_val_if_fail (persist->attrs != NULL, false);
-                               persist->skip = false;
+                               attrs = p11_attrs_build (NULL, NULL);
+                               return_val_if_fail (attrs != NULL, false);
+                               skip = false;
                        }
                        failed = false;
                        break;
                case TOK_FIELD:
-                       if (persist->skip) {
+                       if (skip) {
                                failed = false;
-                       } else if (!persist->attrs) {
-                               p11_lexer_msg (&persist->lexer, "attribute before p11-kit section header");
+                       } else if (!attrs) {
+                               p11_lexer_msg (&lexer, "attribute before p11-kit section header");
                                failed = true;
                        } else {
-                               failed = !field_to_attribute (persist, &persist->lexer);
+                               failed = !field_to_attribute (persist, &lexer, &attrs);
                        }
                        break;
                case TOK_PEM:
-                       if (persist->skip) {
+                       if (skip) {
                                failed = false;
-                       } else if (!persist->attrs) {
-                               p11_lexer_msg (&persist->lexer, "pem block before p11-kit section header");
+                       } else if (!attrs) {
+                               p11_lexer_msg (&lexer, "pem block before p11-kit section header");
                                failed = true;
                        } else {
-                               failed = !pem_to_attributes (persist, &persist->lexer);
+                               failed = !pem_to_attributes (&lexer, &attrs);
                        }
                        break;
                }
@@ -392,10 +670,72 @@ p11_persist_read (p11_persist *persist,
                        break;
        }
 
-       if (persist->attrs && !p11_array_push (objects, persist->attrs))
+       if (attrs && !p11_array_push (objects, attrs))
                return_val_if_reached (false);
-       persist->attrs = NULL;
+       attrs = NULL;
 
-       p11_lexer_done (&persist->lexer);
+       p11_lexer_done (&lexer);
        return !failed;
 }
+
+static CK_ATTRIBUTE *
+find_certificate_value (CK_ATTRIBUTE *attrs)
+{
+       CK_OBJECT_CLASS klass;
+       CK_CERTIFICATE_TYPE type;
+
+       if (!p11_attrs_find_ulong (attrs, CKA_CLASS, &klass) ||
+           klass != CKO_CERTIFICATE)
+               return NULL;
+       if (!p11_attrs_find_ulong (attrs, CKA_CERTIFICATE_TYPE, &type) ||
+           type != CKC_X_509)
+               return NULL;
+       return p11_attrs_find_valid (attrs, CKA_VALUE);
+}
+
+bool
+p11_persist_write (p11_persist *persist,
+                   CK_ATTRIBUTE *attrs,
+                   p11_buffer *buf)
+{
+       char string[sizeof (CK_ULONG) * 4];
+       CK_ATTRIBUTE *cert_value;
+       const char *nick;
+       int i;
+
+       cert_value = find_certificate_value (attrs);
+
+       p11_buffer_add (buf, "[" PERSIST_HEADER "]\n", -1);
+
+       for (i = 0; !p11_attrs_terminator (attrs + i); i++) {
+
+               /* These are written later? */
+               if (cert_value != NULL &&
+                   (attrs[i].type == CKA_CLASS ||
+                    attrs[i].type == CKA_CERTIFICATE_TYPE ||
+                    attrs[i].type == CKA_VALUE))
+                       continue;
+
+               if (attrs[i].ulValueLen == CK_UNAVAILABLE_INFORMATION)
+                       continue;
+
+               nick = p11_constant_nick (p11_constant_types, attrs[i].type);
+               if (nick == NULL) {
+                       snprintf (string, sizeof (string), "%lu", attrs[i].type);
+                       nick = string;
+               }
+
+               p11_buffer_add (buf, nick, -1);
+               p11_buffer_add (buf, ": ", 2);
+               format_value (persist, attrs + i, buf);
+               p11_buffer_add (buf, "\n", 1);
+       }
+
+       if (cert_value != NULL) {
+               if (!p11_pem_write (cert_value->pValue, cert_value->ulValueLen, "CERTIFICATE", buf))
+                       return_val_if_reached (false);
+       }
+
+       p11_buffer_add (buf, "\n", 1);
+       return p11_buffer_ok (buf);
+}
index 04762f4491bb3b5e7f02f7a429390e32b74fce9b..0ef142c04810b6b61a3d2763ad75d70ddcc97a69 100644 (file)
@@ -54,6 +54,10 @@ bool             p11_persist_read   (p11_persist *persist,
                                      size_t length,
                                      p11_array *objects);
 
+bool             p11_persist_write  (p11_persist *persist,
+                                     CK_ATTRIBUTE *object,
+                                     p11_buffer *buf);
+
 void             p11_persist_free   (p11_persist *persist);
 
 #endif /* P11_PERSIST_H_ */
index defeecf195fd2bd494ddcd9d63dd819aaf6c0c67..107f1313dddbdfae4eb450a316925e689eccf66f 100644 (file)
@@ -127,12 +127,44 @@ check_read_msg (const char *file,
        p11_array_free (expected);
 }
 
+static void
+check_write_msg (const char *file,
+                 int line,
+                 const char *function,
+                 const char *expected,
+                 p11_array *input)
+{
+       p11_persist *persist;
+       p11_buffer buf;
+       int i;
+
+       persist = p11_persist_new ();
+       p11_buffer_init_null (&buf, 0);
+
+       for (i = 0; i < input->num; i++) {
+               if (!p11_persist_write (persist, input->elem[i], &buf))
+                       p11_test_fail (file, line, function, "persist write failed");
+       }
+
+       if (strcmp (buf.data, expected) != 0) {
+                p11_test_fail (file, line, function, "persist doesn't match: (\n%s----\n%s\n)", \
+                               expected, (char *)buf.data);
+       }
+
+       p11_buffer_uninit (&buf);
+       p11_array_free (input);
+       p11_persist_free (persist);
+}
+
 #define check_read_success(input, objs) \
        check_read_msg (__FILE__, __LINE__, __FUNCTION__, input, args_to_array objs)
 
 #define check_read_failure(input) \
        check_read_msg (__FILE__, __LINE__, __FUNCTION__, input, NULL)
 
+#define check_write_success(expected, inputs) \
+       check_write_msg (__FILE__, __LINE__, __FUNCTION__, expected, args_to_array inputs)
+
 static CK_OBJECT_CLASS certificate = CKO_CERTIFICATE;
 static CK_CERTIFICATE_TYPE x509 = CKC_X_509;
 static CK_OBJECT_CLASS nss_trust = CKO_NSS_TRUST;
@@ -143,51 +175,53 @@ static CK_BBOOL falsev = CK_FALSE;
 static void
 test_simple (void)
 {
-       const char *input = "[p11-kit-object-v1]\n"
+       const char *output = "[p11-kit-object-v1]\n"
                            "class: data\n"
                            "value: \"blah\"\n"
-                           "application: \"test-persist\"\n";
+                           "application: \"test-persist\"\n\n";
 
-       CK_ATTRIBUTE expected[] = {
+       CK_ATTRIBUTE attrs[] = {
                { CKA_CLASS, &data, sizeof (data) },
                { CKA_VALUE, "blah", 4 },
                { CKA_APPLICATION, "test-persist", 12 },
                { CKA_INVALID },
        };
 
-       check_read_success (input, (expected, NULL));
+       check_read_success (output, (attrs, NULL));
+       check_write_success (output, (attrs, NULL));
 }
 
 static void
 test_number (void)
 {
-       const char *input = "[p11-kit-object-v1]\n"
+       const char *output = "[p11-kit-object-v1]\n"
                            "class: data\n"
-                           "value: 29202390\n"
-                           "application: \"test-persist\"\n";
+                           "value-len: 29202390\n"
+                           "application: \"test-persist\"\n\n";
 
        CK_ULONG value = 29202390;
 
-       CK_ATTRIBUTE expected[] = {
+       CK_ATTRIBUTE attrs[] = {
                { CKA_CLASS, &data, sizeof (data) },
-               { CKA_VALUE, &value, sizeof (value) },
+               { CKA_VALUE_LEN, &value, sizeof (value) },
                { CKA_APPLICATION, "test-persist", 12 },
                { CKA_INVALID },
        };
 
-       check_read_success (input, (expected, NULL));
+       check_read_success (output, (attrs, NULL));
+       check_write_success (output, (attrs, NULL));
 }
 
 static void
 test_bool (void)
 {
-       const char *input = "[p11-kit-object-v1]\n"
+       const char *output = "[p11-kit-object-v1]\n"
                            "class: data\n"
                            "private: true\n"
                            "modifiable: false\n"
-                           "application: \"test-persist\"\n";
+                           "application: \"test-persist\"\n\n";
 
-       CK_ATTRIBUTE expected[] = {
+       CK_ATTRIBUTE attrs[] = {
                { CKA_CLASS, &data, sizeof (data) },
                { CKA_PRIVATE, &truev, sizeof (truev) },
                { CKA_MODIFIABLE, &falsev, sizeof (falsev) },
@@ -195,72 +229,143 @@ test_bool (void)
                { CKA_INVALID },
        };
 
-       check_read_success (input, (expected, NULL));
+       check_read_success (output, (attrs, NULL));
+       check_write_success (output, (attrs, NULL));
 }
 
 static void
 test_oid (void)
 {
-       const char *input = "[p11-kit-object-v1]\n"
+       const char *output = "[p11-kit-object-v1]\n"
                            "class: data\n"
-                           "object-id: 1.2.3.4";
+                           "object-id: 1.2.3.4\n\n";
 
-       CK_ATTRIBUTE expected[] = {
+       CK_ATTRIBUTE attrs[] = {
                { CKA_CLASS, &data, sizeof (data) },
                { CKA_OBJECT_ID, "\x06\x03*\x03\x04", 5 },
                { CKA_INVALID },
        };
 
-       check_read_success (input, (expected, NULL));
+       check_read_success (output, (attrs, NULL));
+       check_write_success (output, (attrs, NULL));
 }
 
 static void
 test_constant (void)
 {
-       const char *input = "[p11-kit-object-v1]\n"
+       const char *output = "[p11-kit-object-v1]\n"
                            "class: data\n"
-                           "trust-server-auth: nss-trust-unknown";
+                           "certificate-type: x-509-attr-cert\n"
+                           "key-type: rsa\n"
+                           "x-assertion-type: x-pinned-certificate\n"
+                           "certificate-category: authority\n"
+                           "mechanism-type: rsa-pkcs-key-pair-gen\n"
+                           "trust-server-auth: nss-trust-unknown\n\n";
 
        CK_TRUST trust = CKT_NSS_TRUST_UNKNOWN;
+       CK_CERTIFICATE_TYPE type = CKC_X_509_ATTR_CERT;
+       CK_X_ASSERTION_TYPE ass = CKT_X_PINNED_CERTIFICATE;
+       CK_MECHANISM_TYPE mech = CKM_RSA_PKCS_KEY_PAIR_GEN;
+       CK_ULONG category = 2;
+       CK_KEY_TYPE key = CKK_RSA;
 
-       CK_ATTRIBUTE expected[] = {
+       CK_ATTRIBUTE attrs[] = {
                { CKA_CLASS, &data, sizeof (data) },
+               { CKA_CERTIFICATE_TYPE, &type, sizeof (type) },
+               { CKA_KEY_TYPE, &key, sizeof (key) },
+               { CKA_X_ASSERTION_TYPE, &ass, sizeof (ass) },
+               { CKA_CERTIFICATE_CATEGORY, &category, sizeof (category) },
+               { CKA_MECHANISM_TYPE, &mech, sizeof (mech) },
                { CKA_TRUST_SERVER_AUTH, &trust, sizeof (trust) },
                { CKA_INVALID },
        };
 
-       check_read_success (input, (expected, NULL));
+       check_read_success (output, (attrs, NULL));
+       check_write_success (output, (attrs, NULL));
+}
+
+static void
+test_unknown (void)
+{
+       const char *output = "[p11-kit-object-v1]\n"
+                           "class: data\n"
+                           "38383838: \"the-value-here\"\n\n";
+
+       CK_ATTRIBUTE attrs[] = {
+               { CKA_CLASS, &data, sizeof (data) },
+               { 38383838, "the-value-here", 14 },
+               { CKA_INVALID },
+       };
+
+       check_read_success (output, (attrs, NULL));
+       check_write_success (output, (attrs, NULL));
 }
 
 static void
 test_multiple (void)
 {
-       const char *input = "[p11-kit-object-v1]\n"
+       const char *output = "[p11-kit-object-v1]\n"
                            "class: data\n"
-                           "object-id: 1.2.3.4\n"
+                           "object-id: 1.2.3.4\n\n"
                            "[p11-kit-object-v1]\n"
                            "class: nss-trust\n"
-                           "trust-server-auth: nss-trust-unknown";
+                           "trust-server-auth: nss-trust-unknown\n\n";
 
        CK_TRUST trust = CKT_NSS_TRUST_UNKNOWN;
 
-       CK_ATTRIBUTE expected1[] = {
+       CK_ATTRIBUTE attrs1[] = {
                { CKA_CLASS, &data, sizeof (data) },
                { CKA_OBJECT_ID, "\x06\x03*\x03\x04", 5 },
                { CKA_INVALID },
        };
 
-       CK_ATTRIBUTE expected2[] = {
+       CK_ATTRIBUTE attrs2[] = {
                { CKA_CLASS, &nss_trust, sizeof (nss_trust) },
                { CKA_TRUST_SERVER_AUTH, &trust, sizeof (trust) },
                { CKA_INVALID },
        };
 
-       check_read_success (input, (expected1, expected2, NULL));
+       check_read_success (output, (attrs1, attrs2, NULL));
+       check_write_success (output, (attrs1, attrs2, NULL));
 }
 
 static void
 test_pem_block (void)
+{
+       const char *output = "[p11-kit-object-v1]\n"
+                           "id: \"292c92\"\n"
+                           "trusted: true\n"
+           "-----BEGIN CERTIFICATE-----\n"
+           "MIICPDCCAaUCED9pHoGc8JpK83P/uUii5N0wDQYJKoZIhvcNAQEFBQAwXzELMAkG\n"
+           "A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz\n"
+           "cyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2\n"
+           "MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV\n"
+           "BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAxIFB1YmxpYyBQcmlt\n"
+           "YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN\n"
+           "ADCBiQKBgQDlGb9to1ZhLZlIcfZn3rmN67eehoAKkQ76OCWvRoiC5XOooJskXQ0f\n"
+           "zGVuDLDQVoQYh5oGmxChc9+0WDlrbsH2FdWoqD+qEgaNMax/sDTXjzRniAnNFBHi\n"
+           "TkVWaR94AoDa3EeRKbs2yWNcxeDXLYd7obcysHswuiovMaruo2fa2wIDAQABMA0G\n"
+           "CSqGSIb3DQEBBQUAA4GBAFgVKTk8d6PaXCUDfGD67gmZPCcQcMgMCeazh88K4hiW\n"
+           "NWLMv5sneYlfycQJ9M61Hd8qveXbhpxoJeUwfLaJFf5n0a3hUKw8fGJLj7qE1xIV\n"
+           "Gx/KXQ/BUpQqEZnae88MNhPVNdwQGVnqlMEAv3WP2fr9dgTbYruQagPZRjXZ+Hxb\n"
+           "-----END CERTIFICATE-----\n"
+                           "\n";
+
+       CK_ATTRIBUTE attrs[] = {
+               { CKA_CLASS, &certificate, sizeof (certificate) },
+               { CKA_ID, "292c92", 6, },
+               { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) },
+               { CKA_VALUE, &verisign_v1_ca, sizeof (verisign_v1_ca) },
+               { CKA_TRUSTED, &truev, sizeof (truev) },
+               { CKA_INVALID },
+       };
+
+       check_read_success (output, (attrs, NULL));
+       check_write_success (output, (attrs, NULL));
+}
+
+static void
+test_pem_middle (void)
 {
        const char *input = "[p11-kit-object-v1]\n"
                            "class: certificate\n"
@@ -436,6 +541,44 @@ test_attribute_first (void)
        p11_message_loud ();
 }
 
+static void
+test_not_boolean (void)
+{
+       const char *output = "[p11-kit-object-v1]\n"
+                           "private: \"x\"\n\n";
+
+       CK_ATTRIBUTE attrs[] = {
+               { CKA_PRIVATE, "x", 1 },
+               { CKA_INVALID },
+       };
+
+       check_write_success (output, (attrs, NULL));
+}
+
+static void
+test_not_ulong (void)
+{
+       char buffer[sizeof (CK_ULONG) + 1];
+       char *output;
+
+       CK_ATTRIBUTE attrs[] = {
+               { CKA_BITS_PER_PIXEL, "xx", 2 },
+               { CKA_VALUE, buffer, sizeof (CK_ULONG) },
+               { CKA_INVALID },
+       };
+
+       memset (buffer, 'x', sizeof (buffer));
+       buffer[sizeof (CK_ULONG)] = 0;
+
+       if (asprintf (&output, "[p11-kit-object-v1]\n"
+                              "bits-per-pixel: \"xx\"\n"
+                              "value: \"%s\"\n\n", buffer) < 0)
+               assert_not_reached ();
+
+       check_write_success (output, (attrs, NULL));
+       free (output);
+}
+
 int
 main (int argc,
       char *argv[])
@@ -446,8 +589,10 @@ main (int argc,
        p11_test (test_bool, "/persist/bool");
        p11_test (test_oid, "/persist/oid");
        p11_test (test_constant, "/persist/constant");
+       p11_test (test_unknown, "/persist/unknown");
        p11_test (test_multiple, "/persist/multiple");
        p11_test (test_pem_block, "/persist/pem_block");
+       p11_test (test_pem_middle, "/persist/pem-middle");
        p11_test (test_pem_invalid, "/persist/pem_invalid");
        p11_test (test_pem_unsupported, "/persist/pem_unsupported");
        p11_test (test_pem_first, "/persist/pem_first");
@@ -456,5 +601,7 @@ main (int argc,
        p11_test (test_bad_field, "/persist/bad_field");
        p11_test (test_skip_unknown, "/persist/skip_unknown");
        p11_test (test_attribute_first, "/persist/attribute_first");
+       p11_test (test_not_boolean, "/persist/not-boolean");
+       p11_test (test_not_ulong, "/persist/not-ulong");
        return p11_test_run (argc, argv);
 }
index 6b990dc3af2d2ff4293785dffee988f1993d4467..6a2294629106f248ed64c0978bb8fba2ec8f9e76 100644 (file)
@@ -147,6 +147,6 @@ test_check_attr_msg (const char *file,
                p11_test_fail (file, line, function,
                               "attribute does not match: (expected %s but found %s)",
                               p11_attr_to_string (expected, klass),
-                              p11_attr_to_string (attr, klass));
+                              attr ? p11_attr_to_string (attr, klass) : "(null)");
        }
 }