diff options
author | Rob Austein <sra@hactrn.net> | 2015-04-28 15:29:12 -0400 |
---|---|---|
committer | Rob Austein <sra@hactrn.net> | 2015-04-28 15:29:12 -0400 |
commit | 0c8d1d765783bbc09cc1ca63ffdd233f0ce31613 (patch) | |
tree | 65114ff0b424e0eb6aa8862c12c305bf26282fcb |
First public commit of PKCS #11 implementation.
-rw-r--r-- | .gitignore | 9 | ||||
-rw-r--r-- | GNUmakefile | 63 | ||||
-rw-r--r-- | README.md | 153 | ||||
-rw-r--r-- | attributes.yaml | 646 | ||||
-rw-r--r-- | pkcs11.c | 3802 | ||||
-rw-r--r-- | pkcs11.h | 301 | ||||
-rw-r--r-- | pkcs11f.h | 912 | ||||
-rw-r--r-- | pkcs11t.h | 1789 | ||||
-rw-r--r-- | schema.sql | 117 | ||||
-rwxr-xr-x | scripts/build-attributes | 403 | ||||
-rw-r--r-- | scripts/convert-schema.sed | 66 | ||||
-rwxr-xr-x | scripts/format-attribute-comments | 85 | ||||
-rwxr-xr-x | scripts/test-hsmcheck | 180 |
13 files changed, 8526 insertions, 0 deletions
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() + |