Hardware security modules and abstract key types
************************************************

In several cases storing the long term cryptographic keys in a hard disk or even in memory poses a significant risk. Once the system they are stored is compromised the keys must be replaced as the secrecy of future sessions is no longer guarranteed. Moreover, past sessions that were not protected by a perfect forward secrecy offering ciphersuite are also to be assumed compromised.

If such threats need to be addressed, then it may be wise storing the keys in a security module such as a smart card, an HSM or the TPM chip. Those modules ensure the protection of the cryptographic keys by only allowing operations on them and preventing their extraction. The purpose of the abstract key API is to provide an API that will allow the handle of keys in memory and files, as well as keys stored in such modules.

In GnuTLS the approach is to handle all keys transparently by the high level API, e.g., the API that loads a key or certificate from a file. The high-level API will accept URIs in addition to files that specify keys on an HSM or in TPM, and a callback function will be used to obtain any required keys. The URI format is defined in TPMURI and PKCS11URI, and is in the process of being standardized across systems.

More information on the API is provided in the next sections. Examples of a URI of a certificate stored in an HSM, as well as a key stored in the TPM chip are shown below. To discover the URIs of the objects the p11tool (see p11tool Invocation), or tpmtool (see tpmtool Invocation) may be used.

     pkcs11:token=Nikos;serial=307521161601031;model=PKCS%2315; \
     manufacturer=EnterSafe;object=test1;objecttype=cert

     tpmkey:uuid=42309df8-d101-11e1-a89a-97bb33c23ad1;storage=user

Abstract key types
==================

Since there are many forms of a public or private keys supported by GnuTLS such as X.509, OpenPGP, PKCS #11 or TPM it is desirable to allow common operations on them. For these reasons the abstract gnutls_privkey_t and gnutls_pubkey_t were introduced in gnutls/abstract.h header. Those types are initialized using a specific type of key and then can be used to perform operations in an abstract way. For example in order to sign an X.509 certificate with a key that resides in a token the following steps can be used.

     #inlude <gnutls/abstract.h>

     void sign_cert( gnutls_x509_crt_t to_be_signed)
     {
     gnutls_x509_crt_t ca_cert;
     gnutls_privkey_t abs_key;

       /* initialize the abstract key */
       gnutls_privkey_init(&abs_key);

       /* keys stored in tokens are identified by URLs */
       gnutls_privkey_import_url(abs_key, key_url);

       gnutls_x509_crt_init(&ca_cert);
       gnutls_x509_crt_import_pkcs11_url(&ca_cert, cert_url);

       /* sign the certificate to be signed */
       gnutls_x509_crt_privkey_sign(to_be_signed, ca_cert, abs_key,
                                    GNUTLS_DIG_SHA256, 0);
     }

Public keys
-----------

An abstract gnutls_pubkey_t can be initialized using the functions below. It can be imported through an existing structure like gnutls_x509_crt_t, or through an ASN.1 encoding of the X.509 SubjectPublicKeyInfo sequence.

gnutls_pubkey_import_x509,gnutls_pubkey_import_openpgp,gnutls_pubkey_import_pkcs11

gnutls_pubkey_import_url,gnutls_pubkey_import_privkey,gnutls_pubkey_import,gnutls_pubkey_export

gnutls_pubkey_export2

Other helper functions that allow directly importing from raw X.509 or OpenPGP structures are shown below.

gnutls_pubkey_import_x509_raw,gnutls_pubkey_import_openpgp_raw

An important function is gnutls_pubkey_import_url which will import public keys from URLs that identify objects stored in tokens (see Smart cards and HSMs and Trusted Platform Module). A function to check for a supported by GnuTLS URL is gnutls_url_is_supported.

gnutls_url_is_supported

Additional functions are available that will return information over a public key, such as a unique key ID, as well as a function that given a public key fingerprint would provide a memorable sketch.

Note that gnutls_pubkey_get_key_id calculates a SHA1 digest of the public key as a DER-formatted, subjectPublicKeyInfo object.  Other implementations use different approaches, e.g., some use the ``common method'' described in section 4.2.1.2 of RFC5280 which calculates a digest on a part of the subjectPublicKeyInfo object.

