The TLS handshakes code still relies on the mbed TLS code to load x509 certificates and private keys, which significantly duplicates the Linux asymmetric keys API. Following files in linux/net/tls/ are implementing the logic:
linux/net/tls/x509_crl.c and linux/include/net/tls/x509_crl.h are responsible for CRL, which is not implemented by the Linux kernel, but required for client side TLS handshakes. The code, after some modifications, should be moved to linuxcrypto/asymmetric_keys/, but this isn't for this task.
At the moment a certificate and a private key are populated to the TLS handshake code by the separate module (Tempesta FW) in the following way:
ttls_x509_crt_parse() or ttls_pk_parse_key() are called to parse the certificate or private key correspondingly. The parsing functions can handle DER or PEM formats.
As the results of the parsing a chain of TlsX509Crt certificates (we'll convert all data structure names to lower case to satisfy the Linux kernel coding style) or TlsPkCtx.
The parsed certificate and the private key are associated with a server name (SNI or 'vhost' in terms of Tempesta FW). tfw_tls_sni() looks up the appropriate server configuration by a SNI shipped in ClientHello message and sets TlsPeerCfg for the current TLS connection handler TlsCtx.
Each server name, and TlsPeerCfg correspondingly, may have multiple pairs of a certificate and a private key.
X509 certificates are parsed into and handled by pages. The pages are scattered (sg_set_buf()) int sk_buff fragments to be sent to a client without copies, we only track the pages reference counter.
High level requirements
We need a generic service, which can listen for example on 443 TCP port and accept ingress TLS connections for many server names (SNIs). The pseudo-configuration for the system might look like:
In this case we have 10 thousand server names and all of them are served on the same TCP port. The required keys/keyrings lookup must be fast enough on such a number of SNIs. Each of the SNIs may have several pairs of x509 certificates and private keys to handle different types of TLS handshake ciphersuites.
There could be several different services (e.g. an NFS and HTTPS servers) operating with different SNIs and different sets of certificates and private keys.
QUESTION: Should we use ACLs for this? Otherwise it seems we need to require the services to be run with different users.
API example
The TLS implementation must register 2 new key_types: tls_cert for TLS certificates and tls_priv for private keys. A keyring handles the set of pairs of a certificate and corresponding private key (e.g. EC and RSA private key and a public key within a certificate) for a particular SNI.
Linux provides add_key(2) system call with asymmetric-key(7) API which allows to load X509 certificates including ECDSA keys. This API should be used instead of current mbedTLS-inherited X509 infrastructure.
TLS listening sockets might be requested by processes with different UIDs and GIDs and/or containers. Different users/groups and containers must be able to update/revoke their certificates and keys, but don't have access to certificates and keys of other users/groups and containers working on the same host. The asymmetric-key(7) API takes care about all the security concerns (see key_task_permission()) and TLS application of the interface should use the same permission control mechanism.
QUESTION: The keys are stored in the associative array (see e.g. search_nested_keyrings()), but can it efficiently handle thousands of keys?
A (by David Howells):
The keyring is a wrapper around an RCU-searchable radix tree of
keys. You also need a good hash function. The tree splits up to 16 ways at
each node, taking a nibble from the {hash, description} each time. With an
ideal hash function, 10000 keys, say, would take log16(10000) = 4 steps to
find the node, and then it would need to iterate through the keys in the
terminal node (up to 16).
Loading certificates and private keys
The new TLS handshakes kernel service must:
register the new key types tls_cert and tls_priv and appropriate instantiation and parsing code
the keys instantiation and parsing code must use the Linux x509_cert_parse() and pkcs8_key_preparse() routines instead of current ttls_x509_crt_parse() or ttls_pk_parse_key(). (Probably we should leave RFC 5915 and PEM parsing for the user space.)
tls_setsockopt() must be extended to accept the extended optval and call request_key() for a server name
struct tls_context should be extened by a pointer to handshake specific handler (TlsCtx in the current code), which must be linked with the keyring
Keys storage
Since request_key()/request_key_rcu() search the keys in the current process context, we can not use the interface to process TLS handshakes in softirq (#1433). Thus, the setsockopt() must extract the keys and place them in alternate storage for the listening socket. The storage must be keyed by SNI string.
CAP_NET_ADMIN capability is required for a process working with the private keys and certificates.
The current asymmetric keys API
The TLS handshakes code still relies on the mbed TLS code to load x509 certificates and private keys, which significantly duplicates the Linux asymmetric keys API. Following files in linux/net/tls/ are implementing the logic:
and in linux/include/net/tls:
linux/net/tls/x509_crl.c
andlinux/include/net/tls/x509_crl.h
are responsible for CRL, which is not implemented by the Linux kernel, but required for client side TLS handshakes. The code, after some modifications, should be moved tolinuxcrypto/asymmetric_keys/
, but this isn't for this task.At the moment a certificate and a private key are populated to the TLS handshake code by the separate module (Tempesta FW) in the following way:
The parsed certificate and the private key are associated with a server name (SNI or 'vhost' in terms of Tempesta FW). tfw_tls_sni() looks up the appropriate server configuration by a SNI shipped in ClientHello message and sets TlsPeerCfg for the current TLS connection handler TlsCtx.
Each server name, and
TlsPeerCfg
correspondingly, may have multiple pairs of a certificate and a private key.X509 certificates are parsed into and handled by pages. The pages are scattered (
sg_set_buf()
) int sk_buff fragments to be sent to a client without copies, we only track the pages reference counter.High level requirements
We need a generic service, which can listen for example on 443 TCP port and accept ingress TLS connections for many server names (SNIs). The pseudo-configuration for the system might look like:
In this case we have 10 thousand server names and all of them are served on the same TCP port. The required keys/keyrings lookup must be fast enough on such a number of SNIs. Each of the SNIs may have several pairs of x509 certificates and private keys to handle different types of TLS handshake ciphersuites.
There could be several different services (e.g. an NFS and HTTPS servers) operating with different SNIs and different sets of certificates and private keys.
QUESTION: Should we use ACLs for this? Otherwise it seems we need to require the services to be run with different users.
API example
The TLS implementation must register 2 new key_types:
tls_cert
for TLS certificates andtls_priv
for private keys. A keyring handles the set of pairs of a certificate and corresponding private key (e.g. EC and RSA private key and a public key within a certificate) for a particular SNI.To create a new keyring for SNI
host0.com
:QUESTION: Do we need to distinguish keyrings for
example.com
for an HTTPS service from an NFS service?Load the certificate and the private key for the SNI:
QUESTION: is it a good idea to load different certificate and private key to the same keyring? E.g.
A(?) It seems it's doable with composing the key description that we want to search for, should be solved also in rxrpc.
Link the keys with TLS listening socket for all the managed server names (SNIs), see also #1433 :
Moving to the Linux asymmetric keys API
General requirements
Linux provides
add_key(2)
system call withasymmetric-key(7)
API which allows to load X509 certificates including ECDSA keys. This API should be used instead of current mbedTLS-inherited X509 infrastructure.TLS listening sockets might be requested by processes with different UIDs and GIDs and/or containers. Different users/groups and containers must be able to update/revoke their certificates and keys, but don't have access to certificates and keys of other users/groups and containers working on the same host. The
asymmetric-key(7)
API takes care about all the security concerns (seekey_task_permission()
) and TLS application of the interface should use the same permission control mechanism.QUESTION: The keys are stored in the associative array (see e.g.
search_nested_keyrings()
), but can it efficiently handle thousands of keys? A (by David Howells):Loading certificates and private keys
The new TLS handshakes kernel service must:
tls_cert
andtls_priv
and appropriate instantiation and parsing codex509_cert_parse()
andpkcs8_key_preparse()
routines instead of currentttls_x509_crt_parse()
orttls_pk_parse_key()
. (Probably we should leave RFC 5915 and PEM parsing for the user space.)tls_setsockopt()
must be extended to accept the extendedoptval
and callrequest_key()
for a server namestruct tls_context
should be extened by a pointer to handshake specific handler (TlsCtx
in the current code), which must be linked with the keyringKeys storage
Since
request_key()
/request_key_rcu()
search the keys in the current process context, we can not use the interface to process TLS handshakes in softirq (#1433). Thus, thesetsockopt()
must extract the keys and place them in alternate storage for the listening socket. The storage must be keyed by SNI string.CAP_NET_ADMIN
capability is required for a process working with the private keys and certificates.References
Kernel key management Kernel Key Retention Service
Testing