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"