[Cryptech-Commits] [user/sra/pkcs11] 01/02: First public commit of PKCS #11 implementation.
git at cryptech.is
git at cryptech.is
Tue Apr 28 22:32:31 UTC 2015
This is an automated email from the git hooks/post-receive script.
sra at hactrn.net pushed a commit to branch master
in repository user/sra/pkcs11.
commit 0c8d1d765783bbc09cc1ca63ffdd233f0ce31613
Author: Rob Austein <sra at hactrn.net>
Date: Tue Apr 28 15:29:12 2015 -0400
First public commit of PKCS #11 implementation.
---
.gitignore | 9 +
GNUmakefile | 63 +
README.md | 153 ++
attributes.yaml | 646 +++++++
pkcs11.c | 3802 +++++++++++++++++++++++++++++++++++++
pkcs11.h | 301 +++
pkcs11f.h | 912 +++++++++
pkcs11t.h | 1789 +++++++++++++++++
schema.sql | 117 ++
scripts/build-attributes | 403 ++++
scripts/convert-schema.sed | 66 +
scripts/format-attribute-comments | 85 +
scripts/test-hsmcheck | 180 ++
13 files changed, 8526 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d3522c6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+*.[oa]
+*.l[oa]
+*.so
+*.so.*
+*~
+.libs
+TAGS
+attributes.h
+schema.h
diff --git a/GNUmakefile b/GNUmakefile
new file mode 100644
index 0000000..a12aaa5
--- /dev/null
+++ b/GNUmakefile
@@ -0,0 +1,63 @@
+# (GNU) Makefile for Cryptech PKCS #11 implementation.
+#
+# Author: Rob Austein
+# Copyright (c) 2015, SUNET
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+CRYPTLIB_DIR = ../cryptlib/build
+SQLITE3_DIR = ../sqlite3
+
+CFLAGS += -g -I${CRYPTLIB_DIR} -I${SQLITE3_DIR} -fPIC -DENABLE_CRYPTLIB_DEVICE=0 -Wall
+LIBS := ${CRYPTLIB_DIR}/libcl.a ${SQLITE3_DIR}/libsqlite3.a
+
+all: libpkcs11.so
+
+clean:
+ rm -rf pkcs11.o pkcs11.so libpkcs11.so* schema.h attributes.h
+
+distclean: clean
+ rm -f TAGS
+
+schema.h: schema.sql scripts/convert-schema.sed GNUmakefile
+ sed -f scripts/convert-schema.sed <schema.sql >schema.h
+
+attributes.h: attributes.yaml scripts/build-attributes GNUmakefile
+ python scripts/build-attributes attributes.yaml attributes.h
+
+pkcs11.o: pkcs11.c schema.h attributes.h
+ ${CC} ${CFLAGS} -c $<
+
+pkcs11.so: pkcs11.o ${LIBS}
+ ${CC} -shared -o $@ -Wl,-Bsymbolic-functions -Wl,-Bsymbolic -Wl,-z,noexecstack -g $^
+
+libpkcs11.so: pkcs11.so
+ objcopy -w -G 'C_*' $< $@
+
+tags: TAGS
+
+TAGS: *.[ch] ${CRYPTLIB_DIR}/cryptlib.h ${SQLITE3_DIR}/sqlite3.h
+ etags $^
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..be84f6b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,153 @@
+PKCS #11
+========
+
+## Introduction ##
+
+This is an implementation of the [PKCS11][] API for the [Cryptech][]
+project. Like most PKCS #11 implementations, this one is incomplete
+and probably always will be: PKCS #11 is very open-ended, and the
+specification includes enough rope for an unwary developer to hang not
+only himself, but all of his friends, relations, and casual
+acquaintances.
+
+
+## Novel design features ##
+
+[PKCS11][]'s data model involves an n-level-deep hierarchy of object
+classes, which is somewhat tedious to implement correctly in C,
+particularly if one wants the correspondence between specification and
+code to be at all obvious. In order to automate much of the drudge
+work involved, this implementation uses an external representation of
+the object class hierarchy, which is processed at compile time by a
+Python script to generate tables which drive the C code which performs
+the necessary type checking.
+
+
+## Current status ##
+
+As of this writing, the implementation supports only the RSA, SHA-1,
+and SHA-2 algorithms, but the design is intended to be extensible.
+
+Underlying cryptographic support is via [Cryptlib][], which may need
+to change (more on this below).
+
+The object store is currently implemented using [SQLite3][], which may
+also need to change (more on this below too).
+
+Testing to date has been done using the `bin/pkcs11/` tools from the
+BIND9 distribution and the `hsmcheck` tool from the OpenDNSSEC
+distribution. Beyond the test results (such as they are) reported by
+these tools, the primary test of whether the PKCS #11 code is working
+as expected has been validation of the signed DNSSEC data generated by
+`hsmcheck -s`, via a script using [DNSPython][].
+
+In a nutshell, the current state is that the code runs without
+throwing any obvious errors, and generates what DNSPython thinks are
+good signatures. Much more testing will be required, by a much wider
+variety of test tools.
+
+
+## Open issues ##
+
+Two critical design choices in this software were made with full
+knowledge that we might need to change them later:
+
+* The use of Cryptlib as a provider for the underlying cryptographic
+ operations, and
+
+* The use of SQLite3 as the object store.
+
+
+### Cryptlib ###
+
+[Cryptlib][] is a very nice piece of software, but it's not really
+designed for use under something like [PKCS11][]. It seemed worth a
+try anyway, because it would have been nice to be able to use
+Cryptlib's RPC mechanism, take advantage of Cryptlib's rule-based data
+protection system, and so forth, but implementing PKCS #11 requires
+doing various things which Cryptlib quite correctly discourages. So,
+not a perfect fit.
+
+The current code works with Cryptlib's software RSA implementation,
+primarily due to an oddity of RSA: once one has handled the PKCS #1.5
+padding, the RSA signature and decryption (sic) operations are
+mathematically identical. Fine so far as this goes, but:
+
+* This probably does not hold for other signature algorithms (well,
+ the math certainly does not, I haven't yet investigated what the
+ Cryptlib API does if one attempts to "decrypt" using an ECDSA key);
+ and
+
+* The Cryptlib manual says that there are some extra protections
+ around keys stored in hardware devices that would forbid using this
+ trick with an FPGA implementation of RSA.
+
+The latter (extra protections) is probably something we could work
+around if necessary, but the former may make this a moot point.
+
+All of the above notwithstanding, Cryptlib was a reasonable choice for
+the initial implementation, as we had no FPGA RSA to work with and
+needed to develop with *something*. Surprisingly little effort has
+gone into Cryptlib-specific code (probably less than would have been
+required with, eg, OpenSSL, because the Cryptlib API is cleaner).
+
+Bottom line: we haven't lost anything by this approach, we're just not
+done yet.
+
+There are a few other issues with using Cryptlib in this context which
+I will detail if they become relevant, but I'll skip them for now
+since I don't think they'll end up being relevant here.
+
+
+### SQLite3 ###
+
+The choice of [SQLite3][] for the data store was made with several
+factors in mind:
+
+* Relative ease of development (it's all just SQL schemas and queries);
+
+* Relative ease of data normalization (foreign key constraints,
+ etcetera) and debugging (command line tool available for arbitrary
+ direct queries against stored data);
+
+* Licensing (SQLite3 is explictly public domain);
+
+* Support for embedded systems; and
+
+* Surprisingly small object code size (everything I found that was
+ significantly smaller had license issues, eg, gdbm).
+
+Overall, this has worked relatively well, but it's not necessarily
+what we want in the long run: it fails the minimum complexity test,
+and at least in the current implementation requires two separate kinds
+of storage, one for keys (currently a PKCS #15 keyring) and one for
+attributes (the SQLite3 database).
+
+The current implementation keeps much of the SQL data in an in-memory
+database: only "token objects" are stored in on disk. This matches
+the required PKCS #11 semantics, and using the same mechanism to
+handle both session objects and token objects simplifies the code
+considerably, but it does mean that much of the SQL code is really
+just dealing with a weird encoding of in-memory data structures.
+
+At this point the schema may be stable enough that it would make sense
+to consider reimplementing without SQL. It's not urgent as long as
+we're just doing proof-of-concept work, but is something we should
+consider seriously before deciding that this is ready for "production"
+status.
+
+
+## Copyright status ##
+
+The [PKCS11][] header files are "derived from the RSA Security Inc.
+PKCS #11 Cryptographic Token Interface (Cryptoki)". See the
+`pkcs11*.h` header files for details.
+
+Code written for the [Cryptech][] project is under the usual Cryptech
+BSD-style license.
+
+[PKCS11]: http://www.cryptsoft.com/pkcs11doc/STANDARD/ "PKCS #11"
+[Cryptlib]: https://www.cs.auckland.ac.nz/~pgut001/cryptlib/ "Cryptlib"
+[SQLite3]: https://www.sqlite.org/ "SQLite3"
+[DNSPython]: http://www.dnspython.org/ "DNSPython"
+[Cryptech]: https://cryptech.is/ "Cryptech"
diff --git a/attributes.yaml b/attributes.yaml
new file mode 100644
index 0000000..ad7a9b6
--- /dev/null
+++ b/attributes.yaml
@@ -0,0 +1,646 @@
+########################################################################
+#
+# PKCS #11 attribute definitions.
+#
+# The architecture of PKCS #11 is heavily based on an n-level-deep
+# object inheritance hierarcy. Concrete object types inherit
+# attribute definitions, default values, usage constraints etc from
+# abstract types. Fine if one happens to be writing in a language
+# that supports this, but C doesn't, and C++ is an abomination.
+#
+# So we handle all this inheritance-related fun here, by specifying
+# object types and attributes in a (relatively) readable way and using
+# a Python script to translate from this into "descriptors" (read-only
+# C tables) we can use to automate some of the most tedious attribute
+# checking in the C code.
+#
+# A secondary goal is to provide enough of a machine-readable
+# description of the PKCS #11 object hierarchy that we can use it to
+# drive automated test scripts, but that's not implemented yet.
+#
+# The base language here is YAML, with a somewhat ad-hoc data layout
+# on top of it. The exact semantics are a bit of a moving target, but
+# the overall layout is:
+#
+# - The top-level data object is a YAML sequence (indicated in YAML by
+# the leading "- " marker, converts to Python list).
+#
+# - Each entry in the sequence describes one object, represented as a
+# YAML mapping (converts to Python dict). Each object description
+# has at least one required field ("name"), several optional fields,
+# and one or more attribute descriptions.
+#
+# - An attribute description is a YAML mapping (Python dict)
+# containing one or more fields describing the attribute.
+#
+# So the overall structure is a sequence of maps of maps.
+#
+# Attribute definitions within the hierarchy are combined, so that,
+# eg, the "rsa_public_key" type inherits the CKA_CLASS definition from
+# the the root object type, the CKA_KEY_TYPE definition from the "key"
+# type, a value of CKO_PUBLIC_KEY for the CKA_CLASS from the
+# "public_key" type, and provides its own value of CKK_RSA for the
+# CKA_KEY_TYPE.
+#
+# No doubt the error checking in the Python script could become much
+# more rigorous than it is now.
+#
+########################################################################
+#
+# Currently-defined object fields:
+#
+# - "name": String, required. Name of this object class. For
+# concrete object types, this controls the name of the corresponding
+# C descriptor.
+#
+# - "concrete": Boolean, optional, default false. If true, this
+# object type should generate a C descriptor.
+#
+# - "superclass": String, optional but present for all but one type.
+# Contains name of parent type.
+#
+# New object fields may be defined at a later date as needed.
+#
+# Any entry in an object mapping whose key starts with "CKA_" is
+# assumed to be an attribute description.
+#
+# Keys in an object mapping which do not start with CKA_ and are not
+# known object fields should result in an error during parsing.
+#
+########################################################################
+#
+# Currently-defined attribute fields:
+#
+# - "type": a PKCS #11 type name (CK_*) or one of a few other types
+# described in the PKCS #11 specification: "rfc2279string",
+# "biginteger", or "bytearray".
+#
+# - "default": data-value (see below) to be used as default if neither
+# the application template nor the PKCS #11 software itself
+# supplies an explicit value. As a special case, the null string
+# ("") means that the default value of the attribute is empty (this
+# is allowed for a few rfc2279string attributes such as CKA_LABEL).
+#
+# - "value": data-value (see below) for this field. If the
+# application specifies a value for this attribute, it must match;
+# otherwise, behaves like default. The special handling of the null
+# string ("") used with default does not apply here.
+#
+# - "footnotes": Sequence (Python list) of integers in the range 1-12.
+# If present, this indicates that the attribute's definition in the
+# PKCS #11 specification has been tagged with the listed footnote
+# numbers from the "common footnotes" in "Table 15" of the
+# specification. These footnotes specify various constraints on the
+# attributes behavior, and the Python script translates them into
+# flags with more meaningful names, but since the specification
+# itself is written in terms of these silly footnote numbers, using
+# the footnote numbers in the YAML makes it easier to check the
+# attribute descriptions in the YAML against the specification.
+#
+# - "unimplemented": boolean, default false. If true, the attribute
+# is known to be in the specification but is not (yet?) supported by
+# the Python script and the C code. This flag is set on a small
+# number of relatively obscure attributes whose internal structure
+# makes them tedious to represent in the attribute database; this is
+# a placeholder for attributes which should be implemented
+# eventually but which were not deemed to be on the critical path.
+#
+# As with object mappings, attribute mappings with unrecognized keys
+# should result in an error during parsing.
+#
+# "data-value" fields ("default" and "value") in an attribute can take
+# one of several forms:
+#
+# - A string value naming a PKCS #11 constant (eg, CK_TRUE);
+#
+# - A sequence of eight bit unsigned numeric values (ie, bytes)
+# specifying a literal value; or
+#
+# - An integer (Python long) specifying a numeric value for a
+# biginteger field, to be converted into a literal value using the
+# smallest possible number of bytes.
+#
+########################################################################
+#
+# Author: Rob Austein
+# Copyright (c) 2015, SUNET
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+########################################################################
+
+###
+# Root of the object tree
+###
+
+- name: object
+
+ CKA_CLASS:
+ footnotes: [1]
+ type: CK_OBJECT_CLASS
+
+###
+# Storage objects
+###
+
+- name: storage
+ superclass: object
+
+ CKA_TOKEN:
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_PRIVATE:
+ type: CK_BBOOL
+ default: CK_TRUE
+
+ CKA_MODIFIABLE:
+ type: CK_BBOOL
+ default: CK_TRUE
+
+ CKA_LABEL:
+ type: rfc2279string
+ default: ""
+
+###
+# Data objects
+###
+
+- name: data
+ superclass: storage
+
+ CKA_CLASS:
+ value: CKO_DATA
+
+ CKA_APPLICATION:
+ type: rfc2279string
+ default: ""
+
+ CKA_OBJECT_ID:
+ type: bytearray
+ default: ""
+
+ CKA_VALUE:
+ type: bytearray
+ default: ""
+
+###
+# Certificate objects
+###
+
+- name: certificate
+ superclass: storage
+
+ CKA_CLASS:
+ value: CKO_CERTIFICATE
+
+ CKA_CERTIFICATE_TYPE:
+ footnotes: [1]
+ type: CK_CERTIFICATE_TYPE
+
+ CKA_TRUSTED:
+ footnotes: [10]
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_CERTIFICATE_CATEGORY:
+ type: CK_ULONG
+ default: 0
+
+ CKA_CHECK_VALUE:
+ type: bytearray
+
+ CKA_START_DATE:
+ type: CK_DATE
+ default: ""
+
+ CKA_END_DATE:
+ type: CK_DATE
+ default: ""
+
+###
+# X.509 public key certificate objects
+###
+
+# NB: For some reason, numeric footnotes in the table describing X.509
+# certificate attributes are NOT the common attribute footnotes
+# from Table 15. Be careful!
+
+- name: x509_public_key_certificate
+ superclass: certificate
+
+ CKA_SUBJECT:
+ type: bytearray
+
+ CKA_ID:
+ type: bytearray
+ default: ""
+
+ CKA_ISSUER:
+ type: bytearray
+ default: ""
+
+ CKA_SERIAL_NUMBER:
+ type: bytearray
+ default: ""
+
+ CKA_VALUE:
+ type: bytearray
+
+ CKA_URL:
+ type: rfc2279string
+ default: ""
+
+ CKA_HASH_OF_SUBJECT_PUBLIC_KEY:
+ type: bytearray
+ default: ""
+
+ CKA_HASH_OF_ISSUER_PUBLIC_KEY:
+ type: bytearray
+ default: ""
+
+ CKA_JAVA_MIDP_SECURITY_DOMAIN:
+ type: CK_ULONG
+ default: 0
+
+ CKA_NAME_HASH_ALGORITHM:
+ type: CK_MECHANISM_TYPE
+ default: CKM_SHA_1
+
+###
+# Key objects
+###
+
+- name: key
+ superclass: storage
+
+ CKA_KEY_TYPE:
+ footnotes: [1, 5]
+ type: CK_KEY_TYPE
+
+ CKA_ID:
+ footnotes: [8]
+ type: bytearray
+ default: ""
+
+ CKA_START_DATE:
+ footnotes: [8]
+ type: CK_DATE
+ default: ""
+
+ CKA_END_DATE:
+ footnotes: [8]
+ type: CK_DATE
+ default: ""
+
+ CKA_DERIVE:
+ footnotes: [8]
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_LOCAL:
+ footnotes: [2, 4, 6]
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_KEY_GEN_MECHANISM:
+ footnotes: [2, 4, 6]
+ type: CK_MECHANISM_TYPE
+ default: CK_UNAVAILABLE_INFORMATION
+
+ CKA_ALLOWED_MECHANISMS:
+ unimplemented: true
+
+###
+# Public key objects
+###
+
+- name: public_key
+ superclass: key
+
+ CKA_CLASS:
+ value: CKO_PUBLIC_KEY
+
+ CKA_SUBJECT:
+ footnotes: [8]
+ type: bytearray
+ default: ""
+
+ CKA_ENCRYPT:
+ footnotes: [8, 9]
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_VERIFY:
+ footnotes: [8, 9]
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_VERIFY_RECOVER:
+ footnotes: [8, 9]
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_WRAP:
+ footnotes: [8, 9]
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_TRUSTED:
+ footnotes: [10]
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_WRAP_TEMPLATE:
+ unimplemented: true
+
+###
+# Private key objects
+###
+
+- name: private_key
+ superclass: key
+
+ CKA_CLASS:
+ value: CKO_PRIVATE_KEY
+
+ CKA_SUBJECT:
+ footnotes: [8]
+ type: bytearray
+ default: ""
+
+ CKA_SENSITIVE:
+ footnotes: [8, 9, 11]
+ type: CK_BBOOL
+ default: CK_TRUE
+
+ CKA_DECRYPT:
+ footnotes: [8, 9]
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_SIGN:
+ footnotes: [8, 9]
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_SIGN_RECOVER:
+ footnotes: [8, 9]
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_UNWRAP:
+ footnotes: [8, 9]
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_EXTRACTABLE:
+ footnotes: [8, 9, 12]
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_ALWAYS_SENSITIVE:
+ footnotes: [2, 4, 6]
+ type: CK_BBOOL
+
+ CKA_NEVER_EXTRACTABLE:
+ footnotes: [2, 4, 6]
+ type: CK_BBOOL
+
+ CKA_WRAP_WITH_TRUSTED:
+ footnotes: [11]
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_UNWRAP_TEMPLATE:
+ unimplemented: true
+
+###
+# Secret key objects
+###
+
+- name: secret_key
+ superclass: key
+
+ CKA_CLASS:
+ value: CKO_SECRET_KEY
+
+ CKA_SENSITIVE:
+ footnotes: [8, 11]
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_ENCRYPT:
+ footnotes: [8, 9]
+ type: CK_BBOOL
+
+ CKA_DECRYPT:
+ footnotes: [8, 9]
+ type: CK_BBOOL
+
+ CKA_SIGN:
+ footnotes: [8, 9]
+ type: CK_BBOOL
+
+ CKA_VERIFY:
+ footnotes: [8, 9]
+ type: CK_BBOOL
+
+ CKA_WRAP:
+ footnotes: [8, 9]
+ type: CK_BBOOL
+
+ CKA_UNWRAP:
+ footnotes: [8, 9]
+ type: CK_BBOOL
+
+ CKA_EXTRACTABLE:
+ footnotes: [8, 9, 12]
+ type: CK_BBOOL
+
+ CKA_ALWAYS_SENSITIVE:
+ footnotes: [2, 4, 6]
+ type: CK_BBOOL
+
+ CKA_NEVER_EXTRACTABLE:
+ footnotes: [2, 4, 6]
+ type: CK_BBOOL
+
+ CKA_CHECK_VALUE:
+ type: bytearray
+
+ CKA_WRAP_WITH_TRUSTED:
+ footnotes: [11]
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_TRUSTED:
+ footnotes: [10]
+ type: CK_BBOOL
+ default: CK_FALSE
+
+ CKA_WRAP_TEMPLATE:
+ unimplemented: true
+
+ CKA_UNWRAP_TEMPLATE:
+ unimplemented: true
+
+###
+# Domain parameter objects
+###
+
+- name: domain_parameters
+ superclass: storage
+
+ CKA_CLASS:
+ value: CKO_DOMAIN_PARAMETERS
+
+ CKA_KEY_TYPE:
+ footnotes: [1]
+ type: CK_KEY_TYPE
+
+ CKA_LOCAL:
+ footnotes: [2, 4]
+ type: CK_BBOOL
+
+###
+# Mechanism objects
+###
+
+- name: mechanism
+ superclass: object
+
+ CKA_CLASS:
+ value: CKO_MECHANISM_INFO
+
+ CKA_MECHANISM_TYPE:
+ type: CK_MECHANISM_TYPE
+
+###
+# RSA public key objects
+###
+
+- name: rsa_public_key
+ superclass: public_key
+ concrete: true
+
+ CKA_KEY_TYPE:
+ value: CKK_RSA
+
+ CKA_MODULUS:
+ footnotes: [1, 4]
+ type: biginteger
+
+ CKA_MODULUS_BITS:
+ footnotes: [2, 3]
+ type: CK_ULONG
+
+ CKA_PUBLIC_EXPONENT:
+ footnotes: [1]
+ type: biginteger
+ value: 0x10001 # We only allow F4 as public exponent
+
+###
+# RSA private key objects
+###
+
+- name: rsa_private_key
+ superclass: private_key
+ concrete: true
+
+ CKA_KEY_TYPE:
+ value: CKK_RSA
+
+ CKA_MODULUS:
+ footnotes: [1, 4, 6]
+ type: biginteger
+
+ CKA_PUBLIC_EXPONENT:
+ footnotes: [4, 6]
+ type: biginteger
+ value: 0x10001 # We only allow F4 as public exponent
+
+ CKA_PRIVATE_EXPONENT:
+ footnotes: [1, 4, 6, 7]
+ type: biginteger
+
+ CKA_PRIME_1:
+ footnotes: [4, 6, 7]
+ type: biginteger
+
+ CKA_PRIME_2:
+ footnotes: [4, 6, 7]
+ type: biginteger
+
+ CKA_EXPONENT_1:
+ footnotes: [4, 6, 7]
+ type: biginteger
+
+ CKA_EXPONENT_2:
+ footnotes: [4, 6, 7]
+ type: biginteger
+
+ CKA_COEFFICIENT:
+ footnotes: [4, 6, 7]
+ type: biginteger
+
+###
+# Eliptic curve public key objects
+###
+
+- name: ec_public_key
+ superclass: public_key
+ concrete: true
+
+ CKA_KEY_TYPE:
+ value: CKK_EC
+
+ CKA_EC_PARAMS:
+ footnotes: [1, 3]
+ type: bytearray
+
+ CKA_EC_POINT:
+ footnotes: [1, 4]
+ type: bytearray
+
+###
+# Elliptic curve private key objects
+###
+
+- name: ec_private_key
+ superclass: private_key
+ concrete: true
+
+ CKA_KEY_TYPE:
+ value: CKK_EC
+
+ CKA_EC_PARAMS:
+ footnotes: [1, 4, 6]
+ type: bytearray
+
+ CKA_VALUE:
+ footnotes: [1, 4, 6, 7]
+ type: biginteger
diff --git a/pkcs11.c b/pkcs11.c
new file mode 100644
index 0000000..5b7576f
--- /dev/null
+++ b/pkcs11.c
@@ -0,0 +1,3802 @@
+/*
+ * pkcs11.c
+ * --------
+ *
+ * This is a partial implementation of PKCS #11 on top of Cryptlib on
+ * top of a HAL connecting to the Cryptech FPGA cores.
+ *
+ * This is still at a very early stage and should not (yet?) be used
+ * for any serious purpose. Among other things, it's not yet entirely
+ * clear whether this approach really is workable.
+ *
+ * Author: Rob Austein
+ * Copyright (c) 2015, SUNET
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include <sqlite3.h>
+
+#include "cryptlib.h"
+
+/*
+ * Magic PKCS #11 macros that must be defined before including
+ * pkcs11.h. For now these are only the Unix versions, add others
+ * later (which may require minor refactoring).
+ */
+
+#define CK_PTR *
+#define CK_DEFINE_FUNCTION(returnType, name) returnType name
+#define CK_DECLARE_FUNCTION(returnType, name) returnType name
+#define CK_DECLARE_FUNCTION_POINTER(returnType, name) returnType (* name)
+#define CK_CALLBACK_FUNCTION(returnType, name) returnType (* name)
+#ifndef NULL_PTR
+#define NULL_PTR NULL
+#endif
+
+#include "pkcs11.h"
+#include "attributes.h"
+
+/*
+ * This PKCS #11 implementation is hardwired with one slot, the token
+ * for which is always present (so we return the same answer
+ * regardless of the value of tokenPresent).
+ */
+
+#define P11_ONE_AND_ONLY_SLOT 0
+
+/*
+ * Placeholders for PIN length limits. Figure out real values later.
+ */
+
+#warning Figure out PIN length limits
+#define P11_MIN_PIN_LENGTH 16
+#define P11_MAX_PIN_LENGTH 4096
+
+/*
+ * Version numbers. Placeholders for now. Cryptlib has a version
+ * number, but from PKCS #11's point of view, Cryptlib is part of the
+ * "hardware", and we're probably going to need something other than
+ * Cryptlib's version number for the hardware, because we have to
+ * represent the version number of the attached Cryptech FPGA cores.
+ *
+ * Software version number is just the version of this PKCS #11
+ * implementation. Probably.
+ */
+
+#warning Figure out hardware and software version numbers
+#define P11_VERSION_SW_MAJOR 0
+#define P11_VERSION_SW_MINOR 0
+#define P11_VERSION_HW_MAJOR 0
+#define P11_VERSION_HW_MINOR 0
+
+/*
+ * A value that can't possibly be a valid Cryptlib handle.
+ */
+
+#ifndef CRYPT_HANDLE_NONE
+#define CRYPT_HANDLE_NONE (-1)
+#endif
+
+/*
+ * Whether to enable hardware (FPGA) support. This option may go away
+ * eventually, once we have enough algorithms implemented in Verilog.
+ */
+
+#ifndef ENABLE_CRYPTLIB_DEVICE
+#define ENABLE_CRYPTLIB_DEVICE 1
+#endif
+
+/*
+ * Whehter to enable software algorithms. This is not really an
+ * option at the moment, as the code won't run or even build properly
+ * if this is disabled. It's a placeholder to let us flag bits of
+ * code that probably should go away if and when we're doing all the
+ * crypto algorithms on the FPGA.
+ */
+
+#ifndef ENABLE_CRYPTLIB_SOFTWARE
+#define ENABLE_CRYPTLIB_SOFTWARE 1
+#endif
+
+#if !ENABLE_CRYPTLIB_SOFTWARE
+#error Code will not work correctly with software algorithm support disabled
+#endif
+
+/*
+ * Debugging control.
+ */
+
+#ifndef DEBUG_SQL
+#define DEBUG_SQL 1
+#endif
+
+/*
+ * Default filename for SQL database lives. Can be overriden at
+ * runtime by setting PKCS11_DATABASE environment variable.
+ */
+
+#ifndef SQL_DATABASE
+#define SQL_DATABASE ".cryptech-pkcs11.db"
+#endif
+
+/*
+ * Default name for PKCS #15 keyring. Can be overriden at runtime by
+ * setting PKCS11_KEYRING environment variable.
+ *
+ * In the long term this probably goes away, as all keys should live
+ * behind the Cryptlib hardware interface, but we need something for
+ * initial testing.
+ */
+
+#ifndef PKCS15_KEYRING
+#define PKCS15_KEYRING ".cryptech-pkcs11.p15"
+#endif
+
+
+
+/*
+ * PKCS #11 session.
+ */
+
+/*
+ * Cryptlib handles in the session structure are defined via a silly
+ * macro so that we can automate initialization and finalization
+ * without accidently missing any of the handles.
+ *
+ * Note that the encryption and decryption cases (other than raw
+ * encryption with no symmetric cipher algorithm) will need to use the
+ * enveloping API: see pp 61-62, 70-71, 190 of the Cryptlib manual.
+ * We may not really need to keep all the contexts around in this case
+ * once we've bound them into the envelope, drive off that bridge when
+ * we get to it.
+ *
+ * Syntax: One handle per line, as calls to to-be-defined macros
+ * SESSION_CRYPTLIB_CONTEXT() or SESSION_CRYPTLIB_ENVELOPE(), entries
+ * separated by semicolons, no semicolon after last entry.
+ */
+
+#define SESSION_CRYPTLIB_HANDLES \
+ SESSION_CRYPTLIB_CONTEXT(sign_key_context); \
+ SESSION_CRYPTLIB_CONTEXT(sign_digest_context); \
+ SESSION_CRYPTLIB_CONTEXT(verify_key_context); \
+ SESSION_CRYPTLIB_CONTEXT(verify_digest_context); \
+ SESSION_CRYPTLIB_CONTEXT(digest_context)
+
+#if 0
+ SESSION_CRYPTLIB_CONTEXT(encrypt_key_context);
+ SESSION_CRYPTLIB_CONTEXT(encrypt_cipher_context);
+ SESSION_CRYPTLIB_CONTEXT(decrypt_key_context);
+ SESSION_CRYPTLIB_CONTEXT(decrypt_cipher_context);
+ SESSION_CRYPTLIB_ENVELOPE(encrypt_envelope);
+ SESSION_CRYPTLIB_ENVELOPE(decrypt_envelope);
+#endif
+
+typedef struct p11_session {
+ CK_SESSION_HANDLE handle; /* Session handle */
+ struct p11_session *link; /* Next session in list */
+ CK_STATE state; /* State (CKS_*) of this session */
+ CK_NOTIFY notify; /* Notification callback */
+ CK_VOID_PTR application; /* Application data */
+ sqlite3_stmt *find_query; /* FindObject*() query state */
+ int find_query_done; /* find_query has terminated */
+
+#define SESSION_CRYPTLIB_CONTEXT(_ctx_) CRYPT_CONTEXT _ctx_
+#define SESSION_CRYPTLIB_ENVELOPE(_env_) CRYPT_ENVELOPE _env_
+ SESSION_CRYPTLIB_HANDLES;
+#undef SESSION_CRYPTLIB_ENVELOPE
+#undef SESSION_CRYPTLIB_CONTEXT
+
+} p11_session_t;
+
+/*
+ * PKCS #11 handle management. PKCS #11 has two kinds of handles:
+ * session handles and object handles. We subdivide object handles
+ * into token object handles (handles for objects that live on the
+ * token) and session object handles (handles for objects that live
+ * only as long as the session does), and we steal a bit of the object
+ * handle as a flag to distinguish between our two kinds of object
+ * handles, considerably simplifing the objected-related SQL code.
+ */
+
+typedef enum {
+ handle_flavor_session,
+ handle_flavor_token_object,
+ handle_flavor_session_object
+} handle_flavor_t;
+
+#define FLAG_HANDLE_TOKEN 0x80000000
+
+#define is_token_handle(_handle_) (((_handle_) & FLAG_HANDLE_TOKEN) != 0)
+
+
+
+/*
+ * Current logged-in user.
+ */
+
+static enum {
+ not_logged_in,
+ logged_in_as_user,
+ logged_in_as_so
+} logged_in_as = not_logged_in;
+
+/*
+ * PKCS #11 sessions for this application.
+ */
+
+static p11_session_t *p11_sessions;
+
+/*
+ * SQL database.
+ */
+
+static sqlite3 *sqldb = NULL;
+
+/*
+ * Saved copy of PIN (sigh).
+ *
+ * We'd like to do better than this, but as long as we're supporting
+ * software keysets which require a password every time we read or
+ * write a private key, we need this. Once we're dealing with just
+ * the hardware interface we should be able to skip this.
+ */
+
+#if ENABLE_CRYPTLIB_SOFTWARE
+static char *pin = NULL;
+#endif
+
+/*
+ * Next PKCS #11 handle to allocate. We use a single handle space for
+ * both session and object handles, and we just keep incrementing
+ * until it wraps, to reduce the amount of time we have to spend
+ * on SQL probes to avoid handle conflicts.
+ */
+
+static CK_ULONG next_handle;
+
+/*
+ * Cryptlib handle for hardware device.
+ */
+
+#if ENABLE_CRYPTLIB_DEVICE
+static CRYPT_DEVICE cryptlib_device = CRYPT_HANDLE_NONE;
+#endif
+
+/*
+ * Filenames for SQL database and PKCS #15 keyring.
+ */
+
+static char *database_filename = NULL;
+static char *keyring_filename = NULL;
+
+
+
+/*
+ * Syntactic sugar for functions returning CK_RV complex enough to
+ * need cleanup actions on failure. Also does very basic logging
+ * for debug-by-printf().
+ */
+
+#define lose(_ck_rv_code_) \
+ do { \
+ rv = (_ck_rv_code_); \
+ fprintf(stderr, "%s:%u: %s\n", __FILE__, __LINE__, #_ck_rv_code_); \
+ goto fail; \
+ } while (0)
+
+/*
+ * Error checking for SQLite calls.
+ */
+
+#if DEBUG_SQL
+#define sql_whine(_expr_) \
+ (fprintf(stderr, "%s:%u: %s returned %s\n", \
+ __FILE__, __LINE__, #_expr_, sqlite3_errmsg(sqldb)), \
+ sql_breakpoint())
+#else
+#define sql_whine(_expr_) \
+ ((void) 0)
+#endif
+
+#define sql_check(_good_, _expr_) \
+ ((_expr_) == (_good_) ? 1 : (sql_whine(_expr_), 0))
+
+#define sql_check_ok(_expr_) sql_check(SQLITE_OK, _expr_)
+#define sql_check_row(_expr_) sql_check(SQLITE_ROW, _expr_)
+#define sql_check_done(_expr_) sql_check(SQLITE_DONE, _expr_)
+#define sql_whine_step() sql_whine(sqlite3_step())
+
+
+
+/*
+ * Filename utilities.
+ */
+
+/*
+ * Construct name of configuration file if we don't already have it cached.
+ */
+
+static char *cf_generate(char **fn, /* Output filename */
+ const char * const env, /* Name of environment variable */
+ const char * const base) /* Filename in home directory */
+{
+ char *var;
+
+ assert(fn != NULL && env != NULL && base != NULL);
+
+ if (*fn != NULL)
+ return *fn;
+
+ if ((var = getenv(env)) != NULL && (*fn = malloc(strlen(var) + 1)) != NULL)
+ strcpy(*fn, var);
+
+ else if (var == NULL && (var = getenv("HOME")) != NULL && (*fn = malloc(strlen(var) + strlen(base) + 2)) != NULL)
+ sprintf(*fn, "%s/%s", var, base);
+
+ else if (var == NULL && (*fn = malloc(strlen(base) + 1)) != NULL)
+ strcpy(*fn, base);
+
+ return *fn;
+}
+
+/*
+ * Closures over cf_generate() for particular filenames.
+ */
+
+static char *cf_sql_database(void)
+{
+ return cf_generate(&database_filename, "PKCS11_DATABASE", SQL_DATABASE);
+}
+
+static char *cf_pkcs15_keyring(void)
+{
+ return cf_generate(&keyring_filename, "PKCS11_KEYRING", PKCS15_KEYRING);
+}
+
+
+
+/*
+ * Wrappers around some of Cryptlib's context functions, so that the
+ * rest of the code can mostly ignore whether a particular algorithm
+ * is implemented in hardware or not. In theory, we could achieve
+ * this simply by always trying cryptDeviceCreateContext() and
+ * checking its return code to see whether we should fall back to
+ * CryptCreateContext(), but for the moment I'm more comfortable with
+ * explictly coding the list of algorithms we expect to be supported
+ * here. This may change at some future date, once the HAL code is a
+ * little further along.
+ */
+
+static int cryptlib_implemented_in_hardware(const CRYPT_ALGO_TYPE algo)
+{
+#if ENABLE_CRYPTLIB_DEVICE
+ switch (algo) {
+ case CRYPT_ALGO_YOU_NEED_TO_SPECIFY_SOMETHING_HERE_BOZO:
+ return 1;
+ }
+#endif
+
+ return 0;
+}
+
+/*
+ * Create a context -- hardware if supported, software otherwise.
+ */
+
+static C_RET cryptlib_create_context(CRYPT_CONTEXT *ctx, const CRYPT_ALGO_TYPE algo)
+{
+#if ENABLE_CRYPTLIB_DEVICE
+ if (cryptlib_implemented_in_hardware(algo))
+ return cryptDeviceCreateContext(cryptlib_device, ctx, algo);
+#endif
+
+ return cryptCreateContext(ctx, CRYPT_UNUSED, algo);
+}
+
+/*
+ * Store a key. This is a no-op for hardware contexts (the hardware
+ * device functions as a key store), but requires writing to the PKCS
+ * #15 keyring for software contexts.
+ */
+
+static C_RET cryptlib_store_key(const CRYPT_CONTEXT ctx)
+{
+ CRYPT_KEYSET keyset;
+ int ret, algo;
+
+ if ((ret = cryptGetAttribute(ctx, CRYPT_CTXINFO_ALGO, &algo)) != CRYPT_OK)
+ return ret;
+
+ if (cryptlib_implemented_in_hardware(algo))
+ return CRYPT_OK;
+
+ ret = cryptKeysetOpen(&keyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, cf_pkcs15_keyring(), CRYPT_KEYOPT_NONE);
+
+ if (ret == CRYPT_ERROR_OPEN || ret == CRYPT_ERROR_NOTFOUND)
+ ret = cryptKeysetOpen(&keyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, cf_pkcs15_keyring(), CRYPT_KEYOPT_CREATE);
+
+ if (ret != CRYPT_OK)
+ return ret;
+
+ ret = cryptAddPrivateKey(keyset, ctx, pin);
+
+ cryptKeysetClose(keyset);
+
+ return ret;
+}
+
+/*
+ * Load a key. This creates a new context.
+ */
+
+static C_RET cryptlib_load_key(CRYPT_CONTEXT *ctx, const char *keyid)
+{
+ CRYPT_KEYSET keyset;
+ int ret;
+
+ assert(ctx != NULL);
+
+ *ctx = CRYPT_HANDLE_NONE;
+
+#if ENABLE_CRYPTLIB_DEVICE
+ if ((ret = cryptGetPrivateKey(cryptlib_device, ctx, CRYPT_KEYID_NAME, keyid, NULL)) == CRYPT_OK)
+ return ret;
+#endif
+
+ if ((ret = cryptKeysetOpen(&keyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, cf_pkcs15_keyring(), CRYPT_KEYOPT_READONLY)) != CRYPT_OK)
+ return ret;
+
+ ret = cryptGetPrivateKey(keyset, ctx, CRYPT_KEYID_NAME, keyid, pin);
+
+ cryptKeysetClose(keyset);
+
+ return ret;
+}
+
+/*
+ * Delete a key.
+ */
+
+static C_RET cryptlib_delete_key(const char *keyid)
+{
+ CRYPT_KEYSET keyset;
+ int ret;
+
+#if ENABLE_CRYPTLIB_DEVICE
+ if ((ret = cryptDeleteKey(cryptlib_device, CRYPT_KEYID_NAME, keyid)) == CRYPT_OK)
+ return ret;
+#endif
+
+ if ((ret = cryptKeysetOpen(&keyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, cf_pkcs15_keyring(), CRYPT_KEYOPT_NONE)) != CRYPT_OK)
+ return ret;
+
+ ret = cryptDeleteKey(keyset, CRYPT_KEYID_NAME, keyid);
+
+ cryptKeysetClose(keyset);
+
+ return ret;
+}
+
+
+
+/*
+ * SQL utilities.
+ */
+
+/*
+ * Hook on which to hang a debugger breakpoint on SQL errors.
+ */
+
+#if DEBUG_SQL
+static void sql_breakpoint(void)
+{
+ fprintf(stderr, "[sql_breakpoint]\n");
+}
+#endif
+
+/*
+ * Execute SQL code that doesn't require a prepared query.
+ */
+
+static int sql_exec(const char *cmd)
+{
+ char *msg = NULL;
+
+ if (sql_check_ok(sqlite3_exec(sqldb, cmd, NULL, NULL, &msg)))
+ return 1;
+
+#if DEBUG_SQL
+ if (msg != NULL)
+ fprintf(stderr, "[%s]\n", msg);
+#endif
+
+ return 0;
+}
+
+/*
+ * Initialize SQL. This includes loading our schema, portions of
+ * which live in the temp (memory) database thus always need to be
+ * created on startup.
+ */
+
+static int sql_init(void)
+{
+ static const char schema[] =
+#include "schema.h"
+ ;
+
+ assert(sqldb == NULL);
+
+ return sql_check_ok(sqlite3_open(cf_sql_database(), &sqldb)) && sql_exec(schema);
+}
+
+/*
+ * Shut down SQL.
+ *
+ * Yes, this can return failure, although it's not clear what we're
+ * meant to do about that if the application is going to shut down
+ * regardless of what we do. I guess we could loop retrying a few
+ * times for errors like SQLITE_BUSY, but that's about it.
+ */
+
+static int sql_fini(void)
+{
+ if (!sql_check_ok(sqlite3_close(sqldb)))
+ return 0;
+
+ sqldb = NULL;
+ return 1;
+}
+
+/*
+ * GCC attribute declaration to help catch format string errors,
+ * ignored by other compilers.
+ */
+
+#ifdef __GNUC__
+static int sql_prepare(sqlite3_stmt **q,
+ const char *format, ...)
+ __attribute__ ((format (printf, 2, 3)));
+#endif
+
+/*
+ * Prepare an SQLite3 query, using vsnprintf() to format the query.
+ *
+ * WARNING WARNING WARNING WARNING
+ *
+ * Do not use this formatting mechanism for anything involving
+ * user-supplied data. It's only intended to handle things like
+ * selecting between two parallel table structures or queries using
+ * manifest constants that are only available in C header files.
+ */
+
+static int sql_prepare(sqlite3_stmt **q, const char *format, ...)
+{
+ char buffer[2048];
+ va_list ap;
+ size_t n;
+
+ va_start(ap, format);
+ n = vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
+
+ if (n >= sizeof(buffer))
+ return SQLITE_TOOBIG;
+
+ return sqlite3_prepare_v2(sqldb, buffer, -1, q, NULL);
+}
+
+
+
+/*
+ * (Extremely) minimal ASN.1 parser, just good enough to pick a few
+ * fields out of something like a well-formed ASN.1 DER representation
+ * of a certificate.
+ */
+
+#define ASN1_UNIVERSAL 0x00
+#define ASN1_APPLICATION 0x40
+#define ASN1_CONTEXT_SPECIFIC 0x80
+#define ASN1_PRIVATE 0xC0
+
+#define ASN1_PRIMITIVE 0x00
+#define ASN1_CONSTRUCTED 0x20
+
+#define ASN1_TAG_MASK 0x1F
+
+#define ASN1_INTEGER (ASN1_PRIMITIVE | 0x02)
+#define ASN1_BIT_STRING (ASN1_PRIMITIVE | 0x03)
+#define ASN1_OCTET_STRING (ASN1_PRIMITIVE | 0x04)
+#define ASN1_NULL (ASN1_PRIMITIVE | 0x05)
+#define ASN1_OBJECT_IDENTIFIER (ASN1_PRIMITIVE | 0x06)
+#define ASN1_SEQUENCE (ASN1_CONSTRUCTED | 0x10)
+#define ASN1_SET (ASN1_CONSTRUCTED | 0x11)
+
+#define ASN1_EXPLICIT_CONTEXT (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED)
+#define ASN1_EXPLICIT_0 (ASN1_EXPLICIT_CONTEXT + 0)
+
+/*
+ * Common setup code for asn1_dive() and asn1_skip().
+ *
+ * Check ASN.1 tag and various errors, decode length field.
+ * Outputs are length of header (tag + length) and value.
+ */
+
+static int asn1_prep(const unsigned char tag,
+ const unsigned char * const der,
+ const size_t len,
+ size_t *phlen,
+ size_t *pvlen)
+{
+ size_t i, hlen, vlen;
+
+ if (der == NULL || len < 2 || phlen == NULL || pvlen == NULL || der[0] != tag || der[1] > 0x84)
+ return 0;
+
+ if ((der[1] & 0x80) == 0) {
+ hlen = 2;
+ vlen = der[1];
+ }
+
+ else {
+ hlen = 2 + (der[1] & 0x7F);
+ vlen = 0;
+
+ if (hlen >= len)
+ return 0;
+
+ for (i = 2; i < hlen; i++)
+ vlen = (vlen << 8) + der[i];
+ }
+
+ if (hlen + vlen > len)
+ return 0;
+
+ *phlen = hlen;
+ *pvlen = vlen;
+ return 1;
+}
+
+/*
+ * Dive into an ASN.1 object.
+ *
+ * The special handling for BIT STRING is only appropriate for the
+ * intended use, where BIT STRING always encapsulates another ASN.1
+ * object like SubjectPublicKeyInfo and is thus always required to be
+ * a multiple of 8 bits in length. If we ever need to use this code
+ * to deal with real bit strings, the special handling will need to
+ * move to a separate function which we can call when appropriate.
+ */
+
+static int asn1_dive(const unsigned char tag,
+ const unsigned char **der,
+ size_t *len)
+{
+ size_t hlen, vlen;
+
+ if (der == NULL || len == NULL || !asn1_prep(tag, *der, *len, &hlen, &vlen))
+ return 0;
+
+ if (tag == ASN1_BIT_STRING) {
+ if (vlen == 0 || hlen >= *len || (*der)[hlen] != 0x00)
+ return 0;
+ hlen++, vlen--;
+ }
+
+ assert(hlen + vlen <= *len);
+ *der += hlen; /* Advance past the header */
+ *len = vlen; /* Shrink range to be just the content */
+ return 1;
+}
+
+/*
+ * Skip over an ASN.1 object.
+ */
+
+static int asn1_skip(const unsigned char tag,
+ const unsigned char **der,
+ size_t *len)
+{
+ size_t hlen, vlen;
+
+ if (der == NULL || len == NULL || !asn1_prep(tag, *der, *len, &hlen, &vlen))
+ return 0;
+
+ assert(hlen + vlen <= *len);
+ *der += hlen + vlen; /* Advance past entire object */
+ *len -= hlen + vlen; /* Reduce range by length of object */
+ return 1;
+}
+
+/*
+ * Grovel through a DER encoded X.509v3 certificate object until we
+ * find the subjectPublicKey field. See the ASN.1 in RFC 5280.
+ *
+ * This is much too simplistic for general use, but should suffice to
+ * pick the subjectPublicKey data out of a certificate generated for
+ * us by Cryptlib.
+ */
+
+static int asn1_find_x509_spki(const unsigned char **der, size_t *len)
+{
+ return (asn1_dive(ASN1_SEQUENCE, der, len) && /* Dive into certificate */
+ asn1_dive(ASN1_SEQUENCE, der, len) && /* Dive into tbsCertificate */
+ asn1_skip(ASN1_EXPLICIT_0, der, len) && /* Skip version */
+ asn1_skip(ASN1_INTEGER, der, len) && /* Skip serialNumber */
+ asn1_skip(ASN1_SEQUENCE, der, len) && /* Skip signature */
+ asn1_skip(ASN1_SEQUENCE, der, len) && /* Skip issuer */
+ asn1_skip(ASN1_SEQUENCE, der, len) && /* skip validity */
+ asn1_skip(ASN1_SEQUENCE, der, len) && /* Skip subject */
+ asn1_dive(ASN1_SEQUENCE, der, len) && /* Dive into subjectPublicKeyInfo */
+ asn1_skip(ASN1_SEQUENCE, der, len) && /* Skip algorithm */
+ asn1_dive(ASN1_BIT_STRING, der, len)); /* Dive into subjectPublicKey */
+}
+
+
+
+/*
+ * Find an unused handle.
+ *
+ * Note that zero is an excluded value (CK_INVALID_HANDLE), hence the
+ * slightly odd arithmetic.
+ *
+ * For object handles, we steal the high-order bit to flag whether the
+ * handle represents a session object or token object.
+ */
+
+static CK_ULONG p11_allocate_unused_handle(const handle_flavor_t flavor)
+{
+ static const char select_format[] =
+ " SELECT %s_id FROM %s WHERE %s_handle = ?";
+
+ const char *table = flavor == handle_flavor_session ? "session" : "object";
+ sqlite3_stmt *q = NULL;
+ CK_ULONG handle;
+ int ret;
+
+ if (!sql_check_ok(sql_prepare(&q, select_format, table, table, table)))
+ goto fail;
+
+ for (;;) {
+
+ handle = ++next_handle;
+ next_handle %= 0xFFFFFFFF;
+
+ switch (flavor) {
+ case handle_flavor_session:
+ break;
+ case handle_flavor_token_object:
+ handle |= FLAG_HANDLE_TOKEN;
+ break;
+ case handle_flavor_session_object:
+ handle &= ~FLAG_HANDLE_TOKEN;
+ break;
+ }
+
+ assert(handle != CK_INVALID_HANDLE);
+
+ if (!sql_check_ok(sqlite3_reset(q)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, handle)))
+ goto fail;
+
+ if ((ret = sqlite3_step(q)) == SQLITE_ROW)
+ continue;
+
+ if (ret == SQLITE_DONE)
+ break;
+
+ sql_whine_step();
+ goto fail;
+
+ }
+
+ sqlite3_finalize(q);
+ return handle;
+
+ fail:
+ sqlite3_finalize(q);
+ return CK_INVALID_HANDLE;
+}
+
+/*
+ * Translate CKA_TOKEN value to handle flavor.
+ */
+
+static handle_flavor_t p11_handle_flavor_from_cka_token(const CK_BBOOL *bbool)
+{
+ assert(bbool != NULL);
+ return *bbool ? handle_flavor_token_object : handle_flavor_session_object;
+}
+
+
+
+/*
+ * Attribute methods.
+ */
+
+/*
+ * Set an attribute for a given object.
+ *
+ * It would be trivial to generalize this to take a CK_ATTRIBUTE_PTR
+ * template instead of a single attribute, at the cost of losing the
+ * const specifiers (CK_ATTRIBUTE_PTR has an internal non-const void*).
+ */
+
+static int p11_attribute_set(const CK_OBJECT_HANDLE object_handle,
+ const CK_ATTRIBUTE_TYPE type,
+ const void * const value,
+ const CK_ULONG length)
+{
+ static const char insert_format[] =
+ " INSERT OR REPLACE INTO %s_attribute (%s_object_id, type, value)"
+ " VALUES ((SELECT %s_object_id FROM object WHERE object_handle = ?1), ?2, ?3)";
+
+ const char *flavor = is_token_handle(object_handle) ? "token" : "session";
+
+ sqlite3_stmt *q = NULL;
+ int ok = 0;
+
+ if (!sql_check_ok(sql_prepare(&q, insert_format, flavor, flavor, flavor)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, object_handle)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 2, type)) ||
+ !sql_check_ok(sqlite3_bind_blob( q, 3, value, length, NULL)) ||
+ !sql_check_done(sqlite3_step(q)))
+ goto fail;
+
+ ok = 1;
+
+ fail:
+ sqlite3_finalize(q);
+ return ok;
+}
+
+/*
+ * Get a single attribute from a given object.
+ *
+ * This could easily be generalized to take a CK_ATTRIBUTE_PTR, at the
+ * cost of more complicated error semantics.
+ */
+
+static int p11_attribute_get(const CK_OBJECT_HANDLE object_handle,
+ const CK_ATTRIBUTE_TYPE type,
+ void *value,
+ CK_ULONG *length,
+ const CK_ULONG maxlength)
+{
+ static const char select_format[] =
+ " SELECT value FROM %s_attribute NATURAL JOIN object"
+ " WHERE object_handle = ?1 AND type = ?2";
+
+ const char *flavor = is_token_handle(object_handle) ? "token" : "session";
+
+ sqlite3_stmt *q = NULL;
+ int ret, ok = 0;
+ CK_ULONG len;
+
+ if (!sql_check_ok(sql_prepare(&q, select_format, flavor)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, object_handle)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 2, type)))
+ goto fail;
+
+ ret = sqlite3_step(q);
+
+ if (ret == SQLITE_DONE)
+ goto fail;
+
+ if (ret != SQLITE_ROW) {
+ sql_whine_step();
+ goto fail;
+ }
+
+ len = sqlite3_column_bytes(q, 0);
+
+ if (length != NULL)
+ *length = len;
+
+ if (value != NULL && maxlength < len)
+ goto fail;
+
+ if (value != NULL)
+ memcpy(value, sqlite3_column_blob(q, 0), len);
+
+ ok = 1;
+
+ fail:
+ sqlite3_finalize(q);
+ return ok;
+}
+
+/*
+ * Wrappers to set and get CK_BBOOL and CK_ULONG values.
+ */
+
+static int p11_attribute_set_bbool(const CK_OBJECT_HANDLE object_handle, const CK_ATTRIBUTE_TYPE type, const CK_BBOOL value)
+{
+ return p11_attribute_set(object_handle, type, &value, sizeof(value));
+}
+
+static int p11_attribute_set_ulong(const CK_OBJECT_HANDLE object_handle, const CK_ATTRIBUTE_TYPE type, const CK_ULONG value)
+{
+ return p11_attribute_set(object_handle, type, &value, sizeof(value));
+}
+
+static int p11_attribute_get_bbool(const CK_OBJECT_HANDLE object_handle, const CK_ATTRIBUTE_TYPE type, CK_BBOOL *value)
+{
+ CK_ULONG length;
+ return p11_attribute_get(object_handle, type, value, &length, sizeof(*value)) && length == sizeof(*value);
+}
+
+static int p11_attribute_get_ulong(const CK_OBJECT_HANDLE object_handle, const CK_ATTRIBUTE_TYPE type, CK_ULONG *value)
+{
+ CK_ULONG length;
+ return p11_attribute_get(object_handle, type, value, &length, sizeof(*value)) && length == sizeof(*value);
+}
+
+/*
+ * Find an attribute in a CK_ATTRIBUTE_PTR template. Returns index
+ * into template, or -1 if not found.
+ */
+
+static int p11_attribute_find_in_template(const CK_ATTRIBUTE_TYPE type,
+ const CK_ATTRIBUTE_PTR template,
+ const CK_ULONG length)
+{
+ int i;
+
+ if (template != NULL)
+ for (i = 0; i < length; i++)
+ if (template[i].type == type)
+ return i;
+
+ return -1;
+}
+
+/*
+ * Map a keyusage-related attribute to a keyusage bit flag.
+ *
+ * Assumes that calling code has already checked whether this
+ * attribute is legal for this object class, that attribute which
+ * should be CK_BBOOLs are of the correct length, etcetera.
+ *
+ * To handle all the possible permutations of specified and default
+ * values, it may be necessary to defer calling this method until
+ * after the default and mandatory values have been merged into the
+ * values supplied by the application-supplied template.
+ */
+
+static void p11_attribute_apply_keyusage(unsigned *keyusage, const CK_ATTRIBUTE_TYPE type, const CK_BBOOL *value)
+{
+ unsigned flag;
+
+ assert(keyusage != NULL && value != NULL);
+
+ switch (type) {
+ case CKA_SIGN: /* Generate signature */
+ case CKA_VERIFY: /* Verify signature */
+ flag = CRYPT_KEYUSAGE_DIGITALSIGNATURE;
+ break;
+ case CKA_ENCRYPT: /* Encrypt bulk data (seldom used) */
+ case CKA_DECRYPT: /* Bulk decryption (seldom used) */
+ flag = CRYPT_KEYUSAGE_DATAENCIPHERMENT;
+ break;
+ case CKA_WRAP: /* Wrap key (normal way of doing encryption) */
+ case CKA_UNWRAP: /* Unwrap key (normal way of doing decryption) */
+ flag = CRYPT_KEYUSAGE_KEYENCIPHERMENT;
+ break;
+ default:
+ return; /* Attribute not related to key usage */
+ }
+
+ if (*value)
+ *keyusage |= flag;
+ else
+ *keyusage &= ~flag;
+}
+
+
+
+/*
+ * Descriptor methods. Descriptors are generated at compile time by
+ * an auxiliary Python script, see attributes.* for details.
+ */
+
+/*
+ * Return the descriptor associated with a particular object class and
+ * key type.
+ */
+
+static const p11_descriptor_t *p11_descriptor_from_key_type(const CK_OBJECT_CLASS object_class,
+ const CK_KEY_TYPE key_type)
+{
+ int i;
+
+ for (i = 0; i < sizeof(p11_descriptor_keyclass_map)/sizeof(*p11_descriptor_keyclass_map); i++) {
+ const p11_descriptor_keyclass_map_t * const m = &p11_descriptor_keyclass_map[i];
+ if (m->object_class == object_class && m->key_type == key_type)
+ return m->descriptor;
+ }
+
+ return NULL;
+}
+
+/*
+ * Find the entry for a particular attribute in a descriptor.
+ */
+
+static const p11_attribute_descriptor_t *p11_find_attribute_in_descriptor(const p11_descriptor_t *descriptor,
+ const CK_ATTRIBUTE_TYPE type)
+{
+ int i;
+
+ if (descriptor != NULL && descriptor->attributes != NULL)
+ for (i = 0; i < descriptor->n_attributes; i++)
+ if (descriptor->attributes[i].type == type)
+ return &descriptor->attributes[i];
+
+ return NULL;
+}
+
+/*
+ * Check whether an attribute is marked as sensitive. If we don't
+ * recognize the attribute, report it as sensitive (safer than the
+ * alternative).
+ */
+
+static int p11_attribute_is_sensitive(const p11_descriptor_t *descriptor,
+ const CK_ATTRIBUTE_TYPE type)
+{
+ const p11_attribute_descriptor_t *a = p11_find_attribute_in_descriptor(descriptor, type);
+ return a == NULL || (a->flags & P11_DESCRIPTOR_SENSITIVE) != 0;
+}
+
+
+
+/*
+ * Object methods.
+ */
+
+/*
+ * Check access rights for an object.
+ */
+
+typedef enum { p11_object_access_read, p11_object_access_write } p11_object_access_t;
+
+static CK_RV p11_object_check_rights(const p11_session_t *session,
+ const CK_OBJECT_HANDLE object_handle,
+ const p11_object_access_t rights)
+{
+ static const char session_handle_query[] =
+ " SELECT session_handle FROM session NATURAL JOIN object WHERE object_handle = ?1";
+
+ CK_BBOOL object_is_private;
+ sqlite3_stmt *q = NULL;
+ CK_RV rv;
+
+ if (session == NULL)
+ lose(CKR_SESSION_HANDLE_INVALID);
+
+ /*
+ * Read-only sessions are, um, read-only.
+ */
+
+ switch (session->state) {
+ case CKS_RO_PUBLIC_SESSION:
+ case CKS_RO_USER_FUNCTIONS:
+ if (rights == p11_object_access_write)
+ lose(CKR_SESSION_READ_ONLY);
+ }
+
+ /*
+ * Private objects don't for sessions in the wrong state.
+ */
+
+ switch (session->state) {
+ case CKS_RO_PUBLIC_SESSION:
+ case CKS_RW_PUBLIC_SESSION:
+ case CKS_RW_SO_FUNCTIONS:
+ if (!p11_attribute_get_bbool(object_handle, CKA_PRIVATE, &object_is_private) || object_is_private)
+ lose(CKR_OBJECT_HANDLE_INVALID);
+ }
+
+ /*
+ * Session objects are only visible to the session which created them.
+ */
+
+ if (!is_token_handle(object_handle) &&
+ (!sql_check_ok(sql_prepare(&q, session_handle_query)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, object_handle)) ||
+ !sql_check_row(sqlite3_step(q)) ||
+ sqlite3_column_int64(q, 0) != session->handle))
+ lose(CKR_OBJECT_HANDLE_INVALID);
+
+ /*
+ * Ran out of reasons to reject, guess we should allow it.
+ */
+
+ rv = CKR_OK;
+
+ fail:
+ sqlite3_finalize(q);
+ return rv;
+}
+
+/*
+ * Delete all private objects, probably because user logged out.
+ *
+ * In the case of token objects, the object itself remains in the
+ * token, we're just deleting our handle for the object.
+ *
+ * In the case of session objects, the object itself goes away.
+ */
+
+static int p11_object_delete_all_private(void)
+{
+ static const char select_format[] =
+ " WITH"
+ " private AS (SELECT session_object_id FROM session_attribute WHERE type = %u AND value <> X'00')"
+ " SELECT keyid FROM session_object WHERE keyid IS NOT NULL AND session_object_id IN private";
+
+ static const char delete_format[] =
+ " WITH"
+ " s AS (SELECT session_object_id FROM session_attribute WHERE type = %u AND value <> X'00'),"
+ " t AS (SELECT token_object_id FROM token_attribute WHERE type = %u AND value <> X'00')"
+ " DELETE FROM object WHERE token_object_id IN t OR session_object_id IN s";
+
+ sqlite3_stmt *q = NULL;
+ int ret, ok = 0;
+
+ if (!sql_check_ok(sql_prepare(&q, select_format, CKA_PRIVATE)))
+ goto fail;
+
+ while ((ret = sqlite3_step(q)) == SQLITE_ROW)
+ if (cryptlib_delete_key((const char *) sqlite3_column_text(q, 0)) != CRYPT_OK)
+ goto fail;
+
+ if (ret != SQLITE_DONE) {
+ sql_whine_step();
+ goto fail;
+ }
+
+ sqlite3_finalize(q);
+ q = NULL;
+
+ if (!sql_check_ok(sql_prepare(&q, delete_format, CKA_PRIVATE, CKA_PRIVATE)) ||
+ !sql_check_done(sqlite3_step(q)))
+ goto fail;
+
+ ok = 1;
+
+ fail:
+ sqlite3_finalize(q);
+ return ok;
+}
+
+/*
+ * Create a new object.
+ *
+ * This is a bit nasty due to the SQL foreign key constraints and the
+ * different handling required for session and token objects.
+ */
+
+static CK_OBJECT_HANDLE p11_object_create(const p11_session_t *session,
+ const handle_flavor_t flavor,
+ const CK_ATTRIBUTE_PTR template,
+ const CK_ULONG template_length,
+ const p11_descriptor_t * const descriptor,
+ const CK_MECHANISM_PTR mechanism)
+{
+ static const char insert_object[] =
+ " INSERT INTO object (object_handle)"
+ " VALUES (?)";
+
+ static const char insert_token_object[] =
+ " INSERT INTO token_object DEFAULT VALUES";
+
+ static const char insert_session_object[] =
+ " INSERT INTO session_object (object_id) VALUES (?)";
+
+ static const char update_object_session_object[] =
+ " UPDATE object SET"
+ " session_id = (SELECT session_id FROM session WHERE session_handle = ?1),"
+ " session_object_id = ?2"
+ " WHERE object_id = ?3";
+
+ static const char update_object_token_object[] =
+ " UPDATE object SET token_object_id = ?1 WHERE object_id = ?2";
+
+ static const char insert_token_attribute[] =
+ " INSERT OR REPLACE INTO token_attribute (token_object_id, type, value)"
+ " VALUES (?1, ?2, ?3)";
+
+ static const char insert_session_attribute[] =
+ " INSERT OR REPLACE INTO session_attribute (session_object_id, type, value)"
+ " VALUES (?1, ?2, ?3)";
+
+ CK_OBJECT_HANDLE object_handle = p11_allocate_unused_handle(flavor);;
+ sqlite3_int64 object_id, session_object_id, token_object_id;
+ sqlite3_stmt *q = NULL;
+ int i, ok = 0;
+
+ assert(session != NULL && template != NULL && descriptor != NULL &&
+ (flavor == handle_flavor_token_object ||
+ flavor == handle_flavor_session_object));
+
+ if (!sql_check_ok(sql_prepare(&q, insert_object)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, object_handle)) ||
+ !sql_check_done(sqlite3_step(q)))
+ goto fail;
+
+ object_id = sqlite3_last_insert_rowid(sqldb);
+
+ sqlite3_finalize(q);
+ q = NULL;
+
+ switch (flavor) {
+
+ case handle_flavor_token_object:
+ if (!sql_check_ok(sql_prepare(&q, insert_token_object)) ||
+ !sql_check_done(sqlite3_step(q)))
+ goto fail;
+ token_object_id = sqlite3_last_insert_rowid(sqldb);
+ sqlite3_finalize(q);
+ q = NULL;
+ if (!sql_check_ok(sql_prepare(&q, update_object_token_object)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, token_object_id)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 2, object_id)) ||
+ !sql_check_done(sqlite3_step(q)))
+ goto fail;
+ sqlite3_finalize(q);
+ q = NULL;
+ if (!sql_check_ok(sql_prepare(&q, insert_token_attribute)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, token_object_id)))
+ goto fail;
+ break;
+
+ case handle_flavor_session_object:
+ if (!sql_check_ok(sql_prepare(&q, insert_session_object)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, object_id)) ||
+ !sql_check_done(sqlite3_step(q)))
+ goto fail;
+ session_object_id = sqlite3_last_insert_rowid(sqldb);
+ sqlite3_finalize(q);
+ q = NULL;
+ if (!sql_check_ok(sql_prepare(&q, update_object_session_object)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, session->handle)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 2, session_object_id)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 3, object_id)) ||
+ !sql_check_done(sqlite3_step(q)))
+ goto fail;
+ sqlite3_finalize(q);
+ q = NULL;
+ if (!sql_check_ok(sql_prepare(&q, insert_session_attribute)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, session_object_id)))
+ goto fail;
+ break;
+
+ default: /* Suppress GCC warning */
+ goto fail;
+ }
+
+ /*
+ * Now populate attributes, starting with the application's
+ * template, which we assume has already been blessed by the API
+ * function that called this method.
+ */
+
+ for (i = 0; i < template_length; i++) {
+ const CK_ATTRIBUTE_TYPE type = template[i].type;
+ const void * val = template[i].pValue;
+ const int len = template[i].ulValueLen;
+
+ if (!sql_check_ok(sqlite3_reset(q)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 2, type)) ||
+ !sql_check_ok(sqlite3_bind_blob( q, 3, val, len, NULL)) ||
+ !sql_check_done(sqlite3_step(q)))
+ goto fail;
+ }
+
+ /*
+ * Next, add defaults from the descriptor.
+ */
+
+ for (i = 0; i < descriptor->n_attributes; i++) {
+ const CK_ATTRIBUTE_TYPE type = descriptor->attributes[i].type;
+ const void * val = descriptor->attributes[i].value;
+ const int len = descriptor->attributes[i].length;
+ const unsigned flags = descriptor->attributes[i].flags;
+
+ if (val == NULL && (flags & P11_DESCRIPTOR_DEFAULT_VALUE) != 0)
+ val = "";
+
+ if (val == NULL || p11_attribute_find_in_template(type, template, template_length) >= 0)
+ continue;
+
+ if (!sql_check_ok(sqlite3_reset(q)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 2, type)) ||
+ !sql_check_ok(sqlite3_bind_blob( q, 3, val, len, NULL)) ||
+ !sql_check_done(sqlite3_step(q)))
+ goto fail;
+ }
+
+ /*
+ * Finally, add generation mechanism attributes as needed.
+ */
+
+ if (mechanism != NULL &&
+ (!sql_check_ok(sqlite3_reset(q)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 2, CKA_LOCAL)) ||
+ !sql_check_ok(sqlite3_bind_blob( q, 3, &const_CK_TRUE, sizeof(const_CK_TRUE), NULL)) ||
+ !sql_check_done(sqlite3_step(q)) ||
+ !sql_check_ok(sqlite3_reset(q)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 2, CKA_KEY_GEN_MECHANISM)) ||
+ !sql_check_ok(sqlite3_bind_blob( q, 3, &mechanism->mechanism, sizeof(mechanism->mechanism), NULL)) ||
+ !sql_check_done(sqlite3_step(q))))
+ goto fail;
+
+ /*
+ * If we made it past all that, we're happy.
+ */
+
+ ok = 1;
+
+ fail:
+ sqlite3_finalize(q);
+ return ok ? object_handle : CK_INVALID_HANDLE;
+}
+
+/*
+ * Get the keyid for an object.
+ *
+ * This may require calculating the keyid from the CKA_ID attribute.
+ */
+
+static int p11_object_get_keyid(const CK_OBJECT_HANDLE object_handle,
+ char *keyid,
+ const size_t maxkeyid)
+{
+ static const char select_format[] =
+ " SELECT keyid FROM %s_object NATURAL JOIN object WHERE object_handle = ?";
+
+ static const char update_format[] =
+ " UPDATE %s_object SET keyid = ?1"
+ " WHERE %s_object_id = (SELECT %s_object_id FROM object WHERE object_handle =?2)";
+
+ const char *flavor = is_token_handle(object_handle) ? "token" : "session";
+
+ sqlite3_stmt *q = NULL;
+ int ok = 0;
+
+ if (!sql_check_ok(sql_prepare(&q, select_format, flavor)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, object_handle)) ||
+ !sql_check_row(sqlite3_step(q)))
+ goto fail;
+
+ if (sqlite3_column_type(q, 0) == SQLITE_NULL) {
+
+ /*
+ * No keyid set yet, have to create one. We use the CKA_ID
+ * attribute for this, zero-filling or truncating as necessary.
+ */
+
+ const CK_ULONG target_length = (CRYPT_MAX_TEXTSIZE < maxkeyid ? CRYPT_MAX_TEXTSIZE : (maxkeyid - 1)) / 2;
+ unsigned char id[CRYPT_MAX_HASHSIZE];
+ CK_ULONG len;
+ int i;
+
+ assert(target_length > 0 && target_length <= sizeof(id) && target_length * 2 < maxkeyid);
+
+ if (!p11_attribute_get(object_handle, CKA_ID, id, &len, sizeof(id)))
+ goto fail;
+
+ if (len < target_length) {
+ memmove(id + target_length - len, id, len);
+ memset(id, 0x00, target_length - len);
+ }
+
+ for (i = 0; i < target_length; i++)
+ sprintf(keyid + (2 * i), "%02x", id[i]);
+ keyid[target_length * 2] = '\0';
+
+ sqlite3_finalize(q);
+ q = NULL;
+
+ if (!sql_check_ok(sql_prepare(&q, update_format, flavor, flavor, flavor)) ||
+ !sql_check_ok(sqlite3_bind_text( q, 1, keyid, strlen(keyid), NULL)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 2, object_handle)) ||
+ !sql_check_done(sqlite3_step(q)))
+ goto fail;
+
+ } else {
+
+ /*
+ * Already had a keyid, just have to copy it.
+ */
+
+ int len = sqlite3_column_bytes(q, 0);
+
+ if (len >= maxkeyid)
+ goto fail;
+
+ memcpy(keyid, sqlite3_column_text(q, 0), len);
+ keyid[len] = '\0';
+
+ }
+
+ ok = 1;
+
+ fail:
+ sqlite3_finalize(q);
+ return ok;
+}
+
+/*
+ * Add attributes representing the SPKI value of a key we've
+ * generated.
+ *
+ * Cryptlib does such a complete job of protecting our keys that it's
+ * rather tedious to extract the raw subjectPublicKeyInfo, but the
+ * PKCS #11 client needs that information, so we have to jump through
+ * some silly hoops. This routine does most of the work, but uses a
+ * separate handler (supplied as an argument) to generate attributes
+ * based on mechanism-specific data from the subjectPublicKey.
+ *
+ * Basic approach here is to generate a temporary certificate from the
+ * key, export that as DER, parse the DER for the data we need, and
+ * destroy the temporary certificate.
+ */
+
+static int p11_object_add_spki(const CK_OBJECT_HANDLE public_handle,
+ const CK_OBJECT_HANDLE private_handle,
+ const CRYPT_CONTEXT key,
+ int (*handler)(const CK_OBJECT_HANDLE,
+ const CK_OBJECT_HANDLE,
+ const unsigned char *,
+ const size_t))
+{
+ static const char label[] = "Don't care";
+ CRYPT_CERTIFICATE cert = CRYPT_HANDLE_NONE;
+ unsigned char *buffer = NULL;
+ const unsigned char *der;
+ int ilen, ok = 0;
+ size_t ulen;
+
+ if (handler == NULL ||
+ cryptCreateCert(&cert, CRYPT_UNUSED, CRYPT_CERTTYPE_CERTIFICATE) != CRYPT_OK ||
+ cryptSetAttribute(cert, CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, key) != CRYPT_OK ||
+ cryptSetAttribute(cert, CRYPT_CERTINFO_XYZZY, 1) != CRYPT_OK ||
+ cryptSetAttributeString(cert, CRYPT_CERTINFO_COMMONNAME, label, sizeof(label)) != CRYPT_OK ||
+ cryptSignCert(cert, key) != CRYPT_OK ||
+ cryptExportCert(NULL, 0, &ilen, CRYPT_CERTFORMAT_CERTIFICATE, cert) != CRYPT_OK ||
+ (der = buffer = malloc(ulen = (size_t) ilen)) == NULL ||
+ cryptExportCert(buffer, ilen, &ilen, CRYPT_CERTFORMAT_CERTIFICATE, cert) != CRYPT_OK ||
+ !asn1_find_x509_spki(&der, &ulen) ||
+ !handler(public_handle, private_handle, der, ulen))
+ goto fail;
+
+ ok = 1;
+
+ fail:
+ if (buffer != NULL)
+ free(buffer);
+ if (cert != CRYPT_HANDLE_NONE)
+ cryptDestroyCert(cert);
+ return ok;
+}
+
+/*
+ * RSA-specific handler to go with p11_object_add_spki().
+ *
+ * Extract RSA modulus and public exponent from the subjectPublicKey
+ * and adds the appropriate attributes to the public and private keys.
+ */
+
+static int p11_object_add_spki_rsa(const CK_OBJECT_HANDLE public_handle,
+ const CK_OBJECT_HANDLE private_handle,
+ const unsigned char *der,
+ const size_t len)
+{
+ const unsigned char *modulus = der, *publicExponent = der;
+ size_t modulus_len = len, publicExponent_len = len;
+
+ /*
+ * Dig the relevant integers out of the ASN.1.
+ */
+ if (!asn1_dive(ASN1_SEQUENCE, &modulus, &modulus_len) ||
+ !asn1_dive(ASN1_INTEGER, &modulus, &modulus_len) ||
+ !asn1_dive(ASN1_SEQUENCE, &publicExponent, &publicExponent_len) ||
+ !asn1_skip(ASN1_INTEGER, &publicExponent, &publicExponent_len) ||
+ !asn1_dive(ASN1_INTEGER, &publicExponent, &publicExponent_len))
+ return 0;
+
+ /*
+ * ASN.1 INTEGERs are signed while PKCS #11 "big integers" are
+ * unsigned, so skip leading zero byte, if present.
+ */
+
+ if (modulus_len > 0 && *modulus == 0x00)
+ modulus_len--, modulus++;
+
+ if (publicExponent_len > 0 && *publicExponent == 0x00)
+ publicExponent_len--, publicExponent++;
+
+ /*
+ * Insert the attributes and we're done.
+ */
+
+ return (p11_attribute_set(public_handle, CKA_MODULUS, modulus, modulus_len) &&
+ p11_attribute_set(public_handle, CKA_PUBLIC_EXPONENT, publicExponent, publicExponent_len) &&
+ p11_attribute_set(private_handle, CKA_MODULUS, modulus, modulus_len) &&
+ p11_attribute_set(private_handle, CKA_PUBLIC_EXPONENT, publicExponent, publicExponent_len));
+}
+
+
+
+/*
+ * Session methods.
+ */
+
+/*
+ * Create a new session.
+ */
+
+static p11_session_t *p11_session_new(void)
+{
+ p11_session_t *session = malloc(sizeof(*session));
+ if (session == NULL)
+ return NULL;
+ memset(session, 0, sizeof(*session));
+
+#define SESSION_CRYPTLIB_CONTEXT(_ctx_) session->_ctx_ = CRYPT_HANDLE_NONE
+#define SESSION_CRYPTLIB_ENVELOPE(_env_) session->_env_ = CRYPT_HANDLE_NONE
+ SESSION_CRYPTLIB_HANDLES;
+#undef SESSION_CRYPTLIB_ENVELOPE
+#undef SESSION_CRYPTLIB_CONTEXT
+
+ return session;
+}
+
+/*
+ * Free a session.
+ */
+
+static void p11_session_free(p11_session_t *session)
+{
+ if (session == NULL)
+ return;
+
+ if (session->find_query != NULL)
+ sqlite3_finalize(session->find_query);
+
+#define SESSION_CRYPTLIB_CONTEXT(_ctx_) if (session->_ctx_ != CRYPT_HANDLE_NONE) cryptDestroyContext(session->_ctx_)
+#define SESSION_CRYPTLIB_ENVELOPE(_env_) if (session->_env_ != CRYPT_HANDLE_NONE) cryptDestroyEnvelope(session->_env_)
+ SESSION_CRYPTLIB_HANDLES;
+#undef SESSION_CRYPTLIB_ENVELOPE
+#undef SESSION_CRYPTLIB_CONTEXT
+
+ free(session);
+}
+
+/*
+ * Assign a handle to a session and add the session to SQL.
+ */
+
+static int p11_session_add(p11_session_t *session)
+{
+ static const char insert_session[] =
+ " INSERT INTO session (session_handle) VALUES (?)";
+
+ sqlite3_stmt *q = NULL;
+ int ok = 0;
+
+ assert(session != NULL);
+
+ session->handle = p11_allocate_unused_handle(handle_flavor_session);
+
+ if (!sql_check_ok(sql_prepare(&q, insert_session)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, session->handle)) ||
+ !sql_check_done(sqlite3_step(q)))
+ goto fail;
+
+ session->link = p11_sessions;
+ p11_sessions = session;
+ ok = 1;
+
+ fail:
+ sqlite3_finalize(q);
+ return ok;
+}
+
+/*
+ * Find a session.
+ *
+ * Since we don't expect the total number of sessions to be all that
+ * high, we use a linked list with a move-to-the-front search. Some
+ * of the other session methods assume this behavior, so be careful if
+ * you decide to change it.
+ */
+
+static p11_session_t *p11_session_find(const CK_SESSION_HANDLE session_handle)
+{
+ p11_session_t **link, *session;
+
+ for (link = &p11_sessions;
+ (session = *link) != NULL && session->handle != session_handle;
+ link = &session->link)
+ ;
+
+ if (session != NULL && link != &p11_sessions) {
+ *link = session->link;
+ session->link = p11_sessions;
+ p11_sessions = session;
+ }
+
+ return session;
+}
+
+/*
+ * Delete a session: remove it from SQL and free the session data
+ * structure.
+ *
+ * Since this destroys all associated session objects, we also have to
+ * delete any keys we might be holding for session objects.
+ *
+ * This method assumes the move-to-the-front behavior of
+ * p11_session_find().
+ */
+
+static CK_RV p11_session_delete(const CK_SESSION_HANDLE session_handle)
+{
+ static const char select_keyid[] =
+ " SELECT keyid FROM session NATURAL JOIN session_object"
+ " WHERE session_handle = ?1 AND keyid IS NOT NULL";
+
+ static const char delete_session[] =
+ " DELETE FROM session WHERE session_handle = ?";
+
+ p11_session_t *session = p11_session_find(session_handle);
+ sqlite3_stmt *q = NULL;
+ CK_RV rv = CKR_OK;
+ int ret;
+
+ if (session == NULL)
+ return CKR_SESSION_HANDLE_INVALID;
+
+ if (!sql_check_ok(sql_prepare(&q, select_keyid)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, session_handle)))
+ lose(CKR_FUNCTION_FAILED);
+
+ while ((ret = sqlite3_step(q)) == SQLITE_ROW)
+ if (cryptlib_delete_key((const char *) sqlite3_column_text(q, 0)) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+
+ if (ret != SQLITE_DONE) {
+ sql_whine_step();
+ lose(CKR_FUNCTION_FAILED);
+ }
+
+ sqlite3_finalize(q);
+ q = NULL;
+
+ if (!sql_check_ok(sql_prepare(&q, delete_session)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, session_handle)) ||
+ !sql_check_done(sqlite3_step(q)))
+ lose(CKR_FUNCTION_FAILED);
+
+ /* Check that move-to-the-front behaved as expected */
+ assert(p11_sessions == session);
+
+ p11_sessions = session->link;
+ p11_session_free(session);
+
+ fail:
+ sqlite3_finalize(q);
+ return rv;
+}
+
+/*
+ * Delete all sessions.
+ *
+ * Like p11_session_delete(), this must also delete any keys held in
+ * session objects.
+ */
+
+static CK_RV p11_session_delete_all(void)
+{
+ static const char select_keys[] =
+ " SELECT keyid FROM session_object WHERE keyid IS NOT NULL";
+
+#warning Should this also clear the object table?
+
+ static const char delete_all_sessions[] =
+ " DELETE FROM session";
+
+ p11_session_t *session;
+ sqlite3_stmt *q = NULL;
+ int ret = SQLITE_OK;
+ CK_RV rv = CKR_OK;
+
+ if (!sql_check_ok(sql_prepare(&q, select_keys)))
+ lose(CKR_FUNCTION_FAILED);
+
+ while ((ret = sqlite3_step(q)) == SQLITE_ROW)
+ if (cryptlib_delete_key((const char *) sqlite3_column_text(q, 0)) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+
+ if (ret != SQLITE_DONE) {
+ sql_whine_step();
+ lose(CKR_FUNCTION_FAILED);
+ }
+
+ sqlite3_finalize(q);
+ q = NULL;
+
+ if (!sql_exec(delete_all_sessions))
+ lose(CKR_FUNCTION_FAILED);
+
+ while (p11_sessions != NULL) {
+ session = p11_sessions;
+ p11_sessions = session->link;
+ p11_session_free(session);
+ }
+
+ fail:
+ sqlite3_finalize(q);
+ return rv;
+}
+
+/*
+ * Check session database against login state for consistency.
+ *
+ * This is mostly useful in assertions.
+ */
+
+static int p11_session_consistent_login(void)
+{
+ p11_session_t *session;
+
+ switch (logged_in_as) {
+
+ case not_logged_in:
+ for (session = p11_sessions; session != NULL; session = session->link)
+ if (session->state != CKS_RO_PUBLIC_SESSION && session->state != CKS_RW_PUBLIC_SESSION)
+ return 0;
+ return 1;
+
+ case logged_in_as_user:
+ for (session = p11_sessions; session != NULL; session = session->link)
+ if (session->state != CKS_RO_USER_FUNCTIONS && session->state != CKS_RW_USER_FUNCTIONS)
+ return 0;
+ return 1;
+
+ case logged_in_as_so:
+ for (session = p11_sessions; session != NULL; session = session->link)
+ if (session->state != CKS_RW_SO_FUNCTIONS)
+ return 0;
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+
+
+/*
+ * PKCS #11 likes space-padded rather than null-terminated strings.
+ */
+
+static int psnprintf(void *buffer_, size_t size, const char *format, ...)
+{
+ char *buffer = buffer_;
+ size_t i, n;
+ va_list ap;
+
+ va_start(ap, format);
+ i = n = vsnprintf(buffer, size, format, ap);
+ va_end(ap);
+
+ while (i < size)
+ buffer[i++] = ' ';
+
+ return n;
+}
+
+
+
+/*
+ * Template checking and key generation.
+ *
+ * This may need refactoring at some point, eg, when we add support
+ * for C_CreateObject().
+ */
+
+/*
+ * First pass: called once per template entry during initial pass over
+ * template to handle generic checks that apply regardless of
+ * attribute type.
+ */
+
+static CK_RV p11_check_keypair_attributes_check_template_1(const CK_ATTRIBUTE_TYPE type,
+ const void * const val,
+ const size_t len,
+ const p11_descriptor_t * const descriptor)
+{
+ const p11_attribute_descriptor_t * const atd = p11_find_attribute_in_descriptor(descriptor, type);
+ CK_RV rv;
+
+ /* Attribute not allowed or not allowed for key generation */
+ if (atd == NULL || (atd->flags & P11_DESCRIPTOR_FORBIDDEN_BY_GENERATE) != 0)
+ lose(CKR_ATTRIBUTE_TYPE_INVALID);
+
+ /* NULL or wrong-sized attribute values */
+ if (val == NULL || (atd->size != 0 && len != atd->size))
+ lose(CKR_ATTRIBUTE_VALUE_INVALID);
+
+ /* Attributes which only the SO user is allowed to set to CK_TRUE */
+ if ((atd->flags & P11_DESCRIPTOR_ONLY_SO_USER_CAN_SET) != 0 && logged_in_as != logged_in_as_so && *(CK_BBOOL *) val)
+ lose(CKR_ATTRIBUTE_VALUE_INVALID);
+
+ /* Attributes which don't match mandatory values */
+ if (atd->value != NULL && (atd->flags & P11_DESCRIPTOR_DEFAULT_VALUE) == 0 && memcmp(val, atd->value, atd->length) != 0)
+ lose(CKR_TEMPLATE_INCONSISTENT);
+
+ rv = CKR_OK;
+
+ fail:
+ return rv;
+}
+
+/*
+ * Second pass: called once per template to check that each attribute
+ * required for that template has been specified exactly once.
+ */
+
+static CK_RV p11_check_keypair_attributes_check_template_2(const p11_session_t *session,
+ const p11_descriptor_t * const descriptor,
+ const CK_ATTRIBUTE_PTR template,
+ const CK_ULONG template_length)
+{
+ const CK_BBOOL *object_is_private;
+ CK_RV rv;
+ int i, j;
+
+ /*
+ * Some session states aren't allowed to play with private objects.
+ */
+
+ switch (session->state) {
+ case CKS_RO_PUBLIC_SESSION:
+ case CKS_RW_PUBLIC_SESSION:
+ case CKS_RW_SO_FUNCTIONS:
+ if ((i = p11_attribute_find_in_template(CKA_PRIVATE, template, template_length)) >= 0) {
+ assert(template[i].pValue != NULL);
+ object_is_private = template[i].pValue;
+ }
+ else {
+ const p11_attribute_descriptor_t * const atd = p11_find_attribute_in_descriptor(descriptor, CKA_PRIVATE);
+ assert(atd != NULL && atd->value != NULL);
+ object_is_private = atd->value;
+ }
+ if (*object_is_private)
+ lose(CKR_TEMPLATE_INCONSISTENT);
+ }
+
+ for (i = 0; i < descriptor->n_attributes; i++) {
+ const p11_attribute_descriptor_t * const atd = &descriptor->attributes[i];
+ const int required_by_api = (atd->flags & P11_DESCRIPTOR_REQUIRED_BY_GENERATE) != 0;
+ const int forbidden_by_api = (atd->flags & P11_DESCRIPTOR_FORBIDDEN_BY_GENERATE) != 0;
+ const int in_descriptor = (atd->flags & P11_DESCRIPTOR_DEFAULT_VALUE) != 0 || atd->value != NULL;
+ const int pos_in_template = p11_attribute_find_in_template(atd->type, template, template_length);
+
+ /* Multiple entries for same attribute */
+ if (pos_in_template >= 0)
+ for (j = pos_in_template + 1; j < template_length; j++)
+ if (template[j].type == atd->type)
+ lose(CKR_TEMPLATE_INCONSISTENT);
+
+ /* Required attribute missing from template */
+ if (!forbidden_by_api && (required_by_api || !in_descriptor) && pos_in_template < 0) {
+ fprintf(stderr, "[Missing attribute 0x%lx]\n", atd->type); /* XXX */
+ lose(CKR_TEMPLATE_INCOMPLETE);
+ }
+ }
+
+ rv = CKR_OK;
+
+ fail:
+ return rv;
+}
+
+/*
+ * Mechanism-independent checks for templates and descriptors when
+ * generating new keypairs.
+ *
+ * PKCS #11 gives the application far too much rope (including but not
+ * limited to the ability to supply completely unrelated templates for
+ * public and private keys in a keypair), so we need to do a fair
+ * amount of checking. We automate as much of the dumb stuff as
+ * possible through the object descriptor.
+ *
+ * Key usage handling here is based on RFC 5280 4.2.1.3, same as
+ * Cryptlib. We reuse Cryptlib's bit flags because they're
+ * convenient.
+ *
+ * We use the PKCS #11 CKA_ID attribute to generate the Cryptlib key
+ * label. PKCS #11 suggests but does not require CKA_ID values for
+ * public and private key to match; we do insist on this, because we
+ * really only have one key label which applies to both the public and
+ * private keys.
+ */
+
+static CK_RV p11_check_keypair_attributes(const p11_session_t *session,
+ const CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+ const CK_ULONG ulPublicKeyAttributeCount,
+ const p11_descriptor_t * const public_descriptor,
+ const CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+ const CK_ULONG ulPrivateKeyAttributeCount,
+ const p11_descriptor_t * const private_descriptor)
+{
+ unsigned public_keyusage = 0, private_keyusage = 0;
+ const CK_BYTE *id = NULL;
+ size_t id_len = 0;
+ CK_RV rv = CKR_OK;
+ int i;
+
+ assert(session != NULL &&
+ pPublicKeyTemplate != NULL && public_descriptor != NULL &&
+ pPrivateKeyTemplate != NULL && private_descriptor != NULL);
+
+ /*
+ * Read-only sessions can't create keys, doh.
+ */
+
+ switch (session->state) {
+ case CKS_RO_PUBLIC_SESSION:
+ case CKS_RO_USER_FUNCTIONS:
+ lose(CKR_SESSION_READ_ONLY);
+ }
+
+ /*
+ * Check values provided in the public and private templates.
+ */
+
+ for (i = 0; i < ulPublicKeyAttributeCount; i++) {
+ const CK_ATTRIBUTE_TYPE type = pPublicKeyTemplate[i].type;
+ const void * const val = pPublicKeyTemplate[i].pValue;
+ const size_t len = pPublicKeyTemplate[i].ulValueLen;
+
+ if ((rv = p11_check_keypair_attributes_check_template_1(type, val, len, public_descriptor)) != CKR_OK)
+ goto fail;
+
+ p11_attribute_apply_keyusage(&public_keyusage, type, val);
+
+ if (type == CKA_ID) {
+ id = val;
+ id_len = len;
+ }
+ }
+
+ for (i = 0; i < ulPrivateKeyAttributeCount; i++) {
+ const CK_ATTRIBUTE_TYPE type = pPrivateKeyTemplate[i].type;
+ const void * const val = pPrivateKeyTemplate[i].pValue;
+ const size_t len = pPrivateKeyTemplate[i].ulValueLen;
+
+ if ((rv = p11_check_keypair_attributes_check_template_1(type, val, len, private_descriptor)) != CKR_OK)
+ goto fail;
+
+ p11_attribute_apply_keyusage(&private_keyusage, type, val);
+
+ if (type == CKA_ID && id == NULL) {
+ id = val;
+ id_len = len;
+ }
+
+ if (type == CKA_ID && (len != id_len || memcmp(id, val, len)))
+ lose(CKR_TEMPLATE_INCONSISTENT);
+ }
+
+ /*
+ * We insist that keyusage be specified for both public and private
+ * key, and that they match. May not need to be this strict.
+ */
+
+ if (public_keyusage != private_keyusage || public_keyusage == 0)
+ lose(CKR_TEMPLATE_INCONSISTENT);
+
+ /*
+ * We require a key ID.
+ */
+
+ if (id == NULL || id_len == 0)
+ lose(CKR_TEMPLATE_INCOMPLETE);
+
+ /*
+ * Check that all required attributes have been specified.
+ */
+
+ if ((rv = p11_check_keypair_attributes_check_template_2(session,
+ public_descriptor,
+ pPublicKeyTemplate,
+ ulPublicKeyAttributeCount)) != CKR_OK ||
+ (rv = p11_check_keypair_attributes_check_template_2(session,
+ private_descriptor,
+ pPrivateKeyTemplate,
+ ulPrivateKeyAttributeCount)) != CKR_OK)
+ goto fail;
+
+ /*
+ * If we get this far, we're happy. Maybe.
+ */
+
+ rv = CKR_OK;
+
+ fail:
+ return rv;
+}
+
+/*
+ * CKM_RSA_PKCS_KEY_PAIR_GEN key pair generation implemetation.
+ *
+ * Much mechanism-independent code has already been factored out of
+ * this function, no doubt much remains that will require further
+ * refactoring once we implement other mechanisms.
+ */
+
+static CK_RV generate_keypair_rsa_pkcs(p11_session_t *session,
+ const CK_MECHANISM_PTR pMechanism,
+ const CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+ const CK_ULONG ulPublicKeyAttributeCount,
+ const CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+ const CK_ULONG ulPrivateKeyAttributeCount,
+ CK_OBJECT_HANDLE_PTR phPublicKey,
+ CK_OBJECT_HANDLE_PTR phPrivateKey)
+{
+ CK_OBJECT_HANDLE private_handle = CK_INVALID_HANDLE;
+ CK_OBJECT_HANDLE public_handle = CK_INVALID_HANDLE;
+ handle_flavor_t public_handle_flavor = handle_flavor_session_object;
+ handle_flavor_t private_handle_flavor = handle_flavor_session_object;
+ char keyid[CRYPT_MAX_HASHSIZE * 2 + 1];
+ CRYPT_CONTEXT ctx = CRYPT_HANDLE_NONE;
+ const CK_BYTE *id = NULL;
+ CK_ULONG keysize = 0;
+ size_t id_len = 0;
+ CK_RV rv;
+ int i;
+
+ /*
+ * Do mechanism-independent checks before anything else.
+ */
+
+ rv = p11_check_keypair_attributes(session,
+ pPublicKeyTemplate, ulPublicKeyAttributeCount, &p11_descriptor_rsa_public_key,
+ pPrivateKeyTemplate, ulPrivateKeyAttributeCount, &p11_descriptor_rsa_private_key);
+ if (rv != CKR_OK)
+ return rv;
+
+ assert(session != NULL && pMechanism != NULL &&
+ pPublicKeyTemplate != NULL && phPublicKey != NULL &&
+ pPrivateKeyTemplate != NULL && phPrivateKey != NULL);
+
+ memset(keyid, 0, sizeof(keyid));
+
+ /*
+ * Grab values and perform mechanism-specific checks.
+ */
+
+ for (i = 0; i < ulPublicKeyAttributeCount; i++) {
+ const CK_ATTRIBUTE_TYPE type = pPublicKeyTemplate[i].type;
+ const void * const val = pPublicKeyTemplate[i].pValue;
+ const size_t len = pPublicKeyTemplate[i].ulValueLen;
+
+ assert(val != NULL);
+
+ switch (type) {
+
+ case CKA_TOKEN: /* Object stored on token */
+ public_handle_flavor = p11_handle_flavor_from_cka_token(val);
+ continue;
+
+ case CKA_ID: /* We use PKCS #11 "ID" as Cryptlib label */
+ id = val;
+ id_len = len;
+ continue;
+
+ case CKA_MODULUS_BITS: /* Keysize in bits -- Cryptlib only allows multiples of 8 */
+ keysize = *(CK_ULONG *) val;
+ if ((keysize & 7) != 0)
+ return CKR_ATTRIBUTE_VALUE_INVALID;
+ continue;
+
+ }
+ }
+
+ for (i = 0; i < ulPrivateKeyAttributeCount; i++) {
+ const CK_ATTRIBUTE_TYPE type = pPrivateKeyTemplate[i].type;
+ const void * const val = pPrivateKeyTemplate[i].pValue;
+ const size_t len = pPrivateKeyTemplate[i].ulValueLen;
+
+ assert (val != NULL);
+
+ switch (type) {
+
+ case CKA_TOKEN: /* Object stored on token */
+ private_handle_flavor = p11_handle_flavor_from_cka_token(val);
+ continue;
+
+ case CKA_ID: /* We use PKCS #11 "ID" as Cryptlib label */
+ id = val;
+ id_len = len;
+ continue;
+
+ }
+ }
+
+ /*
+ * We require a key ID and a key size, and if either key is a token
+ * object, the other must be too.
+ */
+ if (id == NULL || id_len == 0 || keysize == 0 || public_handle_flavor != private_handle_flavor)
+ return CKR_TEMPLATE_INCOMPLETE;
+
+ /*
+ * If we got this far, create the PKCS #11 objects.
+ */
+
+ if (!sql_exec("BEGIN"))
+ lose(CKR_FUNCTION_FAILED);
+
+ public_handle = p11_object_create(session, public_handle_flavor,
+ pPublicKeyTemplate, ulPublicKeyAttributeCount,
+ &p11_descriptor_rsa_public_key, pMechanism);
+
+ private_handle = p11_object_create(session, private_handle_flavor,
+ pPrivateKeyTemplate, ulPrivateKeyAttributeCount,
+ &p11_descriptor_rsa_private_key, pMechanism);
+
+ if (public_handle == CK_INVALID_HANDLE || private_handle == CK_INVALID_HANDLE)
+ lose(CKR_FUNCTION_FAILED);
+
+ /*
+ * Generate the keypair.
+ */
+
+ if (!p11_object_get_keyid(private_handle, keyid, sizeof(keyid)) ||
+ cryptlib_create_context(&ctx, CRYPT_ALGO_RSA) != CRYPT_OK ||
+ cryptSetAttributeString(ctx, CRYPT_CTXINFO_LABEL, keyid, strlen(keyid)) != CRYPT_OK ||
+ cryptSetAttribute(ctx, CRYPT_CTXINFO_KEYSIZE, keysize / 8) != CRYPT_OK ||
+ cryptGenerateKey(ctx) != CRYPT_OK ||
+ !p11_object_add_spki(public_handle, private_handle, ctx, p11_object_add_spki_rsa) ||
+ cryptlib_store_key(ctx) != CRYPT_OK ||
+ cryptDestroyContext(ctx) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+
+ /*
+ * Commit the SQL transaction.
+ */
+
+ if (!sql_exec("COMMIT"))
+ lose(CKR_FUNCTION_FAILED);
+
+ /*
+ * All went well, return handles and we're done.
+ */
+ *phPublicKey = public_handle;
+ *phPrivateKey = private_handle;
+ return CKR_OK;
+
+ fail:
+
+ if (ctx != CRYPT_HANDLE_NONE)
+ cryptDestroyContext(ctx);
+
+ if (ctx != CRYPT_HANDLE_NONE && keyid[0] != 0x00)
+ (void) cryptlib_delete_key(keyid);
+
+ if (!sql_exec("ROLLBACK"))
+ rv = CKR_GENERAL_ERROR;
+
+ return rv;
+}
+
+
+
+/*
+ * PKCS #11 API functions.
+ */
+
+CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
+{
+ int initialized_sql = 0, initialized_cryptlib = 0;
+ CK_C_INITIALIZE_ARGS_PTR a = pInitArgs;
+ CK_RV rv;
+
+ if (a != NULL) {
+ int functions_provided = ((a->CreateMutex != NULL) +
+ (a->DestroyMutex != NULL) +
+ (a->LockMutex != NULL) +
+ (a->UnlockMutex != NULL));
+
+ /*
+ * Reserved is, um, reserved.
+ * Threading parameters must either all be present or all be absent.
+ */
+
+ if (a->pReserved != NULL || (functions_provided & 3) != 0)
+ lose(CKR_ARGUMENTS_BAD);
+
+ /*
+ * At present we don't support threads or locking. This may be a
+ * problem for OpenDNSSEC. Need to figure out what the "obvious"
+ * system threading mechanism is supposed to be, or make it
+ * configurable, or something. For the moment, just return the
+ * correct error code to report that we're lame.
+ */
+
+#warning Thread support check disabled, this needs to be fixed
+#if 0
+ if (functions_provided || (a->flags & CKF_OS_LOCKING_OK) != 0)
+ lose(CKR_CANT_LOCK);
+#endif
+ }
+
+ /*
+ * Initialize SQLite3, opening the database(s) and loading the
+ * schema and views.
+ */
+
+ if (!sql_init())
+ lose(CKR_GENERAL_ERROR);
+
+ initialized_sql = 1;
+
+ /*
+ * Initialize cryptlib and open the hardware crypto device (our FPGA).
+ *
+ * The option settings are to make sure that internal stuff like the
+ * PKCS #15 keyset code uses algorithms we like.
+ */
+
+ if (cryptInit() != CRYPT_OK)
+ lose(CKR_GENERAL_ERROR);
+
+ initialized_cryptlib = 1;
+
+ if (cryptSetAttribute(CRYPT_UNUSED, CRYPT_OPTION_ENCR_ALGO, CRYPT_ALGO_AES) != CRYPT_OK ||
+ cryptSetAttribute(CRYPT_UNUSED, CRYPT_OPTION_ENCR_HASH, CRYPT_ALGO_SHA2) != CRYPT_OK)
+ lose(CKR_GENERAL_ERROR);
+
+#if ENABLE_CRYPTLIB_DEVICE
+ if (cryptDeviceOpen(&cryptlib_device, CRYPT_UNUSED, CRYPT_DEVICE_HARDWARE, NULL) != CRYPT_OK)
+ lose(CKR_GENERAL_ERROR);
+#endif
+
+ return CKR_OK;
+
+ fail:
+
+#if ENABLE_CRYPTLIB_DEVICE
+ if (cryptlib_device != CRYPT_HANDLE_NONE) {
+ cryptDeviceClose(cryptlib_device);
+ cryptlib_device = CRYPT_HANDLE_NONE;
+ }
+#endif
+
+ if (initialized_cryptlib)
+ cryptEnd();
+
+ if (initialized_sql)
+ sql_fini();
+
+ return rv;
+}
+
+CK_RV C_Finalize(CK_VOID_PTR pReserved)
+{
+ if (pReserved != NULL)
+ return CKR_ARGUMENTS_BAD;
+
+ /*
+ * Destroy all current sessions.
+ */
+
+ p11_session_delete_all();
+
+ /*
+ * Shut down SQLite3.
+ */
+
+ if (!sql_fini())
+ return CKR_GENERAL_ERROR;
+
+ /*
+ * Shut down hardware device and exit cryptlib. Is there any point
+ * in checking error codes here?
+ */
+
+#if ENABLE_CRYPTLIB_DEVICE
+ if (cryptlib_device != CRYPT_HANDLE_NONE)
+ cryptDeviceClose(cryptlib_device);
+ cryptlib_device = CRYPT_HANDLE_NONE;
+#endif
+
+ cryptEnd();
+ return CKR_OK;
+}
+
+CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
+{
+ /*
+ * Use pkcs11f.h to build dispatch vector for C_GetFunctionList().
+ * This should be const, but that's not what PKCS #11 says, oh well.
+ */
+
+ static CK_FUNCTION_LIST ck_function_list = {
+ { CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR },
+#define CK_PKCS11_FUNCTION_INFO(name) name,
+#include "pkcs11f.h"
+#undef CK_PKCS11_FUNCTION_INFO
+ };
+
+ if (ppFunctionList == NULL)
+ return CKR_ARGUMENTS_BAD;
+
+ *ppFunctionList = &ck_function_list;
+
+ return CKR_OK;
+}
+
+CK_RV C_GetSlotList(CK_BBOOL tokenPresent,
+ CK_SLOT_ID_PTR pSlotList,
+ CK_ULONG_PTR pulCount)
+{
+ /*
+ * We only have one slot, and it's hardwired.
+ */
+
+ if (pulCount == NULL)
+ return CKR_ARGUMENTS_BAD;
+
+ if (pSlotList != NULL && *pulCount < 1)
+ return CKR_BUFFER_TOO_SMALL;
+
+ *pulCount = 1;
+
+ if (pSlotList != NULL)
+ pSlotList[0] = P11_ONE_AND_ONLY_SLOT;
+
+ return CKR_OK;
+}
+
+CK_RV C_GetTokenInfo(CK_SLOT_ID slotID,
+ CK_TOKEN_INFO_PTR pInfo)
+{
+ if (pInfo == NULL)
+ return CKR_ARGUMENTS_BAD;
+
+ if (slotID != P11_ONE_AND_ONLY_SLOT)
+ return CKR_SLOT_ID_INVALID;
+
+ memset(pInfo, 0, sizeof(*pInfo));
+
+ /*
+ * No real idea (yet) how we get many of the following parameters.
+ * See cryptlib's CRYPT_DEVINFO_* attributes for some hints.
+ *
+ * pInfo->label is supposed to be set when the token is initialized.
+ * Not yet sure what that means in our context, but need something
+ * here or the libhsm test programs will bomb trying to find the
+ * right token, so hard-wire something for now.
+ */
+
+ psnprintf(pInfo->label, sizeof(pInfo->label),
+ "Cryptech Token");
+
+ psnprintf(pInfo->manufacturerID, sizeof(pInfo->manufacturerID),
+ "Cryptech Project");
+
+ psnprintf(pInfo->model, sizeof(pInfo->model),
+ "%04x%04x%04x%04x",
+ P11_VERSION_HW_MAJOR, P11_VERSION_HW_MINOR,
+ P11_VERSION_SW_MAJOR, P11_VERSION_SW_MINOR);
+
+ psnprintf(pInfo->serialNumber, sizeof(pInfo->serialNumber),
+ "007");
+
+ pInfo->flags = CKF_RNG | CKF_LOGIN_REQUIRED;
+
+#warning Have not yet sorted out token flags
+#if 0
+ CKF_RNG
+ CKF_WRITE_PROTECTED
+ CKF_LOGIN_REQUIRED
+ CKF_USER_PIN_INITIALIZED
+ CKF_RESTORE_KEY_NOT_NEEDED
+ CKF_CLOCK_ON_TOKEN
+ CKF_PROTECTED_AUTHENTICATION_PATH
+ CKF_DUAL_CRYPTO_OPERATIONS
+ CKF_TOKEN_INITIALIZED
+ CKF_SECONDARY_AUTHENTICATION
+ CKF_USER_PIN_COUNT_LOW
+ CKF_USER_PIN_FINAL_TRY
+ CKF_USER_PIN_LOCKED
+ CKF_USER_PIN_TO_BE_CHANGED
+ CKF_SO_PIN_COUNT_LOW
+ CKF_SO_PIN_FINAL_TRY
+ CKF_SO_PIN_LOCKED
+ CKF_SO_PIN_TO_BE_CHANGED
+ CKF_ERROR_STATE
+#endif
+
+#warning Much of the TOKEN_INFO we return is nonsense
+ pInfo->ulMaxSessionCount = CK_EFFECTIVELY_INFINITE;
+ pInfo->ulSessionCount = CK_UNAVAILABLE_INFORMATION;
+ pInfo->ulMaxRwSessionCount = CK_EFFECTIVELY_INFINITE;
+ pInfo->ulRwSessionCount = CK_UNAVAILABLE_INFORMATION;
+ pInfo->ulMaxPinLen = P11_MAX_PIN_LENGTH;
+ pInfo->ulMinPinLen = P11_MIN_PIN_LENGTH;
+ pInfo->ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION;
+ pInfo->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION;
+ pInfo->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION;
+ pInfo->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION;
+ pInfo->hardwareVersion.major = P11_VERSION_HW_MAJOR;
+ pInfo->hardwareVersion.minor = P11_VERSION_HW_MINOR;
+ pInfo->firmwareVersion.major = P11_VERSION_SW_MAJOR;
+ pInfo->firmwareVersion.minor = P11_VERSION_SW_MINOR;
+
+#warning Need to sort out hardware clock
+#if 0
+ /*
+ * Eventually we expect cryptech devices to have their own hardware
+ * clocks. Not implemented yet.
+ */
+ pInfo->utcTime;
+#endif
+
+ return CKR_OK;
+}
+
+CK_RV C_OpenSession(CK_SLOT_ID slotID,
+ CK_FLAGS flags,
+ CK_VOID_PTR pApplication,
+ CK_NOTIFY Notify,
+ CK_SESSION_HANDLE_PTR phSession)
+{
+ const int parallel_session = (flags & CKF_SERIAL_SESSION) == 0;
+ const int read_only_session = (flags & CKF_RW_SESSION) == 0;
+ p11_session_t *session = NULL;
+ CK_RV rv;
+
+ if (slotID != P11_ONE_AND_ONLY_SLOT)
+ lose(CKR_SLOT_ID_INVALID);
+
+ if (phSession == NULL)
+ lose(CKR_ARGUMENTS_BAD);
+
+ if (parallel_session)
+ lose(CKR_SESSION_PARALLEL_NOT_SUPPORTED);
+
+ if ((session = p11_session_new()) == NULL)
+ lose(CKR_HOST_MEMORY);
+
+ switch (logged_in_as) {
+
+ case not_logged_in:
+ session->state = read_only_session ? CKS_RO_PUBLIC_SESSION : CKS_RW_PUBLIC_SESSION;
+ break;
+
+ case logged_in_as_user:
+ session->state = read_only_session ? CKS_RO_USER_FUNCTIONS : CKS_RW_USER_FUNCTIONS;
+ break;
+
+ case logged_in_as_so:
+ if (read_only_session)
+ lose(CKR_SESSION_READ_WRITE_SO_EXISTS);
+ session->state = CKS_RW_SO_FUNCTIONS;
+ break;
+ }
+
+ session->notify = Notify;
+ session->application = pApplication;
+
+ if (!p11_session_add(session))
+ lose(CKR_FUNCTION_FAILED);
+
+ assert(p11_session_consistent_login());
+
+ *phSession = session->handle;
+ return CKR_OK;
+
+ fail:
+ p11_session_free(session);
+ return rv;
+}
+
+CK_RV C_CloseSession(CK_SESSION_HANDLE hSession)
+{
+ return p11_session_delete(hSession);
+}
+
+CK_RV C_CloseAllSessions(CK_SLOT_ID slotID)
+{
+ if (slotID != P11_ONE_AND_ONLY_SLOT)
+ return CKR_SLOT_ID_INVALID;
+
+ p11_session_delete_all();
+
+ return CKR_OK;
+}
+
+CK_RV C_Login(CK_SESSION_HANDLE hSession,
+ CK_USER_TYPE userType,
+ CK_UTF8CHAR_PTR pPin,
+ CK_ULONG ulPinLen)
+{
+ p11_session_t *session;
+ int crypt_cmd;
+
+ if (pPin == NULL)
+ return CKR_ARGUMENTS_BAD;
+
+ /*
+ * Mind, I don't really know why this function takes a session
+ * handle, given that the semantics don't seem to call upon us to do
+ * anything special for "this" session.
+ */
+
+ if (p11_session_find(hSession) == NULL)
+ return CKR_SESSION_HANDLE_INVALID;
+
+ /*
+ * This is where the combination of pure-software and hardware
+ * starts to get confusing. See the CRYPT_DEVINFO_* attributes for
+ * the operations we can do during device setup (setting PINs,
+ * logging in using pins, etc).
+ *
+ * All fine, but behaves somewhat differently from the case where
+ * we're doing everything in software and using the PIN primarily as
+ * the encryption password for the PKCS #15 keyring.
+ *
+ * In the long run just want the hardware interface. This will
+ * require cleanup.
+ */
+
+ /*
+ * We don't currently support re-login without an intervening
+ * logout, so reject the login attempt if we're already logged in.
+ */
+
+ if (logged_in_as != not_logged_in)
+ return CKR_USER_ALREADY_LOGGED_IN;
+
+ /*
+ * We don't (yet?) support CKU_CONTEXT_SPECIFIC.
+ */
+
+ switch (userType) {
+ case CKU_USER: crypt_cmd = CRYPT_DEVINFO_AUTHENT_USER; break;
+ case CKU_SO: crypt_cmd = CRYPT_DEVINFO_AUTHENT_SUPERVISOR; break;
+ case CKU_CONTEXT_SPECIFIC: return CKR_OPERATION_NOT_INITIALIZED;
+ default: return CKR_USER_TYPE_INVALID;
+ }
+
+ /*
+ * Read-only SO is an illegal state, so reject the login attempt if
+ * we have any read-only sessions and we're trying to log in as SO.
+ */
+
+ if (userType == CKU_SO)
+ for (session = p11_sessions; session != NULL; session = session->link)
+ if (session->state == CKS_RO_PUBLIC_SESSION)
+ return CKR_SESSION_READ_ONLY_EXISTS;
+
+ /*
+ * Ask Cryptlib to log us in. We may need to examine cryptlib error
+ * return more closely than this.
+ */
+
+#if ENABLE_CRYPTLIB_DEVICE
+ if (cryptSetAttributeString(cryptlib_device, crypt_cmd, pPin, ulPinLen) != CRYPT_OK)
+ return CKR_PIN_INCORRECT;
+#endif
+
+#if ENABLE_CRYPTLIB_SOFTWARE
+ {
+ char *newpin;
+ if (memchr(pPin, '\0', ulPinLen) != NULL)
+ return CKR_PIN_INCORRECT;
+ if ((newpin = malloc(ulPinLen + 1)) == NULL)
+ return CKR_HOST_MEMORY;
+ memcpy(newpin, pPin, ulPinLen);
+ newpin[ulPinLen] = '\0';
+ if (pin != NULL)
+ free(pin);
+ pin = newpin;
+ }
+#endif
+
+ /*
+ * Update global login state, then whack each session into correct new state.
+ */
+
+ assert(p11_session_consistent_login());
+
+ logged_in_as = userType == CKU_SO ? logged_in_as_so : logged_in_as_user;
+
+ for (session = p11_sessions; session != NULL; session = session->link) {
+ switch (session->state) {
+
+ case CKS_RO_PUBLIC_SESSION:
+ assert(userType == CKU_USER);
+ session->state = CKS_RO_USER_FUNCTIONS;
+ continue;
+
+ case CKS_RW_PUBLIC_SESSION:
+ session->state = userType == CKU_SO ? CKS_RW_SO_FUNCTIONS : CKS_RW_USER_FUNCTIONS;
+ continue;
+
+ }
+ }
+
+ assert(p11_session_consistent_login());
+
+ return CKR_OK;
+}
+
+CK_RV C_Logout(CK_SESSION_HANDLE hSession)
+{
+ p11_session_t *session;
+ int crypt_cmd;
+
+ /*
+ * Mind, I don't really know why this function takes a session
+ * handle, given that the semantics don't seem to call upon us to do
+ * anything special for "this" session.
+ */
+
+ if (p11_session_find(hSession) == NULL)
+ return CKR_SESSION_HANDLE_INVALID;
+
+ switch (logged_in_as) {
+ case logged_in_as_user: crypt_cmd = CRYPT_DEVINFO_AUTHENT_USER; break;
+ case logged_in_as_so: crypt_cmd = CRYPT_DEVINFO_AUTHENT_SUPERVISOR; break;
+ case not_logged_in: return CKR_USER_NOT_LOGGED_IN;
+ }
+
+ /*
+ * This is a bit problematic, because Cryptlib doesn't have a logout
+ * function per se. For lack of a better idea, construe logout as a
+ * new authentication attempt with an empty PIN. This is a little
+ * weird, but at least it's something we can use as a relatively
+ * clear signal to the HAL, and it's consistent with the way
+ * cryptlib does things like terminating digest inputs.
+ */
+
+#if ENABLE_CRYPTLIB_DEVICE
+ if (cryptSetAttributeString(cryptlib_device, crypt_cmd, "", 0) != CRYPT_OK)
+ return CKR_FUNCTION_FAILED;
+#endif
+
+#if ENABLE_CRYPTLIB_SOFTWARE
+ if (pin != NULL)
+ free(pin);
+ pin = NULL;
+#endif
+
+ /*
+ * Update global login state, then delete any private objects and
+ * whack every existing session into the right state.
+ */
+
+ assert(p11_session_consistent_login());
+
+ logged_in_as = not_logged_in;
+
+ p11_object_delete_all_private();
+
+ for (session = p11_sessions; session != NULL; session = session->link) {
+ switch (session->state) {
+
+ case CKS_RO_USER_FUNCTIONS:
+ session->state = CKS_RO_PUBLIC_SESSION;
+ continue;
+
+ case CKS_RW_USER_FUNCTIONS:
+ case CKS_RW_SO_FUNCTIONS:
+ session->state = CKS_RW_PUBLIC_SESSION;
+ continue;
+
+ }
+ }
+
+ assert(p11_session_consistent_login());
+
+ return CKR_OK;
+}
+
+CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE hObject)
+{
+ static const char select_format[] =
+ " SELECT %s_object_id, keyid FROM object NATURAL JOIN %s_object WHERE object_handle = ?1";
+
+ static const char delete_object[] =
+ " DELETE FROM object WHERE object_handle = ?";
+
+ static const char delete_token_object[] =
+ " DELETE FROM token_object WHERE token_object_id = ?";
+
+ const char *flavor = is_token_handle(hObject) ? "token" : "session";
+
+ p11_session_t *session = p11_session_find(hSession);
+ sqlite3_stmt *q = NULL;
+ CK_RV rv = CKR_OK;
+ sqlite3_int64 id;
+
+ if ((rv = p11_object_check_rights(session, hObject, p11_object_access_write)) != CKR_OK)
+ goto fail;
+
+ if (!sql_check_ok(sql_prepare(&q, select_format, flavor, flavor)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, hObject)))
+ lose(CKR_FUNCTION_FAILED);
+
+ switch (sqlite3_step(q)) {
+ case SQLITE_ROW:
+ break;
+ case SQLITE_DONE:
+ lose(CKR_OBJECT_HANDLE_INVALID);
+ default:
+ sql_whine_step();
+ lose(CKR_FUNCTION_FAILED);
+ }
+
+ id = sqlite3_column_int64(q, 0);
+
+ if (sqlite3_column_type(q, 1) == SQLITE_TEXT &&
+ cryptlib_delete_key((const char *) sqlite3_column_text(q, 1)) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+
+ sqlite3_finalize(q);
+ q = NULL;
+
+ if (is_token_handle(hObject) &&
+ (!sql_check_ok(sql_prepare(&q, delete_token_object)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, id)) ||
+ !sql_check_done(sqlite3_step(q))))
+ lose(CKR_FUNCTION_FAILED);
+
+ sqlite3_finalize(q);
+ q = NULL;
+
+ if (!sql_check_ok(sql_prepare(&q, delete_object)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, hObject)) ||
+ !sql_check_done(sqlite3_step(q)))
+ lose(CKR_FUNCTION_FAILED);
+
+ fail:
+ sqlite3_finalize(q);
+ return rv;
+}
+
+CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE hObject,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulCount)
+{
+ static const char select_format[] =
+ " SELECT value FROM %s_attribute NATURAL JOIN object"
+ " WHERE object_handle = ?1 AND type = ?2";
+
+ const char *flavor = is_token_handle(hObject) ? "token" : "session";
+
+ p11_session_t *session = p11_session_find(hSession);
+ const p11_descriptor_t *descriptor = NULL;
+ CK_BBOOL cka_sensitive, cka_extractable;
+ CK_OBJECT_CLASS cka_class;
+ CK_KEY_TYPE cka_key_type;
+ int sensitive_object = 0;
+ sqlite3_stmt *q = NULL;
+ CK_RV rv = CKR_OK;
+ int ret, i;
+
+ if (pTemplate == NULL)
+ lose(CKR_ARGUMENTS_BAD);
+
+ if ((rv = p11_object_check_rights(session, hObject, p11_object_access_read)) != CKR_OK)
+ goto fail;
+
+ if (!p11_attribute_get_ulong(hObject, CKA_CLASS, &cka_class))
+ lose(CKR_OBJECT_HANDLE_INVALID);
+
+ switch (cka_class) {
+
+ case CKO_PRIVATE_KEY:
+ case CKO_SECRET_KEY:
+ if (!p11_attribute_get_bbool(hObject, CKA_EXTRACTABLE, &cka_extractable) ||
+ !p11_attribute_get_bbool(hObject, CKA_SENSITIVE, &cka_sensitive))
+ lose(CKR_OBJECT_HANDLE_INVALID);
+
+ sensitive_object = cka_sensitive || !cka_extractable;
+
+ /* Fall through */
+
+ case CKO_PUBLIC_KEY:
+ if (!p11_attribute_get_ulong(hObject, CKA_KEY_TYPE, &cka_key_type))
+ lose(CKR_OBJECT_HANDLE_INVALID);
+ descriptor = p11_descriptor_from_key_type(cka_class, cka_key_type);
+ }
+
+ if (!sql_check_ok(sql_prepare(&q, select_format, flavor)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 1, hObject)))
+ lose(CKR_FUNCTION_FAILED);
+
+ for (i = 0; i < ulCount; i++) {
+
+ if (sensitive_object && p11_attribute_is_sensitive(descriptor, pTemplate[i].type)) {
+ pTemplate[i].ulValueLen = -1;
+ rv = CKR_ATTRIBUTE_SENSITIVE;
+ }
+
+ else if (!sql_check_ok(sqlite3_reset(q)) ||
+ !sql_check_ok(sqlite3_bind_int64(q, 2, pTemplate[i].type)) ||
+ (ret = sqlite3_step(q)) != SQLITE_ROW) {
+ if (ret != SQLITE_DONE)
+ sql_whine_step();
+ pTemplate[i].ulValueLen = -1;
+ rv = CKR_ATTRIBUTE_TYPE_INVALID;
+ }
+
+ else if (pTemplate[i].pValue == NULL) {
+ pTemplate[i].ulValueLen = sqlite3_column_bytes(q, 0);
+ }
+
+ else if (pTemplate[i].ulValueLen >= sqlite3_column_bytes(q, 0)) {
+ pTemplate[i].ulValueLen = sqlite3_column_bytes(q, 0);
+ memcpy(pTemplate[i].pValue, sqlite3_column_blob(q, 0), pTemplate[i].ulValueLen);
+ }
+
+ else {
+ pTemplate[i].ulValueLen = -1;
+ rv = CKR_BUFFER_TOO_SMALL;
+ }
+
+ }
+
+ fail:
+ sqlite3_finalize(q);
+ return rv;
+}
+
+CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulCount)
+{
+ static const char select_missing[] =
+ " WITH"
+ " known AS (SELECT token_object_id FROM object WHERE token_object_id IS NOT NULL)"
+ " SELECT token_object_id FROM token_object WHERE token_object_id NOT IN known";
+
+ static const char insert_missing[] =
+ " INSERT INTO object (object_handle, token_object_id) VALUES (?1, ?2)";
+
+ static const char create_format[] =
+ " CREATE TEMPORARY TABLE findobjects_%lu AS"
+ " SELECT object_id FROM object NATURAL LEFT JOIN session"
+ " WHERE session_handle IS NULL OR session_handle = ?1";
+
+ static const char drop_format[] =
+ " DROP TABLE IF EXISTS findobjects_%lu";
+
+ static const char delete_format[] =
+ " WITH"
+ " matches AS (SELECT object_id"
+ " FROM object NATURAL JOIN session_attribute"
+ " WHERE type = ?1 AND value = ?2"
+ " UNION"
+ " SELECT object_id"
+ " FROM object NATURAL JOIN token_attribute"
+ " WHERE type = ?1 AND value = ?2)"
+ " DELETE FROM findobjects_%lu WHERE object_id NOT IN matches";
+
+ static const char select_format[] =
+ " SELECT object_handle FROM findobjects_%lu NATURAL JOIN object ORDER BY object_id";
+
+ p11_session_t *session = p11_session_find(hSession);
+ sqlite3_stmt *q1 = NULL, *q2 = NULL;
+ CK_RV rv = CKR_OK;
+ int i, ret;
+
+ if (session == NULL)
+ lose(CKR_SESSION_HANDLE_INVALID);
+
+ if (ulCount > 0 && pTemplate == NULL)
+ lose(CKR_ARGUMENTS_BAD);
+
+ if (session->find_query != NULL)
+ lose(CKR_OPERATION_ACTIVE);
+
+ /*
+ * Assign handles to any token objects that don't have them yet.
+ */
+
+ if (!sql_check_ok(sql_prepare(&q1, select_missing)) ||
+ !sql_check_ok(sql_prepare(&q2, insert_missing)))
+ lose(CKR_FUNCTION_FAILED);
+
+ while ((ret = sqlite3_step(q1)) == SQLITE_ROW) {
+ sqlite3_int64 token_object_id = sqlite3_column_int64(q1, 0);
+ CK_OBJECT_HANDLE object_handle = p11_allocate_unused_handle(handle_flavor_token_object);
+
+ if (!sql_check_ok(sqlite3_reset(q2)) ||
+ !sql_check_ok(sqlite3_bind_int64(q2, 1, object_handle)) ||
+ !sql_check_ok(sqlite3_bind_int64(q2, 2, token_object_id)) ||
+ !sql_check_done(sqlite3_step(q2)))
+ lose(CKR_FUNCTION_FAILED);
+ }
+
+ if (ret != SQLITE_DONE) {
+ sql_whine_step();
+ lose(CKR_FUNCTION_FAILED);
+ }
+
+ sqlite3_finalize(q1);
+ sqlite3_finalize(q2);
+ q1 = q2 = NULL;
+
+ /*
+ * Create a temporary table to hold this session's FindObjects
+ * state. Populate this with every object this session knows about,
+ * then prune based on login status and whatever filter attributes
+ * the caller supplied.
+ */
+
+ if (!sql_check_ok(sql_prepare(&q1, drop_format, hSession)) ||
+ !sql_check_done(sqlite3_step(q1)) ||
+ !sql_check_ok(sql_prepare(&q2, create_format, hSession)) ||
+ !sql_check_ok(sqlite3_bind_int64(q2, 1, hSession)) ||
+ !sql_check_done(sqlite3_step(q2)))
+ lose(CKR_FUNCTION_FAILED);
+
+ sqlite3_finalize(q1);
+ sqlite3_finalize(q2);
+ q1 = q2 = NULL;
+
+ if (!sql_check_ok(sql_prepare(&q1, delete_format, hSession)))
+ lose(CKR_FUNCTION_FAILED);
+
+ /*
+ * We only see private objects when logged in as the regular user.
+ */
+
+ if (logged_in_as != logged_in_as_user) {
+ if (!sql_check_ok(sqlite3_bind_int64(q1, 1, CKA_PRIVATE)) ||
+ !sql_check_ok(sqlite3_bind_blob(q1, 2, &const_CK_FALSE, sizeof(const_CK_FALSE), NULL)) ||
+ !sql_check_done(sqlite3_step(q1)))
+ lose(CKR_FUNCTION_FAILED);
+ }
+
+ /*
+ * Filter through the caller-supplied template.
+ *
+ * NB: This doesn't support some of the more obscure searches, such
+ * as searches for sessions or hardware features. Too much rope
+ * already, worry about those if we ever really need them.
+ */
+
+ for (i = 0; i < ulCount; i++)
+ if (!sql_check_ok(sqlite3_reset(q1)) ||
+ !sql_check_ok(sqlite3_bind_int64(q1, 1, pTemplate[i].type)) ||
+ !sql_check_ok(sqlite3_bind_blob( q1, 2, pTemplate[i].pValue,
+ pTemplate[i].ulValueLen, NULL)) ||
+ !sql_check_done(sqlite3_step(q1)))
+ lose(CKR_FUNCTION_FAILED);
+
+ /*
+ * Stash a prepared query in the session object which will return
+ * whatever object handles survived all that filtering.
+ */
+
+ if (!sql_check_ok(sql_prepare(&session->find_query, select_format, hSession)))
+ lose(CKR_FUNCTION_FAILED);
+ session->find_query_done = 0;
+
+ fail:
+ sqlite3_finalize(q1);
+ sqlite3_finalize(q2);
+ return rv;
+}
+
+CK_RV C_FindObjects(CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE_PTR phObject,
+ CK_ULONG ulMaxObjectCount,
+ CK_ULONG_PTR pulObjectCount)
+{
+ p11_session_t *session = p11_session_find(hSession);
+ int i, ret = SQLITE_OK;
+ CK_RV rv = CKR_OK;
+
+ if (session == NULL)
+ lose(CKR_SESSION_HANDLE_INVALID);
+
+ if (session->find_query == NULL)
+ lose(CKR_OPERATION_NOT_INITIALIZED);
+
+ if (phObject == NULL || pulObjectCount == NULL)
+ lose(CKR_ARGUMENTS_BAD);
+
+ /*
+ * C_FindObjectsInit() did all the heavy lifting, we just have to
+ * return the resulting handles.
+ */
+
+ i = 0;
+
+ if (!session->find_query_done)
+ while (i < ulMaxObjectCount && (ret = sqlite3_step(session->find_query)) == SQLITE_ROW)
+ phObject[i++] = (CK_OBJECT_HANDLE) sqlite3_column_int64(session->find_query, 0);
+
+ switch (ret) {
+
+ case SQLITE_DONE:
+ session->find_query_done = 1;
+ break;
+
+ case SQLITE_OK:
+ case SQLITE_ROW:
+ break;
+
+ default:
+ sql_whine_step();
+ lose(CKR_FUNCTION_FAILED);
+
+ }
+
+ *pulObjectCount = i;
+
+ fail:
+ return rv;
+}
+
+CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
+{
+ static const char drop_format[] =
+ " DROP TABLE IF EXISTS findobjects_%lu";
+
+ p11_session_t *session = p11_session_find(hSession);
+ sqlite3_stmt *q = NULL;
+ CK_RV rv = CKR_OK;
+
+ if (session == NULL)
+ lose(CKR_SESSION_HANDLE_INVALID);
+
+ if (session->find_query == NULL)
+ lose(CKR_OPERATION_NOT_INITIALIZED);
+
+ /*
+ * Clean up result query and temporary table.
+ */
+
+ sqlite3_finalize(session->find_query);
+ session->find_query = NULL;
+
+ if (!sql_check_ok(sql_prepare(&q, drop_format, hSession)) ||
+ !sql_check_done(sqlite3_step(q)))
+ lose(CKR_FUNCTION_FAILED);
+
+ fail:
+ sqlite3_finalize(q);
+ return rv;
+}
+
+CK_RV C_DigestInit(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism)
+{
+ p11_session_t *session = p11_session_find(hSession);
+ CRYPT_ALGO_TYPE algo;
+ unsigned hash_len;
+ CK_RV rv;
+
+ if (session == NULL)
+ return CKR_SESSION_HANDLE_INVALID;
+
+ if (pMechanism == NULL)
+ return CKR_ARGUMENTS_BAD;
+
+ if (session->digest_context != CRYPT_HANDLE_NONE)
+ return CKR_OPERATION_ACTIVE;
+
+ switch (pMechanism->mechanism) {
+ case CKM_SHA_1: algo = CRYPT_ALGO_SHA1; break;
+ case CKM_SHA256: algo = CRYPT_ALGO_SHA2; hash_len = 256; break;
+ case CKM_SHA384: algo = CRYPT_ALGO_SHA2; hash_len = 384; break;
+ case CKM_SHA512: algo = CRYPT_ALGO_SHA2; hash_len = 512; break;
+ default: return CKR_MECHANISM_INVALID;
+ }
+
+ assert((hash_len & 7) == 0);
+
+ if (cryptlib_create_context(&session->digest_context, algo) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+
+ if (algo == CRYPT_ALGO_SHA2 &&
+ cryptSetAttribute(session->digest_context, CRYPT_CTXINFO_BLOCKSIZE, hash_len >> 3) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+
+ return CKR_OK;
+
+ fail:
+ if (session->digest_context != CRYPT_HANDLE_NONE)
+ cryptDestroyContext(session->digest_context);
+ session->digest_context = CRYPT_HANDLE_NONE;
+ return rv;
+}
+
+CK_RV C_Digest(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pData,
+ CK_ULONG ulDataLen,
+ CK_BYTE_PTR pDigest,
+ CK_ULONG_PTR pulDigestLen)
+{
+ p11_session_t *session = p11_session_find(hSession);
+ CK_RV rv;
+ int len;
+
+ if (session == NULL)
+ return CKR_SESSION_HANDLE_INVALID;
+
+ if (pData == NULL || pulDigestLen == NULL)
+ return CKR_ARGUMENTS_BAD;
+
+ if (session->digest_context == CRYPT_HANDLE_NONE)
+ return CKR_OPERATION_NOT_INITIALIZED;
+
+ if (pDigest == NULL) {
+ if (cryptGetAttribute(session->digest_context, CRYPT_CTXINFO_BLOCKSIZE, &len) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+ *pulDigestLen = len;
+ return CKR_OK;
+ }
+
+ if (cryptEncrypt(session->digest_context, pData, ulDataLen) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+
+ if (ulDataLen != 0 &&
+ cryptEncrypt(session->digest_context, pData, 0) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+
+ if (cryptGetAttributeString(session->digest_context,
+ CRYPT_CTXINFO_HASHVALUE, NULL, &len) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+
+ if (len > *pulDigestLen)
+ lose(CKR_BUFFER_TOO_SMALL);
+
+ if (cryptGetAttributeString(session->digest_context,
+ CRYPT_CTXINFO_HASHVALUE, pDigest, &len) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+
+ *pulDigestLen = len;
+
+ rv = CKR_OK; /* Fall through */
+
+ fail:
+ cryptDestroyContext(session->digest_context);
+ session->digest_context = CRYPT_HANDLE_NONE;
+ return rv;
+}
+
+CK_RV C_SignInit(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey)
+{
+ p11_session_t *session = p11_session_find(hSession);
+ char keyid[CRYPT_MAX_HASHSIZE * 2 + 1];
+ CRYPT_ALGO_TYPE sign_algo, hash_algo;
+ unsigned hash_size = 0;
+ int key_algo;
+ CK_RV rv;
+
+ if (session == NULL)
+ return CKR_SESSION_HANDLE_INVALID;
+
+ if (pMechanism == NULL)
+ return CKR_ARGUMENTS_BAD;
+
+ if (session->sign_key_context != CRYPT_HANDLE_NONE ||
+ session->sign_digest_context != CRYPT_HANDLE_NONE)
+ return CKR_OPERATION_ACTIVE;
+
+ if ((rv = p11_object_check_rights(session, hKey, p11_object_access_read)) != CKR_OK)
+ goto fail;
+
+ switch (pMechanism->mechanism) {
+ case CKM_RSA_PKCS: sign_algo = CRYPT_ALGO_RSA; hash_algo = CRYPT_ALGO_NONE; break;
+ case CKM_SHA1_RSA_PKCS: sign_algo = CRYPT_ALGO_RSA; hash_algo = CRYPT_ALGO_SHA1; break;
+ case CKM_SHA256_RSA_PKCS: sign_algo = CRYPT_ALGO_RSA; hash_algo = CRYPT_ALGO_SHA2; hash_size = 256; break;
+ case CKM_SHA384_RSA_PKCS: sign_algo = CRYPT_ALGO_RSA; hash_algo = CRYPT_ALGO_SHA2; hash_size = 384; break;
+ case CKM_SHA512_RSA_PKCS: sign_algo = CRYPT_ALGO_RSA; hash_algo = CRYPT_ALGO_SHA2; hash_size = 512; break;
+ default: return CKR_MECHANISM_INVALID;
+ }
+
+ assert((hash_size & 7) == 0);
+
+ if (!p11_object_get_keyid(hKey, keyid, sizeof(keyid)) ||
+ cryptlib_load_key(&session->sign_key_context, keyid) != CRYPT_OK ||
+ cryptGetAttribute(session->sign_key_context, CRYPT_CTXINFO_ALGO, &key_algo) != CRYPT_OK)
+ lose(CKR_KEY_HANDLE_INVALID);
+
+ if (sign_algo != key_algo)
+ lose(CKR_KEY_TYPE_INCONSISTENT);
+
+ if (hash_algo != CRYPT_ALGO_NONE &&
+ cryptlib_create_context(&session->sign_digest_context, hash_algo) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+
+ if (hash_algo == CRYPT_ALGO_SHA2 &&
+ cryptSetAttribute(session->sign_digest_context,
+ CRYPT_CTXINFO_BLOCKSIZE, hash_size >> 3) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+
+ return CKR_OK;
+
+ fail:
+ if (session->sign_key_context != CRYPT_HANDLE_NONE)
+ cryptDestroyContext(session->sign_key_context);
+ session->sign_key_context = CRYPT_HANDLE_NONE;
+
+ if (session->sign_digest_context != CRYPT_HANDLE_NONE)
+ cryptDestroyContext(session->sign_digest_context);
+ session->sign_digest_context = CRYPT_HANDLE_NONE;
+
+ return rv;
+}
+
+CK_RV C_Sign(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pData,
+ CK_ULONG ulDataLen,
+ CK_BYTE_PTR pSignature,
+ CK_ULONG_PTR pulSignatureLen)
+{
+ p11_session_t *session = p11_session_find(hSession);
+ int len, algo;
+ CK_RV rv;
+
+ if (session == NULL)
+ return CKR_SESSION_HANDLE_INVALID;
+
+ if (pData == NULL || pulSignatureLen == NULL)
+ return CKR_ARGUMENTS_BAD;
+
+ if (session->sign_key_context == CRYPT_HANDLE_NONE)
+ return CKR_OPERATION_NOT_INITIALIZED;
+
+ if (pSignature == NULL) {
+ /*
+ * Caller just wants to know the signature length, which we can
+ * get from cryptCreateSignature(), using a dummy hash context if
+ * necessary.
+ *
+ * There may be an easier way: at least for RSA, reading the key's
+ * CRYPT_CTXINFO_KEYSIZE would give us the answer. But the
+ * constraint that messages_size == key_size doesn't necessarily
+ * hold for all asymmetric algorithms, so best to be safe here.
+ */
+
+ CRYPT_CONTEXT ctx = session->sign_digest_context;
+
+ if (ctx == CRYPT_HANDLE_NONE && cryptCreateContext(&ctx, CRYPT_UNUSED, CRYPT_ALGO_SHA2) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+
+ if (cryptCreateSignature(NULL, 0, &len, session->sign_key_context, ctx) != CRYPT_OK)
+ len = 0;
+
+ if (session->sign_digest_context == CRYPT_HANDLE_NONE)
+ cryptDestroyContext(ctx);
+
+ if (len == 0)
+ lose(CKR_FUNCTION_FAILED);
+ }
+
+ else if (session->sign_digest_context != CRYPT_HANDLE_NONE) {
+ /*
+ * Caller wanted a hash-and-sign operation, so we can use cryptCreateSignature().
+ */
+
+ if (cryptEncrypt(session->sign_digest_context, pData, ulDataLen) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+
+ if (ulDataLen != 0 &&
+ cryptEncrypt(session->sign_digest_context, pData, 0) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+
+ if (cryptCreateSignature(pSignature, *pulSignatureLen, &len,
+ session->sign_key_context,
+ session->sign_digest_context) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+ }
+
+ else {
+
+ /*
+ * Caller wanted a pure-signature operation, have to use
+ * cryptDeCrypt() [sic].
+ *
+ * At the moment we just blindly sign this without checking that
+ * what we're signing really is (eg) a valid DigestInfo SEQUENCE.
+ * Should we bother checking the syntax here, given that we have
+ * no way of checking the digest itself (if we get here, we've
+ * never seen the original plaintext, just the purported digest)?
+ */
+
+ if (cryptGetAttribute(session->sign_key_context, CRYPT_CTXINFO_ALGO, &algo) != CRYPT_OK ||
+ cryptGetAttribute(session->sign_key_context, CRYPT_CTXINFO_KEYSIZE, &len) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+
+ switch (algo) {
+
+ case CRYPT_ALGO_RSA:
+
+ /*
+ * Congregation will now please turn to RFC 2313 8.1 as we
+ * construct a PKCS #1.5 type 01 encryption block.
+ */
+
+ if (len > *pulSignatureLen)
+ lose(CKR_BUFFER_TOO_SMALL);
+
+ if (ulDataLen > len - 11)
+ return CKR_DATA_LEN_RANGE;
+
+ pSignature[0] = 0x00;
+ pSignature[1] = 0x01;
+ memset(pSignature + 2, 0xFF, len - 3 - ulDataLen);
+ pSignature[len - ulDataLen - 1] = 0x00;
+ memcpy(pSignature + len - ulDataLen, pData, ulDataLen);
+
+#if 0
+ /* XXX */
+ {
+ int i;
+ fprintf(stderr, "[PKCS #1.5 len %lu ulDataLen %lu block ", len, ulDataLen);
+ for (i = 0; i < len; i++)
+ fprintf(stderr, "%s%02x", i == 0 ? "" : ":", pSignature[i]);
+ fprintf(stderr, "]\n");
+ }
+#endif
+
+ break;
+
+ default:
+ lose(CKR_FUNCTION_FAILED);
+ }
+
+ /*
+ * The terms "encrypt" and "decrypt" get weird when one goes this
+ * far past the API that a sane person would be using. As
+ * explained in RFC 3447, the RSASP1 (signature generation)
+ * operation is the same mathematical operation as the RSADP
+ * (decryption) operation, so we have to use cryptDecrypt(), not
+ * cryptEncrypt() here. No, really.
+ *
+ * Well, this works for RSA, anyway. ECDSA may turn out to be a
+ * whole different bucket of monkey guts.
+ */
+
+ if (cryptDecrypt(session->sign_key_context, pSignature, len) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+ }
+
+ *pulSignatureLen = len;
+
+ rv = CKR_OK; /* Fall through */
+
+ fail:
+
+ if (session->sign_digest_context != CRYPT_HANDLE_NONE)
+ cryptDestroyContext(session->sign_digest_context);
+ session->sign_digest_context = CRYPT_HANDLE_NONE;
+
+ cryptDestroyContext(session->sign_key_context);
+ session->sign_key_context = CRYPT_HANDLE_NONE;
+
+ return rv;
+}
+
+/*
+ * libhsm only uses C_GenerateKey() for DSA parameter generation.
+ * More general use presumably wants this for things like generating
+ * symmetric keys for later wrapping by asymmetric keys.
+ */
+CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulCount,
+ CK_OBJECT_HANDLE_PTR phKey)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_ATTRIBUTE_PTR pPublicKeyTemplate,
+ CK_ULONG ulPublicKeyAttributeCount,
+ CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
+ CK_ULONG ulPrivateKeyAttributeCount,
+ CK_OBJECT_HANDLE_PTR phPublicKey,
+ CK_OBJECT_HANDLE_PTR phPrivateKey)
+{
+ p11_session_t *session = p11_session_find(hSession);
+
+ if (session == NULL)
+ return CKR_SESSION_HANDLE_INVALID;
+
+ if (pMechanism == NULL ||
+ pPublicKeyTemplate == NULL || phPublicKey == NULL ||
+ pPrivateKeyTemplate == NULL || phPrivateKey == NULL)
+ return CKR_ARGUMENTS_BAD;
+
+ switch (pMechanism->mechanism) {
+ case CKM_RSA_PKCS_KEY_PAIR_GEN:
+ return generate_keypair_rsa_pkcs(session, pMechanism,
+ pPublicKeyTemplate, ulPublicKeyAttributeCount,
+ pPrivateKeyTemplate, ulPrivateKeyAttributeCount,
+ phPublicKey, phPrivateKey);
+ default:
+ return CKR_MECHANISM_INVALID;
+ }
+}
+
+CK_RV C_GenerateRandom(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR RandomData,
+ CK_ULONG ulRandomLen)
+{
+ p11_session_t *session = p11_session_find(hSession);
+ CRYPT_CONTEXT ctx = CRYPT_HANDLE_NONE;
+ CK_RV rv = CKR_OK;
+
+ if (session == NULL)
+ return CKR_SESSION_HANDLE_INVALID;
+
+ if (RandomData == NULL)
+ return CKR_ARGUMENTS_BAD;
+
+ /*
+ * Cryptlib doesn't expose the raw TRNG, but, per the manual, block
+ * cipher encryption output with a randomly generated key is good
+ * enough for most sane purposes.
+ *
+ * Not certain why the Cryptlib manual suggests using CFB mode
+ * instead of OFB mode here, but going with the manual for now.
+ */
+
+ if (cryptCreateContext(&ctx, CRYPT_UNUSED, CRYPT_ALGO_AES) != CRYPT_OK ||
+ cryptSetAttribute(ctx, CRYPT_CTXINFO_MODE, CRYPT_MODE_CFB) != CRYPT_OK ||
+ cryptGenerateKey(ctx) != CRYPT_OK ||
+ cryptEncrypt(ctx, RandomData, ulRandomLen) != CRYPT_OK)
+ lose(CKR_FUNCTION_FAILED);
+
+ fail:
+ if (ctx != CRYPT_HANDLE_NONE)
+ (void) cryptDestroyContext(ctx);
+
+ return rv;
+}
+
+
+
+/*
+ * Stubs for unsupported functions below here. Per the PKCS #11
+ * specification, it's OK to skip implementing almost any function in
+ * the API, but if one does so, one must provide a stub which returns
+ * CKR_FUNCTION_NOT_SUPPORTED, because every slot in the dispatch
+ * vector must be populated. We could reuse a single stub for all the
+ * unimplemented slots, but the type signatures wouldn't match, which
+ * would require some nasty casts I'd rather avoid.
+ *
+ * Many of these functions would be straightforward to implement, but
+ * there are enough bald yaks in this saga already.
+ */
+
+CK_RV C_GetInfo(CK_INFO_PTR pInfo)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_GetSlotInfo(CK_SLOT_ID slotID,
+ CK_SLOT_INFO_PTR pInfo)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_GetMechanismList(CK_SLOT_ID slotID,
+ CK_MECHANISM_TYPE_PTR pMechanismList,
+ CK_ULONG_PTR pulCount)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID,
+ CK_MECHANISM_TYPE type,
+ CK_MECHANISM_INFO_PTR pInfo)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_InitToken(CK_SLOT_ID slotID,
+ CK_UTF8CHAR_PTR pPin,
+ CK_ULONG ulPinLen,
+ CK_UTF8CHAR_PTR pLabel)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_InitPIN(CK_SESSION_HANDLE hSession,
+ CK_UTF8CHAR_PTR pPin,
+ CK_ULONG ulPinLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_SetPIN(CK_SESSION_HANDLE hSession,
+ CK_UTF8CHAR_PTR pOldPin,
+ CK_ULONG ulOldLen,
+ CK_UTF8CHAR_PTR pNewPin,
+ CK_ULONG ulNewLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession,
+ CK_SESSION_INFO_PTR pInfo)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_GetOperationState(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pOperationState,
+ CK_ULONG_PTR pulOperationStateLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_SetOperationState(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pOperationState,
+ CK_ULONG ulOperationStateLen,
+ CK_OBJECT_HANDLE hEncryptionKey,
+ CK_OBJECT_HANDLE hAuthenticationKey)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_CreateObject(CK_SESSION_HANDLE hSession,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulCount,
+ CK_OBJECT_HANDLE_PTR phObject)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_CopyObject(CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE hObject,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulCount,
+ CK_OBJECT_HANDLE_PTR phNewObject)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_GetObjectSize(CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE hObject,
+ CK_ULONG_PTR pulSize)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_SetAttributeValue(CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE hObject,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulCount)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_EncryptInit(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_Encrypt(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pData,
+ CK_ULONG ulDataLen,
+ CK_BYTE_PTR pEncryptedData,
+ CK_ULONG_PTR pulEncryptedDataLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_EncryptUpdate(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen,
+ CK_BYTE_PTR pEncryptedPart,
+ CK_ULONG_PTR pulEncryptedPartLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_EncryptFinal(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pLastEncryptedPart,
+ CK_ULONG_PTR pulLastEncryptedPartLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_Decrypt(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pEncryptedData,
+ CK_ULONG ulEncryptedDataLen,
+ CK_BYTE_PTR pData,
+ CK_ULONG_PTR pulDataLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_DecryptUpdate(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pEncryptedPart,
+ CK_ULONG ulEncryptedPartLen,
+ CK_BYTE_PTR pPart,
+ CK_ULONG_PTR pulPartLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_DecryptFinal(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pLastPart,
+ CK_ULONG_PTR pulLastPartLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_DigestUpdate(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_DigestKey(CK_SESSION_HANDLE hSession,
+ CK_OBJECT_HANDLE hKey)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_DigestFinal(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pDigest,
+ CK_ULONG_PTR pulDigestLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_SignUpdate(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_SignFinal(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pSignature,
+ CK_ULONG_PTR pulSignatureLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_SignRecoverInit(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_SignRecover(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pData,
+ CK_ULONG ulDataLen,
+ CK_BYTE_PTR pSignature,
+ CK_ULONG_PTR pulSignatureLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey )
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_Verify(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pData,
+ CK_ULONG ulDataLen,
+ CK_BYTE_PTR pSignature,
+ CK_ULONG ulSignatureLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_VerifyUpdate(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_VerifyFinal(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pSignature,
+ CK_ULONG ulSignatureLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hKey)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_VerifyRecover(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pSignature,
+ CK_ULONG ulSignatureLen,
+ CK_BYTE_PTR pData,
+ CK_ULONG_PTR pulDataLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_DigestEncryptUpdate(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen,
+ CK_BYTE_PTR pEncryptedPart,
+ CK_ULONG_PTR pulEncryptedPartLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_DecryptDigestUpdate(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pEncryptedPart,
+ CK_ULONG ulEncryptedPartLen,
+ CK_BYTE_PTR pPart,
+ CK_ULONG_PTR pulPartLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_SignEncryptUpdate(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pPart,
+ CK_ULONG ulPartLen,
+ CK_BYTE_PTR pEncryptedPart,
+ CK_ULONG_PTR pulEncryptedPartLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pEncryptedPart,
+ CK_ULONG ulEncryptedPartLen,
+ CK_BYTE_PTR pPart,
+ CK_ULONG_PTR pulPartLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_WrapKey(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hWrappingKey,
+ CK_OBJECT_HANDLE hKey,
+ CK_BYTE_PTR pWrappedKey,
+ CK_ULONG_PTR pulWrappedKeyLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hUnwrappingKey,
+ CK_BYTE_PTR pWrappedKey,
+ CK_ULONG ulWrappedKeyLen,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ CK_OBJECT_HANDLE_PTR phKey)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession,
+ CK_MECHANISM_PTR pMechanism,
+ CK_OBJECT_HANDLE hBaseKey,
+ CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulAttributeCount,
+ CK_OBJECT_HANDLE_PTR phKey)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_SeedRandom(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR pSeed,
+ CK_ULONG ulSeedLen)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_GetFunctionStatus(CK_SESSION_HANDLE hSession)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_CancelFunction(CK_SESSION_HANDLE hSession)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+CK_RV C_WaitForSlotEvent(CK_FLAGS flags,
+ CK_SLOT_ID_PTR pSlot,
+ CK_VOID_PTR pRserved)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
+/*
+ * "Any programmer who fails to comply with the standard naming, formatting,
+ * or commenting conventions should be shot. If it so happens that it is
+ * inconvenient to shoot him, then he is to be politely requested to recode
+ * his program in adherence to the above standard."
+ * -- Michael Spier, Digital Equipment Corporation
+ *
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/pkcs11.h b/pkcs11.h
new file mode 100644
index 0000000..996b4db
--- /dev/null
+++ b/pkcs11.h
@@ -0,0 +1,301 @@
+/* 02-Sep-2008 from ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-11/v2-20/ */
+
+/* pkcs11.h include file for PKCS #11. */
+/* $Revision: 1.4 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+#ifndef _PKCS11_H_
+#define _PKCS11_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Before including this file (pkcs11.h) (or pkcs11t.h by
+ * itself), 6 platform-specific macros must be defined. These
+ * macros are described below, and typical definitions for them
+ * are also given. Be advised that these definitions can depend
+ * on both the platform and the compiler used (and possibly also
+ * on whether a Cryptoki library is linked statically or
+ * dynamically).
+ *
+ * In addition to defining these 6 macros, the packing convention
+ * for Cryptoki structures should be set. The Cryptoki
+ * convention on packing is that structures should be 1-byte
+ * aligned.
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, this might be done by using the following
+ * preprocessor directive before including pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(push, cryptoki, 1)
+ *
+ * and using the following preprocessor directive after including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(pop, cryptoki)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, this might be done by using
+ * the following preprocessor directive before including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(1)
+ *
+ * In a UNIX environment, you're on your own for this. You might
+ * not need to do (or be able to do!) anything.
+ *
+ *
+ * Now for the macros:
+ *
+ *
+ * 1. CK_PTR: The indirection string for making a pointer to an
+ * object. It can be used like this:
+ *
+ * typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, it might be defined by:
+ *
+ * #define CK_PTR far *
+ *
+ * In a typical UNIX environment, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ *
+ * 2. CK_DEFINE_FUNCTION(returnType, name): A macro which makes
+ * an exportable Cryptoki library function definition out of a
+ * return type and a function name. It should be used in the
+ * following fashion to define the exposed Cryptoki functions in
+ * a Cryptoki library:
+ *
+ * CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(
+ * CK_VOID_PTR pReserved
+ * )
+ * {
+ * ...
+ * }
+ *
+ * If you're using Microsoft Developer Studio 5.0 to define a
+ * function in a Win32 Cryptoki .dll, it might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ * returnType __declspec(dllexport) name
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to define a function in a Win16 Cryptoki .dll, it
+ * might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ * returnType __export _far _pascal name
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ * returnType name
+ *
+ *
+ * 3. CK_DECLARE_FUNCTION(returnType, name): A macro which makes
+ * an importable Cryptoki library function declaration out of a
+ * return type and a function name. It should be used in the
+ * following fashion:
+ *
+ * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)(
+ * CK_VOID_PTR pReserved
+ * );
+ *
+ * If you're using Microsoft Developer Studio 5.0 to declare a
+ * function in a Win32 Cryptoki .dll, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType __declspec(dllimport) name
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to declare a function in a Win16 Cryptoki .dll, it
+ * might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType __export _far _pascal name
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType name
+ *
+ *
+ * 4. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro
+ * which makes a Cryptoki API function pointer declaration or
+ * function pointer type declaration out of a return type and a
+ * function name. It should be used in the following fashion:
+ *
+ * // Define funcPtr to be a pointer to a Cryptoki API function
+ * // taking arguments args and returning CK_RV.
+ * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args);
+ *
+ * or
+ *
+ * // Define funcPtrType to be the type of a pointer to a
+ * // Cryptoki API function taking arguments args and returning
+ * // CK_RV, and then define funcPtr to be a variable of type
+ * // funcPtrType.
+ * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args);
+ * funcPtrType funcPtr;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to access
+ * functions in a Win32 Cryptoki .dll, in might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType __declspec(dllimport) (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to access functions in a Win16 Cryptoki .dll, it might
+ * be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType __export _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType (* name)
+ *
+ *
+ * 5. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes
+ * a function pointer type for an application callback out of
+ * a return type for the callback and a name for the callback.
+ * It should be used in the following fashion:
+ *
+ * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args);
+ *
+ * to declare a function pointer, myCallback, to a callback
+ * which takes arguments args and returns a CK_RV. It can also
+ * be used like this:
+ *
+ * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args);
+ * myCallbackType myCallback;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to do Win32
+ * Cryptoki development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to do Win16 development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType (* name)
+ *
+ *
+ * 6. NULL_PTR: This macro is the value of a NULL pointer.
+ *
+ * In any ANSI/ISO C environment (and in many others as well),
+ * this should best be defined by
+ *
+ * #ifndef NULL_PTR
+ * #define NULL_PTR 0
+ * #endif
+ */
+
+
+/* All the various Cryptoki types and #define'd values are in the
+ * file pkcs11t.h. */
+#include "pkcs11t.h"
+
+#define __PASTE(x,y) x##y
+
+
+/* ==============================================================
+ * Define the "extern" form of all the entry points.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST 1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ extern CK_DECLARE_FUNCTION(CK_RV, name)
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define the typedef form of all the entry points. That is, for
+ * each Cryptoki function C_XXX, define a type CK_C_XXX which is
+ * a pointer to that kind of function.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST 1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name))
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define structed vector of entry points. A CK_FUNCTION_LIST
+ * contains a CK_VERSION indicating a library's Cryptoki version
+ * and then a whole slew of function pointers to the routines in
+ * the library. This type was declared, but not defined, in
+ * pkcs11t.h.
+ * ==============================================================
+ */
+
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ __PASTE(CK_,name) name;
+
+struct CK_FUNCTION_LIST {
+
+ CK_VERSION version; /* Cryptoki version */
+
+/* Pile all the function pointers into the CK_FUNCTION_LIST. */
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+};
+
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+#undef __PASTE
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pkcs11f.h b/pkcs11f.h
new file mode 100644
index 0000000..a479384
--- /dev/null
+++ b/pkcs11f.h
@@ -0,0 +1,912 @@
+/* pkcs11f.h include file for PKCS #11. */
+/* $Revision: 1.4 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+/* This header file contains pretty much everything about all the */
+/* Cryptoki function prototypes. Because this information is */
+/* used for more than just declaring function prototypes, the */
+/* order of the functions appearing herein is important, and */
+/* should not be altered. */
+
+/* General-purpose */
+
+/* C_Initialize initializes the Cryptoki library. */
+CK_PKCS11_FUNCTION_INFO(C_Initialize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_VOID_PTR pInitArgs /* if this is not NULL_PTR, it gets
+ * cast to CK_C_INITIALIZE_ARGS_PTR
+ * and dereferenced */
+);
+#endif
+
+
+/* C_Finalize indicates that an application is done with the
+ * Cryptoki library. */
+CK_PKCS11_FUNCTION_INFO(C_Finalize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_VOID_PTR pReserved /* reserved. Should be NULL_PTR */
+);
+#endif
+
+
+/* C_GetInfo returns general information about Cryptoki. */
+CK_PKCS11_FUNCTION_INFO(C_GetInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_INFO_PTR pInfo /* location that receives information */
+);
+#endif
+
+
+/* C_GetFunctionList returns the function list. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_FUNCTION_LIST_PTR_PTR ppFunctionList /* receives pointer to
+ * function list */
+);
+#endif
+
+
+
+/* Slot and token management */
+
+/* C_GetSlotList obtains a list of slots in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_BBOOL tokenPresent, /* only slots with tokens? */
+ CK_SLOT_ID_PTR pSlotList, /* receives array of slot IDs */
+ CK_ULONG_PTR pulCount /* receives number of slots */
+);
+#endif
+
+
+/* C_GetSlotInfo obtains information about a particular slot in
+ * the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* the ID of the slot */
+ CK_SLOT_INFO_PTR pInfo /* receives the slot information */
+);
+#endif
+
+
+/* C_GetTokenInfo obtains information about a particular token
+ * in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_TOKEN_INFO_PTR pInfo /* receives the token information */
+);
+#endif
+
+
+/* C_GetMechanismList obtains a list of mechanism types
+ * supported by a token. */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of token's slot */
+ CK_MECHANISM_TYPE_PTR pMechanismList, /* gets mech. array */
+ CK_ULONG_PTR pulCount /* gets # of mechs. */
+);
+#endif
+
+
+/* C_GetMechanismInfo obtains information about a particular
+ * mechanism possibly supported by a token. */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_MECHANISM_TYPE type, /* type of mechanism */
+ CK_MECHANISM_INFO_PTR pInfo /* receives mechanism info */
+);
+#endif
+
+
+/* C_InitToken initializes a token. */
+CK_PKCS11_FUNCTION_INFO(C_InitToken)
+#ifdef CK_NEED_ARG_LIST
+/* pLabel changed from CK_CHAR_PTR to CK_UTF8CHAR_PTR for v2.10 */
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_UTF8CHAR_PTR pPin, /* the SO's initial PIN */
+ CK_ULONG ulPinLen, /* length in bytes of the PIN */
+ CK_UTF8CHAR_PTR pLabel /* 32-byte token label (blank padded) */
+);
+#endif
+
+
+/* C_InitPIN initializes the normal user's PIN. */
+CK_PKCS11_FUNCTION_INFO(C_InitPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_UTF8CHAR_PTR pPin, /* the normal user's PIN */
+ CK_ULONG ulPinLen /* length in bytes of the PIN */
+);
+#endif
+
+
+/* C_SetPIN modifies the PIN of the user who is logged in. */
+CK_PKCS11_FUNCTION_INFO(C_SetPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_UTF8CHAR_PTR pOldPin, /* the old PIN */
+ CK_ULONG ulOldLen, /* length of the old PIN */
+ CK_UTF8CHAR_PTR pNewPin, /* the new PIN */
+ CK_ULONG ulNewLen /* length of the new PIN */
+);
+#endif
+
+
+
+/* Session management */
+
+/* C_OpenSession opens a session between an application and a
+ * token. */
+CK_PKCS11_FUNCTION_INFO(C_OpenSession)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* the slot's ID */
+ CK_FLAGS flags, /* from CK_SESSION_INFO */
+ CK_VOID_PTR pApplication, /* passed to callback */
+ CK_NOTIFY Notify, /* callback function */
+ CK_SESSION_HANDLE_PTR phSession /* gets session handle */
+);
+#endif
+
+
+/* C_CloseSession closes a session between an application and a
+ * token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseSession)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+/* C_CloseAllSessions closes all sessions with a token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID /* the token's slot */
+);
+#endif
+
+
+/* C_GetSessionInfo obtains information about the session. */
+CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_SESSION_INFO_PTR pInfo /* receives session info */
+);
+#endif
+
+
+/* C_GetOperationState obtains the state of the cryptographic operation
+ * in a session. */
+CK_PKCS11_FUNCTION_INFO(C_GetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pOperationState, /* gets state */
+ CK_ULONG_PTR pulOperationStateLen /* gets state length */
+);
+#endif
+
+
+/* C_SetOperationState restores the state of the cryptographic
+ * operation in a session. */
+CK_PKCS11_FUNCTION_INFO(C_SetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pOperationState, /* holds state */
+ CK_ULONG ulOperationStateLen, /* holds state length */
+ CK_OBJECT_HANDLE hEncryptionKey, /* en/decryption key */
+ CK_OBJECT_HANDLE hAuthenticationKey /* sign/verify key */
+);
+#endif
+
+
+/* C_Login logs a user into a token. */
+CK_PKCS11_FUNCTION_INFO(C_Login)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_USER_TYPE userType, /* the user type */
+ CK_UTF8CHAR_PTR pPin, /* the user's PIN */
+ CK_ULONG ulPinLen /* the length of the PIN */
+);
+#endif
+
+
+/* C_Logout logs a user out from a token. */
+CK_PKCS11_FUNCTION_INFO(C_Logout)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Object management */
+
+/* C_CreateObject creates a new object. */
+CK_PKCS11_FUNCTION_INFO(C_CreateObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* the object's template */
+ CK_ULONG ulCount, /* attributes in template */
+ CK_OBJECT_HANDLE_PTR phObject /* gets new object's handle. */
+);
+#endif
+
+
+/* C_CopyObject copies an object, creating a new object for the
+ * copy. */
+CK_PKCS11_FUNCTION_INFO(C_CopyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* template for new object */
+ CK_ULONG ulCount, /* attributes in template */
+ CK_OBJECT_HANDLE_PTR phNewObject /* receives handle of copy */
+);
+#endif
+
+
+/* C_DestroyObject destroys an object. */
+CK_PKCS11_FUNCTION_INFO(C_DestroyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject /* the object's handle */
+);
+#endif
+
+
+/* C_GetObjectSize gets the size of an object in bytes. */
+CK_PKCS11_FUNCTION_INFO(C_GetObjectSize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ULONG_PTR pulSize /* receives size of object */
+);
+#endif
+
+
+/* C_GetAttributeValue obtains the value of one or more object
+ * attributes. */
+CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs; gets vals */
+ CK_ULONG ulCount /* attributes in template */
+);
+#endif
+
+
+/* C_SetAttributeValue modifies the value of one or more object
+ * attributes */
+CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs and values */
+ CK_ULONG ulCount /* attributes in template */
+);
+#endif
+
+
+/* C_FindObjectsInit initializes a search for token and session
+ * objects that match a template. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */
+ CK_ULONG ulCount /* attrs in search template */
+);
+#endif
+
+
+/* C_FindObjects continues a search for token and session
+ * objects that match a template, obtaining additional object
+ * handles. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjects)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_OBJECT_HANDLE_PTR phObject, /* gets obj. handles */
+ CK_ULONG ulMaxObjectCount, /* max handles to get */
+ CK_ULONG_PTR pulObjectCount /* actual # returned */
+);
+#endif
+
+
+/* C_FindObjectsFinal finishes a search for token and session
+ * objects. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Encryption and decryption */
+
+/* C_EncryptInit initializes an encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of encryption key */
+);
+#endif
+
+
+/* C_Encrypt encrypts single-part data. */
+CK_PKCS11_FUNCTION_INFO(C_Encrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pData, /* the plaintext data */
+ CK_ULONG ulDataLen, /* bytes of plaintext */
+ CK_BYTE_PTR pEncryptedData, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedDataLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptUpdate continues a multiple-part encryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext data len */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptFinal finishes a multiple-part encryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session handle */
+ CK_BYTE_PTR pLastEncryptedPart, /* last c-text */
+ CK_ULONG_PTR pulLastEncryptedPartLen /* gets last size */
+);
+#endif
+
+
+/* C_DecryptInit initializes a decryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of decryption key */
+);
+#endif
+
+
+/* C_Decrypt decrypts encrypted data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Decrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedData, /* ciphertext */
+ CK_ULONG ulEncryptedDataLen, /* ciphertext length */
+ CK_BYTE_PTR pData, /* gets plaintext */
+ CK_ULONG_PTR pulDataLen /* gets p-text size */
+);
+#endif
+
+
+/* C_DecryptUpdate continues a multiple-part decryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* encrypted data */
+ CK_ULONG ulEncryptedPartLen, /* input length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* p-text size */
+);
+#endif
+
+
+/* C_DecryptFinal finishes a multiple-part decryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pLastPart, /* gets plaintext */
+ CK_ULONG_PTR pulLastPartLen /* p-text size */
+);
+#endif
+
+
+
+/* Message digesting */
+
+/* C_DigestInit initializes a message-digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism /* the digesting mechanism */
+);
+#endif
+
+
+/* C_Digest digests data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Digest)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* data to be digested */
+ CK_ULONG ulDataLen, /* bytes of data to digest */
+ CK_BYTE_PTR pDigest, /* gets the message digest */
+ CK_ULONG_PTR pulDigestLen /* gets digest length */
+);
+#endif
+
+
+/* C_DigestUpdate continues a multiple-part message-digesting
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* data to be digested */
+ CK_ULONG ulPartLen /* bytes of data to be digested */
+);
+#endif
+
+
+/* C_DigestKey continues a multi-part message-digesting
+ * operation, by digesting the value of a secret key as part of
+ * the data already digested. */
+CK_PKCS11_FUNCTION_INFO(C_DigestKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hKey /* secret key to digest */
+);
+#endif
+
+
+/* C_DigestFinal finishes a multiple-part message-digesting
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pDigest, /* gets the message digest */
+ CK_ULONG_PTR pulDigestLen /* gets byte count of digest */
+);
+#endif
+
+
+
+/* Signing and MACing */
+
+/* C_SignInit initializes a signature (private key encryption)
+ * operation, where the signature is (will be) an appendix to
+ * the data, and plaintext cannot be recovered from the
+ *signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of signature key */
+);
+#endif
+
+
+/* C_Sign signs (encrypts with private key) data in a single
+ * part, where the signature is (will be) an appendix to the
+ * data, and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_Sign)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* the data to sign */
+ CK_ULONG ulDataLen, /* count of bytes to sign */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+/* C_SignUpdate continues a multiple-part signature operation,
+ * where the signature is (will be) an appendix to the data,
+ * and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* the data to sign */
+ CK_ULONG ulPartLen /* count of bytes to sign */
+);
+#endif
+
+
+/* C_SignFinal finishes a multiple-part signature operation,
+ * returning the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+/* C_SignRecoverInit initializes a signature operation, where
+ * the data can be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of the signature key */
+);
+#endif
+
+
+/* C_SignRecover signs data in a single operation, where the
+ * data can be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* the data to sign */
+ CK_ULONG ulDataLen, /* count of bytes to sign */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+
+/* Verifying signatures and MACs */
+
+/* C_VerifyInit initializes a verification operation, where the
+ * signature is an appendix to the data, and plaintext cannot
+ * cannot be recovered from the signature (e.g. DSA). */
+CK_PKCS11_FUNCTION_INFO(C_VerifyInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
+ CK_OBJECT_HANDLE hKey /* verification key */
+);
+#endif
+
+
+/* C_Verify verifies a signature in a single-part operation,
+ * where the signature is an appendix to the data, and plaintext
+ * cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_Verify)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* signed data */
+ CK_ULONG ulDataLen, /* length of signed data */
+ CK_BYTE_PTR pSignature, /* signature */
+ CK_ULONG ulSignatureLen /* signature length*/
+);
+#endif
+
+
+/* C_VerifyUpdate continues a multiple-part verification
+ * operation, where the signature is an appendix to the data,
+ * and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* signed data */
+ CK_ULONG ulPartLen /* length of signed data */
+);
+#endif
+
+
+/* C_VerifyFinal finishes a multiple-part verification
+ * operation, checking the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* signature to verify */
+ CK_ULONG ulSignatureLen /* signature length */
+);
+#endif
+
+
+/* C_VerifyRecoverInit initializes a signature verification
+ * operation, where the data is recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
+ CK_OBJECT_HANDLE hKey /* verification key */
+);
+#endif
+
+
+/* C_VerifyRecover verifies a signature in a single-part
+ * operation, where the data is recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* signature to verify */
+ CK_ULONG ulSignatureLen, /* signature length */
+ CK_BYTE_PTR pData, /* gets signed data */
+ CK_ULONG_PTR pulDataLen /* gets signed data len */
+);
+#endif
+
+
+
+/* Dual-function cryptographic operations */
+
+/* C_DigestEncryptUpdate continues a multiple-part digesting
+ * and encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext length */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptDigestUpdate continues a multiple-part decryption and
+ * digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* ciphertext */
+ CK_ULONG ulEncryptedPartLen, /* ciphertext length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* gets plaintext len */
+);
+#endif
+
+
+/* C_SignEncryptUpdate continues a multiple-part signing and
+ * encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext length */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptVerifyUpdate continues a multiple-part decryption and
+ * verify operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* ciphertext */
+ CK_ULONG ulEncryptedPartLen, /* ciphertext length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* gets p-text length */
+);
+#endif
+
+
+
+/* Key management */
+
+/* C_GenerateKey generates a secret key, creating a new key
+ * object. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* key generation mech. */
+ CK_ATTRIBUTE_PTR pTemplate, /* template for new key */
+ CK_ULONG ulCount, /* # of attrs in template */
+ CK_OBJECT_HANDLE_PTR phKey /* gets handle of new key */
+);
+#endif
+
+
+/* C_GenerateKeyPair generates a public-key/private-key pair,
+ * creating new key objects. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session
+ * handle */
+ CK_MECHANISM_PTR pMechanism, /* key-gen
+ * mech. */
+ CK_ATTRIBUTE_PTR pPublicKeyTemplate, /* template
+ * for pub.
+ * key */
+ CK_ULONG ulPublicKeyAttributeCount, /* # pub.
+ * attrs. */
+ CK_ATTRIBUTE_PTR pPrivateKeyTemplate, /* template
+ * for priv.
+ * key */
+ CK_ULONG ulPrivateKeyAttributeCount, /* # priv.
+ * attrs. */
+ CK_OBJECT_HANDLE_PTR phPublicKey, /* gets pub.
+ * key
+ * handle */
+ CK_OBJECT_HANDLE_PTR phPrivateKey /* gets
+ * priv. key
+ * handle */
+);
+#endif
+
+
+/* C_WrapKey wraps (i.e., encrypts) a key. */
+CK_PKCS11_FUNCTION_INFO(C_WrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */
+ CK_OBJECT_HANDLE hWrappingKey, /* wrapping key */
+ CK_OBJECT_HANDLE hKey, /* key to be wrapped */
+ CK_BYTE_PTR pWrappedKey, /* gets wrapped key */
+ CK_ULONG_PTR pulWrappedKeyLen /* gets wrapped key size */
+);
+#endif
+
+
+/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new
+ * key object. */
+CK_PKCS11_FUNCTION_INFO(C_UnwrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_MECHANISM_PTR pMechanism, /* unwrapping mech. */
+ CK_OBJECT_HANDLE hUnwrappingKey, /* unwrapping key */
+ CK_BYTE_PTR pWrappedKey, /* the wrapped key */
+ CK_ULONG ulWrappedKeyLen, /* wrapped key len */
+ CK_ATTRIBUTE_PTR pTemplate, /* new key template */
+ CK_ULONG ulAttributeCount, /* template length */
+ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
+);
+#endif
+
+
+/* C_DeriveKey derives a key from a base key, creating a new key
+ * object. */
+CK_PKCS11_FUNCTION_INFO(C_DeriveKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_MECHANISM_PTR pMechanism, /* key deriv. mech. */
+ CK_OBJECT_HANDLE hBaseKey, /* base key */
+ CK_ATTRIBUTE_PTR pTemplate, /* new key template */
+ CK_ULONG ulAttributeCount, /* template length */
+ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
+);
+#endif
+
+
+
+/* Random number generation */
+
+/* C_SeedRandom mixes additional seed material into the token's
+ * random number generator. */
+CK_PKCS11_FUNCTION_INFO(C_SeedRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSeed, /* the seed material */
+ CK_ULONG ulSeedLen /* length of seed material */
+);
+#endif
+
+
+/* C_GenerateRandom generates random data. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR RandomData, /* receives the random data */
+ CK_ULONG ulRandomLen /* # of bytes to generate */
+);
+#endif
+
+
+
+/* Parallel function management */
+
+/* C_GetFunctionStatus is a legacy function; it obtains an
+ * updated status of a function running in parallel with an
+ * application. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+/* C_CancelFunction is a legacy function; it cancels a function
+ * running in parallel. */
+CK_PKCS11_FUNCTION_INFO(C_CancelFunction)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Functions added in for Cryptoki Version 2.01 or later */
+
+/* C_WaitForSlotEvent waits for a slot event (token insertion,
+ * removal, etc.) to occur. */
+CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_FLAGS flags, /* blocking/nonblocking flag */
+ CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */
+ CK_VOID_PTR pRserved /* reserved. Should be NULL_PTR */
+);
+#endif
diff --git a/pkcs11t.h b/pkcs11t.h
new file mode 100644
index 0000000..386bb04
--- /dev/null
+++ b/pkcs11t.h
@@ -0,0 +1,1789 @@
+/* pkcs11t.h include file for PKCS #11 V 2.30 - draft 1 */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+/* See top of pkcs11.h for information about the macros that
+ * must be defined and the structure-packing conventions that
+ * must be set before including this file. */
+
+#ifndef _PKCS11T_H_
+#define _PKCS11T_H_ 1
+
+#define CRYPTOKI_VERSION_MAJOR 2
+#define CRYPTOKI_VERSION_MINOR 30
+#define CRYPTOKI_VERSION_AMENDMENT 0
+
+#define CK_TRUE 1
+#define CK_FALSE 0
+
+#ifndef CK_DISABLE_TRUE_FALSE
+#ifndef FALSE
+#define FALSE CK_FALSE
+#endif
+
+#ifndef TRUE
+#define TRUE CK_TRUE
+#endif
+#endif
+
+/* an unsigned 8-bit value */
+typedef unsigned char CK_BYTE;
+
+/* an unsigned 8-bit character */
+typedef CK_BYTE CK_CHAR;
+
+/* an 8-bit UTF-8 character */
+typedef CK_BYTE CK_UTF8CHAR;
+
+/* a BYTE-sized Boolean flag */
+typedef CK_BYTE CK_BBOOL;
+
+/* an unsigned value, at least 32 bits long */
+typedef unsigned long int CK_ULONG;
+
+/* a signed value, the same size as a CK_ULONG */
+typedef long int CK_LONG;
+
+/* at least 32 bits; each bit is a Boolean flag */
+typedef CK_ULONG CK_FLAGS;
+
+
+/* some special values for certain CK_ULONG variables */
+#define CK_UNAVAILABLE_INFORMATION (~0UL)
+#define CK_EFFECTIVELY_INFINITE 0
+
+
+typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+typedef CK_CHAR CK_PTR CK_CHAR_PTR;
+typedef CK_UTF8CHAR CK_PTR CK_UTF8CHAR_PTR;
+typedef CK_ULONG CK_PTR CK_ULONG_PTR;
+typedef void CK_PTR CK_VOID_PTR;
+
+/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */
+typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR;
+
+
+/* The following value is always invalid if used as a session */
+/* handle or object handle */
+#define CK_INVALID_HANDLE 0
+
+
+typedef struct CK_VERSION {
+ CK_BYTE major; /* integer portion of version number */
+ CK_BYTE minor; /* 1/100ths portion of version number */
+} CK_VERSION;
+
+typedef CK_VERSION CK_PTR CK_VERSION_PTR;
+
+
+typedef struct CK_INFO {
+ /* manufacturerID and libraryDecription have been changed from
+ * CK_CHAR to CK_UTF8CHAR for v2.10 */
+ CK_VERSION cryptokiVersion; /* Cryptoki interface ver */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_FLAGS flags; /* must be zero */
+
+ CK_UTF8CHAR libraryDescription[32]; /* blank padded */
+ CK_VERSION libraryVersion; /* version of library */
+} CK_INFO;
+
+typedef CK_INFO CK_PTR CK_INFO_PTR;
+
+
+/* CK_NOTIFICATION enumerates the types of notifications that
+ * Cryptoki provides to an application */
+typedef CK_ULONG CK_NOTIFICATION;
+#define CKN_SURRENDER 0
+#define CKN_OTP_CHANGED 1
+
+
+typedef CK_ULONG CK_SLOT_ID;
+
+typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR;
+
+
+/* CK_SLOT_INFO provides information about a slot */
+typedef struct CK_SLOT_INFO {
+ /* slotDescription and manufacturerID have been changed from
+ * CK_CHAR to CK_UTF8CHAR for v2.10 */
+ CK_UTF8CHAR slotDescription[64]; /* blank padded */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_FLAGS flags;
+
+ CK_VERSION hardwareVersion; /* version of hardware */
+ CK_VERSION firmwareVersion; /* version of firmware */
+} CK_SLOT_INFO;
+
+/* flags: bit flags that provide capabilities of the slot
+ * Bit Flag Mask Meaning
+ */
+#define CKF_TOKEN_PRESENT 0x00000001 /* a token is there */
+#define CKF_REMOVABLE_DEVICE 0x00000002 /* removable devices*/
+#define CKF_HW_SLOT 0x00000004 /* hardware slot */
+
+typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR;
+
+
+/* CK_TOKEN_INFO provides information about a token */
+typedef struct CK_TOKEN_INFO {
+ /* label, manufacturerID, and model have been changed from
+ * CK_CHAR to CK_UTF8CHAR for v2.10 */
+ CK_UTF8CHAR label[32]; /* blank padded */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_UTF8CHAR model[16]; /* blank padded */
+ CK_CHAR serialNumber[16]; /* blank padded */
+ CK_FLAGS flags; /* see below */
+
+ CK_ULONG ulMaxSessionCount; /* max open sessions */
+ CK_ULONG ulSessionCount; /* sess. now open */
+ CK_ULONG ulMaxRwSessionCount; /* max R/W sessions */
+ CK_ULONG ulRwSessionCount; /* R/W sess. now open */
+ CK_ULONG ulMaxPinLen; /* in bytes */
+ CK_ULONG ulMinPinLen; /* in bytes */
+ CK_ULONG ulTotalPublicMemory; /* in bytes */
+ CK_ULONG ulFreePublicMemory; /* in bytes */
+ CK_ULONG ulTotalPrivateMemory; /* in bytes */
+ CK_ULONG ulFreePrivateMemory; /* in bytes */
+ CK_VERSION hardwareVersion; /* version of hardware */
+ CK_VERSION firmwareVersion; /* version of firmware */
+ CK_CHAR utcTime[16]; /* time */
+} CK_TOKEN_INFO;
+
+/* The flags parameter is defined as follows:
+ * Bit Flag Mask Meaning
+ */
+#define CKF_RNG 0x00000001 /* has random #
+ * generator */
+#define CKF_WRITE_PROTECTED 0x00000002 /* token is
+ * write-
+ * protected */
+#define CKF_LOGIN_REQUIRED 0x00000004 /* user must
+ * login */
+#define CKF_USER_PIN_INITIALIZED 0x00000008 /* normal user's
+ * PIN is set */
+
+/* CKF_RESTORE_KEY_NOT_NEEDED. If it is set,
+ * that means that *every* time the state of cryptographic
+ * operations of a session is successfully saved, all keys
+ * needed to continue those operations are stored in the state */
+#define CKF_RESTORE_KEY_NOT_NEEDED 0x00000020
+
+/* CKF_CLOCK_ON_TOKEN. If it is set, that means
+ * that the token has some sort of clock. The time on that
+ * clock is returned in the token info structure */
+#define CKF_CLOCK_ON_TOKEN 0x00000040
+
+/* CKF_PROTECTED_AUTHENTICATION_PATH. If it is
+ * set, that means that there is some way for the user to login
+ * without sending a PIN through the Cryptoki library itself */
+#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100
+
+/* CKF_DUAL_CRYPTO_OPERATIONS. If it is true,
+ * that means that a single session with the token can perform
+ * dual simultaneous cryptographic operations (digest and
+ * encrypt; decrypt and digest; sign and encrypt; and decrypt
+ * and sign) */
+#define CKF_DUAL_CRYPTO_OPERATIONS 0x00000200
+
+/* CKF_TOKEN_INITIALIZED. If it is true, the
+ * token has been initialized using C_InitializeToken or an
+ * equivalent mechanism outside the scope of PKCS #11.
+ * Calling C_InitializeToken when this flag is set will cause
+ * the token to be reinitialized. */
+#define CKF_TOKEN_INITIALIZED 0x00000400
+
+/* CKF_SECONDARY_AUTHENTICATION. If it is
+ * true, the token supports secondary authentication for
+ * private key objects. This flag is deprecated in v2.11 and
+ onwards. */
+#define CKF_SECONDARY_AUTHENTICATION 0x00000800
+
+/* CKF_USER_PIN_COUNT_LOW. If it is true, an
+ * incorrect user login PIN has been entered at least once
+ * since the last successful authentication. */
+#define CKF_USER_PIN_COUNT_LOW 0x00010000
+
+/* CKF_USER_PIN_FINAL_TRY. If it is true,
+ * supplying an incorrect user PIN will it to become locked. */
+#define CKF_USER_PIN_FINAL_TRY 0x00020000
+
+/* CKF_USER_PIN_LOCKED. If it is true, the
+ * user PIN has been locked. User login to the token is not
+ * possible. */
+#define CKF_USER_PIN_LOCKED 0x00040000
+
+/* CKF_USER_PIN_TO_BE_CHANGED. If it is true,
+ * the user PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card. */
+#define CKF_USER_PIN_TO_BE_CHANGED 0x00080000
+
+/* CKF_SO_PIN_COUNT_LOW. If it is true, an
+ * incorrect SO login PIN has been entered at least once since
+ * the last successful authentication. */
+#define CKF_SO_PIN_COUNT_LOW 0x00100000
+
+/* CKF_SO_PIN_FINAL_TRY. If it is true,
+ * supplying an incorrect SO PIN will it to become locked. */
+#define CKF_SO_PIN_FINAL_TRY 0x00200000
+
+/* CKF_SO_PIN_LOCKED if new for v2.10. If it is true, the SO
+ * PIN has been locked. SO login to the token is not possible.
+ */
+#define CKF_SO_PIN_LOCKED 0x00400000
+
+/* CKF_SO_PIN_TO_BE_CHANGED. If it is true,
+ * the SO PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card. */
+#define CKF_SO_PIN_TO_BE_CHANGED 0x00800000
+
+#define CKF_ERROR_STATE 0x01000000
+
+typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR;
+
+
+/* CK_SESSION_HANDLE is a Cryptoki-assigned value that
+ * identifies a session */
+typedef CK_ULONG CK_SESSION_HANDLE;
+
+typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR;
+
+
+/* CK_USER_TYPE enumerates the types of Cryptoki users */
+typedef CK_ULONG CK_USER_TYPE;
+/* Security Officer */
+#define CKU_SO 0
+/* Normal user */
+#define CKU_USER 1
+/* Context specific */
+#define CKU_CONTEXT_SPECIFIC 2
+
+/* CK_STATE enumerates the session states */
+typedef CK_ULONG CK_STATE;
+#define CKS_RO_PUBLIC_SESSION 0
+#define CKS_RO_USER_FUNCTIONS 1
+#define CKS_RW_PUBLIC_SESSION 2
+#define CKS_RW_USER_FUNCTIONS 3
+#define CKS_RW_SO_FUNCTIONS 4
+
+
+/* CK_SESSION_INFO provides information about a session */
+typedef struct CK_SESSION_INFO {
+ CK_SLOT_ID slotID;
+ CK_STATE state;
+ CK_FLAGS flags; /* see below */
+ CK_ULONG ulDeviceError; /* device-dependent error code */
+} CK_SESSION_INFO;
+
+/* The flags are defined in the following table:
+ * Bit Flag Mask Meaning
+ */
+#define CKF_RW_SESSION 0x00000002 /* session is r/w */
+#define CKF_SERIAL_SESSION 0x00000004 /* no parallel */
+
+typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR;
+
+
+/* CK_OBJECT_HANDLE is a token-specific identifier for an
+ * object */
+typedef CK_ULONG CK_OBJECT_HANDLE;
+
+typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR;
+
+
+/* CK_OBJECT_CLASS is a value that identifies the classes (or
+ * types) of objects that Cryptoki recognizes. It is defined
+ * as follows: */
+typedef CK_ULONG CK_OBJECT_CLASS;
+
+/* The following classes of objects are defined: */
+#define CKO_DATA 0x00000000
+#define CKO_CERTIFICATE 0x00000001
+#define CKO_PUBLIC_KEY 0x00000002
+#define CKO_PRIVATE_KEY 0x00000003
+#define CKO_SECRET_KEY 0x00000004
+#define CKO_HW_FEATURE 0x00000005
+#define CKO_DOMAIN_PARAMETERS 0x00000006
+#define CKO_MECHANISM 0x00000007
+#define CKO_OTP_KEY 0x00000008
+
+#define CKO_VENDOR_DEFINED 0x80000000
+
+typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR;
+
+/* CK_HW_FEATURE_TYPE is a
+ * value that identifies the hardware feature type of an object
+ * with CK_OBJECT_CLASS equal to CKO_HW_FEATURE. */
+typedef CK_ULONG CK_HW_FEATURE_TYPE;
+
+/* The following hardware feature types are defined */
+#define CKH_MONOTONIC_COUNTER 0x00000001
+#define CKH_CLOCK 0x00000002
+#define CKH_USER_INTERFACE 0x00000003
+#define CKH_VENDOR_DEFINED 0x80000000
+
+/* CK_KEY_TYPE is a value that identifies a key type */
+typedef CK_ULONG CK_KEY_TYPE;
+
+/* the following key types are defined: */
+#define CKK_RSA 0x00000000
+#define CKK_DSA 0x00000001
+#define CKK_DH 0x00000002
+/* CKK_ECDSA is deprecated in v2.11, CKK_EC is preferred. */
+#define CKK_ECDSA 0x00000003
+#define CKK_EC 0x00000003
+#define CKK_X9_42_DH 0x00000004
+#define CKK_KEA 0x00000005
+#define CKK_GENERIC_SECRET 0x00000010
+#define CKK_RC2 0x00000011
+#define CKK_RC4 0x00000012
+#define CKK_DES 0x00000013
+#define CKK_DES2 0x00000014
+#define CKK_DES3 0x00000015
+#define CKK_CAST 0x00000016
+#define CKK_CAST3 0x00000017
+/* CKK_CAST5 is deprecated in v2.11, CKK_CAST128 is preferred. */
+#define CKK_CAST5 0x00000018
+#define CKK_CAST128 0x00000018
+#define CKK_RC5 0x00000019
+#define CKK_IDEA 0x0000001A
+#define CKK_SKIPJACK 0x0000001B
+#define CKK_BATON 0x0000001C
+#define CKK_JUNIPER 0x0000001D
+#define CKK_CDMF 0x0000001E
+#define CKK_AES 0x0000001F
+#define CKK_BLOWFISH 0x00000020
+#define CKK_TWOFISH 0x00000021
+#define CKK_SECURID 0x00000022
+#define CKK_HOTP 0x00000023
+#define CKK_ACTI 0x00000024
+#define CKK_CAMELLIA 0x00000025
+#define CKK_ARIA 0x00000026
+#define CKK_MD5_HMAC 0x00000027
+#define CKK_SHA_1_HMAC 0x00000028
+#define CKK_RIPEMD128_HMAC 0x00000029
+#define CKK_RIPEMD160_HMAC 0x0000002A
+#define CKK_SHA256_HMAC 0x0000002B
+#define CKK_SHA384_HMAC 0x0000002C
+#define CKK_SHA512_HMAC 0x0000002D
+#define CKK_SHA224_HMAC 0x0000002E
+#define CKK_SEED 0x0000002F
+#define CKK_GOSTR3410 0x00000030
+#define CKK_GOSTR3411 0x00000031
+#define CKK_GOST28147 0x00000032
+
+#define CKK_VENDOR_DEFINED 0x80000000
+
+
+/* CK_CERTIFICATE_TYPE is a value that identifies a certificate
+ * type */
+typedef CK_ULONG CK_CERTIFICATE_TYPE;
+
+/* The following certificate types are defined: */
+#define CKC_X_509 0x00000000
+#define CKC_X_509_ATTR_CERT 0x00000001
+#define CKC_WTLS 0x00000002
+#define CKC_VENDOR_DEFINED 0x80000000
+
+
+/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute
+ * type */
+typedef CK_ULONG CK_ATTRIBUTE_TYPE;
+
+/* The CKF_ARRAY_ATTRIBUTE flag identifies an attribute which
+ consists of an array of values. */
+#define CKF_ARRAY_ATTRIBUTE 0x40000000
+
+/* The following OTP-related defines relate to the CKA_OTP_FORMAT attribute */
+#define CK_OTP_FORMAT_DECIMAL 0
+#define CK_OTP_FORMAT_HEXADECIMAL 1
+#define CK_OTP_FORMAT_ALPHANUMERIC 2
+#define CK_OTP_FORMAT_BINARY 3
+
+/* The following OTP-related defines relate to the CKA_OTP_..._REQUIREMENT attributes */
+#define CK_OTP_PARAM_IGNORED 0
+#define CK_OTP_PARAM_OPTIONAL 1
+#define CK_OTP_PARAM_MANDATORY 2
+
+/* The following attribute types are defined: */
+#define CKA_CLASS 0x00000000
+#define CKA_TOKEN 0x00000001
+#define CKA_PRIVATE 0x00000002
+#define CKA_LABEL 0x00000003
+#define CKA_APPLICATION 0x00000010
+#define CKA_VALUE 0x00000011
+#define CKA_OBJECT_ID 0x00000012
+#define CKA_CERTIFICATE_TYPE 0x00000080
+#define CKA_ISSUER 0x00000081
+#define CKA_SERIAL_NUMBER 0x00000082
+#define CKA_AC_ISSUER 0x00000083
+#define CKA_OWNER 0x00000084
+#define CKA_ATTR_TYPES 0x00000085
+#define CKA_TRUSTED 0x00000086
+#define CKA_CERTIFICATE_CATEGORY 0x00000087
+#define CKA_JAVA_MIDP_SECURITY_DOMAIN 0x00000088
+#define CKA_URL 0x00000089
+#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY 0x0000008A
+#define CKA_HASH_OF_ISSUER_PUBLIC_KEY 0x0000008B
+#define CKA_CHECK_VALUE 0x00000090
+
+#define CKA_KEY_TYPE 0x00000100
+#define CKA_SUBJECT 0x00000101
+#define CKA_ID 0x00000102
+#define CKA_SENSITIVE 0x00000103
+#define CKA_ENCRYPT 0x00000104
+#define CKA_DECRYPT 0x00000105
+#define CKA_WRAP 0x00000106
+#define CKA_UNWRAP 0x00000107
+#define CKA_SIGN 0x00000108
+#define CKA_SIGN_RECOVER 0x00000109
+#define CKA_VERIFY 0x0000010A
+#define CKA_VERIFY_RECOVER 0x0000010B
+#define CKA_DERIVE 0x0000010C
+#define CKA_START_DATE 0x00000110
+#define CKA_END_DATE 0x00000111
+#define CKA_MODULUS 0x00000120
+#define CKA_MODULUS_BITS 0x00000121
+#define CKA_PUBLIC_EXPONENT 0x00000122
+#define CKA_PRIVATE_EXPONENT 0x00000123
+#define CKA_PRIME_1 0x00000124
+#define CKA_PRIME_2 0x00000125
+#define CKA_EXPONENT_1 0x00000126
+#define CKA_EXPONENT_2 0x00000127
+#define CKA_COEFFICIENT 0x00000128
+#define CKA_PRIME 0x00000130
+#define CKA_SUBPRIME 0x00000131
+#define CKA_BASE 0x00000132
+
+#define CKA_PRIME_BITS 0x00000133
+#define CKA_SUBPRIME_BITS 0x00000134
+/* (To retain backwards-compatibility) */
+#define CKA_SUB_PRIME_BITS CKA_SUBPRIME_BITS
+
+#define CKA_VALUE_BITS 0x00000160
+#define CKA_VALUE_LEN 0x00000161
+#define CKA_EXTRACTABLE 0x00000162
+#define CKA_LOCAL 0x00000163
+#define CKA_NEVER_EXTRACTABLE 0x00000164
+#define CKA_ALWAYS_SENSITIVE 0x00000165
+#define CKA_KEY_GEN_MECHANISM 0x00000166
+
+#define CKA_MODIFIABLE 0x00000170
+
+/* CKA_ECDSA_PARAMS is deprecated in v2.11,
+ * CKA_EC_PARAMS is preferred. */
+#define CKA_ECDSA_PARAMS 0x00000180
+#define CKA_EC_PARAMS 0x00000180
+
+#define CKA_EC_POINT 0x00000181
+
+/* CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS,
+ * are new for v2.10. Deprecated in v2.11 and onwards. */
+#define CKA_SECONDARY_AUTH 0x00000200
+#define CKA_AUTH_PIN_FLAGS 0x00000201
+
+#define CKA_ALWAYS_AUTHENTICATE 0x00000202
+
+#define CKA_WRAP_WITH_TRUSTED 0x00000210
+#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000211)
+#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000212)
+#define CKA_DERIVE_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000213)
+
+#define CKA_OTP_FORMAT 0x00000220
+#define CKA_OTP_LENGTH 0x00000221
+#define CKA_OTP_TIME_INTERVAL 0x00000222
+#define CKA_OTP_USER_FRIENDLY_MODE 0x00000223
+#define CKA_OTP_CHALLENGE_REQUIREMENT 0x00000224
+#define CKA_OTP_TIME_REQUIREMENT 0x00000225
+#define CKA_OTP_COUNTER_REQUIREMENT 0x00000226
+#define CKA_OTP_PIN_REQUIREMENT 0x00000227
+#define CKA_OTP_COUNTER 0x0000022E
+#define CKA_OTP_TIME 0x0000022F
+#define CKA_OTP_USER_IDENTIFIER 0x0000022A
+#define CKA_OTP_SERVICE_IDENTIFIER 0x0000022B
+#define CKA_OTP_SERVICE_LOGO 0x0000022C
+#define CKA_OTP_SERVICE_LOGO_TYPE 0x0000022D
+
+#define CKA_GOSTR3410_PARAMS 0x00000250
+#define CKA_GOSTR3411_PARAMS 0x00000251
+#define CKA_GOST28147_PARAMS 0x00000252
+
+#define CKA_HW_FEATURE_TYPE 0x00000300
+#define CKA_RESET_ON_INIT 0x00000301
+#define CKA_HAS_RESET 0x00000302
+
+#define CKA_PIXEL_X 0x00000400
+#define CKA_PIXEL_Y 0x00000401
+#define CKA_RESOLUTION 0x00000402
+#define CKA_CHAR_ROWS 0x00000403
+#define CKA_CHAR_COLUMNS 0x00000404
+#define CKA_COLOR 0x00000405
+#define CKA_BITS_PER_PIXEL 0x00000406
+#define CKA_CHAR_SETS 0x00000480
+#define CKA_ENCODING_METHODS 0x00000481
+#define CKA_MIME_TYPES 0x00000482
+#define CKA_MECHANISM_TYPE 0x00000500
+#define CKA_REQUIRED_CMS_ATTRIBUTES 0x00000501
+#define CKA_DEFAULT_CMS_ATTRIBUTES 0x00000502
+#define CKA_SUPPORTED_CMS_ATTRIBUTES 0x00000503
+#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE|0x00000600)
+
+#define CKA_VENDOR_DEFINED 0x80000000
+
+/* CK_ATTRIBUTE is a structure that includes the type, length
+ * and value of an attribute */
+typedef struct CK_ATTRIBUTE {
+ CK_ATTRIBUTE_TYPE type;
+ CK_VOID_PTR pValue;
+ CK_ULONG ulValueLen; /* in bytes */
+} CK_ATTRIBUTE;
+
+typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR;
+
+
+/* CK_DATE is a structure that defines a date */
+typedef struct CK_DATE{
+ CK_CHAR year[4]; /* the year ("1900" - "9999") */
+ CK_CHAR month[2]; /* the month ("01" - "12") */
+ CK_CHAR day[2]; /* the day ("01" - "31") */
+} CK_DATE;
+
+
+/* CK_MECHANISM_TYPE is a value that identifies a mechanism
+ * type */
+typedef CK_ULONG CK_MECHANISM_TYPE;
+
+/* the following mechanism types are defined: */
+#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000
+#define CKM_RSA_PKCS 0x00000001
+#define CKM_RSA_9796 0x00000002
+#define CKM_RSA_X_509 0x00000003
+
+#define CKM_MD2_RSA_PKCS 0x00000004
+#define CKM_MD5_RSA_PKCS 0x00000005
+#define CKM_SHA1_RSA_PKCS 0x00000006
+
+#define CKM_RIPEMD128_RSA_PKCS 0x00000007
+#define CKM_RIPEMD160_RSA_PKCS 0x00000008
+#define CKM_RSA_PKCS_OAEP 0x00000009
+
+#define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000A
+#define CKM_RSA_X9_31 0x0000000B
+#define CKM_SHA1_RSA_X9_31 0x0000000C
+#define CKM_RSA_PKCS_PSS 0x0000000D
+#define CKM_SHA1_RSA_PKCS_PSS 0x0000000E
+
+#define CKM_DSA_KEY_PAIR_GEN 0x00000010
+#define CKM_DSA 0x00000011
+#define CKM_DSA_SHA1 0x00000012
+#define CKM_DSA_SHA224 0x00000013
+#define CKM_DSA_SHA256 0x00000014
+#define CKM_DSA_SHA384 0x00000015
+#define CKM_DSA_SHA512 0x00000016
+#define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020
+#define CKM_DH_PKCS_DERIVE 0x00000021
+
+#define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030
+#define CKM_X9_42_DH_DERIVE 0x00000031
+#define CKM_X9_42_DH_HYBRID_DERIVE 0x00000032
+#define CKM_X9_42_MQV_DERIVE 0x00000033
+
+#define CKM_SHA256_RSA_PKCS 0x00000040
+#define CKM_SHA384_RSA_PKCS 0x00000041
+#define CKM_SHA512_RSA_PKCS 0x00000042
+#define CKM_SHA256_RSA_PKCS_PSS 0x00000043
+#define CKM_SHA384_RSA_PKCS_PSS 0x00000044
+#define CKM_SHA512_RSA_PKCS_PSS 0x00000045
+
+#define CKM_SHA224_RSA_PKCS 0x00000046
+#define CKM_SHA224_RSA_PKCS_PSS 0x00000047
+
+#define CKM_RC2_KEY_GEN 0x00000100
+#define CKM_RC2_ECB 0x00000101
+#define CKM_RC2_CBC 0x00000102
+#define CKM_RC2_MAC 0x00000103
+
+#define CKM_RC2_MAC_GENERAL 0x00000104
+#define CKM_RC2_CBC_PAD 0x00000105
+
+#define CKM_RC4_KEY_GEN 0x00000110
+#define CKM_RC4 0x00000111
+#define CKM_DES_KEY_GEN 0x00000120
+#define CKM_DES_ECB 0x00000121
+#define CKM_DES_CBC 0x00000122
+#define CKM_DES_MAC 0x00000123
+
+#define CKM_DES_MAC_GENERAL 0x00000124
+#define CKM_DES_CBC_PAD 0x00000125
+
+#define CKM_DES2_KEY_GEN 0x00000130
+#define CKM_DES3_KEY_GEN 0x00000131
+#define CKM_DES3_ECB 0x00000132
+#define CKM_DES3_CBC 0x00000133
+#define CKM_DES3_MAC 0x00000134
+
+#define CKM_DES3_MAC_GENERAL 0x00000135
+#define CKM_DES3_CBC_PAD 0x00000136
+#define CKM_DES3_CMAC_GENERAL 0x00000137
+#define CKM_DES3_CMAC 0x00000138
+#define CKM_CDMF_KEY_GEN 0x00000140
+#define CKM_CDMF_ECB 0x00000141
+#define CKM_CDMF_CBC 0x00000142
+#define CKM_CDMF_MAC 0x00000143
+#define CKM_CDMF_MAC_GENERAL 0x00000144
+#define CKM_CDMF_CBC_PAD 0x00000145
+
+#define CKM_DES_OFB64 0x00000150
+#define CKM_DES_OFB8 0x00000151
+#define CKM_DES_CFB64 0x00000152
+#define CKM_DES_CFB8 0x00000153
+
+#define CKM_MD2 0x00000200
+
+#define CKM_MD2_HMAC 0x00000201
+#define CKM_MD2_HMAC_GENERAL 0x00000202
+
+#define CKM_MD5 0x00000210
+
+#define CKM_MD5_HMAC 0x00000211
+#define CKM_MD5_HMAC_GENERAL 0x00000212
+
+#define CKM_SHA_1 0x00000220
+
+#define CKM_SHA_1_HMAC 0x00000221
+#define CKM_SHA_1_HMAC_GENERAL 0x00000222
+
+#define CKM_RIPEMD128 0x00000230
+#define CKM_RIPEMD128_HMAC 0x00000231
+#define CKM_RIPEMD128_HMAC_GENERAL 0x00000232
+#define CKM_RIPEMD160 0x00000240
+#define CKM_RIPEMD160_HMAC 0x00000241
+#define CKM_RIPEMD160_HMAC_GENERAL 0x00000242
+
+#define CKM_SHA256 0x00000250
+#define CKM_SHA256_HMAC 0x00000251
+#define CKM_SHA256_HMAC_GENERAL 0x00000252
+
+#define CKM_SHA224 0x00000255
+#define CKM_SHA224_HMAC 0x00000256
+#define CKM_SHA224_HMAC_GENERAL 0x00000257
+#define CKM_SHA384 0x00000260
+#define CKM_SHA384_HMAC 0x00000261
+#define CKM_SHA384_HMAC_GENERAL 0x00000262
+#define CKM_SHA512 0x00000270
+#define CKM_SHA512_HMAC 0x00000271
+#define CKM_SHA512_HMAC_GENERAL 0x00000272
+#define CKM_SECURID_KEY_GEN 0x00000280
+#define CKM_SECURID 0x00000282
+#define CKM_HOTP_KEY_GEN 0x00000290
+#define CKM_HOTP 0x00000291
+#define CKM_ACTI 0x000002A0
+#define CKM_ACTI_KEY_GEN 0x000002A1
+
+#define CKM_CAST_KEY_GEN 0x00000300
+#define CKM_CAST_ECB 0x00000301
+#define CKM_CAST_CBC 0x00000302
+#define CKM_CAST_MAC 0x00000303
+#define CKM_CAST_MAC_GENERAL 0x00000304
+#define CKM_CAST_CBC_PAD 0x00000305
+#define CKM_CAST3_KEY_GEN 0x00000310
+#define CKM_CAST3_ECB 0x00000311
+#define CKM_CAST3_CBC 0x00000312
+#define CKM_CAST3_MAC 0x00000313
+#define CKM_CAST3_MAC_GENERAL 0x00000314
+#define CKM_CAST3_CBC_PAD 0x00000315
+/* Note that CAST128 and CAST5 are the same algorithm */
+#define CKM_CAST5_KEY_GEN 0x00000320
+#define CKM_CAST128_KEY_GEN 0x00000320
+#define CKM_CAST5_ECB 0x00000321
+#define CKM_CAST128_ECB 0x00000321
+#define CKM_CAST5_CBC 0x00000322
+#define CKM_CAST128_CBC 0x00000322
+#define CKM_CAST5_MAC 0x00000323
+#define CKM_CAST128_MAC 0x00000323
+#define CKM_CAST5_MAC_GENERAL 0x00000324
+#define CKM_CAST128_MAC_GENERAL 0x00000324
+#define CKM_CAST5_CBC_PAD 0x00000325
+#define CKM_CAST128_CBC_PAD 0x00000325
+#define CKM_RC5_KEY_GEN 0x00000330
+#define CKM_RC5_ECB 0x00000331
+#define CKM_RC5_CBC 0x00000332
+#define CKM_RC5_MAC 0x00000333
+#define CKM_RC5_MAC_GENERAL 0x00000334
+#define CKM_RC5_CBC_PAD 0x00000335
+#define CKM_IDEA_KEY_GEN 0x00000340
+#define CKM_IDEA_ECB 0x00000341
+#define CKM_IDEA_CBC 0x00000342
+#define CKM_IDEA_MAC 0x00000343
+#define CKM_IDEA_MAC_GENERAL 0x00000344
+#define CKM_IDEA_CBC_PAD 0x00000345
+#define CKM_GENERIC_SECRET_KEY_GEN 0x00000350
+#define CKM_CONCATENATE_BASE_AND_KEY 0x00000360
+#define CKM_CONCATENATE_BASE_AND_DATA 0x00000362
+#define CKM_CONCATENATE_DATA_AND_BASE 0x00000363
+#define CKM_XOR_BASE_AND_DATA 0x00000364
+#define CKM_EXTRACT_KEY_FROM_KEY 0x00000365
+#define CKM_SSL3_PRE_MASTER_KEY_GEN 0x00000370
+#define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371
+#define CKM_SSL3_KEY_AND_MAC_DERIVE 0x00000372
+
+#define CKM_SSL3_MASTER_KEY_DERIVE_DH 0x00000373
+#define CKM_TLS_PRE_MASTER_KEY_GEN 0x00000374
+#define CKM_TLS_MASTER_KEY_DERIVE 0x00000375
+#define CKM_TLS_KEY_AND_MAC_DERIVE 0x00000376
+#define CKM_TLS_MASTER_KEY_DERIVE_DH 0x00000377
+
+#define CKM_TLS_PRF 0x00000378
+
+#define CKM_SSL3_MD5_MAC 0x00000380
+#define CKM_SSL3_SHA1_MAC 0x00000381
+#define CKM_MD5_KEY_DERIVATION 0x00000390
+#define CKM_MD2_KEY_DERIVATION 0x00000391
+#define CKM_SHA1_KEY_DERIVATION 0x00000392
+
+#define CKM_SHA256_KEY_DERIVATION 0x00000393
+#define CKM_SHA384_KEY_DERIVATION 0x00000394
+#define CKM_SHA512_KEY_DERIVATION 0x00000395
+
+#define CKM_SHA224_KEY_DERIVATION 0x00000396
+
+#define CKM_PBE_MD2_DES_CBC 0x000003A0
+#define CKM_PBE_MD5_DES_CBC 0x000003A1
+#define CKM_PBE_MD5_CAST_CBC 0x000003A2
+#define CKM_PBE_MD5_CAST3_CBC 0x000003A3
+#define CKM_PBE_MD5_CAST5_CBC 0x000003A4
+#define CKM_PBE_MD5_CAST128_CBC 0x000003A4
+#define CKM_PBE_SHA1_CAST5_CBC 0x000003A5
+#define CKM_PBE_SHA1_CAST128_CBC 0x000003A5
+#define CKM_PBE_SHA1_RC4_128 0x000003A6
+#define CKM_PBE_SHA1_RC4_40 0x000003A7
+#define CKM_PBE_SHA1_DES3_EDE_CBC 0x000003A8
+#define CKM_PBE_SHA1_DES2_EDE_CBC 0x000003A9
+#define CKM_PBE_SHA1_RC2_128_CBC 0x000003AA
+#define CKM_PBE_SHA1_RC2_40_CBC 0x000003AB
+
+#define CKM_PKCS5_PBKD2 0x000003B0
+
+#define CKM_PBA_SHA1_WITH_SHA1_HMAC 0x000003C0
+
+#define CKM_WTLS_PRE_MASTER_KEY_GEN 0x000003D0
+#define CKM_WTLS_MASTER_KEY_DERIVE 0x000003D1
+#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC 0x000003D2
+#define CKM_WTLS_PRF 0x000003D3
+#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE 0x000003D4
+#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE 0x000003D5
+
+#define CKM_KEY_WRAP_LYNKS 0x00000400
+#define CKM_KEY_WRAP_SET_OAEP 0x00000401
+
+#define CKM_CMS_SIG 0x00000500
+
+#define CKM_KIP_DERIVE 0x00000510
+#define CKM_KIP_WRAP 0x00000511
+#define CKM_KIP_MAC 0x00000512
+
+#define CKM_CAMELLIA_KEY_GEN 0x00000550
+#define CKM_CAMELLIA_ECB 0x00000551
+#define CKM_CAMELLIA_CBC 0x00000552
+#define CKM_CAMELLIA_MAC 0x00000553
+#define CKM_CAMELLIA_MAC_GENERAL 0x00000554
+#define CKM_CAMELLIA_CBC_PAD 0x00000555
+#define CKM_CAMELLIA_ECB_ENCRYPT_DATA 0x00000556
+#define CKM_CAMELLIA_CBC_ENCRYPT_DATA 0x00000557
+#define CKM_CAMELLIA_CTR 0x00000558
+
+#define CKM_ARIA_KEY_GEN 0x00000560
+#define CKM_ARIA_ECB 0x00000561
+#define CKM_ARIA_CBC 0x00000562
+#define CKM_ARIA_MAC 0x00000563
+#define CKM_ARIA_MAC_GENERAL 0x00000564
+#define CKM_ARIA_CBC_PAD 0x00000565
+#define CKM_ARIA_ECB_ENCRYPT_DATA 0x00000566
+#define CKM_ARIA_CBC_ENCRYPT_DATA 0x00000567
+
+#define CKM_SEED_KEY_GEN 0x00000650
+#define CKM_SEED_ECB 0x00000651
+#define CKM_SEED_CBC 0x00000652
+#define CKM_SEED_MAC 0x00000653
+#define CKM_SEED_MAC_GENERAL 0x00000654
+#define CKM_SEED_CBC_PAD 0x00000655
+#define CKM_SEED_ECB_ENCRYPT_DATA 0x00000656
+#define CKM_SEED_CBC_ENCRYPT_DATA 0x00000657
+
+#define CKM_SKIPJACK_KEY_GEN 0x00001000
+#define CKM_SKIPJACK_ECB64 0x00001001
+#define CKM_SKIPJACK_CBC64 0x00001002
+#define CKM_SKIPJACK_OFB64 0x00001003
+#define CKM_SKIPJACK_CFB64 0x00001004
+#define CKM_SKIPJACK_CFB32 0x00001005
+#define CKM_SKIPJACK_CFB16 0x00001006
+#define CKM_SKIPJACK_CFB8 0x00001007
+#define CKM_SKIPJACK_WRAP 0x00001008
+#define CKM_SKIPJACK_PRIVATE_WRAP 0x00001009
+#define CKM_SKIPJACK_RELAYX 0x0000100a
+#define CKM_KEA_KEY_PAIR_GEN 0x00001010
+#define CKM_KEA_KEY_DERIVE 0x00001011
+#define CKM_FORTEZZA_TIMESTAMP 0x00001020
+#define CKM_BATON_KEY_GEN 0x00001030
+#define CKM_BATON_ECB128 0x00001031
+#define CKM_BATON_ECB96 0x00001032
+#define CKM_BATON_CBC128 0x00001033
+#define CKM_BATON_COUNTER 0x00001034
+#define CKM_BATON_SHUFFLE 0x00001035
+#define CKM_BATON_WRAP 0x00001036
+
+/* CKM_ECDSA_KEY_PAIR_GEN is deprecated in v2.11,
+ * CKM_EC_KEY_PAIR_GEN is preferred */
+#define CKM_ECDSA_KEY_PAIR_GEN 0x00001040
+#define CKM_EC_KEY_PAIR_GEN 0x00001040
+
+#define CKM_ECDSA 0x00001041
+#define CKM_ECDSA_SHA1 0x00001042
+#define CKM_ECDSA_SHA224 0x00001043
+#define CKM_ECDSA_SHA256 0x00001044
+#define CKM_ECDSA_SHA384 0x00001045
+#define CKM_ECDSA_SHA512 0x00001046
+
+#define CKM_ECDH1_DERIVE 0x00001050
+#define CKM_ECDH1_COFACTOR_DERIVE 0x00001051
+#define CKM_ECMQV_DERIVE 0x00001052
+
+#define CKM_JUNIPER_KEY_GEN 0x00001060
+#define CKM_JUNIPER_ECB128 0x00001061
+#define CKM_JUNIPER_CBC128 0x00001062
+#define CKM_JUNIPER_COUNTER 0x00001063
+#define CKM_JUNIPER_SHUFFLE 0x00001064
+#define CKM_JUNIPER_WRAP 0x00001065
+#define CKM_FASTHASH 0x00001070
+
+#define CKM_AES_KEY_GEN 0x00001080
+#define CKM_AES_ECB 0x00001081
+#define CKM_AES_CBC 0x00001082
+#define CKM_AES_MAC 0x00001083
+#define CKM_AES_MAC_GENERAL 0x00001084
+#define CKM_AES_CBC_PAD 0x00001085
+#define CKM_AES_CTR 0x00001086
+#define CKM_AES_CTS 0x00001089
+#define CKM_AES_CMAC 0x0000108A
+#define CKM_AES_CMAC_GENERAL 0x0000108B
+
+#define CKM_BLOWFISH_KEY_GEN 0x00001090
+#define CKM_BLOWFISH_CBC 0x00001091
+#define CKM_TWOFISH_KEY_GEN 0x00001092
+#define CKM_TWOFISH_CBC 0x00001093
+
+#define CKM_AES_GCM 0x00001087
+#define CKM_AES_CCM 0x00001088
+#define CKM_AES_KEY_WRAP 0x00001090
+#define CKM_AES_KEY_WRAP_PAD 0x00001091
+
+#define CKM_BLOWFISH_CBC_PAD 0x00001094
+#define CKM_TWOFISH_CBC_PAD 0x00001095
+
+#define CKM_DES_ECB_ENCRYPT_DATA 0x00001100
+#define CKM_DES_CBC_ENCRYPT_DATA 0x00001101
+#define CKM_DES3_ECB_ENCRYPT_DATA 0x00001102
+#define CKM_DES3_CBC_ENCRYPT_DATA 0x00001103
+#define CKM_AES_ECB_ENCRYPT_DATA 0x00001104
+#define CKM_AES_CBC_ENCRYPT_DATA 0x00001105
+
+#define CKM_GOSTR3410_KEY_PAIR_GEN 0x00001200
+#define CKM_GOSTR3410 0x00001201
+#define CKM_GOSTR3410_WITH_GOSTR3411 0x00001202
+#define CKM_GOSTR3410_KEY_WRAP 0x00001203
+#define CKM_GOSTR3410_DERIVE 0x00001204
+#define CKM_GOSTR3411 0x00001210
+#define CKM_GOSTR3411_HMAC 0x00001211
+#define CKM_GOST28147_KEY_GEN 0x00001220
+#define CKM_GOST28147_ECB 0x00001221
+#define CKM_GOST28147 0x00001222
+#define CKM_GOST28147_MAC 0x00001223
+#define CKM_GOST28147_KEY_WRAP 0x00001224
+
+#define CKM_DSA_PARAMETER_GEN 0x00002000
+#define CKM_DH_PKCS_PARAMETER_GEN 0x00002001
+#define CKM_X9_42_DH_PARAMETER_GEN 0x00002002
+
+#define CKM_AES_OFB 0x00002104
+#define CKM_AES_CFB64 0x00002105
+#define CKM_AES_CFB8 0x00002106
+#define CKM_AES_CFB128 0x00002107
+
+#define CKM_RSA_PKCS_TPM_1_1 0x00004001
+#define CKM_RSA_PKCS_OAEP_TPM_1_1 0x00004002
+
+#define CKM_VENDOR_DEFINED 0x80000000
+
+typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR;
+
+
+/* CK_MECHANISM is a structure that specifies a particular
+ * mechanism */
+typedef struct CK_MECHANISM {
+ CK_MECHANISM_TYPE mechanism;
+ CK_VOID_PTR pParameter;
+ CK_ULONG ulParameterLen; /* in bytes */
+} CK_MECHANISM;
+
+typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR;
+
+
+/* CK_MECHANISM_INFO provides information about a particular
+ * mechanism */
+typedef struct CK_MECHANISM_INFO {
+ CK_ULONG ulMinKeySize;
+ CK_ULONG ulMaxKeySize;
+ CK_FLAGS flags;
+} CK_MECHANISM_INFO;
+
+/* The flags are defined as follows:
+ * Bit Flag Mask Meaning */
+#define CKF_HW 0x00000001 /* performed by HW */
+
+/* Specify whether or not a mechanism can be used for a particular task */
+#define CKF_ENCRYPT 0x00000100
+#define CKF_DECRYPT 0x00000200
+#define CKF_DIGEST 0x00000400
+#define CKF_SIGN 0x00000800
+#define CKF_SIGN_RECOVER 0x00001000
+#define CKF_VERIFY 0x00002000
+#define CKF_VERIFY_RECOVER 0x00004000
+#define CKF_GENERATE 0x00008000
+#define CKF_GENERATE_KEY_PAIR 0x00010000
+#define CKF_WRAP 0x00020000
+#define CKF_UNWRAP 0x00040000
+#define CKF_DERIVE 0x00080000
+
+/* Describe a token's EC capabilities not available in mechanism
+ * information. */
+#define CKF_EC_F_P 0x00100000
+#define CKF_EC_F_2M 0x00200000
+#define CKF_EC_ECPARAMETERS 0x00400000
+#define CKF_EC_NAMEDCURVE 0x00800000
+#define CKF_EC_UNCOMPRESS 0x01000000
+#define CKF_EC_COMPRESS 0x02000000
+
+#define CKF_EXTENSION 0x80000000 /* FALSE for this version */
+
+typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR;
+
+
+/* CK_RV is a value that identifies the return value of a
+ * Cryptoki function */
+typedef CK_ULONG CK_RV;
+
+#define CKR_OK 0x00000000
+#define CKR_CANCEL 0x00000001
+#define CKR_HOST_MEMORY 0x00000002
+#define CKR_SLOT_ID_INVALID 0x00000003
+
+/* CKR_FLAGS_INVALID was removed for v2.0 */
+
+#define CKR_GENERAL_ERROR 0x00000005
+#define CKR_FUNCTION_FAILED 0x00000006
+
+#define CKR_ARGUMENTS_BAD 0x00000007
+#define CKR_NO_EVENT 0x00000008
+#define CKR_NEED_TO_CREATE_THREADS 0x00000009
+#define CKR_CANT_LOCK 0x0000000A
+
+#define CKR_ATTRIBUTE_READ_ONLY 0x00000010
+#define CKR_ATTRIBUTE_SENSITIVE 0x00000011
+#define CKR_ATTRIBUTE_TYPE_INVALID 0x00000012
+#define CKR_ATTRIBUTE_VALUE_INVALID 0x00000013
+#define CKR_DATA_INVALID 0x00000020
+#define CKR_DATA_LEN_RANGE 0x00000021
+#define CKR_DEVICE_ERROR 0x00000030
+#define CKR_DEVICE_MEMORY 0x00000031
+#define CKR_DEVICE_REMOVED 0x00000032
+#define CKR_ENCRYPTED_DATA_INVALID 0x00000040
+#define CKR_ENCRYPTED_DATA_LEN_RANGE 0x00000041
+#define CKR_FUNCTION_CANCELED 0x00000050
+#define CKR_FUNCTION_NOT_PARALLEL 0x00000051
+
+#define CKR_FUNCTION_NOT_SUPPORTED 0x00000054
+
+#define CKR_KEY_HANDLE_INVALID 0x00000060
+
+/* CKR_KEY_SENSITIVE was removed for v2.0 */
+
+#define CKR_KEY_SIZE_RANGE 0x00000062
+#define CKR_KEY_TYPE_INCONSISTENT 0x00000063
+
+#define CKR_KEY_NOT_NEEDED 0x00000064
+#define CKR_KEY_CHANGED 0x00000065
+#define CKR_KEY_NEEDED 0x00000066
+#define CKR_KEY_INDIGESTIBLE 0x00000067
+#define CKR_KEY_FUNCTION_NOT_PERMITTED 0x00000068
+#define CKR_KEY_NOT_WRAPPABLE 0x00000069
+#define CKR_KEY_UNEXTRACTABLE 0x0000006A
+
+#define CKR_MECHANISM_INVALID 0x00000070
+#define CKR_MECHANISM_PARAM_INVALID 0x00000071
+
+/* CKR_OBJECT_CLASS_INCONSISTENT and CKR_OBJECT_CLASS_INVALID
+ * were removed for v2.0 */
+#define CKR_OBJECT_HANDLE_INVALID 0x00000082
+#define CKR_OPERATION_ACTIVE 0x00000090
+#define CKR_OPERATION_NOT_INITIALIZED 0x00000091
+#define CKR_PIN_INCORRECT 0x000000A0
+#define CKR_PIN_INVALID 0x000000A1
+#define CKR_PIN_LEN_RANGE 0x000000A2
+
+#define CKR_PIN_EXPIRED 0x000000A3
+#define CKR_PIN_LOCKED 0x000000A4
+
+#define CKR_SESSION_CLOSED 0x000000B0
+#define CKR_SESSION_COUNT 0x000000B1
+#define CKR_SESSION_HANDLE_INVALID 0x000000B3
+#define CKR_SESSION_PARALLEL_NOT_SUPPORTED 0x000000B4
+#define CKR_SESSION_READ_ONLY 0x000000B5
+#define CKR_SESSION_EXISTS 0x000000B6
+
+#define CKR_SESSION_READ_ONLY_EXISTS 0x000000B7
+#define CKR_SESSION_READ_WRITE_SO_EXISTS 0x000000B8
+
+#define CKR_SIGNATURE_INVALID 0x000000C0
+#define CKR_SIGNATURE_LEN_RANGE 0x000000C1
+#define CKR_TEMPLATE_INCOMPLETE 0x000000D0
+#define CKR_TEMPLATE_INCONSISTENT 0x000000D1
+#define CKR_TOKEN_NOT_PRESENT 0x000000E0
+#define CKR_TOKEN_NOT_RECOGNIZED 0x000000E1
+#define CKR_TOKEN_WRITE_PROTECTED 0x000000E2
+#define CKR_UNWRAPPING_KEY_HANDLE_INVALID 0x000000F0
+#define CKR_UNWRAPPING_KEY_SIZE_RANGE 0x000000F1
+#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x000000F2
+#define CKR_USER_ALREADY_LOGGED_IN 0x00000100
+#define CKR_USER_NOT_LOGGED_IN 0x00000101
+#define CKR_USER_PIN_NOT_INITIALIZED 0x00000102
+#define CKR_USER_TYPE_INVALID 0x00000103
+
+#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000104
+#define CKR_USER_TOO_MANY_TYPES 0x00000105
+
+#define CKR_WRAPPED_KEY_INVALID 0x00000110
+#define CKR_WRAPPED_KEY_LEN_RANGE 0x00000112
+#define CKR_WRAPPING_KEY_HANDLE_INVALID 0x00000113
+#define CKR_WRAPPING_KEY_SIZE_RANGE 0x00000114
+#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT 0x00000115
+#define CKR_RANDOM_SEED_NOT_SUPPORTED 0x00000120
+
+#define CKR_RANDOM_NO_RNG 0x00000121
+
+#define CKR_DOMAIN_PARAMS_INVALID 0x00000130
+
+#define CKR_BUFFER_TOO_SMALL 0x00000150
+#define CKR_SAVED_STATE_INVALID 0x00000160
+#define CKR_INFORMATION_SENSITIVE 0x00000170
+#define CKR_STATE_UNSAVEABLE 0x00000180
+
+#define CKR_CRYPTOKI_NOT_INITIALIZED 0x00000190
+#define CKR_CRYPTOKI_ALREADY_INITIALIZED 0x00000191
+#define CKR_MUTEX_BAD 0x000001A0
+#define CKR_MUTEX_NOT_LOCKED 0x000001A1
+
+#define CKR_NEW_PIN_MODE 0x000001B0
+#define CKR_NEXT_OTP 0x000001B1
+#define CKR_EXCEEDED_MAX_ITERATIONS 0x000001B5
+#define CKR_FIPS_SELF_TEST_FAILED 0x000001B6
+#define CKR_LIBRARY_LOAD_FAILED 0x000001B7
+#define CKR_PIN_TOO_WEAK 0x000001B8
+#define CKR_PUBLIC_KEY_INVALID 0x000001B9
+
+#define CKR_FUNCTION_REJECTED 0x00000200
+
+#define CKR_VENDOR_DEFINED 0x80000000
+
+
+/* CK_NOTIFY is an application callback that processes events */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_NOTIFICATION event,
+ CK_VOID_PTR pApplication /* passed to C_OpenSession */
+);
+
+
+/* CK_FUNCTION_LIST is a structure holding a Cryptoki spec
+ * version and pointers of appropriate types to all the
+ * Cryptoki functions */
+typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST;
+
+typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR;
+
+typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR;
+
+
+/* CK_CREATEMUTEX is an application callback for creating a
+ * mutex object */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)(
+ CK_VOID_PTR_PTR ppMutex /* location to receive ptr to mutex */
+);
+
+
+/* CK_DESTROYMUTEX is an application callback for destroying a
+ * mutex object */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_LOCKMUTEX is an application callback for locking a mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_UNLOCKMUTEX is an application callback for unlocking a
+ * mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_C_INITIALIZE_ARGS provides the optional arguments to
+ * C_Initialize */
+typedef struct CK_C_INITIALIZE_ARGS {
+ CK_CREATEMUTEX CreateMutex;
+ CK_DESTROYMUTEX DestroyMutex;
+ CK_LOCKMUTEX LockMutex;
+ CK_UNLOCKMUTEX UnlockMutex;
+ CK_FLAGS flags;
+ CK_VOID_PTR pReserved;
+} CK_C_INITIALIZE_ARGS;
+
+/* flags: bit flags that provide capabilities of the slot
+ * Bit Flag Mask Meaning
+ */
+#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001
+#define CKF_OS_LOCKING_OK 0x00000002
+
+typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR;
+
+
+/* additional flags for parameters to functions */
+
+/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */
+#define CKF_DONT_BLOCK 1
+
+/*
+ * CK_RSA_PKCS_OAEP_MGF_TYPE is used to indicate the Message
+ * Generation Function (MGF) applied to a message block when
+ * formatting a message block for the PKCS #1 OAEP encryption
+ * scheme. */
+typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE;
+
+typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
+
+/* The following MGFs are defined */
+#define CKG_MGF1_SHA1 0x00000001
+#define CKG_MGF1_SHA256 0x00000002
+#define CKG_MGF1_SHA384 0x00000003
+#define CKG_MGF1_SHA512 0x00000004
+#define CKG_MGF1_SHA224 0x00000005
+
+/*
+ * CK_RSA_PKCS_OAEP_SOURCE_TYPE is used to indicate the source
+ * of the encoding parameter when formatting a message block
+ * for the PKCS #1 OAEP encryption scheme. */
+typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE;
+
+typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR;
+
+/* The following encoding parameter sources are defined */
+#define CKZ_DATA_SPECIFIED 0x00000001
+
+/*
+ * CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_OAEP mechanism. */
+typedef struct CK_RSA_PKCS_OAEP_PARAMS {
+ CK_MECHANISM_TYPE hashAlg;
+ CK_RSA_PKCS_MGF_TYPE mgf;
+ CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
+ CK_VOID_PTR pSourceData;
+ CK_ULONG ulSourceDataLen;
+} CK_RSA_PKCS_OAEP_PARAMS;
+
+typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR;
+
+/*
+ * CK_RSA_PKCS_PSS_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_PSS mechanism(s). */
+typedef struct CK_RSA_PKCS_PSS_PARAMS {
+ CK_MECHANISM_TYPE hashAlg;
+ CK_RSA_PKCS_MGF_TYPE mgf;
+ CK_ULONG sLen;
+} CK_RSA_PKCS_PSS_PARAMS;
+
+typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR;
+
+typedef CK_ULONG CK_EC_KDF_TYPE;
+
+/* The following EC Key Derivation Functions are defined */
+#define CKD_NULL 0x00000001
+#define CKD_SHA1_KDF 0x00000002
+/* The following X9.42 DH key derivation functions are defined */
+#define CKD_SHA1_KDF_ASN1 0x00000003
+#define CKD_SHA1_KDF_CONCATENATE 0x00000004
+#define CKD_SHA224_KDF 0x00000005
+#define CKD_SHA256_KDF 0x00000006
+#define CKD_SHA384_KDF 0x00000007
+#define CKD_SHA512_KDF 0x00000008
+#define CKD_CPDIVERSIFY_KDF 0x00000009
+
+
+/*
+ * CK_ECDH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms,
+ * where each party contributes one key pair.
+ */
+typedef struct CK_ECDH1_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_ECDH1_DERIVE_PARAMS;
+
+typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR;
+
+
+/*
+ * CK_ECDH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECMQV_DERIVE mechanism, where each party contributes two key pairs. */
+typedef struct CK_ECDH2_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+} CK_ECDH2_DERIVE_PARAMS;
+
+typedef CK_ECDH2_DERIVE_PARAMS CK_PTR CK_ECDH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_ECMQV_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+ CK_OBJECT_HANDLE publicKey;
+} CK_ECMQV_DERIVE_PARAMS;
+
+typedef CK_ECMQV_DERIVE_PARAMS CK_PTR CK_ECMQV_DERIVE_PARAMS_PTR;
+
+/* Typedefs and defines for the CKM_X9_42_DH_KEY_PAIR_GEN and the
+ * CKM_X9_42_DH_PARAMETER_GEN mechanisms */
+typedef CK_ULONG CK_X9_42_DH_KDF_TYPE;
+typedef CK_X9_42_DH_KDF_TYPE CK_PTR CK_X9_42_DH_KDF_TYPE_PTR;
+
+/*
+ * CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_DERIVE key derivation mechanism, where each party
+ * contributes one key pair */
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_X9_42_DH1_DERIVE_PARAMS;
+
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS CK_PTR CK_X9_42_DH1_DERIVE_PARAMS_PTR;
+
+/*
+ * CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE key derivation
+ * mechanisms, where each party contributes two key pairs */
+typedef struct CK_X9_42_DH2_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+} CK_X9_42_DH2_DERIVE_PARAMS;
+
+typedef CK_X9_42_DH2_DERIVE_PARAMS CK_PTR CK_X9_42_DH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_X9_42_MQV_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+ CK_OBJECT_HANDLE publicKey;
+} CK_X9_42_MQV_DERIVE_PARAMS;
+
+typedef CK_X9_42_MQV_DERIVE_PARAMS CK_PTR CK_X9_42_MQV_DERIVE_PARAMS_PTR;
+
+/* CK_KEA_DERIVE_PARAMS provides the parameters to the
+ * CKM_KEA_DERIVE mechanism */
+typedef struct CK_KEA_DERIVE_PARAMS {
+ CK_BBOOL isSender;
+ CK_ULONG ulRandomLen;
+ CK_BYTE_PTR pRandomA;
+ CK_BYTE_PTR pRandomB;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_KEA_DERIVE_PARAMS;
+
+typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR;
+
+
+/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and
+ * CKM_RC2_MAC mechanisms. An instance of CK_RC2_PARAMS just
+ * holds the effective keysize */
+typedef CK_ULONG CK_RC2_PARAMS;
+
+typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR;
+
+
+/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC
+ * mechanism */
+typedef struct CK_RC2_CBC_PARAMS {
+ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */
+
+ CK_BYTE iv[8]; /* IV for CBC mode */
+} CK_RC2_CBC_PARAMS;
+
+typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR;
+
+
+/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC2_MAC_GENERAL mechanism */
+typedef struct CK_RC2_MAC_GENERAL_PARAMS {
+ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */
+ CK_ULONG ulMacLength; /* Length of MAC in bytes */
+} CK_RC2_MAC_GENERAL_PARAMS;
+
+typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR \
+ CK_RC2_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and
+ * CKM_RC5_MAC mechanisms */
+typedef struct CK_RC5_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+} CK_RC5_PARAMS;
+
+typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR;
+
+
+/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC
+ * mechanism */
+typedef struct CK_RC5_CBC_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+ CK_BYTE_PTR pIv; /* pointer to IV */
+ CK_ULONG ulIvLen; /* length of IV in bytes */
+} CK_RC5_CBC_PARAMS;
+
+typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR;
+
+
+/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC5_MAC_GENERAL mechanism */
+typedef struct CK_RC5_MAC_GENERAL_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+ CK_ULONG ulMacLength; /* Length of MAC in bytes */
+} CK_RC5_MAC_GENERAL_PARAMS;
+
+typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR \
+ CK_RC5_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_MAC_GENERAL_PARAMS provides the parameters to most block
+ * ciphers' MAC_GENERAL mechanisms. Its value is the length of
+ * the MAC */
+typedef CK_ULONG CK_MAC_GENERAL_PARAMS;
+
+typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR;
+
+typedef struct CK_DES_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[8];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_DES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[16];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_AES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_PRIVATE_WRAP mechanism */
+typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS {
+ CK_ULONG ulPasswordLen;
+ CK_BYTE_PTR pPassword;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPAndGLen;
+ CK_ULONG ulQLen;
+ CK_ULONG ulRandomLen;
+ CK_BYTE_PTR pRandomA;
+ CK_BYTE_PTR pPrimeP;
+ CK_BYTE_PTR pBaseG;
+ CK_BYTE_PTR pSubprimeQ;
+} CK_SKIPJACK_PRIVATE_WRAP_PARAMS;
+
+typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR \
+ CK_SKIPJACK_PRIVATE_WRAP_PTR;
+
+
+/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_RELAYX mechanism */
+typedef struct CK_SKIPJACK_RELAYX_PARAMS {
+ CK_ULONG ulOldWrappedXLen;
+ CK_BYTE_PTR pOldWrappedX;
+ CK_ULONG ulOldPasswordLen;
+ CK_BYTE_PTR pOldPassword;
+ CK_ULONG ulOldPublicDataLen;
+ CK_BYTE_PTR pOldPublicData;
+ CK_ULONG ulOldRandomLen;
+ CK_BYTE_PTR pOldRandomA;
+ CK_ULONG ulNewPasswordLen;
+ CK_BYTE_PTR pNewPassword;
+ CK_ULONG ulNewPublicDataLen;
+ CK_BYTE_PTR pNewPublicData;
+ CK_ULONG ulNewRandomLen;
+ CK_BYTE_PTR pNewRandomA;
+} CK_SKIPJACK_RELAYX_PARAMS;
+
+typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR \
+ CK_SKIPJACK_RELAYX_PARAMS_PTR;
+
+
+typedef struct CK_PBE_PARAMS {
+ CK_BYTE_PTR pInitVector;
+ CK_UTF8CHAR_PTR pPassword;
+ CK_ULONG ulPasswordLen;
+ CK_BYTE_PTR pSalt;
+ CK_ULONG ulSaltLen;
+ CK_ULONG ulIteration;
+} CK_PBE_PARAMS;
+
+typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR;
+
+
+/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the
+ * CKM_KEY_WRAP_SET_OAEP mechanism */
+typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS {
+ CK_BYTE bBC; /* block contents byte */
+ CK_BYTE_PTR pX; /* extra data */
+ CK_ULONG ulXLen; /* length of extra data in bytes */
+} CK_KEY_WRAP_SET_OAEP_PARAMS;
+
+typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR \
+ CK_KEY_WRAP_SET_OAEP_PARAMS_PTR;
+
+
+typedef struct CK_SSL3_RANDOM_DATA {
+ CK_BYTE_PTR pClientRandom;
+ CK_ULONG ulClientRandomLen;
+ CK_BYTE_PTR pServerRandom;
+ CK_ULONG ulServerRandomLen;
+} CK_SSL3_RANDOM_DATA;
+
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS {
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_VERSION_PTR pVersion;
+} CK_SSL3_MASTER_KEY_DERIVE_PARAMS;
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+ CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_OUT {
+ CK_OBJECT_HANDLE hClientMacSecret;
+ CK_OBJECT_HANDLE hServerMacSecret;
+ CK_OBJECT_HANDLE hClientKey;
+ CK_OBJECT_HANDLE hServerKey;
+ CK_BYTE_PTR pIVClient;
+ CK_BYTE_PTR pIVServer;
+} CK_SSL3_KEY_MAT_OUT;
+
+typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_PARAMS {
+ CK_ULONG ulMacSizeInBits;
+ CK_ULONG ulKeySizeInBits;
+ CK_ULONG ulIVSizeInBits;
+ CK_BBOOL bIsExport;
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_SSL3_KEY_MAT_PARAMS;
+
+typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR;
+
+typedef struct CK_TLS_PRF_PARAMS {
+ CK_BYTE_PTR pSeed;
+ CK_ULONG ulSeedLen;
+ CK_BYTE_PTR pLabel;
+ CK_ULONG ulLabelLen;
+ CK_BYTE_PTR pOutput;
+ CK_ULONG_PTR pulOutputLen;
+} CK_TLS_PRF_PARAMS;
+
+typedef CK_TLS_PRF_PARAMS CK_PTR CK_TLS_PRF_PARAMS_PTR;
+
+typedef struct CK_WTLS_RANDOM_DATA {
+ CK_BYTE_PTR pClientRandom;
+ CK_ULONG ulClientRandomLen;
+ CK_BYTE_PTR pServerRandom;
+ CK_ULONG ulServerRandomLen;
+} CK_WTLS_RANDOM_DATA;
+
+typedef CK_WTLS_RANDOM_DATA CK_PTR CK_WTLS_RANDOM_DATA_PTR;
+
+typedef struct CK_WTLS_MASTER_KEY_DERIVE_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_WTLS_RANDOM_DATA RandomInfo;
+ CK_BYTE_PTR pVersion;
+} CK_WTLS_MASTER_KEY_DERIVE_PARAMS;
+
+typedef CK_WTLS_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+ CK_WTLS_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+typedef struct CK_WTLS_PRF_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_BYTE_PTR pSeed;
+ CK_ULONG ulSeedLen;
+ CK_BYTE_PTR pLabel;
+ CK_ULONG ulLabelLen;
+ CK_BYTE_PTR pOutput;
+ CK_ULONG_PTR pulOutputLen;
+} CK_WTLS_PRF_PARAMS;
+
+typedef CK_WTLS_PRF_PARAMS CK_PTR CK_WTLS_PRF_PARAMS_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_OUT {
+ CK_OBJECT_HANDLE hMacSecret;
+ CK_OBJECT_HANDLE hKey;
+ CK_BYTE_PTR pIV;
+} CK_WTLS_KEY_MAT_OUT;
+
+typedef CK_WTLS_KEY_MAT_OUT CK_PTR CK_WTLS_KEY_MAT_OUT_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_ULONG ulMacSizeInBits;
+ CK_ULONG ulKeySizeInBits;
+ CK_ULONG ulIVSizeInBits;
+ CK_ULONG ulSequenceNumber;
+ CK_BBOOL bIsExport;
+ CK_WTLS_RANDOM_DATA RandomInfo;
+ CK_WTLS_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_WTLS_KEY_MAT_PARAMS;
+
+typedef CK_WTLS_KEY_MAT_PARAMS CK_PTR CK_WTLS_KEY_MAT_PARAMS_PTR;
+
+typedef struct CK_CMS_SIG_PARAMS {
+ CK_OBJECT_HANDLE certificateHandle;
+ CK_MECHANISM_PTR pSigningMechanism;
+ CK_MECHANISM_PTR pDigestMechanism;
+ CK_UTF8CHAR_PTR pContentType;
+ CK_BYTE_PTR pRequestedAttributes;
+ CK_ULONG ulRequestedAttributesLen;
+ CK_BYTE_PTR pRequiredAttributes;
+ CK_ULONG ulRequiredAttributesLen;
+} CK_CMS_SIG_PARAMS;
+
+typedef CK_CMS_SIG_PARAMS CK_PTR CK_CMS_SIG_PARAMS_PTR;
+
+typedef struct CK_KEY_DERIVATION_STRING_DATA {
+ CK_BYTE_PTR pData;
+ CK_ULONG ulLen;
+} CK_KEY_DERIVATION_STRING_DATA;
+
+typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR \
+ CK_KEY_DERIVATION_STRING_DATA_PTR;
+
+
+/* The CK_EXTRACT_PARAMS is used for the
+ * CKM_EXTRACT_KEY_FROM_KEY mechanism. It specifies which bit
+ * of the base key should be used as the first bit of the
+ * derived key */
+typedef CK_ULONG CK_EXTRACT_PARAMS;
+
+typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR;
+
+/*
+ * CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to
+ * indicate the Pseudo-Random Function (PRF) used to generate
+ * key bits using PKCS #5 PBKDF2. */
+typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE;
+
+typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR;
+
+#define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001
+
+
+/*
+ * CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the
+ * source of the salt value when deriving a key using PKCS #5
+ * PBKDF2. */
+typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE;
+
+typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR;
+
+/* The following salt value sources are defined in PKCS #5 v2.0. */
+#define CKZ_SALT_SPECIFIED 0x00000001
+
+/*
+ * CK_PKCS5_PBKD2_PARAMS is a structure that provides the
+ * parameters to the CKM_PKCS5_PBKD2 mechanism. */
+typedef struct CK_PKCS5_PBKD2_PARAMS {
+ CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource;
+ CK_VOID_PTR pSaltSourceData;
+ CK_ULONG ulSaltSourceDataLen;
+ CK_ULONG iterations;
+ CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
+ CK_VOID_PTR pPrfData;
+ CK_ULONG ulPrfDataLen;
+ CK_UTF8CHAR_PTR pPassword;
+ CK_ULONG_PTR ulPasswordLen;
+} CK_PKCS5_PBKD2_PARAMS;
+
+typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR;
+
+typedef CK_ULONG CK_OTP_PARAM_TYPE;
+typedef CK_OTP_PARAM_TYPE CK_PARAM_TYPE; /* B/w compatibility */
+
+typedef struct CK_OTP_PARAM {
+ CK_OTP_PARAM_TYPE type;
+ CK_VOID_PTR pValue;
+ CK_ULONG ulValueLen;
+} CK_OTP_PARAM;
+
+typedef CK_OTP_PARAM CK_PTR CK_OTP_PARAM_PTR;
+
+typedef struct CK_OTP_PARAMS {
+ CK_OTP_PARAM_PTR pParams;
+ CK_ULONG ulCount;
+} CK_OTP_PARAMS;
+
+typedef CK_OTP_PARAMS CK_PTR CK_OTP_PARAMS_PTR;
+
+typedef struct CK_OTP_SIGNATURE_INFO {
+ CK_OTP_PARAM_PTR pParams;
+ CK_ULONG ulCount;
+} CK_OTP_SIGNATURE_INFO;
+
+typedef CK_OTP_SIGNATURE_INFO CK_PTR CK_OTP_SIGNATURE_INFO_PTR;
+
+#define CK_OTP_VALUE 0
+#define CK_OTP_PIN 1
+#define CK_OTP_CHALLENGE 2
+#define CK_OTP_TIME 3
+#define CK_OTP_COUNTER 4
+#define CK_OTP_FLAGS 5
+#define CK_OTP_OUTPUT_LENGTH 6
+#define CK_OTP_OUTPUT_FORMAT 7
+
+#define CKF_NEXT_OTP 0x00000001
+#define CKF_EXCLUDE_TIME 0x00000002
+#define CKF_EXCLUDE_COUNTER 0x00000004
+#define CKF_EXCLUDE_CHALLENGE 0x00000008
+#define CKF_EXCLUDE_PIN 0x00000010
+#define CKF_USER_FRIENDLY_OTP 0x00000020
+
+typedef struct CK_KIP_PARAMS {
+ CK_MECHANISM_PTR pMechanism;
+ CK_OBJECT_HANDLE hKey;
+ CK_BYTE_PTR pSeed;
+ CK_ULONG ulSeedLen;
+} CK_KIP_PARAMS;
+
+typedef CK_KIP_PARAMS CK_PTR CK_KIP_PARAMS_PTR;
+
+typedef struct CK_AES_CTR_PARAMS {
+ CK_ULONG ulCounterBits;
+ CK_BYTE cb[16];
+} CK_AES_CTR_PARAMS;
+
+typedef CK_AES_CTR_PARAMS CK_PTR CK_AES_CTR_PARAMS_PTR;
+
+typedef struct CK_AES_GCM_PARAMS {
+ CK_BYTE_PTR pIv;
+ CK_ULONG ulIvLen;
+ CK_ULONG ulIvBits;
+ CK_BYTE_PTR pAAD;
+ CK_ULONG ulAADLen;
+ CK_ULONG ulTagBits;
+} CK_AES_GCM_PARAMS;
+
+typedef CK_AES_GCM_PARAMS CK_PTR CK_AES_GCM_PARAMS_PTR;
+
+typedef struct CK_AES_CCM_PARAMS {
+ CK_ULONG ulDataLen; /*plaintext or ciphertext*/
+ CK_BYTE_PTR pNonce;
+ CK_ULONG ulNonceLen;
+ CK_BYTE_PTR pAAD;
+ CK_ULONG ulAADLen;
+ CK_ULONG ulMACLen;
+} CK_AES_CCM_PARAMS;
+
+typedef CK_AES_CCM_PARAMS CK_PTR CK_AES_CCM_PARAMS_PTR;
+
+typedef struct CK_CAMELLIA_CTR_PARAMS {
+ CK_ULONG ulCounterBits;
+ CK_BYTE cb[16];
+} CK_CAMELLIA_CTR_PARAMS;
+
+typedef CK_CAMELLIA_CTR_PARAMS CK_PTR CK_CAMELLIA_CTR_PARAMS_PTR;
+
+typedef struct CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[16];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+typedef struct CK_ARIA_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[16];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_ARIA_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_ARIA_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_ARIA_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+#endif
diff --git a/schema.sql b/schema.sql
new file mode 100644
index 0000000..82d9482
--- /dev/null
+++ b/schema.sql
@@ -0,0 +1,117 @@
+-- SQLite3 schema for Cryptech PKCS #11 implementation.
+--
+-- Author: Rob Austein
+-- Copyright (c) 2015, SUNET
+--
+-- Redistribution and use in source and binary forms, with or
+-- without modification, are permitted provided that the following
+-- conditions are met:
+--
+-- 1. Redistributions of source code must retain the above copyright
+-- notice, this list of conditions and the following disclaimer.
+--
+-- 2. Redistributions in binary form must reproduce the above copyright
+-- notice, this list of conditions and the following disclaimer in
+-- the documentation and/or other materials provided with the
+-- distribution.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+-- FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+-- COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+-- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+-- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+-- STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+-- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-- Notes:
+--
+-- The CHECK constraints in the attribute tables are checking
+-- CKA_TOKEN, to make sure we don't accidently file token objects in
+-- the session table or vice versa.
+--
+-- temp.object.token_object_id is a foreign-key reference to
+-- main.token_object.id, but we can't use a real foreign key reference
+-- because they're in different databases. If we're careful about how
+-- we do our joins, this is harmless, but may lead to some clutter if
+-- a long running session has handles on token objects which some
+-- other process deletes from the database. If this happens and we
+-- care for some reason, we can clean up such clutter with something
+-- like:
+--
+-- WITH
+-- known AS (SELECT token_object_id FROM token_object)
+-- DELETE FROM object
+-- WHERE token_object_id IS NOT NULL
+-- AND token_object_id NOT IN known;
+
+PRAGMA foreign_keys = ON;
+
+CREATE TEMPORARY TABLE IF NOT EXISTS session (
+ session_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+ session_handle INTEGER NOT NULL UNIQUE
+ CHECK (session_handle > 0 AND session_handle <= 0xFFFFFFFF)
+);
+
+CREATE TEMPORARY TABLE IF NOT EXISTS object (
+ object_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+ object_handle INTEGER NOT NULL UNIQUE
+ CHECK (object_handle > 0 AND object_handle <= 0xFFFFFFFF),
+ session_id INTEGER REFERENCES session
+ ON DELETE CASCADE ON UPDATE CASCADE
+ DEFERRABLE INITIALLY DEFERRED,
+ token_object_id INTEGER,
+ session_object_id INTEGER REFERENCES session_object
+ ON DELETE CASCADE ON UPDATE CASCADE
+ DEFERRABLE INITIALLY DEFERRED,
+ CHECK (token_object_id IS NULL OR (session_id IS NULL AND session_object_id IS NULL)),
+ UNIQUE (token_object_id),
+ UNIQUE (session_id, session_object_id)
+);
+
+CREATE TEMPORARY TABLE IF NOT EXISTS session_object (
+ session_object_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+ keyid TEXT UNIQUE,
+ object_id INTEGER NOT NULL UNIQUE
+ REFERENCES object
+ ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+CREATE TEMPORARY TABLE IF NOT EXISTS session_attribute (
+ type INTEGER NOT NULL,
+ session_object_id INTEGER NOT NULL REFERENCES session_object
+ ON DELETE CASCADE ON UPDATE CASCADE,
+ value BLOB NOT NULL,
+ UNIQUE (type, session_object_id),
+ CHECK (type <> 1 OR value = X'00')
+);
+
+CREATE TABLE IF NOT EXISTS token_object (
+ token_object_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+ keyid TEXT UNIQUE
+);
+
+CREATE TABLE IF NOT EXISTS token_attribute (
+ type INTEGER NOT NULL,
+ token_object_id INTEGER NOT NULL REFERENCES token_object
+ ON DELETE CASCADE ON UPDATE CASCADE,
+ value BLOB NOT NULL,
+ UNIQUE (type, token_object_id),
+ CHECK (type <> 1 OR value <> X'00')
+);
+
+-- http://sqlite.org/foreignkeys.html says we might want these.
+
+CREATE INDEX IF NOT EXISTS temp.object__session ON object(session_id);
+CREATE INDEX IF NOT EXISTS temp.object__session_object ON object(session_object_id);
+CREATE INDEX IF NOT EXISTS temp.session_object__object ON session_object(object_id);
+CREATE INDEX IF NOT EXISTS temp.session_attribute__session_object ON session_attribute(session_object_id);
+CREATE INDEX IF NOT EXISTS token_attribute__token_object ON token_attribute(token_object_id);
+
+-- Local variables:
+-- indent-tabs-mode: nil
+-- End:
diff --git a/scripts/build-attributes b/scripts/build-attributes
new file mode 100755
index 0000000..891bdb6
--- /dev/null
+++ b/scripts/build-attributes
@@ -0,0 +1,403 @@
+#!/usr/bin/env python
+
+"""
+Generate a C header file based on a YAML description of PKCS #11
+attributes. See comments in attributes.yaml for details.
+"""
+
+# Author: Rob Austein
+# Copyright (c) 2015, SUNET
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This requires a third-party YAML parser. On Debian-family Linux,
+# you can install this with:
+#
+# sudo apt-get install python-yaml
+
+import os
+import sys
+import yaml
+import argparse
+
+
+def define_flags(flag_names):
+ """
+ Flag definitions. Called later, here at front of program just to
+ make them easier to find.
+ """
+
+ flag_names.create("DEFAULT_VALUE", "Value field contains default")
+ flag_names.footnote( 1, "REQUIRED_BY_CREATEOBJECT")
+ flag_names.footnote( 2, "FORBIDDEN_BY_CREATEOBJECT")
+ flag_names.footnote( 3, "REQUIRED_BY_GENERATE")
+ flag_names.footnote( 4, "FORBIDDEN_BY_GENERATE")
+ flag_names.footnote( 5, "REQUIRED_BY_UNWRAP")
+ flag_names.footnote( 6, "FORBIDDEN_BY_UNWRAP")
+ flag_names.footnote( 7, "SENSITIVE")
+ flag_names.footnote( 8, "PERHAPS_MODIFIABLE")
+ flag_names.footnote( 9, "DEFAULT_IS_TOKEN_SPECIFIC")
+ flag_names.footnote(10, "ONLY_SO_USER_CAN_SET")
+ flag_names.footnote(11, "LATCHES_WHEN_TRUE")
+ flag_names.footnote(12, "LATCHES_WHEN_FALSE")
+
+
+class PKCS11ParseError(Exception):
+ "Failure parsing PCKS #11 object definitions from YAML data."
+
+
+def write_lines(*lines, **d):
+ """
+ Utility to simplify writing formatted text to the output stream.
+ """
+
+ for line in lines:
+ args.output_file.write((line % d) + "\n")
+
+
+class Flags(object):
+ """
+ Descriptor flag database.
+
+ Many of these are derived from PKCS #11 Table 15 footnotes
+ """
+
+ prefix = "P11_DESCRIPTOR_" # Prefix string for all descriptor flags
+
+ def __init__(self):
+ self.names = []
+ self.notes = {}
+ self.width = 0
+
+ def create(self, name, comment = None):
+ """
+ Create a descriptor flag.
+ """
+
+ assert len(self.names) < 32
+ name = self.prefix + name
+ self.names.append((name, comment))
+ if len(name) > self.width:
+ self.width = len(name)
+
+ def footnote(self, number, name):
+ """
+ Create a descriptor flag for a PKCS #11 table 15 footnote.
+ """
+
+ assert number not in self.notes
+ self.create(name, "Section 10.2 table 15 footnote #%2d" % number)
+ self.notes[number] = self.prefix + name
+
+ def write(self):
+ """
+ Generate the flags, assigning bit positions as we go.
+ """
+
+ assert len(self.names) < 32
+ self.width = (((self.width + 4) >> 2) << 2) - 1
+ bit = 1
+ for name, comment in self.names:
+ format = "#define %(name)s 0x%(bit)08x"
+ if comment is not None:
+ format += " /* %(comment)s */"
+ write_lines(format, bit = bit, comment = comment, name = "%-*s" % (self.width, name))
+ bit <<= 1
+
+
+class AttributeNumbers(dict):
+ """
+ Attribute names and numbers scraped (yuck) from pkcs11t.h.
+ """
+
+ def __init__(self, filename):
+ with open(filename, "r") as f:
+ for line in f:
+ word = line.split()
+ if len(word) <= 2 or word[0] != "#define" or not word[1].startswith("CKA_"):
+ continue
+ if word[2] in self:
+ continue
+ if word[2].startswith("(CKF_ARRAY_ATTRIBUTE|"):
+ word[2] = word[2].translate(None, "()").split("|")[1]
+ self[word[1]] = int(word[2], 16)
+
+
+class Attribute(object):
+ """
+ Definition of one attribute.
+ """
+
+ def __init__(self, name, type = None, footnotes = None, default = None, value = None, unimplemented = False):
+ assert value is None or default is None
+ self.name = name
+ self.type = type
+ self.footnotes = footnotes
+ self.default = self.convert_integers(default)
+ self.value = self.convert_integers(value)
+ self.unimplemented = unimplemented
+
+ @staticmethod
+ def convert_integers(val):
+ """
+ Convert a non-negative integer initialization value into a byte array.
+ """
+
+ if not isinstance(val, (int, long)):
+ return val
+ if val < 0:
+ raise ValueError("Negative integers not legal here: %s" % val)
+ bytes = []
+ while val > 0:
+ bytes.insert(0, val & 0xFF)
+ val >>= 8
+ return bytes or [0]
+
+ def inherit(self, other):
+ """
+ Merge values from paraent attribute definition, if any.
+ """
+
+ for k in ("type", "footnotes", "default", "value"):
+ if getattr(self, k) is None:
+ setattr(self, k, getattr(other, k))
+ self.unimplemented = self.unimplemented or other.unimplemented
+
+ def format_flags(self):
+ """
+ Generate the descriptor flags field.
+ """
+
+ flags = []
+ if self.footnotes:
+ flags.extend(flag_names.notes[f] for f in self.footnotes)
+ if self.value is None and self.default is not None:
+ flags.append("P11_DESCRIPTOR_DEFAULT_VALUE")
+ flags = " | ".join(flags)
+ return flags or "0"
+
+ def format_size(self):
+ """
+ Generate the descriptor size field.
+ """
+
+ if isinstance(self.type, str) and self.type.startswith("CK_"):
+ return "sizeof(%s)" % self.type
+ elif self.type in ("rfc2279string", "biginteger", "bytearray"):
+ return "0"
+ else:
+ raise PKCS11ParseError("Unknown meta-type %r" % self.type)
+
+ def format_length(self):
+ """
+ Generate the descriptor length field.
+ """
+
+ value = self.value or self.default
+ if isinstance(value, list):
+ return "sizeof(const_0x%s)" % "".join("%02x" % v for v in value)
+ elif value and isinstance(self.type, str) and self.type.startswith("CK_"):
+ return "sizeof(%s)" % self.type
+ else:
+ return "0"
+
+ def format_value(self):
+ """
+ Generate the descriptor value field.
+ """
+
+ value = self.value or self.default
+ if not value:
+ return "NULL_PTR"
+ elif isinstance(value, list):
+ return "const_0x" + "".join("%02x" % v for v in value)
+ else:
+ return "&const_" + value
+
+ def format_constant(self, constants):
+ """
+ Generate constant initializer values. These are merged so that we
+ only end up declaring one copy of each initializer value no matter
+ how many attributes use it.
+ """
+
+ value = self.value or self.default
+ if not self.unimplemented and value:
+ if isinstance(value, list):
+ constants.add("static const CK_BYTE const_%s[] = { %s };" % (
+ "0x" + "".join("%02x" % v for v in value),
+ ", ".join("0x%02x" % v for v in value)))
+ else:
+ constants.add("static const %s const_%s = %s;" % (self.type, value, value))
+
+ def generate(self):
+ """
+ Generate the descriptor line for this attribute.
+ """
+
+ if not self.unimplemented:
+ args.output_file.write(" { %s, %s, %s, %s, %s },\n" % (
+ self.name, self.format_size(), self.format_length(), self.format_value(), self.format_flags()))
+
+
+class Class(object):
+ """
+ A PKCS #11 class.
+ """
+
+ def __init__(self, db, name, superclass = None, concrete = False, **attrs):
+ assert all(a.startswith("CKA_") for a in attrs), "Non-attribute: %r" % [a for a in attrs if not a.startswith("CKA_")]
+ self.attributes = dict((k, Attribute(k, **v)) for k, v in attrs.iteritems())
+ self.db = db
+ self.name = name
+ self.superclass = superclass
+ self.concrete = concrete
+
+ def inherit(self, other):
+ """
+ Inherit attributes from parent type.
+ """
+
+ for k, v in other.attributes.iteritems():
+ if k not in self.attributes:
+ self.attributes[k] = v
+ else:
+ self.attributes[k].inherit(v)
+
+ def collect_constants(self, constants):
+ """
+ Collect initialization constants for all attributes.
+ """
+
+ if self.concrete:
+ for a in self.attributes.itervalues():
+ a.format_constant(constants)
+
+ def generate(self):
+ """
+ Generate a descriptor for this type.
+ """
+
+ if self.concrete:
+
+ write_lines("",
+ "static const p11_attribute_descriptor_t p11_attribute_descriptor_%(name)s[] = {",
+ name = self.name)
+
+ for a in sorted(self.attributes, key = lambda x: attribute_numbers[x]):
+ self.attributes[a].generate()
+
+ write_lines("};",
+ "",
+ "static const p11_descriptor_t p11_descriptor_%(name)s = {",
+ " p11_attribute_descriptor_%(name)s,",
+ " sizeof(p11_attribute_descriptor_%(name)s)/sizeof(p11_attribute_descriptor_t)",
+ "};",
+ name = self.name)
+
+ def keyclassmap(self):
+ """
+ Generate a keyclass map entry if this is a concrete key type.
+ """
+
+ if self.concrete and all(k in self.attributes and self.attributes[k].value for k in ("CKA_CLASS", "CKA_KEY_TYPE")):
+ write_lines(" { %s, %s, &p11_descriptor_%s }," % (
+ self.attributes["CKA_CLASS"].value, self.attributes["CKA_KEY_TYPE"].value, self.name))
+
+
+class DB(object):
+ """
+ Object type database parsed from YAML
+ """
+
+ def __init__(self, y):
+ self.ordered = [Class(self, **y) for y in y]
+ self.named = dict((c.name, c) for c in self.ordered)
+ for c in self.ordered:
+ if c.superclass is not None:
+ c.inherit(self.named[c.superclass])
+
+ def generate(self):
+ """
+ Generate output for everything in the database.
+ """
+
+ constants = set()
+ for c in self.ordered:
+ c.collect_constants(constants)
+ for constant in sorted(constants):
+ write_lines(constant)
+ for c in self.ordered:
+ c.generate()
+ write_lines("",
+ "static const p11_descriptor_keyclass_map_t p11_descriptor_keyclass_map[] = {")
+ for c in self.ordered:
+ c.keyclassmap()
+ write_lines("};")
+
+# Main program
+
+parser = argparse.ArgumentParser(description = __doc__, formatter_class = argparse.ArgumentDefaultsHelpFormatter)
+parser.add_argument("--pkcs11t-file", help = "Alternate location for pkcs11t.h", default = "pkcs11t.h")
+parser.add_argument("yaml_file", help = "Input YAML file", nargs = "?", type = argparse.FileType("r"), default = sys.stdin)
+parser.add_argument("output_file", help = "Output .h file", nargs = "?", type = argparse.FileType("w"), default = sys.stdout)
+args = parser.parse_args()
+
+attribute_numbers = AttributeNumbers(args.pkcs11t_file)
+
+db = DB(yaml.load(args.yaml_file))
+
+args.output_file.write('''\
+/*
+ * This file was generated automatically from %(input)s by %(script)s. Do not edit this file directly.
+ */
+
+typedef struct {
+ CK_ATTRIBUTE_TYPE type;
+ CK_ULONG size; /* Size in bytes if this is a fixed-length attribute */
+ CK_ULONG length; /* Length in bytes of the object to which value points */
+ const void *value; /* Default or constant depending on P11_DESCRIPTOR_DEFAULT_VALUE */
+ unsigned long flags; /* (NULL value with P11_DESCRIPTOR_DEFAULT_VALUE means zero length default */
+} p11_attribute_descriptor_t;
+
+typedef struct {
+ const p11_attribute_descriptor_t *attributes;
+ CK_ULONG n_attributes;
+} p11_descriptor_t;
+
+typedef struct {
+ CK_OBJECT_CLASS object_class;
+ CK_KEY_TYPE key_type;
+ const p11_descriptor_t *descriptor;
+} p11_descriptor_keyclass_map_t;
+
+''' % dict(script = os.path.basename(sys.argv[0]), input = args.yaml_file.name))
+
+flag_names = Flags()
+define_flags(flag_names)
+flag_names.write()
+write_lines("")
+db.generate()
diff --git a/scripts/convert-schema.sed b/scripts/convert-schema.sed
new file mode 100644
index 0000000..55aaadc
--- /dev/null
+++ b/scripts/convert-schema.sed
@@ -0,0 +1,66 @@
+# Generate schema.h from schema.sql.
+#
+# If this script gets any more complicated, it should probably be
+# recoded in Python and have done.
+#
+# Author: Rob Austein
+# Copyright (c) 2015, SUNET
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+# Add header. Note that both newlines and leading spaces need to be
+# quoted with backslashes, be careful....
+1i\
+ /*\
+\ * Automatically generated from schema.sql, edit that file instead of this one.\
+\ */\
+\
+
+# Debugging hack: ordinarily we keep all the per-session stuff in the
+# "temp" database, but debugging is easier when we let it all go to
+# disk. Uncomment these lines to remove all the "TEMPORARY" and
+# "temp." qualifiers.
+#s/ TEMPORARY / /g
+#s/ temp[.]/ /g
+
+# Delete comment lines, trailing whitespace, and blank lines.
+/^[ ]*--/d
+s/[ ]*$//
+/^$/d
+
+# Quote backslashes and doublequotes, if any.
+s/\\/\\\\/g
+s/"/\\"/g
+
+# Quote each line of text. Literal transcription would be:
+#
+# s/^.*$/"&\\n"/
+#
+# but SQL doesn't need the line breaks, so we can use
+# whitespace to generate something a bit more readable.
+#
+s/^.*$/" &"/
diff --git a/scripts/format-attribute-comments b/scripts/format-attribute-comments
new file mode 100755
index 0000000..3c13bba
--- /dev/null
+++ b/scripts/format-attribute-comments
@@ -0,0 +1,85 @@
+#!/bin/sh -
+#
+# Script to extract tables from the PKCS #11 specification and format
+# them as YAML comment blocks.
+#
+# This isn't even half-assed, more like quarter-assed. If I thought
+# we'd be using it a lot I'd rewrite it in Python.
+#
+# Author: Rob Austein
+# Copyright (c) 2015, SUNET
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+url=http://www.cryptsoft.com/pkcs11doc/download/pkcs11doc-v230.tgz
+
+tar=${url##*/}
+
+test -r $tar ||
+wget $url ||
+exit
+
+tar -tf $tar |
+
+awk '
+ /group__SEC__(9|11)__.*\.html/ {
+
+ n = split($0, a, "[/.]");
+ title = a[n-1];
+
+ n = split($0, a, /__/);
+ s1 = a[3];
+ s2 = (a[4] ~ /^[0-9]+$/) ? a[4] : 0;
+ s3 = (a[5] ~ /^[0-9]+$/) ? a[5] : 0;
+ idx = sprintf("%04d%04d%04d", s1, s2, s3);
+
+ print idx, $0, title;
+ }
+' |
+
+sort -n |
+
+while read idx fn title
+do
+
+ tar -xOf $tar $fn |
+
+ w3m -dump -O us-ascii -T text/html |
+
+ awk -v title=$title '
+ BEGIN {
+ print "";
+ print "###";
+ print "#", title;
+ print "###";
+ print "";
+ }
+ /^[|+]/ {
+ print "#", $0;
+ }
+ '
+
+done
diff --git a/scripts/test-hsmcheck b/scripts/test-hsmcheck
new file mode 100755
index 0000000..b7a5643
--- /dev/null
+++ b/scripts/test-hsmcheck
@@ -0,0 +1,180 @@
+#!/usr/bin/env python
+
+"""
+Run the OpenDNSSEC libhsm/check/hsmcheck tool with Cryptech PKCS #11,
+using DNSpython to verify the DNSSEC data produced by"hsmcheck -s".
+
+This script knows far too much about the output generated by hsmcheck,
+but what were you expecting from an ad hoc test tool that gets its
+input by screen scraping the output of another ad hoc test tool?
+"""
+
+# Author: Rob Austein
+# Copyright (c) 2015, SUNET
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import sys
+
+from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter, FileType as ArgumentFileType
+from tempfile import NamedTemporaryFile
+from subprocess import check_call, check_output
+from xml.etree.ElementTree import ElementTree, Element, SubElement
+
+
+def write_config():
+ """
+ Write hsmcheck configuration file.
+ """
+
+ e = Element("Configuration")
+ r = SubElement(e, "RepositoryList")
+ r = SubElement(r, "Repository", name = "default")
+ SubElement(r, "Module").text = args.driver
+ SubElement(r, "TokenLabel").text = args.token_label
+ SubElement(r, "PIN").text = args.pin
+ ElementTree(e).write(args.write_config)
+ args.write_config.flush()
+
+
+def hsmcheck(flag):
+ """
+ Run hsmcheck program with appropriate options and verbosity.
+ """
+
+ assert flag in "rgsd"
+ cmd = (args.hsmcheck_binary, "-c", args.write_config.name, "-" + flag)
+ if args.verbose:
+ sys.stdout.write("Running: %s\n" % " ".join(cmd))
+ if flag == "s":
+ text = check_output(cmd)
+ sys.stdout.write(text)
+ if not args.no_dnssec:
+ check_dnssec(text)
+ else:
+ check_call(cmd)
+
+
+def check_dnssec(text):
+ """
+ Use DNSPython to attempt DNSSEC validation on "hsmcheck -s" output.
+
+ This requires the DNSPython toolkit, which in turn requires
+ PyCrypto; ECDSA support (not yet tested) requires a third package.
+ On Debian-family Linux, you can install these with:
+
+ sudo apt-get install python-dnspython python-crypto python-ecdsa
+
+ Equivalent packages exist for other platforms.
+ """
+
+ try:
+ from dns.exception import DNSException
+ import dns.dnssec
+ import dns.rrset
+ import Crypto.PublicKey.RSA
+ #import ecdsa.ecdsa
+ except ImportError:
+ sys.exit("Problem importing DNSPython or supporting crypto packages, are they installed?")
+
+ wired_ttl = "3600"
+ wired_rdclass = "IN"
+
+ rrs = {}
+
+ for line in text.splitlines():
+
+ try:
+ name, ttl, rdclass, rdtype, rdata = line.split(None, 4)
+ except ValueError:
+ continue
+
+ if ttl != wired_ttl or rdclass != wired_rdclass:
+ continue
+
+ try:
+ rrs[name, rdtype].append(rdata)
+ except KeyError:
+ rrs[name, rdtype] = [rdata]
+
+ # Done parsing. We expect to have seen an A RRset, an RRSIG of that
+ # A RRset, and the DNSKEY that we'll need to verify the RRSIG.
+
+ if len(rrs) != 3:
+ sys.exit("Expected two RRsets and an RRSIG, got %r" % rrs)
+
+ rrs = dict((rdtype, dns.rrset.from_text_list(name, int(wired_ttl), wired_rdclass, rdtype, rrs[name, rdtype]))
+ for name, rdtype in rrs)
+
+ try:
+ dns.dnssec.validate(rrs["A"], rrs["RRSIG"], { rrs["DNSKEY"].name : rrs["DNSKEY"] })
+ except DNSException, e:
+ sys.exit("DNSSEC verification failed: %s" % e)
+
+ sys.stdout.write("\nDNSSEC verification successful!\n\n")
+
+
+# Main program.
+
+try:
+ default_config = NamedTemporaryFile()
+ default_hsmcheck = os.getenv("HSMCHECK", "hsmcheck")
+ default_driver = os.getenv("PKCS11_DRIVER",
+ os.path.realpath(os.path.join(os.path.dirname(sys.argv[0]), "..", "libpkcs11.so")))
+
+ parser = ArgumentParser(description = __doc__, formatter_class = ArgumentDefaultsHelpFormatter)
+ one_of = parser.add_mutually_exclusive_group()
+ one_of.add_argument("-a", "--all", "--rgsd", const = "rgsd", dest = "test", action = "store_const", help = "run all tests")
+ one_of.add_argument("-r", "--random", const = "r", dest = "test", action = "store_const", help = "just test random numbers")
+ one_of.add_argument("-g", "--generate", const = "g", dest = "test", action = "store_const", help = "just test key generation")
+ one_of.add_argument("-s", "--sign", const = "s", dest = "test", action = "store_const", help = "just test DNSSEC-signature")
+ one_of.add_argument("-d", "--delete", const = "d", dest = "test", action = "store_const", help = "just delete key")
+ parser.add_argument("-b", "--hsmcheck-binary", default = default_hsmcheck, help = "location of hsmcheck program")
+ parser.add_argument("-p", "--pin", default = "12345", help = "HSM PIN to use for tests")
+ parser.add_argument("-t", "--token-label", default = "Cryptech Token", help = "PKCS #11 label of Cryptech token")
+ parser.add_argument("-n", "--no-dnssec", action = "store_true", help = "do not attempt DNSSEC validation")
+ parser.add_argument("-v", "--verbose", action = "store_true", help = "bark more")
+ parser.add_argument("-D", "--driver", default = default_driver, help = "location of PKCS #11 driver")
+ parser.add_argument("-w", "--write-config", default = default_config, help = "write generated configuration to this file",
+ type = ArgumentFileType("w"))
+ parser.add_argument("--debug", action = "store_true", help = "debug this script")
+ parser.set_defaults(test = "rgsd")
+ args = parser.parse_args()
+
+ try:
+ write_config()
+ for flag in args.test:
+ hsmcheck(flag)
+
+ except Exception as e:
+ if args.debug:
+ raise
+ sys.exit("Failed: %s" % e)
+
+finally:
+ default_config.close()
+
More information about the Commits
mailing list