|
Packit |
aea12f |
@node Hardware security modules and abstract key types
|
|
Packit |
aea12f |
@chapter Abstract key types and Hardware security modules
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
In several cases storing the long term cryptographic keys in a hard disk or
|
|
Packit |
aea12f |
even in memory poses a significant risk. Once the system they are stored
|
|
Packit |
aea12f |
is compromised the keys must be replaced as the secrecy of future sessions
|
|
Packit |
aea12f |
is no longer guaranteed. Moreover, past sessions that were not protected by a
|
|
Packit |
aea12f |
perfect forward secrecy offering ciphersuite are also to be assumed compromised.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
If such threats need to be addressed, then it may be wise storing the keys in a security
|
|
Packit |
aea12f |
module such as a smart card, an HSM or the TPM chip. Those modules ensure the
|
|
Packit |
aea12f |
protection of the cryptographic keys by only allowing operations on them and
|
|
Packit |
aea12f |
preventing their extraction. The purpose of the abstract key API is to provide
|
|
Packit |
aea12f |
an API that will allow the handle of keys in memory and files, as well as keys
|
|
Packit |
aea12f |
stored in such modules.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
In GnuTLS the approach is to handle all keys transparently by the high level API, e.g.,
|
|
Packit |
aea12f |
the API that loads a key or certificate from a file.
|
|
Packit |
aea12f |
The high-level API will accept URIs in addition to files that specify keys on an HSM or in TPM,
|
|
Packit |
aea12f |
and a callback function will be used to obtain any required keys. The URI format is defined in
|
|
Packit |
aea12f |
@xcite{PKCS11URI}.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
More information on the API is provided in the next sections. Examples of a URI of a certificate
|
|
Packit |
aea12f |
stored in an HSM, as well as a key stored in the TPM chip are shown below. To discover the URIs
|
|
Packit |
aea12f |
of the objects the @code{p11tool} (see @ref{p11tool Invocation}).
|
|
Packit |
aea12f |
@example
|
|
Packit |
aea12f |
pkcs11:token=Nikos;serial=307521161601031;model=PKCS%2315; \
|
|
Packit |
aea12f |
manufacturer=EnterSafe;object=test1;type=cert
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@end example
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@menu
|
|
Packit |
aea12f |
* Abstract key types::
|
|
Packit |
aea12f |
* Application-specific keys::
|
|
Packit |
aea12f |
* Smart cards and HSMs::
|
|
Packit |
aea12f |
* Trusted Platform Module::
|
|
Packit |
aea12f |
@end menu
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node Abstract key types
|
|
Packit |
aea12f |
@section Abstract key types
|
|
Packit |
aea12f |
@cindex abstract types
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
Since there are many forms of a public or private keys supported by @acronym{GnuTLS} such as
|
|
Packit |
aea12f |
@acronym{X.509}, @acronym{PKCS} #11 or TPM it is desirable to allow common operations
|
|
Packit |
aea12f |
on them. For these reasons the abstract @code{gnutls_privkey_t} and @code{gnutls_pubkey_t} were
|
|
Packit |
aea12f |
introduced in @code{gnutls/@-abstract.h} header. Those types are initialized using a specific type of
|
|
Packit |
aea12f |
key and then can be used to perform operations in an abstract way. For example in order
|
|
Packit |
aea12f |
to sign an X.509 certificate with a key that resides in a token the following steps can be
|
|
Packit |
aea12f |
used.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@example
|
|
Packit |
aea12f |
#include <gnutls/abstract.h>
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
void sign_cert( gnutls_x509_crt_t to_be_signed)
|
|
Packit |
aea12f |
@{
|
|
Packit |
aea12f |
gnutls_x509_crt_t ca_cert;
|
|
Packit |
aea12f |
gnutls_privkey_t abs_key;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* initialize the abstract key */
|
|
Packit |
aea12f |
gnutls_privkey_init(&abs_key);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* keys stored in tokens are identified by URLs */
|
|
Packit |
aea12f |
gnutls_privkey_import_url(abs_key, key_url);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
gnutls_x509_crt_init(&ca_cert);
|
|
Packit |
aea12f |
gnutls_x509_crt_import_url(&ca_cert, cert_url);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* sign the certificate to be signed */
|
|
Packit |
aea12f |
gnutls_x509_crt_privkey_sign(to_be_signed, ca_cert, abs_key,
|
|
Packit |
aea12f |
GNUTLS_DIG_SHA256, 0);
|
|
Packit |
aea12f |
@}
|
|
Packit |
aea12f |
@end example
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@menu
|
|
Packit |
aea12f |
* Abstract public keys::
|
|
Packit |
aea12f |
* Abstract private keys::
|
|
Packit |
aea12f |
* Operations::
|
|
Packit |
aea12f |
@end menu
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node Abstract public keys
|
|
Packit |
aea12f |
@subsection Public keys
|
|
Packit |
aea12f |
An abstract @code{gnutls_pubkey_t} can be initialized and freed by
|
|
Packit |
aea12f |
using the functions below.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncB{gnutls_pubkey_init,gnutls_pubkey_deinit}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
After initialization its values can be imported from
|
|
Packit |
aea12f |
an existing structure like @code{gnutls_x509_crt_t},
|
|
Packit |
aea12f |
or through an ASN.1 encoding of the X.509 @code{SubjectPublicKeyInfo}
|
|
Packit |
aea12f |
sequence.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncB{gnutls_pubkey_import_x509,gnutls_pubkey_import_pkcs11}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncD{gnutls_pubkey_import_url,gnutls_pubkey_import_privkey,gnutls_pubkey_import,gnutls_pubkey_export}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_pubkey_export2}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
Other helper functions that allow directly importing from raw X.509 structures are shown below.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncA{gnutls_pubkey_import_x509_raw}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
An important function is @funcref{gnutls_pubkey_import_url} which will import
|
|
Packit |
aea12f |
public keys from URLs that identify objects stored in tokens (see @ref{Smart cards and HSMs} and @ref{Trusted Platform Module}).
|
|
Packit |
aea12f |
A function to check for a supported by GnuTLS URL is @funcref{gnutls_url_is_supported}.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_url_is_supported}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
Additional functions are available that will return
|
|
Packit |
aea12f |
information over a public key, such as a unique key ID, as well as a function
|
|
Packit |
aea12f |
that given a public key fingerprint would provide a memorable sketch.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
Note that @funcref{gnutls_pubkey_get_key_id} calculates a SHA1 digest of the
|
|
Packit |
aea12f |
public key as a DER-formatted, subjectPublicKeyInfo object. Other implementations
|
|
Packit |
aea12f |
use different approaches, e.g., some use the ``common method'' described in
|
|
Packit |
aea12f |
section 4.2.1.2 of @xcite{RFC5280} which calculates a digest on a part of the
|
|
Packit |
aea12f |
subjectPublicKeyInfo object.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncD{gnutls_pubkey_get_pk_algorithm,gnutls_pubkey_get_preferred_hash_algorithm,gnutls_pubkey_get_key_id,gnutls_random_art}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
To export the key-specific parameters, or obtain a unique key ID the following functions are provided.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncD{gnutls_pubkey_export_rsa_raw2,gnutls_pubkey_export_dsa_raw2,gnutls_pubkey_export_ecc_raw2,gnutls_pubkey_export_ecc_x962}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node Abstract private keys
|
|
Packit |
aea12f |
@subsection Private keys
|
|
Packit |
aea12f |
An abstract @code{gnutls_privkey_t} can be initialized and freed by
|
|
Packit |
aea12f |
using the functions below.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncB{gnutls_privkey_init,gnutls_privkey_deinit}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
After initialization its values can be imported from
|
|
Packit |
aea12f |
an existing structure like @code{gnutls_x509_privkey_t},
|
|
Packit |
aea12f |
but unlike public keys it cannot be exported. That is
|
|
Packit |
aea12f |
to allow abstraction over keys stored in hardware that
|
|
Packit |
aea12f |
makes available only operations.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncB{gnutls_privkey_import_x509,gnutls_privkey_import_pkcs11}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
Other helper functions that allow directly importing from raw X.509
|
|
Packit |
aea12f |
structures are shown below. Again, as with public keys, private keys
|
|
Packit |
aea12f |
can be imported from a hardware module using URLs.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_privkey_import_url}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncD{gnutls_privkey_import_x509_raw,gnutls_privkey_get_pk_algorithm,gnutls_privkey_get_type,gnutls_privkey_status}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
In order to support cryptographic operations using
|
|
Packit |
aea12f |
an external API, the following function is provided.
|
|
Packit |
aea12f |
This allows for a simple extensibility API without
|
|
Packit |
aea12f |
resorting to @acronym{PKCS} #11.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_privkey_import_ext4}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
On the private keys where exporting of parameters is possible (i.e.,
|
|
Packit |
aea12f |
software keys), the following functions are also available.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncC{gnutls_privkey_export_rsa_raw2,gnutls_privkey_export_dsa_raw2,gnutls_privkey_export_ecc_raw2}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node Operations
|
|
Packit |
aea12f |
@subsection Operations
|
|
Packit |
aea12f |
The abstract key types can be used to access signing and
|
|
Packit |
aea12f |
signature verification operations with the underlying keys.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_pubkey_verify_data2}
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_pubkey_verify_hash2}
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_pubkey_encrypt_data}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_privkey_sign_data}
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_privkey_sign_hash}
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_privkey_decrypt_data}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
Signing existing structures, such as certificates, CRLs,
|
|
Packit |
aea12f |
or certificate requests, as well as associating public
|
|
Packit |
aea12f |
keys with structures is also possible using the
|
|
Packit |
aea12f |
key abstractions.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_x509_crq_set_pubkey}
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_x509_crt_set_pubkey}
|
|
Packit |
aea12f |
@showfuncC{gnutls_x509_crt_privkey_sign,gnutls_x509_crl_privkey_sign,gnutls_x509_crq_privkey_sign}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node Application-specific keys
|
|
Packit |
aea12f |
@section System and application-specific keys
|
|
Packit |
aea12f |
@cindex Application-specific keys
|
|
Packit |
aea12f |
@cindex System-specific keys
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@subsection System-specific keys
|
|
Packit |
aea12f |
In several systems there are keystores which allow to read, store and use certificates
|
|
Packit |
aea12f |
and private keys. For these systems GnuTLS provides the system-key API in @code{gnutls/system-keys.h}.
|
|
Packit |
aea12f |
That API provides the ability to iterate through all stored keys, add and delete keys as well
|
|
Packit |
aea12f |
as use these keys using a URL which starts with "system:". The format of the URLs is system-specific.
|
|
Packit |
aea12f |
The @code{systemkey} tool is also provided to assist in listing keys and debugging.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
The systems supported via this API are the following.
|
|
Packit |
aea12f |
@itemize
|
|
Packit |
aea12f |
@item Windows Cryptography API (CNG)
|
|
Packit |
aea12f |
@end itemize
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_system_key_iter_get_info}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncC{gnutls_system_key_iter_deinit,gnutls_system_key_add_x509,gnutls_system_key_delete}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@subsection Application-specific keys
|
|
Packit |
aea12f |
For systems where GnuTLS doesn't provide a system specific store,
|
|
Packit |
aea12f |
it may often be desirable to define a custom class of keys
|
|
Packit |
aea12f |
that are identified via URLs and available to GnuTLS calls such as @funcref{gnutls_certificate_set_x509_key_file2}.
|
|
Packit |
aea12f |
Such keys can be registered using the API in @code{gnutls/urls.h}. The function
|
|
Packit |
aea12f |
which registers such keys is @funcref{gnutls_register_custom_url}.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_register_custom_url}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
The input to this function are three callback functions as well as
|
|
Packit |
aea12f |
the prefix of the URL, (e.g., "mypkcs11:") and the length of the prefix.
|
|
Packit |
aea12f |
The types of the callbacks are shown below, and are expected to
|
|
Packit |
aea12f |
use the exported gnutls functions to import the keys and certificates.
|
|
Packit |
aea12f |
E.g., a typical @code{import_key} callback should use @funcref{gnutls_privkey_import_ext4}.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@example
|
|
Packit |
aea12f |
typedef int (*gnutls_privkey_import_url_func)(gnutls_privkey_t pkey,
|
|
Packit |
aea12f |
const char *url,
|
|
Packit |
aea12f |
unsigned flags);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
typedef int (*gnutls_x509_crt_import_url_func)(gnutls_x509_crt_t pkey,
|
|
Packit |
aea12f |
const char *url,
|
|
Packit |
aea12f |
unsigned flags);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* The following callbacks are optional */
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* This is to enable gnutls_pubkey_import_url() */
|
|
Packit |
aea12f |
typedef int (*gnutls_pubkey_import_url_func)(gnutls_pubkey_t pkey,
|
|
Packit |
aea12f |
const char *url, unsigned flags);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
/* This is to allow constructing a certificate chain. It will be provided
|
|
Packit |
aea12f |
* the initial certificate URL and the certificate to find its issuer, and must
|
|
Packit |
aea12f |
* return zero and the DER encoding of the issuer's certificate. If not available,
|
|
Packit |
aea12f |
* it should return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE. */
|
|
Packit |
aea12f |
typedef int (*gnutls_get_raw_issuer_func)(const char *url, gnutls_x509_crt_t crt,
|
|
Packit |
aea12f |
gnutls_datum_t *issuer_der, unsigned flags);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
typedef struct custom_url_st @{
|
|
Packit |
aea12f |
const char *name;
|
|
Packit |
aea12f |
unsigned name_size;
|
|
Packit |
aea12f |
gnutls_privkey_import_url_func import_key;
|
|
Packit |
aea12f |
gnutls_x509_crt_import_url_func import_crt;
|
|
Packit |
aea12f |
gnutls_pubkey_import_url_func import_pubkey;
|
|
Packit |
aea12f |
gnutls_get_raw_issuer_func get_issuer;
|
|
Packit |
aea12f |
@} gnutls_custom_url_st;
|
|
Packit |
aea12f |
@end example
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node Smart cards and HSMs
|
|
Packit |
aea12f |
@section Smart cards and HSMs
|
|
Packit |
aea12f |
@cindex PKCS #11 tokens
|
|
Packit |
aea12f |
@cindex hardware tokens
|
|
Packit |
aea12f |
@cindex hardware security modules
|
|
Packit |
aea12f |
@cindex smart cards
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
In this section we present the smart-card and hardware security module (HSM) support
|
|
Packit |
aea12f |
in @acronym{GnuTLS} using @acronym{PKCS} #11 @xcite{PKCS11}. Hardware security
|
|
Packit |
aea12f |
modules and smart cards provide a way to store private keys and perform
|
|
Packit |
aea12f |
operations on them without exposing them. This decouples cryptographic
|
|
Packit |
aea12f |
keys from the applications that use them and provide an additional
|
|
Packit |
aea12f |
security layer against cryptographic key extraction.
|
|
Packit |
aea12f |
Since this can also be achieved in software components such as in Gnome keyring,
|
|
Packit |
aea12f |
we will use the term security module to describe any cryptographic key
|
|
Packit |
aea12f |
separation subsystem.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@acronym{PKCS} #11 is plugin API allowing applications to access cryptographic
|
|
Packit |
aea12f |
operations on a security module, as well as to objects residing on it. PKCS
|
|
Packit |
aea12f |
#11 modules exist for hardware tokens such as smart cards@footnote{For example, OpenSC-supported cards.},
|
|
Packit |
aea12f |
cryptographic tokens, as well as for software modules like @acronym{Gnome Keyring}.
|
|
Packit |
aea12f |
The objects residing on a security module may be certificates, public keys,
|
|
Packit |
aea12f |
private keys or secret keys. Of those certificates and public/private key
|
|
Packit |
aea12f |
pairs can be used with @acronym{GnuTLS}. PKCS #11's main advantage is that
|
|
Packit |
aea12f |
it allows operations on private key objects such as decryption
|
|
Packit |
aea12f |
and signing without exposing the key. In GnuTLS the PKCS #11 functionality is
|
|
Packit |
aea12f |
available in @code{gnutls/pkcs11.h}.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@float Figure,fig-pkcs11-vision
|
|
Packit |
aea12f |
@image{pkcs11-vision,9cm}
|
|
Packit |
aea12f |
@caption{PKCS #11 module usage.}
|
|
Packit |
aea12f |
@end float
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@menu
|
|
Packit |
aea12f |
* PKCS11 Initialization::
|
|
Packit |
aea12f |
* PKCS11 Manual Initialization::
|
|
Packit |
aea12f |
* Accessing objects that require a PIN::
|
|
Packit |
aea12f |
* Reading objects::
|
|
Packit |
aea12f |
* Writing objects::
|
|
Packit |
aea12f |
* PKCS11 Low Level Access::
|
|
Packit |
aea12f |
* Using a PKCS11 token with TLS::
|
|
Packit |
aea12f |
* Verifying certificates over PKCS11::
|
|
Packit |
aea12f |
* p11tool Invocation::
|
|
Packit |
aea12f |
@end menu
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node PKCS11 Initialization
|
|
Packit |
aea12f |
@subsection Initialization
|
|
Packit |
aea12f |
To allow all @acronym{GnuTLS} applications to transparently access smart cards
|
|
Packit |
aea12f |
and tokens, @acronym{PKCS} #11 is automatically initialized during the first
|
|
Packit |
aea12f |
call of a @acronym{PKCS} #11 related function, in a thread safe way.
|
|
Packit |
aea12f |
The default initialization process, utilizes p11-kit configuration, and loads any
|
|
Packit |
aea12f |
appropriate @acronym{PKCS} #11 modules. The p11-kit configuration
|
|
Packit Service |
991b93 |
files@footnote{@url{https://p11-glue.github.io/p11-glue/p11-kit.html}} are typically stored in @code{/etc/pkcs11/modules/}.
|
|
Packit |
aea12f |
For example a file that will instruct GnuTLS to load the @acronym{OpenSC} module,
|
|
Packit |
aea12f |
could be named @code{/etc/pkcs11/modules/opensc.module} and contain the following:
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@example
|
|
Packit |
aea12f |
module: /usr/lib/opensc-pkcs11.so
|
|
Packit |
aea12f |
@end example
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
If you use these configuration files, then there is no need for other initialization in
|
|
Packit |
aea12f |
@acronym{GnuTLS}, except for the PIN and token callbacks (see next section).
|
|
Packit |
aea12f |
In several cases, however, it is desirable to limit badly behaving modules
|
|
Packit |
aea12f |
(e.g., modules that add an unacceptable delay on initialization)
|
|
Packit |
aea12f |
to single applications. That can be done using the ``enable-in:'' option
|
|
Packit |
aea12f |
followed by the base name of applications that this module should be used.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
It is also possible to manually initialize or even disable the PKCS #11 subsystem if the
|
|
Packit |
aea12f |
default settings are not desirable or not available (see @ref{PKCS11 Manual Initialization}
|
|
Packit |
aea12f |
for more information).
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
Note that, PKCS #11 modules behave in a peculiar way after a fork; they
|
|
Packit |
aea12f |
require a reinitialization of all the used PKCS #11 resources.
|
|
Packit |
aea12f |
While GnuTLS automates that process, there are corner cases where
|
|
Packit |
aea12f |
it is not possible to handle it correctly in an automated way@footnote{For
|
|
Packit |
aea12f |
example when an open session is to be reinitialized, but the PIN is not available
|
|
Packit |
aea12f |
to GnuTLS (e.g., it was entered at a pinpad).}. For that, it is
|
|
Packit |
aea12f |
recommended not to mix fork() and PKCS #11 module usage. It is recommended
|
|
Packit |
aea12f |
to initialize and use any PKCS #11 resources in a single process.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
Older versions of @acronym{GnuTLS} required to call @funcref{gnutls_pkcs11_reinit}
|
|
Packit |
aea12f |
after a fork() call; since 3.3.0 this is no longer required.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node PKCS11 Manual Initialization
|
|
Packit |
aea12f |
@subsection Manual initialization of user-specific modules
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
In systems where one cannot rely on a globally available p11-kit configuration
|
|
Packit |
aea12f |
to be available, it is still possible to utilize PKCS #11 objects. That
|
|
Packit |
aea12f |
can be done by loading directly the PKCS #11 shared module in the
|
|
Packit |
aea12f |
application using @funcref{gnutls_pkcs11_add_provider}, after having
|
|
Packit |
aea12f |
called @funcref{gnutls_pkcs11_init} specifying the @code{GNUTLS_PKCS11_FLAG_MANUAL}
|
|
Packit |
aea12f |
flag.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_pkcs11_add_provider}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
In that case, the application will only have access to the modules explicitly
|
|
Packit |
aea12f |
loaded. If the @code{GNUTLS_PKCS11_FLAG_MANUAL} flag is specified and no calls
|
|
Packit |
aea12f |
to @funcref{gnutls_pkcs11_add_provider} are made, then the PKCS #11 functionality
|
|
Packit |
aea12f |
is effectively disabled.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_pkcs11_init}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node Accessing objects that require a PIN
|
|
Packit |
aea12f |
@subsection Accessing objects that require a PIN
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
Objects stored in token such as a private keys are typically protected
|
|
Packit |
aea12f |
from access by a PIN or password. This PIN may be required to either read
|
|
Packit |
aea12f |
the object (if allowed) or to perform operations with it. To allow obtaining
|
|
Packit |
aea12f |
the PIN when accessing a protected object, as well as probe
|
|
Packit |
aea12f |
the user to insert the token the following functions allow to set a callback.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncD{gnutls_pkcs11_set_token_function,gnutls_pkcs11_set_pin_function,gnutls_pkcs11_add_provider,gnutls_pkcs11_get_pin_function}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
The callback is of type @funcintref{gnutls_pin_callback_t} and will have as
|
|
Packit |
aea12f |
input the provided userdata, the PIN attempt number, a URL describing the
|
|
Packit |
aea12f |
token, a label describing the object and flags. The PIN must be at most
|
|
Packit |
aea12f |
of @code{pin_max} size and must be copied to pin variable. The function must
|
|
Packit |
aea12f |
return 0 on success or a negative error code otherwise.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@verbatim
|
|
Packit |
aea12f |
typedef int (*gnutls_pin_callback_t) (void *userdata, int attempt,
|
|
Packit |
aea12f |
const char *token_url,
|
|
Packit |
aea12f |
const char *token_label,
|
|
Packit |
aea12f |
unsigned int flags,
|
|
Packit |
aea12f |
char *pin, size_t pin_max);
|
|
Packit |
aea12f |
@end verbatim
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
The flags are of @code{gnutls_pin_flag_t} type and are explained below.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showenumdesc{gnutls_pin_flag_t,The @code{gnutls_pin_@-flag_t} enumeration.}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
Note that due to limitations of @acronym{PKCS} #11 there are issues when multiple libraries
|
|
Packit |
aea12f |
are sharing a module. To avoid this problem GnuTLS uses @acronym{p11-kit}
|
|
Packit |
aea12f |
that provides a middleware to control access to resources over the
|
|
Packit |
aea12f |
multiple users.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
To avoid conflicts with multiple registered callbacks for PIN functions,
|
|
Packit |
aea12f |
@funcref{gnutls_pkcs11_get_pin_function} may be used to check for any previously
|
|
Packit |
aea12f |
set functions. In addition context specific PIN functions are allowed, e.g., by
|
|
Packit |
aea12f |
using functions below.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncE{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}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node Reading objects
|
|
Packit |
aea12f |
@subsection Reading objects
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
All @acronym{PKCS} #11 objects are referenced by @acronym{GnuTLS} functions by
|
|
Packit |
aea12f |
URLs as described in @xcite{PKCS11URI}.
|
|
Packit |
aea12f |
This allows for a consistent naming of objects across systems and applications
|
|
Packit |
aea12f |
in the same system. For example a public
|
|
Packit |
aea12f |
key on a smart card may be referenced as:
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@example
|
|
Packit |
aea12f |
pkcs11:token=Nikos;serial=307521161601031;model=PKCS%2315; \
|
|
Packit |
aea12f |
manufacturer=EnterSafe;object=test1;type=public;\
|
|
Packit |
aea12f |
id=32f153f3e37990b08624141077ca5dec2d15faed
|
|
Packit |
aea12f |
@end example
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
while the smart card itself can be referenced as:
|
|
Packit |
aea12f |
@example
|
|
Packit |
aea12f |
pkcs11:token=Nikos;serial=307521161601031;model=PKCS%2315;manufacturer=EnterSafe
|
|
Packit |
aea12f |
@end example
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
Objects stored in a @acronym{PKCS} #11 token can typically be extracted
|
|
Packit |
aea12f |
if they are not marked as sensitive. Usually only private keys are marked as
|
|
Packit |
aea12f |
sensitive and cannot be extracted, while certificates and other data can
|
|
Packit |
aea12f |
be retrieved. The functions that can be used to enumerate and access objects
|
|
Packit |
aea12f |
are shown below.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncC{gnutls_pkcs11_obj_list_import_url4,gnutls_pkcs11_obj_import_url,gnutls_pkcs11_obj_export_url}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_pkcs11_obj_get_info}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncC{gnutls_x509_crt_import_pkcs11,gnutls_x509_crt_import_url,gnutls_x509_crt_list_import_pkcs11}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
Properties of the physical token can also be accessed and altered with @acronym{GnuTLS}.
|
|
Packit |
aea12f |
For example data in a token can be erased (initialized), PIN can be altered, etc.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncE{gnutls_pkcs11_token_init,gnutls_pkcs11_token_get_url,gnutls_pkcs11_token_get_info,gnutls_pkcs11_token_get_flags,gnutls_pkcs11_token_set_pin}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
The following examples demonstrate the usage of the API. The first example
|
|
Packit |
aea12f |
will list all available PKCS #11 tokens in a system and the latter will
|
|
Packit |
aea12f |
list all certificates in a token that have a corresponding private key.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@example
|
|
Packit |
aea12f |
int i;
|
|
Packit |
aea12f |
char* url;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
gnutls_global_init();
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
for (i=0;;i++)
|
|
Packit |
aea12f |
@{
|
|
Packit |
aea12f |
ret = gnutls_pkcs11_token_get_url(i, &url;;
|
|
Packit |
aea12f |
if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
|
|
Packit |
aea12f |
break;
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
if (ret < 0)
|
|
Packit |
aea12f |
exit(1);
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
fprintf(stdout, "Token[%d]: URL: %s\n", i, url);
|
|
Packit |
aea12f |
gnutls_free(url);
|
|
Packit |
aea12f |
@}
|
|
Packit |
aea12f |
gnutls_global_deinit();
|
|
Packit |
aea12f |
@end example
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@verbatiminclude examples/ex-pkcs11-list.c
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node Writing objects
|
|
Packit |
aea12f |
@subsection Writing objects
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
With @acronym{GnuTLS} you can copy existing private keys and certificates
|
|
Packit |
aea12f |
to a token. Note that when copying private keys it is recommended to mark
|
|
Packit |
aea12f |
them as sensitive using the @code{GNUTLS_@-PKCS11_OBJ_@-FLAG_@-MARK_@-SENSITIVE}
|
|
Packit |
aea12f |
to prevent its extraction. An object can be marked as private using the flag
|
|
Packit |
aea12f |
@code{GNUTLS_@-PKCS11_OBJ_@-FLAG_@-MARK_@-PRIVATE}, to require PIN to be
|
|
Packit |
aea12f |
entered before accessing the object (for operations or otherwise).
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_pkcs11_copy_x509_privkey2}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_pkcs11_copy_x509_crt2}
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_pkcs11_delete_url}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node PKCS11 Low Level Access
|
|
Packit |
aea12f |
@subsection Low Level Access
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
When it is needed to use PKCS#11 functionality which is not wrapped by
|
|
Packit |
aea12f |
GnuTLS, it is possible to extract the PKCS#11 session, object or token pointers.
|
|
Packit |
aea12f |
That allows an application to still access the low-level functionality,
|
|
Packit |
aea12f |
while at the same time take advantage of the URI addressing scheme supported
|
|
Packit |
aea12f |
by GnuTLS.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_pkcs11_token_get_ptr}
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_pkcs11_obj_get_ptr}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node Using a PKCS11 token with TLS
|
|
Packit |
aea12f |
@subsection Using a @acronym{PKCS} #11 token with TLS
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
It is possible to use a @acronym{PKCS} #11 token to a TLS
|
|
Packit |
aea12f |
session, as shown in @ref{ex-pkcs11-client}. In addition
|
|
Packit |
aea12f |
the following functions can be used to load PKCS #11 key and
|
|
Packit |
aea12f |
certificates by specifying a PKCS #11 URL instead of a filename.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncB{gnutls_certificate_set_x509_trust_file,gnutls_certificate_set_x509_key_file2}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node Verifying certificates over PKCS11
|
|
Packit |
aea12f |
@subsection Verifying certificates over @acronym{PKCS} #11
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
The @acronym{PKCS} #11 API can be used to allow all applications in the
|
|
Packit |
aea12f |
same operating system to access shared cryptographic keys and certificates in a
|
|
Packit |
aea12f |
uniform way, as in @ref{fig-pkcs11-vision}. That way applications could load their
|
|
Packit |
aea12f |
trusted certificate list, as well as user certificates from a common PKCS #11 module.
|
|
Packit Service |
991b93 |
Such a provider is the p11-kit trust storage module@footnote{@url{https://p11-glue.github.io/p11-glue/trust-module.html}}
|
|
Packit |
aea12f |
and it provides access to the trusted Root CA certificates in a system. That
|
|
Packit |
aea12f |
provides a more dynamic list of Root CA certificates, as opposed to a static
|
|
Packit |
aea12f |
list in a file or directory.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
That store, allows for blacklisting of CAs or certificates, as well as
|
|
Packit |
aea12f |
categorization of the Root CAs (Web verification, Code signing, etc.), in
|
|
Packit |
aea12f |
addition to restricting their purpose via stapled extensions@footnote{See
|
|
Packit |
aea12f |
the 'Restricting the scope of CA certificates' post at @url{https://nmav.gnutls.org/2016/06/restricting-scope-of-ca-certificates.html}}.
|
|
Packit |
aea12f |
GnuTLS will utilize the p11-kit trust module as the default trust store
|
|
Packit |
aea12f |
if configured to; i.e., if '--with-default-trust-store-pkcs11=pkcs11:' is given to
|
|
Packit |
aea12f |
the configure script.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@include invoke-p11tool.texi
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node Trusted Platform Module
|
|
Packit |
aea12f |
@section Trusted Platform Module (TPM)
|
|
Packit |
aea12f |
@cindex trusted platform module
|
|
Packit |
aea12f |
@cindex TPM
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
In this section we present the Trusted Platform Module (TPM) support
|
|
Packit |
aea12f |
in @acronym{GnuTLS}. Note that we recommend against using TPM with this
|
|
Packit |
aea12f |
API because it is restricted to TPM 1.2. We recommend instead
|
|
Packit |
aea12f |
to use PKCS#11 wrappers for TPM such as CHAPS@footnote{@url{https://github.com/google/chaps-linux}} or opencryptoki@footnote{@url{https://sourceforge.net/projects/opencryptoki/}}.
|
|
Packit |
aea12f |
These will allow using the standard smart card and HSM functionality (see @ref{Smart cards and HSMs}) for TPM keys.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
There was a big hype when the TPM chip was introduced into
|
|
Packit |
aea12f |
computers. Briefly it is a co-processor in your PC that allows it to perform
|
|
Packit |
aea12f |
calculations independently of the main processor. This has good and bad
|
|
Packit |
aea12f |
side-effects. In this section we focus on the good ones; these are the fact that
|
|
Packit |
aea12f |
you can use the TPM chip to perform cryptographic operations on keys stored in it, without
|
|
Packit |
aea12f |
accessing them. That is very similar to the operation of a @acronym{PKCS} #11 smart card.
|
|
Packit |
aea12f |
The chip allows for storage and usage of RSA keys, but has quite some
|
|
Packit |
aea12f |
operational differences from @acronym{PKCS} #11 module, and thus require different handling.
|
|
Packit |
aea12f |
The basic TPM operations supported and used by GnuTLS, are key generation and signing.
|
|
Packit |
aea12f |
That support is currently limited to TPM 1.2.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
The next sections assume that the TPM chip in the system is already initialized and
|
|
Packit |
aea12f |
in a operational state. If not, ensure that the TPM chip is enabled by your BIOS,
|
|
Packit |
aea12f |
that the @code{tcsd} daemon is running, and that TPM ownership is set
|
|
Packit |
aea12f |
(by running @code{tpm_takeownership}).
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
In GnuTLS the TPM functionality is available in @code{gnutls/tpm.h}.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@menu
|
|
Packit |
aea12f |
* Keys in TPM::
|
|
Packit |
aea12f |
* Key generation::
|
|
Packit |
aea12f |
* Using keys::
|
|
Packit |
aea12f |
* tpmtool Invocation::
|
|
Packit |
aea12f |
@end menu
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node Keys in TPM
|
|
Packit |
aea12f |
@subsection Keys in TPM
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
The RSA keys in the TPM module may either be stored in a flash memory
|
|
Packit |
aea12f |
within TPM or stored in a file in disk. In the former case the key can
|
|
Packit |
aea12f |
provide operations as with @acronym{PKCS} #11 and is identified by
|
|
Packit |
aea12f |
a URL. The URL is described in @xcite{TPMURI} and is of the following form.
|
|
Packit |
aea12f |
@verbatim
|
|
Packit |
aea12f |
tpmkey:uuid=42309df8-d101-11e1-a89a-97bb33c23ad1;storage=user
|
|
Packit |
aea12f |
@end verbatim
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
It consists from a unique identifier of the key as well as the part of the
|
|
Packit |
aea12f |
flash memory the key is stored at. The two options for the storage field are
|
|
Packit |
aea12f |
`user' and `system'. The user keys are typically only available to the generating
|
|
Packit |
aea12f |
user and the system keys to all users. The stored in TPM keys are called
|
|
Packit |
aea12f |
registered keys.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
The keys that are stored in the disk are exported from the TPM but in an
|
|
Packit |
aea12f |
encrypted form. To access them two passwords are required. The first is the TPM
|
|
Packit |
aea12f |
Storage Root Key (SRK), and the other is a key-specific password. Also those keys are
|
|
Packit |
aea12f |
identified by a URL of the form:
|
|
Packit |
aea12f |
@verbatim
|
|
Packit |
aea12f |
tpmkey:file=/path/to/file
|
|
Packit |
aea12f |
@end verbatim
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
When objects require a PIN to be accessed the same callbacks as with PKCS #11
|
|
Packit |
aea12f |
objects are expected (see @ref{Accessing objects that require a PIN}). Note
|
|
Packit |
aea12f |
that the PIN function may be called multiple times to unlock the SRK and
|
|
Packit |
aea12f |
the specific key in use. The label in the key function will then be set to
|
|
Packit |
aea12f |
`SRK' when unlocking the SRK key, or to `TPM' when unlocking any other key.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node Key generation
|
|
Packit |
aea12f |
@subsection Key generation
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
All keys used by the TPM must be generated by the TPM. This can be
|
|
Packit |
aea12f |
done using @funcref{gnutls_tpm_privkey_generate}.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_tpm_privkey_generate}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncC{gnutls_tpm_get_registered,gnutls_tpm_key_list_deinit,gnutls_tpm_key_list_get_url}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_tpm_privkey_delete}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@node Using keys
|
|
Packit |
aea12f |
@subsection Using keys
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@subsubheading Importing keys
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
The TPM keys can be used directly by the abstract key types and do not require
|
|
Packit |
aea12f |
any special structures. Moreover functions like @funcref{gnutls_certificate_set_x509_key_file2}
|
|
Packit |
aea12f |
can access TPM URLs.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncB{gnutls_privkey_import_tpm_raw,gnutls_pubkey_import_tpm_raw}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_privkey_import_tpm_url}
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_pubkey_import_tpm_url}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@subsubheading Listing and deleting keys
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
The registered keys (that are stored in the TPM) can be listed using one of
|
|
Packit |
aea12f |
the following functions. Those keys are unfortunately only identified by
|
|
Packit |
aea12f |
their UUID and have no label or other human friendly identifier.
|
|
Packit |
aea12f |
Keys can be deleted from permament storage using @funcref{gnutls_tpm_privkey_delete}.
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncC{gnutls_tpm_get_registered,gnutls_tpm_key_list_deinit,gnutls_tpm_key_list_get_url}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@showfuncdesc{gnutls_tpm_privkey_delete}
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
|
|
Packit |
aea12f |
@include invoke-tpmtool.texi
|
|
Packit |
aea12f |
|