summaryrefslogtreecommitdiff
path: root/doc/cha-cert-auth.texi
diff options
context:
space:
mode:
Diffstat (limited to 'doc/cha-cert-auth.texi')
-rw-r--r--doc/cha-cert-auth.texi626
1 files changed, 626 insertions, 0 deletions
diff --git a/doc/cha-cert-auth.texi b/doc/cha-cert-auth.texi
new file mode 100644
index 0000000000..7b76857eff
--- /dev/null
+++ b/doc/cha-cert-auth.texi
@@ -0,0 +1,626 @@
+@node More on certificate authentication
+@chapter More on Certificate Authentication
+@anchor{Certificate Authentication}
+@cindex Certificate authentication
+
+@menu
+* The X.509 trust model::
+* The OpenPGP trust model::
+* Digital signatures::
+* PKCS #11 tokens::
+@end menu
+
+@node The X.509 trust model
+@section The @acronym{X.509} Trust Model
+@cindex @acronym{X.509} certificates
+
+The @acronym{X.509} protocols rely on a hierarchical trust model. In
+this trust model Certification Authorities (CAs) are used to certify
+entities. Usually more than one certification authorities exist, and
+certification authorities may certify other authorities to issue
+certificates as well, following a hierarchical model.
+
+@image{gnutls-x509,7cm,9.5cm}
+
+One needs to trust one or more CAs for his secure communications. In
+that case only the certificates issued by the trusted authorities are
+acceptable. See the figure above for a typical example. The API for
+handling @acronym{X.509} certificates is described at section
+@ref{sec:x509api}. Some examples are listed below.
+
+@menu
+* X.509 certificates::
+* Verifying X.509 certificate paths::
+* PKCS #10 certificate requests::
+* PKCS #12 structures::
+@end menu
+
+@node X.509 certificates
+@subsection @acronym{X.509} Certificates
+
+An @acronym{X.509} certificate usually contains information about the
+certificate holder, the signer, a unique serial number, expiration
+dates and some other fields @xcite{PKIX} as shown in the table below.
+
+@table @code
+
+@item version:
+The field that indicates the version of the certificate.
+
+@item serialNumber:
+This field holds a unique serial number per certificate.
+
+@item issuer:
+Holds the issuer's distinguished name.
+
+@item validity:
+The activation and expiration dates.
+
+@item subject:
+The subject's distinguished name of the certificate.
+
+@item extensions:
+The extensions are fields only present in version 3 certificates.
+
+@end table
+
+The certificate's @emph{subject or issuer name} is not just a single
+string. It is a Distinguished name and in the @acronym{ASN.1}
+notation is a sequence of several object IDs with their corresponding
+values. Some of available OIDs to be used in an @acronym{X.509}
+distinguished name are defined in @file{gnutls/x509.h}.
+
+The @emph{Version} field in a certificate has values either 1 or 3 for
+version 3 certificates. Version 1 certificates do not support the
+extensions field so it is not possible to distinguish a CA from a
+person, thus their usage should be avoided.
+
+The @emph{validity} dates are there to indicate the date that the
+specific certificate was activated and the date the certificate's key
+would be considered invalid.
+
+Certificate @emph{extensions} are there to include information about
+the certificate's subject that did not fit in the typical certificate
+fields. Those may be e-mail addresses, flags that indicate whether the
+belongs to a CA etc. All the supported @acronym{X.509} version 3
+extensions are shown in the table below.
+
+@table @code
+
+@item subject key id (2.5.29.14):
+An identifier of the key of the subject.
+
+@item authority key id (2.5.29.35):
+An identifier of the authority's key used to sign the certificate.
+
+@item subject alternative name (2.5.29.17):
+Alternative names to subject's distinguished name.
+
+@item key usage (2.5.29.15):
+Constraints the key's usage of the certificate.
+
+@item extended key usage (2.5.29.37):
+Constraints the purpose of the certificate.
+
+@item basic constraints (2.5.29.19):
+Indicates whether this is a CA certificate or not, and specify the
+maximum path lengths of certificate chains.
+
+@item CRL distribution points (2.5.29.31):
+This extension is set by the CA, in order to inform about the issued
+CRLs.
+
+@item Proxy Certification Information (1.3.6.1.5.5.7.1.14):
+Proxy Certificates includes this extension that contains the OID of
+the proxy policy language used, and can specify limits on the maximum
+lengths of proxy chains. Proxy Certificates are specified in
+@xcite{RFC3820}.
+
+@end table
+
+In @acronym{GnuTLS} the @acronym{X.509} certificate structures are
+handled using the @code{gnutls_x509_crt_t} type and the corresponding
+private keys with the @code{gnutls_x509_privkey_t} type. All the
+available functions for @acronym{X.509} certificate handling have
+their prototypes in @file{gnutls/x509.h}. An example program to
+demonstrate the @acronym{X.509} parsing capabilities can be found at
+section @ref{ex:x509-info}.
+
+@node Verifying X.509 certificate paths
+@subsection Verifying @acronym{X.509} Certificate Paths
+@cindex Verifying certificate paths
+
+Verifying certificate paths is important in @acronym{X.509}
+authentication. For this purpose the function
+@ref{gnutls_x509_crt_verify} is provided. The output of this function
+is the bitwise OR of the elements of the
+@code{gnutls_certificate_status_t} enumeration. A detailed
+description of these elements can be found in figure below. The
+function @ref{gnutls_certificate_verify_peers2} is equivalent to the
+previous one, and will verify the peer's certificate in a TLS session.
+
+@table @code
+
+@item GNUTLS_CERT_INVALID:
+The certificate is not signed by one of the known authorities, or
+the signature is invalid.
+
+@item GNUTLS_CERT_REVOKED:
+The certificate has been revoked by its CA.
+
+@item GNUTLS_CERT_SIGNER_NOT_FOUND:
+The certificate's issuer is not known. This is the case when the
+issuer is not in the trusted certificates list.
+
+@item GNUTLS_CERT_SIGNER_NOT_CA:
+The certificate's signer was not a CA. This may happen if
+this was a version 1 certificate, which is common with some CAs, or
+a version 3 certificate without the basic constrains extension.
+
+@anchor{GNUTLS_CERT_INSECURE_ALGORITHM}
+@item GNUTLS_CERT_INSECURE_ALGORITHM:
+The certificate was signed using an insecure algorithm such as MD2 or
+MD5. These algorithms have been broken and should not be trusted.
+
+@end table
+
+There is also to possibility to pass some input to the verification
+functions in the form of flags. For @ref{gnutls_x509_crt_verify} the
+flags are passed straightforward, but
+@ref{gnutls_certificate_verify_peers2} depends on the flags set by
+calling @ref{gnutls_certificate_set_verify_flags}. All the available
+flags are part of the enumeration
+@ref{gnutls_certificate_verify_flags} and are explained in the table
+below.
+
+@anchor{gnutls_certificate_verify_flags}
+@tindex gnutls_certificate_verify_flags
+@table @code
+@item GNUTLS_VERIFY_DISABLE_CA_SIGN:
+If set a signer does not have to be a certificate authority. This
+flag should normaly be disabled, unless you know what this means.
+
+@item GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT:
+Allow only trusted CA certificates that have version 1. This is
+safer than GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT, and should be
+used instead. That way only signers in your trusted list will be
+allowed to have certificates of version 1.
+
+@item GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT:
+Allow CA certificates that have version 1 (both root and
+intermediate). This is dangerous since those haven't the
+basicConstraints extension. Must be used in combination with
+GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT.
+
+@item GNUTLS_VERIFY_DO_NOT_ALLOW_SAME:
+If a certificate is not signed by anyone trusted but exists in
+the trusted CA list do not treat it as trusted.
+
+@item GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2:
+Allow certificates to be signed using the old MD2 algorithm.
+
+@item GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5:
+Allow certificates to be signed using the broken MD5 algorithm.
+@end table
+
+Although the verification of a certificate path indicates that the
+certificate is signed by trusted authority, does not reveal anything
+about the peer's identity. It is required to verify if the
+certificate's owner is the one you expect. For more information
+consult @xcite{RFC2818} and section @ref{ex:verify} for an example.
+
+@node PKCS #10 certificate requests
+@subsection @acronym{PKCS} #10 Certificate Requests
+@cindex Certificate requests
+@cindex @acronym{PKCS} #10
+
+A certificate request is a structure, which contain information about
+an applicant of a certificate service. It usually contains a private
+key, a distinguished name and secondary data such as a challenge
+password. @acronym{GnuTLS} supports the requests defined in
+@acronym{PKCS} #10 @xcite{RFC2986}. Other certificate request's format
+such as PKIX's @xcite{RFC4211} are not currently supported.
+
+In @acronym{GnuTLS} the @acronym{PKCS} #10 structures are handled
+using the @code{gnutls_x509_crq_t} type. An example of a certificate
+request generation can be found at section @ref{ex:crq}.
+
+@node PKCS #12 structures
+@subsection @acronym{PKCS} #12 Structures
+@cindex @acronym{PKCS} #12
+
+A @acronym{PKCS} #12 structure @xcite{PKCS12} usually contains a user's
+private keys and certificates. It is commonly used in browsers to
+export and import the user's identities.
+
+In @acronym{GnuTLS} the @acronym{PKCS} #12 structures are handled
+using the @code{gnutls_pkcs12_t} type. This is an abstract type that
+may hold several @code{gnutls_pkcs12_bag_t} types. The Bag types are
+the holders of the actual data, which may be certificates, private
+keys or encrypted data. An Bag of type encrypted should be decrypted
+in order for its data to be accessed.
+
+An example of a @acronym{PKCS} #12 structure generation can be found
+at section @ref{ex:pkcs12}.
+
+@node The OpenPGP trust model
+@section The @acronym{OpenPGP} Trust Model
+@cindex @acronym{OpenPGP} Keys
+
+The @acronym{OpenPGP} key authentication relies on a distributed trust
+model, called the ``web of trust''. The ``web of trust'' uses a
+decentralized system of trusted introducers, which are the same as a
+CA. @acronym{OpenPGP} allows anyone to sign anyone's else public
+key. When Alice signs Bob's key, she is introducing Bob's key to
+anyone who trusts Alice. If someone trusts Alice to introduce keys,
+then Alice is a trusted introducer in the mind of that observer.
+
+@image{gnutls-pgp,11cm,9cm}
+
+For example: If David trusts Alice to be an introducer, and Alice
+signed Bob's key, Dave also trusts Bob's key to be the real one.
+
+There are some key points that are important in that model. In the
+example Alice has to sign Bob's key, only if she is sure that the key
+belongs to Bob. Otherwise she may also make Dave falsely believe that
+this is Bob's key. Dave has also the responsibility to know who to
+trust. This model is similar to real life relations.
+
+Just see how Charlie behaves in the previous example. Although he has
+signed Bob's key - because he knows, somehow, that it belongs to Bob -
+he does not trust Bob to be an introducer. Charlie decided to trust
+only Kevin, for some reason. A reason could be that Bob is lazy
+enough, and signs other people's keys without being sure that they
+belong to the actual owner.
+
+@subsection @acronym{OpenPGP} Keys
+
+In @acronym{GnuTLS} the @acronym{OpenPGP} key structures
+@xcite{RFC2440} are handled using the @code{gnutls_openpgp_crt_t} type
+and the corresponding private keys with the
+@code{gnutls_openpgp_privkey_t} type. All the prototypes for the key
+handling functions can be found at @file{gnutls/openpgp.h}.
+
+@subsection Verifying an @acronym{OpenPGP} Key
+
+The verification functions of @acronym{OpenPGP} keys, included in
+@acronym{GnuTLS}, are simple ones, and do not use the features of the
+``web of trust''. For that reason, if the verification needs are
+complex, the assistance of external tools like @acronym{GnuPG} and
+GPGME (@url{http://www.gnupg.org/related_software/gpgme/}) is
+recommended.
+
+There is one verification function in @acronym{GnuTLS}, the
+@ref{gnutls_openpgp_crt_verify_ring}. This checks an
+@acronym{OpenPGP} key against a given set of public keys (keyring) and
+returns the key status. The key verification status is the same as in
+@acronym{X.509} certificates, although the meaning and interpretation
+are different. For example an @acronym{OpenPGP} key may be valid, if
+the self signature is ok, even if no signers were found. The meaning
+of verification status is shown in the figure below.
+
+@table @code
+
+@item CERT_INVALID:
+A signature on the key is invalid. That means that the key was
+modified by somebody, or corrupted during transport.
+
+@item CERT_REVOKED:
+The key has been revoked by its owner.
+
+@item CERT_SIGNER_NOT_FOUND:
+The key was not signed by a known signer.
+
+@item GNUTLS_CERT_INSECURE_ALGORITHM:
+The certificate was signed using an insecure algorithm such as MD2 or
+MD5. These algorithms have been broken and should not be trusted.
+
+@end table
+
+@node Digital signatures
+@section Digital Signatures
+@cindex Digital signatures
+
+In this section we will provide some information about digital
+signatures, how they work, and give the rationale for disabling some
+of the algorithms used.
+
+Digital signatures work by using somebody's secret key to sign some
+arbitrary data. Then anybody else could use the public key of that
+person to verify the signature. Since the data may be arbitrary it is
+not suitable input to a cryptographic digital signature algorithm. For
+this reason and also for performance cryptographic hash algorithms are
+used to preprocess the input to the signature algorithm. This works as
+long as it is difficult enough to generate two different messages with
+the same hash algorithm output. In that case the same signature could
+be used as a proof for both messages. Nobody wants to sign an innocent
+message of donating 1 @euro{} to Greenpeace and find out that he
+donated 1.000.000 @euro{} to Bad Inc.
+
+For a hash algorithm to be called cryptographic the following three
+requirements must hold:
+
+@enumerate
+@item Preimage resistance.
+That means the algorithm must be one way and given the output of the
+hash function @math{H(x)}, it is impossible to calculate @math{x}.
+
+@item 2nd preimage resistance.
+That means that given a pair @math{x,y} with @math{y=H(x)} it is
+impossible to calculate an @math{x'} such that @math{y=H(x')}.
+
+@item Collision resistance.
+That means that it is impossible to calculate random @math{x} and
+@math{x'} such @math{H(x')=H(x)}.
+@end enumerate
+
+The last two requirements in the list are the most important in
+digital signatures. These protect against somebody who would like to
+generate two messages with the same hash output. When an algorithm is
+considered broken usually it means that the Collision resistance of
+the algorithm is less than brute force. Using the birthday paradox the
+brute force attack takes
+@iftex
+@math{2^{(\rm{hash\ size}) / 2}}
+@end iftex
+@ifnottex
+@math{2^{((hash size) / 2)}}
+@end ifnottex
+operations. Today colliding certificates using the MD5 hash algorithm
+have been generated as shown in @xcite{WEGER}.
+
+There has been cryptographic results for the SHA-1 hash algorithms as
+well, although they are not yet critical. Before 2004, MD5 had a
+presumed collision strength of @math{2^{64}}, but it has been showed
+to have a collision strength well under @math{2^{50}}. As of November
+2005, it is believed that SHA-1's collision strength is around
+@math{2^{63}}. We consider this sufficiently hard so that we still
+support SHA-1. We anticipate that SHA-256/386/512 will be used in
+publicly-distributed certificates in the future. When @math{2^{63}}
+can be considered too weak compared to the computer power available
+sometime in the future, SHA-1 will be disabled as well. The collision
+attacks on SHA-1 may also get better, given the new interest in tools
+for creating them.
+
+@subsection Trading Security for Interoperability
+
+If you connect to a server and use GnuTLS' functions to verify the
+certificate chain, and get a @ref{GNUTLS_CERT_INSECURE_ALGORITHM}
+validation error (@pxref{Verifying X.509 certificate paths}), it means
+that somewhere in the certificate chain there is a certificate signed
+using @code{RSA-MD2} or @code{RSA-MD5}. These two digital signature
+algorithms are considered broken, so GnuTLS fail when attempting to
+verify the certificate. In some situations, it may be useful to be
+able to verify the certificate chain anyway, assuming an attacker did
+not utilize the fact that these signatures algorithms are broken.
+This section will give help on how to achieve that.
+
+First, it is important to know that you do not have to enable any of
+the flags discussed here to be able to use trusted root CA
+certificates signed using @code{RSA-MD2} or @code{RSA-MD5}. The only
+attack today is that it is possible to generate certificates with
+colliding signatures (collision resistance); you cannot generate a
+certificate that has the same signature as an already existing
+signature (2nd preimage resistance).
+
+If you are using @ref{gnutls_certificate_verify_peers2} to verify the
+certificate chain, you can call
+@ref{gnutls_certificate_set_verify_flags} with the
+@code{GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2} or
+@code{GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5} flag, as in:
+
+@example
+ gnutls_certificate_set_verify_flags (x509cred,
+ GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
+@end example
+
+This will tell the verifier algorithm to enable @code{RSA-MD5} when
+verifying the certificates.
+
+If you are using @ref{gnutls_x509_crt_verify} or
+@ref{gnutls_x509_crt_list_verify}, you can pass the
+@code{GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5} parameter directly in the
+@code{flags} parameter.
+
+If you are using these flags, it may also be a good idea to warn the
+user when verification failure occur for this reason. The simplest is
+to not use the flags by default, and only fall back to using them
+after warning the user. If you wish to inspect the certificate chain
+yourself, you can use @ref{gnutls_certificate_get_peers} to extract
+the raw server's certificate chain, then use
+@ref{gnutls_x509_crt_import} to parse each of the certificates, and
+then use @ref{gnutls_x509_crt_get_signature_algorithm} to find out the
+signing algorithm used for each certificate. If any of the
+intermediary certificates are using @code{GNUTLS_SIGN_RSA_MD2} or
+@code{GNUTLS_SIGN_RSA_MD5}, you could present a warning.
+
+
+@node PKCS #11 tokens
+@section @acronym{PKCS #11} tokens
+@anchor{sec:pkcs11}
+@cindex @acronym{PKCS #11} tokens
+
+@subsection Introduction
+This section copes with the @acronym{PKCS #11} support in @acronym{GnuTLS}.
+@acronym{PKCS #11} is plugin API allowing applications to access cryptographic
+operations on a token, as well as to objects residing on the token. A token can
+be a real hardware token such as a smart card, or it can be a software component
+such as @acronym{Gnome Keyring}. The objects residing on such token can be
+certificates, public keys, private keys or even plain data or secret keys. Of those
+certificates and public/private key pairs can be used with @acronym{GnuTLS}. It's
+main advantage is that it allows operations on private key objects such as decryption
+and signing without accessing the key itself.
+
+@subsection Initialization
+To allow all the @acronym{GnuTLS} applications to access @acronym{PKCS #11} tokens
+it is adviceable to use @code{/etc/gnutls/pkcs11.conf}. This file has the following
+format:
+
+@verbatim
+load=/usr/lib/opensc-pkcs11.so
+load=/usr/lib/gnome-keyring/gnome-keyring-pkcs11.so
+@end verbatim
+
+If you use this file, then there is no need for other initialization in
+@acronym{GnuTLS}, except for the PIN and token functions, to allow retrieving a PIN
+when accessing a protected object, such as a private key, or allowing probing
+the user to insert the token. All the initialization functions are below.
+
+@itemize
+
+@item @ref{gnutls_pkcs11_init}: Global initialization
+
+@item @ref{gnutls_pkcs11_deinit}: Global deinitialization
+
+@item @ref{gnutls_pkcs11_set_token_function}: Sets the token insertion function
+
+@item @ref{gnutls_pkcs11_set_pin_function}: Sets the PIN request function
+
+@item @ref{gnutls_pkcs11_add_provider}: Adds an additional @acronym{PKCS #11} provider
+
+@end itemize
+
+@subsection Reading Objects
+
+All @acronym{PKCS #11} objects are referenced by @acronym{GnuTLS} functions by
+URLs as described in @code{draft-pechanec-pkcs11uri-01}. For example a public
+key on a smart card may be referenced as:
+
+@example
+pkcs11:token=Nikos;serial=307521161601031;model=PKCS%2315;manufacturer=EnterSafe;\
+object=test1;objecttype=public;\
+id=32:f1:53:f3:e3:79:90:b0:86:24:14:10:77:ca:5d:ec:2d:15:fa:ed
+@end example
+
+while the smart card itself can be referenced as:
+@example
+pkcs11:token=Nikos;serial=307521161601031;model=PKCS%2315;manufacturer=EnterSafe
+@end example
+
+
+Objects can be accessed with the following functions
+@itemize
+
+@item @ref{gnutls_pkcs11_obj_init}: Initializes an object
+
+@item @ref{gnutls_pkcs11_obj_import_url}: To import an object from a url
+
+@item @ref{gnutls_pkcs11_obj_export_url}: To export the URL of the object
+
+@item @ref{gnutls_pkcs11_obj_deinit}: To deinitialize an object
+
+@item @ref{gnutls_pkcs11_obj_export}: To export data associated with object
+
+@item @ref{gnutls_pkcs11_obj_get_info}: To obtain information about an object
+
+@item @ref{gnutls_pkcs11_obj_list_import_url}: To mass load of objects
+
+@item @ref{gnutls_x509_crt_import_pkcs11}: Import a certificate object
+
+@item @ref{gnutls_x509_crt_import_pkcs11_url}: Helper function to directly import a URL into a certificate
+
+@item @ref{gnutls_x509_crt_list_import_pkcs11}: Mass import of certificates
+
+@end itemize
+
+
+Functions that relate to token handling are shown below
+@itemize
+
+@item @ref{gnutls_pkcs11_token_get_url}: Returns the URL of a token
+
+@item @ref{gnutls_pkcs11_token_get_info}: Obtain information about a token
+
+@item @ref{gnutls_pkcs11_token_get_flags}: Returns flags about a token (i.e. hardware or software)
+
+@end itemize
+
+The following example will list all tokens.
+@verbatim
+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_global_deinit();
+@end verbatim
+
+
+The next one will list all objects in a token:
+@verbatim
+gnutls_pkcs11_obj_t *obj_list;
+unsigned int obj_list_size = 0;
+gnutls_datum_t cinfo;
+int i;
+
+ crt_list_size = 0;
+ ret = gnutls_pkcs11_obj_list_import_url( crt_list, NULL, url, \
+ GNUTLS_PKCS11_OBJ_ATTR_CRT_WITH_PRIVKEY);
+ if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
+ exit(1);
+
+ crt_list = malloc(sizeof(*crt_list)*crt_list_size);
+ if (crt_list == NULL)
+ exit(1);
+
+ ret = gnutls_pkcs11_obj_list_import_url( crt_list, &crt_list_size, url, flags);
+ if (ret < 0)
+ exit(1);
+
+ /* now all certificates are in crt_list */
+
+ for (i=0;i<crt_list_size;i++) {
+
+ ret = gnutls_x509_crt_init(&xcrt);
+ if (ret < 0)
+ exit(1);
+
+ ret = gnutls_x509_crt_import_pkcs11(xcrt, crt_list[i]);
+ if (ret < 0)
+ exit(1);
+
+ ret = gnutls_x509_crt_print (xcrt, GNUTLS_CRT_PRINT_FULL, &cinfo);
+ if (ret < 0)
+ exit(1);
+
+ fprintf(stdout, "cert[%d]:\n %s\n\n", cinfo.data);
+
+ gnutls_free(cinfo.data);
+ gnutls_x509_crt_deinit(&xcrt);
+ }
+@end verbatim
+
+
+@subsection Writing Objects
+
+With @acronym{GnuTLS} you can copy existing private keys and certificates
+to a token. This can be achieved with the following functions
+
+@itemize
+
+@item @ref{gnutls_pkcs11_delete_url}: To delete an object
+
+@item @ref{gnutls_pkcs11_copy_x509_privkey}: To copy a private key to a token
+
+@item @ref{gnutls_pkcs11_copy_x509_crt}: To copy a certificate to a token
+
+@end itemize
+
+
+@subsection Using a @acronym{PKCS #11} token with TLS
+
+This example will demonstrate how to load keys and certificates
+from a @acronym{PKCS} #11 token, and use it with a TLS connection.
+
+@verbatiminclude examples/ex-cert-select-pkcs11.c
+