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.
Along with the PKCS #11 library itself, the package includes a
companion Python interface ("py11"), which uses the ctypes module from
the Python standard library to talk to the PKCS #11 implementation.
The Python implementation is intended primarily to simplify testing
the C code.
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.
As of this writing, the implementation supports only the RSA, ECDSA,
SHA-1, and SHA-2 algorithms, but the design is intended to be
extensible.
The underlying cryptographic support comes from the Cryptech
libhal
package.
The object store is currently implemented using SQLite3, which may
also need to change (more on this below).
Testing to date has been done using the bin/pkcs11/
tools from the
BIND9 distribution, the hsmcheck
and ods-hsmutil
tools from the
OpenDNSSEC distribution, the hsmbully
diagnostic tool, and a
preliminary set of unit tests using Python's unittest library. 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, generates what DNSPython thinks are good
signatures, and passes some fairly basic tests. More testing would be
a really good idea.
The choice to use use of SQLite3 as the PKCS #11 object store was
made with full knowledge that we might need to change it later. That
said, we made the initial choice 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, if only because it fails the minimum
complexity test.
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.
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.