gnutls_pubkey_get_pk_algorithm,gnutls_pubkey_get_preferred_hash_algorithm,gnutls_pubkey_get_key_id,gnutls_random_art

To export the key-specific parameters, or obtain a unique key ID the following functions are provided.

gnutls_pubkey_export_rsa_raw,gnutls_pubkey_export_dsa_raw,gnutls_pubkey_export_ecc_raw,gnutls_pubkey_export_ecc_x962

Private keys
------------

An abstract gnutls_privkey_t can be initialized using the functions below. It can be imported through an existing structure like gnutls_x509_privkey_t, but unlike public keys it cannot be exported. That is to allow abstraction over keys stored in hardware that makes available only operations.

gnutls_privkey_import_x509,gnutls_privkey_import_openpgp,gnutls_privkey_import_pkcs11

Other helper functions that allow directly importing from raw X.509 or OpenPGP structures are shown below. Again, as with public keys, private keys can be imported from a hardware module using URLs.

gnutls_privkey_import_x509_raw,gnutls_privkey_import_openpgp_raw

gnutls_privkey_import_url

gnutls_privkey_get_pk_algorithm,gnutls_privkey_get_type,gnutls_privkey_status

In order to support cryptographic operations using an external API, the following function is provided. This allows for a simple extensibility API without resorting to PKCS #11.

gnutls_privkey_import_ext2

Operations
----------

The abstract key types can be used to access signing and signature verification operations with the underlying keys.

gnutls_pubkey_verify_data2 gnutls_pubkey_verify_hash2 gnutls_pubkey_encrypt_data

gnutls_privkey_sign_data gnutls_privkey_sign_hash gnutls_privkey_decrypt_data

Signing existing structures, such as certificates, CRLs, or certificate requests, as well as associating public keys with structures is also possible using the key abstractions.

gnutls_x509_crq_set_pubkey gnutls_x509_crt_set_pubkey gnutls_x509_crt_privkey_sign,gnutls_x509_crl_privkey_sign,gnutls_x509_crq_privkey_sign

Smart cards and HSMs
====================

In this section we present the smart-card and hardware security module (HSM) support in GnuTLS using PKCS #11 PKCS11. Hardware security modules and smart cards provide a way to store private keys and perform operations on them without exposing them. This decouples cryptographic keys from the applications that use them and provide an additional security layer against cryptographic key extraction. Since this can also be achieved in software components such as in Gnome keyring, we will use the term security module to describe any cryptographic key separation subsystem.

PKCS #11 is plugin API allowing applications to access cryptographic operations on a security module, as well as to objects residing on it. PKCS #11 modules exist for hardware tokens such as smart cards (http://www.opensc-project.org), cryptographic tokens, as well as for software modules like Gnome Keyring. The objects residing on a security module may be certificates, public keys, private keys or secret keys. Of those certificates and public/private key pairs can be used with GnuTLS. PKCS #11's main advantage is that it allows operations on private key objects such as decryption and signing without exposing the key. In GnuTLS the PKCS #11 functionality is available in gnutls/pkcs11.h.

Moreover PKCS #11 can be (ab)used to allow all applications in the same operating system to access shared cryptographic keys and certificates in a uniform way, as in fig-pkcs11-vision. That way applications could load their trusted certificate list, as well as user certificates from a common PKCS #11 module. Such a provider is the p11-kit trust storage module (http://p11-glue.freedesktop.org/trust-module.html).

Figure: PKCS #11 module usage.

Initialization
--------------

To allow all GnuTLS applications to transparently access smard cards and tokens, PKCS #11 is automatically initialized during the global initialization (see gnutls_global_init). The initialization function, to select which modules to load reads certain module configuration files. Those are stored in /etc/pkcs11/modules/ and are the configuration files of p11-kit (http://p11-glue.freedesktop.org/). For example a file that will load the OpenSC module, could be named /etc/pkcs11/modules/opensc.module and contain the following:

     module: /usr/lib/opensc-pkcs11.so

If you use these configuration files, then there is no need for other initialization in GnuTLS, except for the PIN and token functions (see next section). In several cases, however, it is desirable to limit badly behaving modules (e.g., modules that add an unacceptable delay on initialization) to single applications. That can be done using the ``enable-in:'' option followed by the base name of applications that this module should be used.

