[gnutls-dev] RFC: PKCS#11 plans
Simon Josefsson
simon at josefsson.org
Sun Apr 22 14:27:16 CEST 2007
Hi! I've started experimenting with PKCS#11 support in GnuTLS, and it
seems possible to do it. This e-mail provides a starting point for
discussions. I'm not at all sure how to implement this, so your
thoughts and ideas are very much appreciated!
I've created a new branch gnutls_1_7_8_with_pkcs11 that will contain
these experiments. If they are successful, they will be integrated
into the 1.7.x branch and become part of the next stable release
(which I hope to get out before or during the summer).
There are several ways to support PKCS#11 in GnuTLS, I can think of at
least three:
1) Build-time linking to a particular PKCS#11 implementation.
Applications would likely have to call a new API, and my initial
guess at what it would look would be:
int gnutls_certificate_set_pkcs11 (gnutls_certificate_credentials_t res,
const char *key_id);
where KEY_ID would be an optional string denoting the Key ID of the
key to use as the private key. If KEY_ID is NULL, it would use any
private key it finds.
This is easy to use and program for, but offers limited
flexibility.
Refinement
----------
One way to make this more flexible would be to place the API in a
special library: libgnutls_pkcs11_foo where foo is the PKCS#11
library it uses. In other words, there could be:
libgnutls_pkcs11_scute.so uses the GnuPG 2.x PKCS#11 module
libgnutls_pkcs11_seahorse.so uses the GNOME SeaHorse PKCS#11 plugin
libgnutls_pkcs11_nss.so uses the Mozilla NSS PKCS#11 module
...
Each of those libraries would be directly linked to the particular
PKCS#11 library. Applications, if they need PKCS#11 functionality,
would have to link to one of these libraries. They are mutually
exclusive, so you can't use both seahorse and scute, which is a
serious disadvantage. Still, sometimes it may be sufficient.
2) Runtime linking to a application-chosen PKCS#11 implementation.
This would likely use dlopen(), and applications would need to
specify the path to the PKCS#11 plugin. You'll need a new API for
this as well, I'm thinking something like this:
int gnutls_certificate_set_pkcs11 (gnutls_certificate_credentials_t res,
const char *library,
const char *key_id);
This would dlopen() LIBRARY and search for KEY_ID, which may be
NULL to indicate that any private key is fine.
Applications can support more than one PKCS#11 plugin with this
approach. For example, it can do two calls:
gnutls_certificate_set_pkcs11 (res, "/usr/lib/libscute.so", NULL);
gnutls_certificate_set_pkcs11 (res, "/usr/lib/libnss.so", NULL);
This seems like a nice approach, although it seems sub-optimal that
applications have to provide library paths. Applications shouldn't
have to care about such details.
Refinement
----------
If LIBRARY is NULL, GnuTLS could use a static list of known
PKCS#11-providers, or it could read the list from a
/etc/gnutls-pkcs11.conf, ~/.gnutls-pkcs11.conf, GNUTLS_PKCS11
environment variable, or similar.
3) IPC to a gnutls-daemon that is responsible for the PKCS#11 management.
Here there is no linkage to any PKCS#11 plugin at all, which I
consider a major advantage -- I would not want buffer-overflow
attacks in PKCS#11 plugins to cause problems in the GnuTLS library.
The gnutls-daemon is responsible for loading and calling the
PKCS#11 plugins correctly. The APIs can look the same as previous,
in case the gnutls-daemon can dlopen() libraries. In other words,
the following:
int gnutls_certificate_set_pkcs11 (gnutls_certificate_credentials_t res,
const char *library,
const char *key_id);
would indicate that the certificate structure should talk to the
gnutls-daemon, and ask it to search for KEY_ID (if non-null) in
LIBRARY (if given), or just be happy with any private key at all.
What do you think?
/Simon
More information about the Gnutls-dev
mailing list