988 lines
41 KiB
XML
988 lines
41 KiB
XML
<?xml version='1.0' encoding='utf-8' ?>
|
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
|
]>
|
|
<chapter id="chap-Defensive_Coding-TLS">
|
|
<title>Transport Layer Security</title>
|
|
<para>
|
|
Transport Layer Security (TLS, formerly Secure Sockets
|
|
Layer/SSL) is the recommended way to to protect integrity and
|
|
confidentiality while data is transferred over an untrusted
|
|
network connection, and to identify the endpoint.
|
|
</para>
|
|
<section id="sect-Defensive_Coding-TLS-Pitfalls">
|
|
<title>Common Pitfalls</title>
|
|
<para>
|
|
TLS implementations are difficult to use, and most of them lack
|
|
a clean API design. The following sections contain
|
|
implementation-specific advice, and some generic pitfalls are
|
|
mentioned below.
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
Most TLS implementations have questionable default TLS
|
|
cipher suites. Most of them enable anonymous Diffie-Hellman
|
|
key exchange (but we generally want servers to authenticate
|
|
themselves). Many do not disable ciphers which are subject
|
|
to brute-force attacks because of restricted key lengths.
|
|
Some even disable all variants of AES in the default
|
|
configuration.
|
|
</para>
|
|
<para>
|
|
When overriding the cipher suite defaults, it is recommended
|
|
to disable all cipher suites which are not present on a
|
|
whitelist, instead of simply enabling a list of cipher
|
|
suites. This way, if an algorithm is disabled by default in
|
|
the TLS implementation in a future security update, the
|
|
application will not re-enable it.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The name which is used in certificate validation must match
|
|
the name provided by the user or configuration file. No host
|
|
name canonicalization or IP address lookup must be performed.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The TLS handshake has very poor performance if the TCP Nagle
|
|
algorithm is active. You should switch on the
|
|
<literal>TCP_NODELAY</literal> socket option (at least for the
|
|
duration of the handshake), or use the Linux-specific
|
|
<literal>TCP_CORK</literal> option.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-Nagle">
|
|
<title>Deactivating the TCP Nagle algorithm</title>
|
|
<xi:include href="snippets/TLS-Nagle.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Implementing proper session resumption decreases handshake
|
|
overhead considerably. This is important if the upper-layer
|
|
protocol uses short-lived connections (like most application
|
|
of HTTPS).
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Both client and server should work towards an orderly
|
|
connection shutdown, that is send
|
|
<literal>close_notify</literal> alerts and respond to them.
|
|
This is especially important if the upper-layer protocol
|
|
does not provide means to detect connection truncation (like
|
|
some uses of HTTP).
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
When implementing a server using event-driven programming,
|
|
it is important to handle the TLS handshake properly because
|
|
it includes multiple network round-trips which can block
|
|
when an ordinary TCP <function>accept</function> would not.
|
|
Otherwise, a client which fails to complete the TLS
|
|
handshake for some reason will prevent the server from
|
|
handling input from other clients.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Unlike regular file descriptors, TLS connections cannot be
|
|
passed between processes. Some TLS implementations add
|
|
additional restrictions, and TLS connections generally
|
|
cannot be used across <function>fork</function> function
|
|
calls (see <xref
|
|
linkend="sect-Defensive_Coding-Tasks-Processes-Fork-Parallel"/>).
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<section id="sect-Defensive_Coding-TLS-OpenSSL">
|
|
<title>OpenSSL Pitfalls</title>
|
|
<para>
|
|
Some OpenSSL function use <emphasis>tri-state return
|
|
values</emphasis>. Correct error checking is extremely
|
|
important. Several functions return <literal>int</literal>
|
|
values with the following meaning:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
The value <literal>1</literal> indicates success (for
|
|
example, a successful signature verification).
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The value <literal>0</literal> indicates semantic
|
|
failure (for example, a signature verification which was
|
|
unsuccessful because the signing certificate was
|
|
self-signed).
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The value <literal>-1</literal> indicates a low-level
|
|
error in the system, such as failure to allocate memory
|
|
using <function>malloc</function>.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
Treating such tri-state return values as booleans can lead
|
|
to security vulnerabilities. Note that some OpenSSL
|
|
functions return boolean results or yet another set of
|
|
status indicators. Each function needs to be checked
|
|
individually.
|
|
</para>
|
|
<para>
|
|
Recovering precise error information is difficult.
|
|
<xref linkend="ex-Defensive_Coding-TLS-OpenSSL-Errors"/>
|
|
shows how to obtain a more precise error code after a function
|
|
call on an <literal>SSL</literal> object has failed. However,
|
|
there are still cases where no detailed error information is
|
|
available (e.g., if <function>SSL_shutdown</function> fails
|
|
due to a connection teardown by the other end).
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-OpenSSL-Errors">
|
|
<title>Obtaining OpenSSL error codes</title>
|
|
<xi:include href="snippets/TLS-OpenSSL-Errors.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
The <function>OPENSSL_config</function> function is
|
|
documented to never fail. In reality, it can terminate the
|
|
entire process if there is a failure accessing the
|
|
configuration file. An error message is written to standard
|
|
error, but which might not be visible if the function is
|
|
called from a daemon process.
|
|
</para>
|
|
<para>
|
|
OpenSSL contains two separate ASN.1 DER decoders. One set
|
|
of decoders operate on BIO handles (the input/output stream
|
|
abstraction provided by OpenSSL); their decoder function
|
|
names start with <literal>d2i_</literal> and end in
|
|
<literal>_fp</literal> or <literal>_bio</literal> (e.g.,
|
|
<function>d2i_X509_fp</function> or
|
|
<function>d2i_X509_bio</function>). These decoders must not
|
|
be used for parsing data from untrusted sources; instead,
|
|
the variants without the <literal>_fp</literal> and
|
|
<literal>_bio</literal> (e.g.,
|
|
<function>d2i_X509</function>) shall be used. The BIO
|
|
variants have received considerably less testing and are not
|
|
very robust.
|
|
</para>
|
|
<para>
|
|
For the same reason, the OpenSSL command line tools (such as
|
|
<command>openssl x509</command>) are generally generally less
|
|
robust than the actual library code. They use the BIO
|
|
functions internally, and not the more robust variants.
|
|
</para>
|
|
<para>
|
|
The command line tools do not always indicate failure in the
|
|
exit status of the <application>openssl</application> process.
|
|
For instance, a verification failure in <command>openssl
|
|
verify</command> result in an exit status of zero.
|
|
</para>
|
|
<para>
|
|
The OpenSSL server and client applications (<command>openssl
|
|
s_client</command> and <command>openssl s_server</command>)
|
|
are debugging tools and should <emphasis>never</emphasis> be
|
|
used as generic clients. For instance, the
|
|
<application>s_client</application> tool reacts in a
|
|
surprisign way to lines starting with <literal>R</literal> and
|
|
<literal>Q</literal>.
|
|
</para>
|
|
<para>
|
|
OpenSSL allows application code to access private key
|
|
material over documented interfaces. This can significantly
|
|
increase the part of the code base which has to undergo
|
|
security certification.
|
|
</para>
|
|
</section>
|
|
<section id="sect-Defensive_Coding-TLS-Pitfalls-GNUTLS">
|
|
<title>GNUTLS Pitfalls</title>
|
|
<para>
|
|
<filename>libgnutls.so.26</filename> links to
|
|
<filename>libpthread.so.0</filename>. Loading the threading
|
|
library too late causes problems, so the main program should
|
|
be linked with <literal>-lpthread</literal> as well. As a
|
|
result, it can be difficult to use GNUTLS in a plugin which is
|
|
loaded with the <function>dlopen</function> function. Another
|
|
side effect is that applications which merely link against
|
|
GNUTLS (even without actually using it) may incur a
|
|
substantial overhead because other libraries automatically
|
|
switch to thread-safe algorithms.
|
|
</para>
|
|
<para>
|
|
The <function>gnutls_global_init</function> function must be
|
|
called before using any functionality provided by the library.
|
|
This function is not thread-safe, so external locking is
|
|
required, but it is not clear which lock should be used.
|
|
Omitting the synchronization does not just lead to a memory
|
|
leak, as it is suggested in the GNUTLS documentation, but to
|
|
undefined behavior because there is no barrier that would
|
|
enforce memory ordering.
|
|
</para>
|
|
<para>
|
|
The <function>gnutls_global_deinit</function> function does
|
|
not actually deallocate all resources allocated by
|
|
<function>gnutls_global_init</function>. It is currently not
|
|
thread-safe. Therefore, it is best to avoid calling it
|
|
altogether.
|
|
</para>
|
|
<para>
|
|
The X.509 implementation in GNUTLS is rather lenient. For
|
|
example, it is possible to create and process X.509
|
|
version 1 certificates which carry extensions. These
|
|
certificates are (correctly) rejected by other
|
|
implementations.
|
|
</para>
|
|
</section>
|
|
<section id="sect-Defensive_Coding-TLS-Pitfalls-OpenJDK">
|
|
<title>OpenJDK Pitfalls</title>
|
|
<para>
|
|
The Java cryptographic framework is highly modular. As a
|
|
result, when you request an object implementing some
|
|
cryptographic functionality, you cannot be completely sure
|
|
that you end up with the well-tested, reviewed implementation
|
|
in OpenJDK.
|
|
</para>
|
|
<para>
|
|
OpenJDK (in the source code as published by Oracle) and other
|
|
implementations of the Java platform require that the system
|
|
administrator has installed so-called <emphasis>unlimited
|
|
strength jurisdiction policy files</emphasis>. Without this
|
|
step, it is not possible to use the secure algorithms which
|
|
offer sufficient cryptographic strength. Most downstream
|
|
redistributors of OpenJDK remove this requirement.
|
|
</para>
|
|
<para>
|
|
Some versions of OpenJDK use <filename>/dev/random</filename>
|
|
as the randomness source for nonces and other random data
|
|
which is needed for TLS operation, but does not actually
|
|
require physical randomness. As a result, TLS applications
|
|
can block, waiting for more bits to become available in
|
|
<filename>/dev/random</filename>.
|
|
</para>
|
|
</section>
|
|
<section id="sect-Defensive_Coding-TLS-Pitfalls-NSS">
|
|
<title>NSS Pitfalls</title>
|
|
<para>
|
|
NSS was not designed to be used by other libraries which can
|
|
be linked into applications without modifying them. There is
|
|
a lot of global state. There does not seem to be a way to
|
|
perform required NSS initialization without race conditions.
|
|
</para>
|
|
<para>
|
|
If the NSPR descriptor is in an unexpected state, the
|
|
<function>SSL_ForceHandshake</function> function can succeed,
|
|
but no TLS handshake takes place, the peer is not
|
|
authenticated, and subsequent data is exchanged in the clear.
|
|
</para>
|
|
<para>
|
|
NSS disables itself if it detects that the process underwent a
|
|
<function>fork</function> after the library has been
|
|
initialized. This behavior is required by the PKCS#11 API
|
|
specification.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
<section id="sect-Defensive_Coding-TLS-Client">
|
|
<title>TLS Clients</title>
|
|
<para>
|
|
Secure use of TLS in a client generally involves all of the
|
|
following steps. (Individual instructions for specific TLS
|
|
implementations follow in the next sections.)
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
The client must configure the TLS library to use a set of
|
|
trusted root certificates. These certificates are provided
|
|
by the system in <filename
|
|
class="directory">/etc/ssl/certs</filename> or files derived
|
|
from it.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The client selects sufficiently strong cryptographic
|
|
primitives and disables insecure ones (such as no-op
|
|
encryption). Compression and SSL version 2 support must be
|
|
disabled (including the SSLv2-compatible handshake).
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The client initiates the TLS connection. The Server Name
|
|
Indication extension should be used if supported by the
|
|
TLS implementation. Before switching to the encrypted
|
|
connection state, the contents of all input and output
|
|
buffers must be discarded.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The client needs to validate the peer certificate provided
|
|
by the server, that is, the client must check that there
|
|
is a cryptographically protected chain from a trusted root
|
|
certificate to the peer certificate. (Depending on the
|
|
TLS implementation, a TLS handshake can succeed even if
|
|
the certificate cannot be validated.)
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
The client must check that the configured or user-provided
|
|
server name matches the peer certificate provided by the
|
|
server.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
It is safe to provide users detailed diagnostics on
|
|
certificate validation failures. Other causes of handshake
|
|
failures and, generally speaking, any details on other errors
|
|
reported by the TLS implementation (particularly exception
|
|
tracebacks), must not be divulged in ways that make them
|
|
accessible to potential attackers. Otherwise, it is possible
|
|
to create decryption oracles.
|
|
</para>
|
|
<important>
|
|
<para>
|
|
Depending on the application, revocation checking (against
|
|
certificate revocations lists or via OCSP) and session
|
|
resumption are important aspects of production-quality
|
|
client. These aspects are not yet covered.
|
|
</para>
|
|
</important>
|
|
<section>
|
|
<title>Implementation TLS Clients With OpenSSL</title>
|
|
<para>
|
|
In the following code, the error handling is only exploratory.
|
|
Proper error handling is required for production use,
|
|
especially in libraries.
|
|
<!-- FIXME: Cross-reference event-driven I/O section when it
|
|
exists and mention that this is really quite complex to
|
|
implement. -->
|
|
</para>
|
|
<para>
|
|
The OpenSSL library needs explicit initialization (see <xref
|
|
linkend="ex-Defensive_Coding-TLS-OpenSSL-Init"/>).
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-OpenSSL-Init">
|
|
<title>OpenSSL library initialization</title>
|
|
<xi:include href="snippets/TLS-Client-OpenSSL-Init.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
After that, a context object has to be created, which acts as
|
|
a factory for connection objects (<xref
|
|
linkend="ex-Defensive_Coding-TLS-Client-OpenSSL-CTX"/>). We
|
|
use an explicit cipher list so that we do not pick up any
|
|
strange ciphers when OpenSSL is upgraded. The actual version
|
|
requested in the client hello depends on additional
|
|
restrictions in the OpenSSL library. If possible, you should
|
|
follow the example code and use the default list of trusted
|
|
root certificate authorities provided by the system because
|
|
you would have to maintain your own set otherwise, which can
|
|
be cumbersome.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-Client-OpenSSL-CTX">
|
|
<title>OpenSSL client context creation</title>
|
|
<xi:include href="snippets/TLS-Client-OpenSSL-CTX.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
A single context object can be used to create multiple
|
|
connection objects. It is safe to use the same
|
|
<literal>SSL_CTX</literal> object for creating connections
|
|
concurrently from multiple threads, provided that the
|
|
<literal>SSL_CTX</literal> object is not modified (e.g.,
|
|
callbacks must not be changed).
|
|
</para>
|
|
<para>
|
|
After creating the TCP socket and disabling the Nagle
|
|
algorithm (per <xref
|
|
linkend="ex-Defensive_Coding-TLS-Nagle"/>), the actual
|
|
connection object needs to be created, as show in <xref
|
|
linkend="ex-Defensive_Coding-TLS-Client-OpenSSL-CTX"/>. If
|
|
the handshake started by <function>SSL_connect</function>
|
|
fails, the <function>ssl_print_error_and_exit</function>
|
|
function from <xref
|
|
linkend="ex-Defensive_Coding-TLS-OpenSSL-Errors"/> is called.
|
|
</para>
|
|
<para>
|
|
The <function>certificate_validity_override</function>
|
|
function provides an opportunity to override the validity of
|
|
the certificate in case the OpenSSL check fails. If such
|
|
functionality is not required, the call can be removed,
|
|
otherwise, the application developer has to implement it.
|
|
</para>
|
|
<para>
|
|
The host name passed to the functions
|
|
<function>SSL_set_tlsext_host_name</function> and
|
|
<function>X509_check_host</function> must be the name that was
|
|
passed to <function>getaddrinfo</function> or a similar name
|
|
resolution function. No host name canonicalization must be
|
|
performed. The <function>X509_check_host</function> function
|
|
used in the final step for host name matching is currently
|
|
only implemented in OpenSSL 1.1, which is not released yet.
|
|
In case host name matching fails, the function
|
|
<function>certificate_host_name_override</function> is called.
|
|
This function should check user-specific certificate store, to
|
|
allow a connection even if the host name does not match the
|
|
certificate. This function has to be provided by the
|
|
application developer. Note that the override must be keyed
|
|
by both the certificate <emphasis>and</emphasis> the host
|
|
name.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-Client-OpenSSL-Connect">
|
|
<title>Creating a client connection using OpenSSL</title>
|
|
<xi:include href="snippets/TLS-Client-OpenSSL-Connect.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
The connection object can be used for sending and receiving
|
|
data, as in <xref
|
|
linkend="ex-Defensive_Coding-TLS-OpenSSL-Connection-Use"/>.
|
|
It is also possible to create a <literal>BIO</literal> object
|
|
and use the <literal>SSL</literal> object as the underlying
|
|
transport, using <function>BIO_set_ssl</function>.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-OpenSSL-Connection-Use">
|
|
<title>Using an OpenSSL connection to send and receive data</title>
|
|
<xi:include href="snippets/TLS-Client-OpenSSL-Connection-Use.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
When it is time to close the connection, the
|
|
<function>SSL_shutdown</function> function needs to be called
|
|
twice for an orderly, synchronous connection termination
|
|
(<xref
|
|
linkend="ex-Defensive_Coding-TLS-OpenSSL-Connection-Close"/>).
|
|
This exchanges <literal>close_notify</literal> alerts with the
|
|
server. The additional logic is required to deal with an
|
|
unexpected <literal>close_notify</literal> from the server.
|
|
Note that is necessary to explicitly close the underlying
|
|
socket after the connection object has been freed.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-OpenSSL-Connection-Close">
|
|
<title>Closing an OpenSSL connection in an orderly fashion</title>
|
|
<xi:include href="snippets/TLS-OpenSSL-Connection-Close.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
<xref linkend="ex-Defensive_Coding-TLS-OpenSSL-Context-Close"/> shows how
|
|
to deallocate the context object when it is no longer needed
|
|
because no further TLS connections will be established.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-OpenSSL-Context-Close">
|
|
<title>Closing an OpenSSL connection in an orderly fashion</title>
|
|
<xi:include href="snippets/TLS-OpenSSL-Context-Close.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
</section>
|
|
<section id="sect-Defensive_Coding-TLS-Client-GNUTLS">
|
|
<title>Implementation TLS Clients With GNUTLS</title>
|
|
<para>
|
|
This section describes how to implement a TLS client with full
|
|
certificate validation (but without certificate revocation
|
|
checking). Note that the error handling in is only
|
|
exploratory and needs to be replaced before production use.
|
|
</para>
|
|
<para>
|
|
The GNUTLS library needs explicit initialization:
|
|
</para>
|
|
<informalexample id="ex-Defensive_Coding-TLS-GNUTLS-Init">
|
|
<xi:include href="snippets/TLS-GNUTLS-Init.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</informalexample>
|
|
<para>
|
|
Failing to do so can result in obscure failures in Base64
|
|
decoding. See <xref
|
|
linkend="sect-Defensive_Coding-TLS-Pitfalls-GNUTLS"/> for
|
|
additional aspects of initialization.
|
|
</para>
|
|
<para>
|
|
Before setting up TLS connections, a credentials objects has
|
|
to be allocated and initialized with the set of trusted root
|
|
CAs (<xref
|
|
linkend="ex-Defensive_Coding-TLS-Client-GNUTLS-Credentials"/>).
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-Client-GNUTLS-Credentials">
|
|
<title>Initializing a GNUTLS credentials structure</title>
|
|
<xi:include href="snippets/TLS-Client-GNUTLS-Credentials.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
After the last TLS connection has been closed, this credentials
|
|
object should be freed:
|
|
</para>
|
|
<informalexample>
|
|
<xi:include href="snippets/TLS-GNUTLS-Credentials-Close.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</informalexample>
|
|
<para>
|
|
During its lifetime, the credentials object can be used to
|
|
initialize TLS session objects from multiple threads, provided
|
|
that it is not changed.
|
|
</para>
|
|
<para>
|
|
Once the TCP connection has been established, the Nagle
|
|
algorithm should be disabled (see <xref
|
|
linkend="ex-Defensive_Coding-TLS-Nagle"/>). After that, the
|
|
socket can be associated with a new GNUTLS session object.
|
|
The previously allocated credentials object provides the set
|
|
of root CAs. The <literal>NORMAL</literal> set of cipher
|
|
suites and protocols provides a reasonable default. Then the
|
|
TLS handshake must be initiated. This is shown in <xref
|
|
linkend="ex-Defensive_Coding-TLS-Client-GNUTLS-Connect"/>.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-Client-GNUTLS-Connect">
|
|
<title>Establishing a TLS client connection using GNUTLS</title>
|
|
<xi:include href="snippets/TLS-Client-GNUTLS-Connect.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
After the handshake has been completed, the server certificate
|
|
needs to be verified (<xref
|
|
linkend="ex-Defensive_Coding-TLS-Client-GNUTLS-Verify"/>). In
|
|
the example, the user-defined
|
|
<function>certificate_validity_override</function> function is
|
|
called if the verification fails, so that a separate,
|
|
user-specific trust store can be checked. This function call
|
|
can be omitted if the functionality is not needed.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-Client-GNUTLS-Verify">
|
|
<title>Verifying a server certificate using GNUTLS</title>
|
|
<xi:include href="snippets/TLS-Client-GNUTLS-Verify.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
In the next step (<xref
|
|
linkend="ex-Defensive_Coding-TLS-Client-GNUTLS-Match"/>, the
|
|
certificate must be matched against the host name (note the
|
|
unusual return value from
|
|
<function>gnutls_x509_crt_check_hostname</function>). Again,
|
|
an override function
|
|
<function>certificate_host_name_override</function> is called.
|
|
Note that the override must be keyed to the certificate
|
|
<emphasis>and</emphasis> the host name. The function call can
|
|
be omitted if the override is not needed.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-Client-GNUTLS-Match">
|
|
<title>Matching the server host name and certificate in a
|
|
GNUTLS client</title>
|
|
<xi:include href="snippets/TLS-Client-GNUTLS-Match.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
In newer GNUTLS versions, certificate checking and host name
|
|
validation can be combined using the
|
|
<function>gnutls_certificate_verify_peers3</function> function.
|
|
</para>
|
|
<para>
|
|
An established TLS session can be used for sending and
|
|
receiving data, as in <xref
|
|
linkend="ex-Defensive_Coding-TLS-GNUTLS-Use"/>.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-GNUTLS-Use">
|
|
<title>Using a GNUTLS session</title>
|
|
<xi:include href="snippets/TLS-GNUTLS-Use.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
In order to shut down a connection in an orderly manner, you
|
|
should call the <function>gnutls_bye</function> function.
|
|
Finally, the session object can be deallocated using
|
|
<function>gnutls_deinit</function> (see <xref
|
|
linkend="ex-Defensive_Coding-TLS-GNUTLS-Disconnect"/>).
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-GNUTLS-Disconnect">
|
|
<title>Using a GNUTLS session</title>
|
|
<xi:include href="snippets/TLS-GNUTLS-Disconnect.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
</section>
|
|
<section id="sect-Defensive_Coding-TLS-Client-OpenJDK">
|
|
<title>Implementing TLS Clients With OpenJDK</title>
|
|
<para>
|
|
The examples below use the following cryptographic-related
|
|
classes:
|
|
</para>
|
|
<informalexample>
|
|
<xi:include href="snippets/TLS-Client-OpenJDK-Import.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</informalexample>
|
|
<para>
|
|
If compatibility with OpenJDK 6 is required, it is necessary
|
|
to use the internal class
|
|
<literal>sun.security.util.HostnameChecker</literal>. (The
|
|
public OpenJDK API does not provide any support for dissecting
|
|
the subject distinguished name of an X.509 certificate, so a
|
|
custom-written DER parser is needed—or we have to use an
|
|
internal class, which we do below.) In OpenJDK 7, the
|
|
<function>setEndpointIdentificationAlgorithm</function> method
|
|
was added to the
|
|
<literal>javax.net.ssl.SSLParameters</literal> class,
|
|
providing an official way to implement host name checking.
|
|
</para>
|
|
<para>
|
|
TLS connections are established using an
|
|
<literal>SSLContext</literal> instance. With a properly
|
|
configured OpenJDK installation, the
|
|
<literal>SunJSSE</literal> provider uses the system-wide set
|
|
of trusted root certificate authorities, so no further
|
|
configuration is necessary. For backwards compatibility with
|
|
OpenJDK 6, the <literal>TLSv1</literal> provider has to
|
|
be supported as a fall-back option. This is shown in <xref
|
|
linkend="ex-Defensive_Coding-TLS-Client-OpenJDK-Context"/>.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-Client-OpenJDK-Context">
|
|
<title>Setting up an <literal>SSLContext</literal> for OpenJDK TLS
|
|
clients</title>
|
|
<xi:include href="snippets/TLS-Client-OpenJDK-Context.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
In addition to the context, a TLS parameter object will be
|
|
needed which adjusts the cipher suites and protocols (<xref
|
|
linkend="ex-Defensive_Coding-TLS-OpenJDK-Parameters"/>). Like
|
|
the context, these parameters can be reused for multiple TLS
|
|
connections.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-OpenJDK-Parameters">
|
|
<title>Setting up <literal>SSLParameters</literal> for TLS use
|
|
with OpenJDK</title>
|
|
<xi:include href="snippets/TLS-OpenJDK-Parameters.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
As initialized above, the parameter object does not yet
|
|
require host name checking. This has to be enabled
|
|
separately, and this is only supported by OpenJDK 7 and later:
|
|
</para>
|
|
<informalexample>
|
|
<xi:include href="snippets/TLS-Client-OpenJDK-Hostname.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</informalexample>
|
|
<para>
|
|
All application protocols can use the
|
|
<literal>"HTTPS"</literal> algorithm. (The algorithms have
|
|
minor differences with regard to wildcard handling, which
|
|
should not matter in practice.)
|
|
</para>
|
|
<para>
|
|
<xref linkend="ex-Defensive_Coding-TLS-Client-OpenJDK-Connect"/>
|
|
shows how to establish the connection. Before the handshake
|
|
is initialized, the protocol and cipher configuration has to
|
|
be performed, by applying the parameter object
|
|
<literal>params</literal>. (After this point, changes to
|
|
<literal>params</literal> will not affect this TLS socket.)
|
|
As mentioned initially, host name checking requires using an
|
|
internal API on OpenJDK 6.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-Client-OpenJDK-Connect">
|
|
<title>Establishing a TLS connection with OpenJDK</title>
|
|
<xi:include href="snippets/TLS-Client-OpenJDK-Connect.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
Starting with OpenJDK 7, the last lines can be omitted,
|
|
provided that host name verification has been enabled by
|
|
calling the
|
|
<function>setEndpointIdentificationAlgorithm</function> method
|
|
on the <literal>params</literal> object (before it was applied
|
|
to the socket).
|
|
</para>
|
|
<para>
|
|
The TLS socket can be used as a regular socket, as shown in
|
|
<xref linkend="ex-Defensive_Coding-TLS-Client-OpenJDK-Use"/>.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-Client-OpenJDK-Use">
|
|
<title>Using a TLS client socket in OpenJDK</title>
|
|
<xi:include href="snippets/TLS-Client-OpenJDK-Use.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<section>
|
|
<title>Overriding server certificate validation with OpenJDK 6</title>
|
|
<para>
|
|
Overriding certificate validation requires a custom trust
|
|
manager. With OpenJDK 6, the trust manager lacks
|
|
information about the TLS session, and to which server the
|
|
connection is made. Certificate overrides have to be tied
|
|
to specific servers (host names). Consequently, different
|
|
<literal>TrustManager</literal> and
|
|
<literal>SSLContext</literal> objects have to be used for
|
|
different servers.
|
|
</para>
|
|
<para>
|
|
In the trust manager shown in <xref
|
|
linkend="ex-Defensive_Coding-TLS-Client-MyTrustManager"/>,
|
|
the server certificate is identified by its SHA-256 hash.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-Client-MyTrustManager">
|
|
<title>A customer trust manager for OpenJDK TLS clients</title>
|
|
<xi:include href="snippets/TLS-Client-OpenJDK-MyTrustManager.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
This trust manager has to be passed to the
|
|
<literal>init</literal> method of the
|
|
<literal>SSLContext</literal> object, as show in <xref
|
|
linkend="ex-Defensive_Coding-TLS-Client-Context_For_Cert"/>.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-Client-Context_For_Cert">
|
|
<title>Using a custom TLS trust manager with OpenJDK</title>
|
|
<xi:include href="snippets/TLS-Client-OpenJDK-Context_For_Cert.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
When certificate overrides are in place, host name
|
|
verification should not be performed because there is no
|
|
security requirement that the host name in the certificate
|
|
matches the host name used to establish the connection (and
|
|
it often will not). However, without host name
|
|
verification, it is not possible to perform transparent
|
|
fallback to certification validation using the system
|
|
certificate store.
|
|
</para>
|
|
<para>
|
|
The approach described above works with OpenJDK 6 and later
|
|
versions. Starting with OpenJDK 7, it is possible to use a
|
|
custom subclass of the
|
|
<literal>javax.net.ssl.X509ExtendedTrustManager</literal>
|
|
class. The OpenJDK TLS implementation will call the new
|
|
methods, passing along TLS session information. This can be
|
|
used to implement certificate overrides as a fallback (if
|
|
certificate or host name verification fails), and a trust
|
|
manager object can be used for multiple servers because the
|
|
server address is available to the trust manager.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
<section id="sect-Defensive_Coding-TLS-Client-NSS">
|
|
<title>Implementing TLS Clients With NSS</title>
|
|
<para>
|
|
The following code shows how to implement a simple TLS client
|
|
using NSS. Note that the error handling needs replacing
|
|
before production use.
|
|
</para>
|
|
<para>
|
|
Using NSS needs several header files, as shown in
|
|
<xref linkend="ex-Defensive_Coding-TLS-NSS-Includes"/>.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-NSS-Includes">
|
|
<title>Include files for NSS</title>
|
|
<xi:include href="snippets/TLS-NSS-Includes.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
Initializing the NSS library is a complex task (<xref
|
|
linkend="ex-Defensive_Coding-TLS-NSS-Init"/>). It is not
|
|
thread-safe. By default, the library is in export mode, and
|
|
all strong ciphers are disabled. Therefore, after creating
|
|
the <literal>NSSInitCContext</literal> object, we probe all
|
|
the strong ciphers we want to use, and check if at least one
|
|
of them is available. If not, we call
|
|
<function>NSS_SetDomesticPolicy</function> to switch to
|
|
unrestricted policy mode. This function replaces the existing
|
|
global cipher suite policy, that is why we avoid calling it
|
|
unless absolutely necessary.
|
|
</para>
|
|
<para>
|
|
The simplest way to configured the trusted root certificates
|
|
involves loading the <filename>libnssckbi.so</filename> NSS
|
|
module with a call to the
|
|
<function>SECMOD_LoadUserModule</function> function. The root
|
|
certificates are compiled into this module. (The PEM module
|
|
for NSS, <filename>libnsspem.so</filename>, offers a way to
|
|
load trusted CA certificates from a file.)
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-NSS-Init">
|
|
<title>Initializing the NSS library</title>
|
|
<xi:include href="snippets/TLS-NSS-Init.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
Some of the effects of the initialization can be reverted with
|
|
the following function calls:
|
|
</para>
|
|
<informalexample id="ex-Defensive_Coding-TLS-NSS-Close">
|
|
<xi:include href="snippets/TLS-NSS-Close.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</informalexample>
|
|
<para>
|
|
After NSS has been initialized, the TLS connection can be
|
|
created (<xref
|
|
linkend="ex-Defensive_Coding-TLS-Client-NSS-Connect"/>). The
|
|
internal <function>PR_ImportTCPSocket</function> function is
|
|
used to turn the POSIX file descriptor
|
|
<literal>sockfd</literal> into an NSPR file descriptor. (This
|
|
function is de-facto part of the NSS public ABI, so it will
|
|
not go away.) Creating the TLS-capable file descriptor
|
|
requires a <emphasis>model</emphasis> descriptor, which is
|
|
configured with the desired set of protocols and ciphers.
|
|
(The <literal>good_ciphers</literal> variable is part of <xref
|
|
linkend="ex-Defensive_Coding-TLS-NSS-Init"/>.) We cannot
|
|
resort to disabling ciphers not on a whitelist because by
|
|
default, the AES cipher suites are disabled. The model
|
|
descriptor is not needed anymore after TLS support has been
|
|
activated for the existing connection descriptor.
|
|
</para>
|
|
<para>
|
|
The call to <function>SSL_BadCertHook</function> can be
|
|
omitted if no mechanism to override certificate verification
|
|
is needed. The <literal>bad_certificate</literal> function
|
|
must check both the host name specified for the connection and
|
|
the certificate before granting the override.
|
|
</para>
|
|
<para>
|
|
Triggering the actual handshake requires three function calls,
|
|
<function>SSL_ResetHandshake</function>,
|
|
<function>SSL_SetURL</function>, and
|
|
<function>SSL_ForceHandshake</function>. (If
|
|
<function>SSL_ResetHandshake</function> is omitted,
|
|
<function>SSL_ForceHandshake</function> will succeed, but the
|
|
data will not be encrypted.) During the handshake, the
|
|
certificate is verified and matched against the host name.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-Client-NSS-Connect">
|
|
<title>Creating a TLS connection with NSS</title>
|
|
<xi:include href="snippets/TLS-Client-NSS-Connect.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
After the connection has been established, <xref
|
|
linkend="ex-Defensive_Coding-TLS-NSS-Use"/> shows how to use
|
|
the NSPR descriptor to communicate with the server.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-NSS-Use">
|
|
<title>Using NSS for sending and receiving data</title>
|
|
<xi:include href="snippets/TLS-NSS-Use.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
<xref linkend="ex-Defensive_Coding-TLS-Client-NSS-Close"/>
|
|
shows how to close the connection.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-Client-NSS-Close">
|
|
<title>Closing NSS client connections</title>
|
|
<xi:include href="snippets/TLS-Client-NSS-Close.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
</section>
|
|
<section id="sect-Defensive_Coding-TLS-Client-Python">
|
|
<title>Implementing TLS Clients With Python</title>
|
|
<para>
|
|
The Python distribution provides a TLS implementation in the
|
|
<literal>ssl</literal> module (actually a wrapper around
|
|
OpenSSL). The exported interface is somewhat restricted, so
|
|
that the client code shown below does not fully implement the
|
|
recommendations in <xref
|
|
linkend="sect-Defensive_Coding-TLS-OpenSSL"/>.
|
|
</para>
|
|
<important>
|
|
<para>
|
|
Currently, most Python function which accept
|
|
<literal>https://</literal> URLs or otherwise implement
|
|
HTTPS support do not perform certificate validation at all.
|
|
(For example, this is true for the <literal>httplib</literal>
|
|
and <literal>xmlrpclib</literal> modules.) If you use
|
|
HTTPS, you should not use the built-in HTTP clients. The
|
|
<literal>Curl</literal> class in the <literal>curl</literal>
|
|
module, as provided by the <literal>python-pycurl</literal>
|
|
package implements proper certificate validation.
|
|
</para>
|
|
</important>
|
|
<para>
|
|
The <literal>ssl</literal> module currently does not perform
|
|
host name checking on the server certificate. <xref
|
|
linkend="ex-Defensive_Coding-TLS-Client-Python-check_host_name"/>
|
|
shows how to implement certificate matching, using the parsed
|
|
certificate returned by <function>getpeercert</function>.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-Client-Python-check_host_name">
|
|
<title>Implementing TLS host name checking Python (without
|
|
wildcard support)</title>
|
|
<xi:include href="snippets/TLS-Client-Python-check_host_name.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
To turn a regular, connected TCP socket into a TLS-enabled
|
|
socket, use the <function>ssl.wrap_socket</function> function.
|
|
The function call in <xref
|
|
linkend="ex-Defensive_Coding-TLS-Client-Python-Connect"/>
|
|
provides additional arguments to override questionable
|
|
defaults in OpenSSL and in the Python module.
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<literal>ciphers="HIGH:-aNULL:-eNULL:-PSK:RC4-SHA:RC4-MD5"</literal>
|
|
selects relatively strong cipher suites with
|
|
certificate-based authentication. (The call to
|
|
<function>check_host_name</function> function provides
|
|
additional protection against anonymous cipher suites.)
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>ssl_version=ssl.PROTOCOL_TLSv1</literal> disables
|
|
SSL 2.0 support. By default, the <literal>ssl</literal>
|
|
module sends an SSL 2.0 client hello, which is rejected by
|
|
some servers. Ideally, we would request OpenSSL to
|
|
negotiated the most recent TLS version supported by the
|
|
server and the client, but the Python module does not
|
|
allow this.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>cert_reqs=ssl.CERT_REQUIRED</literal> turns on
|
|
certificate validation.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<literal>ca_certs='/etc/ssl/certs/ca-bundle.crt'</literal>
|
|
initializes the certificate store with a set of trusted
|
|
root CAs. Unfortunately, it is necessary to hard-code
|
|
this path into applications because the default path in
|
|
OpenSSL is not available through the Python
|
|
<literal>ssl</literal> module.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
The <literal>ssl</literal> module (and OpenSSL) perform
|
|
certificate validation, but the certificate must be compared
|
|
manually against the host name, by calling the
|
|
<function>check_host_name</function> defined above.
|
|
</para>
|
|
<example id="ex-Defensive_Coding-TLS-Client-Python-Connect">
|
|
<title>Establishing a TLS client connection with Python</title>
|
|
<xi:include href="snippets/TLS-Client-Python-Connect.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</example>
|
|
<para>
|
|
After the connection has been established, the TLS socket can
|
|
be used like a regular socket:
|
|
</para>
|
|
<informalexample>
|
|
<xi:include href="snippets/TLS-Python-Use.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</informalexample>
|
|
<para>
|
|
Closing the TLS socket is straightforward as well:
|
|
</para>
|
|
<informalexample>
|
|
<xi:include href="snippets/TLS-Python-Close.xml"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" />
|
|
</informalexample>
|
|
</section>
|
|
</section>
|
|
</chapter>
|