In all cases, you can also manually initialize the PKCS #11 subsystem if the default settings are not desirable. To completely disable PKCS #11 support you need to call gnutls_pkcs11_init with the flag GNUTLS_PKCS11_FLAG_MANUAL prior to gnutls_global_init.

gnutls_pkcs11_init

Note that PKCS #11 modules must be reinitialized on the child processes after a fork. In older versions of GnuTLS it was required to call gnutls_pkcs11_reinit; since 3.3.0 this is no longer required, as reinitialization occurs automatically.

Accessing objects that require a PIN
------------------------------------

Objects stored in token such as a private keys are typically protected from access by a PIN or password. This PIN may be required to either read the object (if allowed) or to perform operations with it. To allow obtaining the PIN when accessing a protected object, as well as probe the user to insert the token the following functions allow to set a callback.

gnutls_pkcs11_set_token_function,gnutls_pkcs11_set_pin_function,gnutls_pkcs11_add_provider,gnutls_pkcs11_get_pin_function

The callback is of type gnutls_pin_callback_t and will have as input the provided userdata, the PIN attempt number, a URL describing the token, a label describing the object and flags. The PIN must be at most of pin_max size and must be copied to pin variable. The function must return 0 on success or a negative error code otherwise.

typedef int (*gnutls_pin_callback_t) (void *userdata, int attempt,
                                      const char *token_url,
                                      const char *token_label,
                                      unsigned int flags,
                                      char *pin, size_t pin_max);

The flags are of gnutls_pin_flag_t type and are explained below.

gnutls_pin_flag_t,The gnutls_pin_flag_t enumeration.

Note that due to limitations of PKCS #11 there are issues when multiple libraries are sharing a module. To avoid this problem GnuTLS uses p11-kit that provides a middleware to control access to resources over the multiple users.

To avoid conflicts with multiple registered callbacks for PIN functions, gnutls_pkcs11_get_pin_function may be used to check for any previously set functions. In addition context specific PIN functions are allowed, e.g., by using functions below.

gnutls_certificate_set_pin_function,gnutls_pubkey_set_pin_function,gnutls_privkey_set_pin_function,gnutls_pkcs11_obj_set_pin_function,gnutls_x509_crt_set_pin_function

Reading objects
---------------

All PKCS #11 objects are referenced by GnuTLS functions by URLs as described in PKCS11URI. This allows for a consistent naming of objects across systems and applications in the same system. For example a public key on a smart card may be referenced as:

     pkcs11:token=Nikos;serial=307521161601031;model=PKCS%2315; \
     manufacturer=EnterSafe;object=test1;objecttype=public;\
     id=32f153f3e37990b08624141077ca5dec2d15faed

while the smart card itself can be referenced as:

     pkcs11:token=Nikos;serial=307521161601031;model=PKCS%2315;manufacturer=EnterSafe

Objects stored in a PKCS #11 token can be extracted if they are not marked as sensitive. Usually only private keys are marked as sensitive and cannot be extracted, while certificates and other data can be retrieved. The functions that can be used to access objects are shown below.

gnutls_pkcs11_obj_import_url,gnutls_pkcs11_obj_export_url

gnutls_pkcs11_obj_get_info

gnutls_x509_crt_import_pkcs11,gnutls_x509_crt_import_pkcs11_url,gnutls_x509_crt_list_import_pkcs11

Properties of the physical token can also be accessed and altered with GnuTLS. For example data in a token can be erased (initialized), PIN can be altered, etc.

gnutls_pkcs11_token_init,gnutls_pkcs11_token_get_url,gnutls_pkcs11_token_get_info,gnutls_pkcs11_token_get_flags,gnutls_pkcs11_token_set_pin

The following examples demonstrate the usage of the API. The first example will list all available PKCS #11 tokens in a system and the latter will list all certificates in a token that have a corresponding private key.

     int i;
     char* url;

     gnutls_global_init();

     for (i=0;;i++)
       {
         ret = gnutls_pkcs11_token_get_url(i, &url);
         if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
           break;

         if (ret < 0)
           exit(1);

         fprintf(stdout, "Token[%d]: URL: %s\n", i, url);
         gnutls_free(url);
       }
     gnutls_global_deinit();

     [file ex-pkcs11-list.c not included]

