Overview and operation
======================

The technical specification ETSI TS 103 523-3 (Enterprise Transport
Security, or ETS) defines a variant of the TLS 1.3 protocol in which
the server uses static (EC)DH keys instead of ephemeral ones.  This
distribution provides an implementation of ETS to support the
evaluation and adoption of the mechanism.

The current support for ETS in this implementation does not consist of
extensions to the existing API, but rather relies on additional
keywords added to the OpenSSL config file format that enable ETS and
configure its operation.

To enable ETS for an existing OpenSSL-based application:

    1. Build and install this distribution.  (Subsequent system-wide
       or per-process configuration of the dynamic linker in the usual
       way may be required, but is beyond the scope of this document)

    2. Generate the static (EC)DH private key material that will be
       used with ETS, and optionally, generate a corresponding
       certificate. (See below)

    3. Prepare a suitable OpenSSL configuration file. (See below)

    4. Launch the application with the environment variable
       OPENSSL_CONF set to point to the OpenSSL configuration file
       prepared above.

Runtime behavior
----------------
When the application is launched, the configuration file pointed to by
the OPENSSL_CONF environment variable will be loaded, and the
ETS-related keywords will be processed.  Any configured key files are
loaded at this point.

During establishment of a TLS 1.3 connection, if ETS is enabled, the
certificate chosen for the connection (via the usual OpenSSL
machinery) is examined to see if it contains visibility information
(as defined in ETSI TS 103 523-3).  If it does, then (EC)DH key
selection is limited to the subset of ETS keys specified via the
OpenSSL configuration file that have corresponding visibility
information in the certificate.  Otherwise, if there is no visibility
information in the certificate, all ETS keys specified via the OpenSSL
configuration file are eligible for selection.

Then, if ETS is enabled and there is an ETS private (EC)DH key
available for the group selected as part of the TLS 1.3 handshake in
progress, that key is used for the connection.  Otherwise, if no ETS
key corresponding to the negotiated group is available, the behavior
depends on the ETS mode selected (see below).


Preparing the OpenSSL configuration file
========================================

This section describes a minimal OpenSSL configuration file suitable
for enabling ETS and configuring its operation.  More information on
the OpenSSL configuration file format in general is located at
https://www.openssl.org/docs/man1.1.1/man5/config.html.

The following contents can be placed in a separate file and customized
as required:

openssl_conf = openssl_init

[openssl_init]
ssl_conf = ssl_section

[ssl_section]
system_default = default_section

[default_section]
# ETSMode is off, optional, or required.
#  - off: normal TLS 1.3 operation (ephemeral (EC)DH keys always used)
#  - optional: use ETS static keys if available, otherwise generate
#              ephemeral ones
#  - required: must use ETS static keys, if no static key is suitable,
               connection will fail
ETSMode = required

# ETSKeyStore is a colon-separated list of file and directory path
# names.  Named directories will be processed recursively.  Files that
# cannot be correctly parsed as PEM files containing private keys will
# be ignored.  Colons appearing in path names can be escaped with '\'.
# ETSKeyStore = static-key-1.pem:static-key-2.pem:/some/dir/with/keys
ETSKeyStore = /etc/pki/ets/private/static


Generating a static (EC)DH key
==============================

The following commands can be used to generate an (EC)DH private key
for use with ETS.

DH groups (example is ffdhe3072)
--------------------------------
openssl genpkey -algorithm DH -pkeyopt dh_param:ffdhe3072 -out mykey.pem

ECDH groups (non-X, example is secp384r1)
-----------------------------------------
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:secp384r1 -out mykey.pem

ECDH groups (X, example is X25519)
----------------------------------
openssl genpkey -algorithm X25519 -out mykey.pem


Generating a certificate with visibility information
====================================================

This section describes how to generate the ETS key fingerprints
required to construct the visibility information certificate extension
contents as well as how to provide the visibility information to
include in a given certificate to the openssl command used to generate
that certificate.

Generating an ETS key fingerprint
---------------------------------
openssl pkey -pubout -in mykey.pem -out mykey-pub.pem
openssl pkey -pubin -in mykey-pub.pem -noout -ets_fingerprint

Constructing the extension configuration file
---------------------------------------------

This subsection describes how to include visibility information in a
certificate using the X.509 associatedInformation extension
representation.  In the following example, it is assumed that there
are two ETS keys to be included in the visibility information, with
their fingerprints determined as described above.

First, the following contents are placed in a separate file, assumed
to be named vi.conf.

[visibility_information_1]
fingerprint = FORMAT:HEX,OCTETSTRING:00010203040506070809
accessDescription = UTF8:User-supplied string 1
[visibility_information_2]
fingerprint = FORMAT:HEX,OCTETSTRING:0102030405060708090a
accessDescription = UTF8:User-supplied string 2
[visibility_information_attribute_values]
vi1 = SEQUENCE:visibility_information_1
vi2 = SEQUENCE:visibility_information_2
[visibility_information]
associatedInformation = attribute:etsVisibility;SET:visibility_information_attribute_values

Then, the file vi.conf is provided as the extension data specification
to the openssl command used to generate the certificate, using the
generation of a self-signed certificate as an example.

The following command sequence additionally requires a file named
myreq.conf with the contents:

[req]
distinguished_name = req_distinguished_name
prompt = no

[req_distinguished_name]
countryName = ZZ
organizationName = ETS Example
commonName = ets.example.org

The example command sequence is then:

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out mycert.key
openssl req -new -batch -nodes -key mycert.key -out mycert.csr -sha256 -config myreq.conf
openssl x509 -req -in mycert.csr -out mycert.crt -signkey mycert.key -days 365 -sha256 \
    -extfile vi.conf -extensions visibility_information

The certificate contents can be examined with:

openssl x509 -text -noout -in mycert.crt