Writing objects
---------------

With GnuTLS you can copy existing private keys and certificates to a token. Note that when copying private keys it is recommended to mark them as sensitive using the GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE to prevent its extraction. An object can be marked as private using the flag GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE, to require PIN to be entered before accessing the object (for operations or otherwise).

gnutls_pkcs11_copy_x509_privkey

gnutls_pkcs11_copy_x509_crt gnutls_pkcs11_delete_url

Using a PKCS #11 token with TLS
-------------------------------

It is possible to use a PKCS #11 token to a TLS session, as shown in ex-pkcs11-client. In addition the following functions can be used to load PKCS #11 key and certificates by specifying a PKCS #11 URL instead of a filename.

gnutls_certificate_set_x509_trust_file,gnutls_certificate_set_x509_key_file2 gnutls_certificate_set_x509_system_trust

     [file invoke-p11tool.texi not included]

Trusted Platform Module (TPM)
=============================

In this section we present the Trusted Platform Module (TPM) support in GnuTLS.

There was a big hype when the TPM chip was introduced into computers. Briefly it is a co-processor in your PC that allows it to perform calculations independently of the main processor. This has good and bad side-effects. In this section we focus on the good ones; these are the fact that you can use the TPM chip to perform cryptographic operations on keys stored in it, without accessing them. That is very similar to the operation of a PKCS #11 smart card. The chip allows for storage and usage of RSA keys, but has quite some operational differences from PKCS #11 module, and thus require different handling. The basic TPM operations supported and used by GnuTLS, are key generation and signing.

The next sections assume that the TPM chip in the system is already initialized and in a operational state.

In GnuTLS the TPM functionality is available in gnutls/tpm.h.

Keys in TPM
-----------

The RSA keys in the TPM module may either be stored in a flash memory within TPM or stored in a file in disk. In the former case the key can provide operations as with PKCS #11 and is identified by a URL. The URL is described in TPMURI and is of the following form.
tpmkey:uuid=42309df8-d101-11e1-a89a-97bb33c23ad1;storage=user

It consists from a unique identifier of the key as well as the part of the flash memory the key is stored at. The two options for the storage field are `user' and `system'. The user keys are typically only available to the generating user and the system keys to all users. The stored in TPM keys are called registered keys.

The keys that are stored in the disk are exported from the TPM but in an encrypted form. To access them two passwords are required. The first is the TPM Storage Root Key (SRK), and the other is a key-specific password. Also those keys are identified by a URL of the form:
tpmkey:file=/path/to/file

When objects require a PIN to be accessed the same callbacks as with PKCS #11 objects are expected (see Accessing objects that require a PIN). Note that the PIN function may be called multiple times to unlock the SRK and the specific key in use. The label in the key function will then be set to `SRK' when unlocking the SRK key, or to `TPM' when unlocking any other key.

Key generation
--------------

All keys used by the TPM must be generated by the TPM. This can be done using gnutls_tpm_privkey_generate.

gnutls_tpm_privkey_generate

gnutls_tpm_get_registered,gnutls_tpm_key_list_deinit,gnutls_tpm_key_list_get_url

gnutls_tpm_privkey_delete

Using keys
----------

Importing keys
..............

The TPM keys can be used directly by the abstract key types and do not require any special structures. Moreover functions like gnutls_certificate_set_x509_key_file2 can access TPM URLs.

gnutls_privkey_import_tpm_raw,gnutls_pubkey_import_tpm_raw

gnutls_privkey_import_tpm_url gnutls_pubkey_import_tpm_url

Listing and deleting keys
.........................

The registered keys (that are stored in the TPM) can be listed using one of the following functions. Those keys are unfortunately only identified by their UUID and have no label or other human friendly identifier. Keys can be deleted from permament storage using gnutls_tpm_privkey_delete.

gnutls_tpm_get_registered,gnutls_tpm_key_list_deinit,gnutls_tpm_key_list_get_url

gnutls_tpm_privkey_delete

     [file invoke-tpmtool.texi not included]