944 lines
30 KiB
Text
944 lines
30 KiB
Text
|
|
:experimental:
|
|
|
|
[[chap-Defensive_Coding-TLS]]
|
|
= Transport Layer Security (TLS)
|
|
include::{partialsdir}/entities.adoc[]
|
|
|
|
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. At this
|
|
chapter we describe the available libraries in Fedora as well
|
|
as known pitfalls, and safe ways to write applications with them.
|
|
|
|
When using any library, in addition to this guide, it is recommended to consult the
|
|
library' documentation.
|
|
|
|
* link:++https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS++[NSS documentation]
|
|
|
|
* link:++http://www.gnutls.org/manual/++[GnuTLS documentation]
|
|
|
|
* link:++https://www.openssl.org/docs/++[OpenSSL documentation]
|
|
|
|
* link:++https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html++[OpenJDK documentation]
|
|
|
|
[[sect-Defensive_Coding-TLS-Pitfalls]]
|
|
== Common Pitfalls
|
|
|
|
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.
|
|
|
|
* 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.
|
|
+
|
|
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.
|
|
|
|
* 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.
|
|
|
|
* The TLS handshake has very poor performance if the TCP Nagle
|
|
algorithm is active. You should switch on the
|
|
`TCP_NODELAY` socket option (at least for the
|
|
duration of the handshake), or use the Linux-specific
|
|
`TCP_CORK` option.
|
|
+
|
|
[[ex-Defensive_Coding-TLS-Nagle]]
|
|
.Deactivating the TCP Nagle algorithm
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Nagle.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
* 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).
|
|
|
|
* Both client and server should work towards an orderly
|
|
connection shutdown, that is send
|
|
`close_notify` 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).
|
|
|
|
* 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 `accept` 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.
|
|
|
|
* 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 `fork` function
|
|
calls (see <<sect-Defensive_Coding-Tasks-Processes-Fork-Parallel>>).
|
|
|
|
[[sect-Defensive_Coding-TLS-OpenSSL]]
|
|
=== OpenSSL Pitfalls
|
|
|
|
Some OpenSSL function use *tri-state return
|
|
values*. Correct error checking is extremely
|
|
important. Several functions return `int`
|
|
values with the following meaning:
|
|
|
|
* The value `1` indicates success (for
|
|
example, a successful signature verification).
|
|
|
|
* The value `0` indicates semantic
|
|
failure (for example, a signature verification which was
|
|
unsuccessful because the signing certificate was
|
|
self-signed).
|
|
|
|
* The value `-1` indicates a low-level
|
|
error in the system, such as failure to allocate memory
|
|
using `malloc`.
|
|
|
|
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.
|
|
|
|
Recovering precise error information is difficult.
|
|
<<ex-Defensive_Coding-TLS-OpenSSL-Errors>>
|
|
shows how to obtain a more precise error code after a function
|
|
call on an `SSL` object has failed. However,
|
|
there are still cases where no detailed error information is
|
|
available (e.g., if `SSL_shutdown` fails
|
|
due to a connection teardown by the other end).
|
|
|
|
[[ex-Defensive_Coding-TLS-OpenSSL-Errors]]
|
|
.Obtaining OpenSSL error codes
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-OpenSSL-Errors.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
The `OPENSSL_config` 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.
|
|
|
|
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 `d2i_` and end in
|
|
`_fp` or `_bio` (e.g.,
|
|
`d2i_X509_fp` or
|
|
`d2i_X509_bio`). These decoders must not
|
|
be used for parsing data from untrusted sources; instead,
|
|
the variants without the `_fp` and
|
|
`_bio` (e.g.,
|
|
`d2i_X509`) shall be used. The BIO
|
|
variants have received considerably less testing and are not
|
|
very robust.
|
|
|
|
For the same reason, the OpenSSL command line tools (such as
|
|
[command]`openssl x509`) are generally generally less
|
|
robust than the actual library code. They use the BIO
|
|
functions internally, and not the more robust variants.
|
|
|
|
The command line tools do not always indicate failure in the
|
|
exit status of the [application]*openssl* process.
|
|
For instance, a verification failure in [command]`openssl
|
|
verify` result in an exit status of zero.
|
|
|
|
OpenSSL command-line commands, such as [command]`openssl
|
|
genrsa`, do not ensure that physical entropy is used
|
|
for key generation—they obtain entropy from
|
|
`/dev/urandom` and other sources, but not
|
|
from `/dev/random`. This can result in
|
|
weak keys if the system lacks a proper entropy source (e.g., a
|
|
virtual machine with solid state storage). Depending on local
|
|
policies, keys generated by these OpenSSL tools should not be
|
|
used in high-value, critical functions.
|
|
|
|
The OpenSSL server and client applications ([command]`openssl
|
|
s_client` and [command]`openssl s_server`)
|
|
are debugging tools and should *never* be
|
|
used as generic clients. For instance, the
|
|
[application]*s_client* tool reacts in a
|
|
surprising way to lines starting with `R` and
|
|
`Q`.
|
|
|
|
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.
|
|
|
|
[[sect-Defensive_Coding-TLS-Pitfalls-GnuTLS]]
|
|
=== GnuTLS Pitfalls
|
|
|
|
Older versions of GnuTLS had several peculiarities described
|
|
in previous versions of this guide; as of GnuTLS 3.3.10, these
|
|
issues are no longer applicable.
|
|
|
|
[[sect-Defensive_Coding-TLS-Pitfalls-OpenJDK]]
|
|
=== OpenJDK Pitfalls
|
|
|
|
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.
|
|
|
|
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 *unlimited
|
|
strength jurisdiction policy files*. 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.
|
|
|
|
Some versions of OpenJDK use `/dev/random`
|
|
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
|
|
`/dev/random`.
|
|
|
|
[[sect-Defensive_Coding-TLS-Pitfalls-NSS]]
|
|
=== NSS Pitfalls
|
|
|
|
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.
|
|
|
|
If the NSPR descriptor is in an unexpected state, the
|
|
`SSL_ForceHandshake` function can succeed,
|
|
but no TLS handshake takes place, the peer is not
|
|
authenticated, and subsequent data is exchanged in the clear.
|
|
|
|
NSS disables itself if it detects that the process underwent a
|
|
`fork` after the library has been
|
|
initialized. This behavior is required by the PKCS#11 API
|
|
specification.
|
|
|
|
[[sect-Defensive_Coding-TLS-Client]]
|
|
== TLS Clients
|
|
|
|
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.)
|
|
|
|
* The client must configure the TLS library to use a set of
|
|
trusted root certificates. These certificates are provided
|
|
by the system in various formats and files. These are documented in `update-ca-trust`
|
|
man page in Fedora. Portable applications should not hard-code
|
|
any paths; they should rely on APIs which set the default
|
|
for the system trust store.
|
|
|
|
* The client selects sufficiently strong cryptographic
|
|
primitives and disables insecure ones (such as no-op
|
|
encryption). Compression support and SSL version 3 or lower must be
|
|
disabled (including the SSLv2-compatible handshake).
|
|
|
|
* 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.
|
|
|
|
* 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.)
|
|
|
|
* The client must check that the configured or user-provided
|
|
server name matches the peer certificate provided by the
|
|
server.
|
|
|
|
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.
|
|
|
|
[IMPORTANT]
|
|
====
|
|
|
|
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.
|
|
|
|
====
|
|
|
|
=== Implementation TLS Clients With OpenSSL
|
|
|
|
In the following code, the error handling is only exploratory.
|
|
Proper error handling is required for production use,
|
|
especially in libraries.
|
|
|
|
The OpenSSL library needs explicit initialization (see <<ex-Defensive_Coding-TLS-OpenSSL-Init>>).
|
|
|
|
[[ex-Defensive_Coding-TLS-OpenSSL-Init]]
|
|
.OpenSSL library initialization
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-OpenSSL-Init.adoc[]
|
|
|
|
----
|
|
|
|
====
|
|
|
|
After that, a context object has to be created, which acts as
|
|
a factory for connection objects (<<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.
|
|
|
|
[[ex-Defensive_Coding-TLS-Client-OpenSSL-CTX]]
|
|
.OpenSSL client context creation
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-OpenSSL-CTX.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
A single context object can be used to create multiple
|
|
connection objects. It is safe to use the same
|
|
`SSL_CTX` object for creating connections
|
|
concurrently from multiple threads, provided that the
|
|
`SSL_CTX` object is not modified (e.g.,
|
|
callbacks must not be changed).
|
|
|
|
After creating the TCP socket and disabling the Nagle
|
|
algorithm (per <<ex-Defensive_Coding-TLS-Nagle>>), the actual
|
|
connection object needs to be created, as show in <<ex-Defensive_Coding-TLS-Client-OpenSSL-CTX>>. If
|
|
the handshake started by `SSL_connect`
|
|
fails, the `ssl_print_error_and_exit`
|
|
function from <<ex-Defensive_Coding-TLS-OpenSSL-Errors>> is called.
|
|
|
|
The `certificate_validity_override`
|
|
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.
|
|
|
|
The host name passed to the functions
|
|
`SSL_set_tlsext_host_name` and
|
|
`X509_check_host` must be the name that was
|
|
passed to `getaddrinfo` or a similar name
|
|
resolution function. No host name canonicalization must be
|
|
performed. The `X509_check_host` 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
|
|
`certificate_host_name_override` 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 *and* the host
|
|
name.
|
|
|
|
[[ex-Defensive_Coding-TLS-Client-OpenSSL-Connect]]
|
|
.Creating a client connection using OpenSSL
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-OpenSSL-Connect.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
The connection object can be used for sending and receiving
|
|
data, as in <<ex-Defensive_Coding-TLS-OpenSSL-Connection-Use>>.
|
|
It is also possible to create a `BIO` object
|
|
and use the `SSL` object as the underlying
|
|
transport, using `BIO_set_ssl`.
|
|
|
|
[[ex-Defensive_Coding-TLS-OpenSSL-Connection-Use]]
|
|
.Using an OpenSSL connection to send and receive data
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-OpenSSL-Connection-Use.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
When it is time to close the connection, the
|
|
`SSL_shutdown` function needs to be called
|
|
twice for an orderly, synchronous connection termination
|
|
(<<ex-Defensive_Coding-TLS-OpenSSL-Connection-Close>>).
|
|
This exchanges `close_notify` alerts with the
|
|
server. The additional logic is required to deal with an
|
|
unexpected `close_notify` from the server.
|
|
Note that is necessary to explicitly close the underlying
|
|
socket after the connection object has been freed.
|
|
|
|
[[ex-Defensive_Coding-TLS-OpenSSL-Connection-Close]]
|
|
.Closing an OpenSSL connection in an orderly fashion
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-OpenSSL-Connection-Close.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
<<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.
|
|
|
|
[[ex-Defensive_Coding-TLS-OpenSSL-Context-Close]]
|
|
.Closing an OpenSSL connection in an orderly fashion
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-OpenSSL-Context-Close.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
[[sect-Defensive_Coding-TLS-Client-GnuTLS]]
|
|
=== Implementation TLS Clients With GnuTLS
|
|
|
|
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.
|
|
|
|
Before setting up TLS connections, a credentials objects has
|
|
to be allocated and initialized with the set of trusted root
|
|
CAs (<<ex-Defensive_Coding-TLS-Client-GNUTLS-Credentials>>).
|
|
|
|
[[ex-Defensive_Coding-TLS-Client-GNUTLS-Credentials]]
|
|
.Initializing a GnuTLS credentials structure
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-GNUTLS-Credentials.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
After the last TLS connection has been closed, this credentials
|
|
object should be freed:
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-GNUTLS-Credentials-Close.adoc[]
|
|
----
|
|
|
|
During its lifetime, the credentials object can be used to
|
|
initialize TLS session objects from multiple threads, provided
|
|
that it is not changed.
|
|
|
|
Once the TCP connection has been established, the Nagle
|
|
algorithm should be disabled (see <<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. Then the TLS handshake must be initiated.
|
|
This is shown in <<ex-Defensive_Coding-TLS-Client-GNUTLS-Connect>>.
|
|
|
|
[[ex-Defensive_Coding-TLS-Client-GNUTLS-Connect]]
|
|
.Establishing a TLS client connection using GnuTLS
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-GNUTLS-Connect.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
After the handshake has been completed, the server certificate
|
|
needs to be verified against the server's hostname (<<ex-Defensive_Coding-TLS-Client-GNUTLS-Verify>>). In
|
|
the example, the user-defined
|
|
`certificate_validity_override` 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.
|
|
|
|
[[ex-Defensive_Coding-TLS-Client-GNUTLS-Verify]]
|
|
.Verifying a server certificate using GnuTLS
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-GNUTLS-Verify.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
An established TLS session can be used for sending and
|
|
receiving data, as in <<ex-Defensive_Coding-TLS-GNUTLS-Use>>.
|
|
|
|
[[ex-Defensive_Coding-TLS-GNUTLS-Use]]
|
|
.Using a GnuTLS session
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-GNUTLS-Use.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
In order to shut down a connection in an orderly manner, you
|
|
should call the `gnutls_bye` function.
|
|
Finally, the session object can be deallocated using
|
|
`gnutls_deinit` (see <<ex-Defensive_Coding-TLS-GNUTLS-Disconnect>>).
|
|
|
|
[[ex-Defensive_Coding-TLS-GNUTLS-Disconnect]]
|
|
.Closing a GnuTLS session in an orderly fashion
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-GNUTLS-Disconnect.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
[[sect-Defensive_Coding-TLS-Client-OpenJDK]]
|
|
=== Implementing TLS Clients With OpenJDK
|
|
|
|
The examples below use the following cryptographic-related
|
|
classes:
|
|
|
|
[source,java]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-OpenJDK-Import.adoc[]
|
|
|
|
----
|
|
|
|
If compatibility with OpenJDK 6 is required, it is necessary
|
|
to use the internal class
|
|
`sun.security.util.HostnameChecker`. (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
|
|
`setEndpointIdentificationAlgorithm` method
|
|
was added to the
|
|
`javax.net.ssl.SSLParameters` class,
|
|
providing an official way to implement host name checking.
|
|
|
|
TLS connections are established using an
|
|
`SSLContext` instance. With a properly
|
|
configured OpenJDK installation, the
|
|
`SunJSSE` provider uses the system-wide set
|
|
of trusted root certificate authorities, so no further
|
|
configuration is necessary. For backwards compatibility with
|
|
OpenJDK{nbsp}6, the `TLSv1` provider has to
|
|
be supported as a fall-back option. This is shown in <<ex-Defensive_Coding-TLS-Client-OpenJDK-Context>>.
|
|
|
|
[[ex-Defensive_Coding-TLS-Client-OpenJDK-Context]]
|
|
.Setting up an `SSLContext` for OpenJDK TLS clients
|
|
====
|
|
|
|
[source,java]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-OpenJDK-Context.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
In addition to the context, a TLS parameter object will be
|
|
needed which adjusts the cipher suites and protocols (<<ex-Defensive_Coding-TLS-OpenJDK-Parameters>>). Like
|
|
the context, these parameters can be reused for multiple TLS
|
|
connections.
|
|
|
|
[[ex-Defensive_Coding-TLS-OpenJDK-Parameters]]
|
|
.Setting up `SSLParameters` for TLS use with OpenJDK
|
|
====
|
|
|
|
[source,java]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-OpenJDK-Parameters.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
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:
|
|
|
|
[source,java]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-OpenJDK-Hostname.adoc[]
|
|
----
|
|
|
|
All application protocols can use the
|
|
`"HTTPS"` algorithm. (The algorithms have
|
|
minor differences with regard to wildcard handling, which
|
|
should not matter in practice.)
|
|
|
|
<<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
|
|
`params`. (After this point, changes to
|
|
`params` will not affect this TLS socket.)
|
|
As mentioned initially, host name checking requires using an
|
|
internal API on OpenJDK 6.
|
|
|
|
[[ex-Defensive_Coding-TLS-Client-OpenJDK-Connect]]
|
|
.Establishing a TLS connection with OpenJDK
|
|
====
|
|
|
|
[source,java]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-OpenJDK-Connect.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
Starting with OpenJDK 7, the last lines can be omitted,
|
|
provided that host name verification has been enabled by
|
|
calling the
|
|
`setEndpointIdentificationAlgorithm` method
|
|
on the `params` object (before it was applied
|
|
to the socket).
|
|
|
|
The TLS socket can be used as a regular socket, as shown in
|
|
<<ex-Defensive_Coding-TLS-Client-OpenJDK-Use>>.
|
|
|
|
[[ex-Defensive_Coding-TLS-Client-OpenJDK-Use]]
|
|
.Using a TLS client socket in OpenJDK
|
|
====
|
|
|
|
[source,java]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-OpenJDK-Use.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
==== Overriding server certificate validation with OpenJDK 6
|
|
|
|
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
|
|
`TrustManager` and
|
|
`SSLContext` objects have to be used for
|
|
different servers.
|
|
|
|
In the trust manager shown in <<ex-Defensive_Coding-TLS-Client-MyTrustManager>>,
|
|
the server certificate is identified by its SHA-256 hash.
|
|
|
|
[[ex-Defensive_Coding-TLS-Client-MyTrustManager]]
|
|
.A customer trust manager for OpenJDK TLS clients
|
|
====
|
|
|
|
[source,java]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-OpenJDK-MyTrustManager.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
This trust manager has to be passed to the
|
|
`init` method of the
|
|
`SSLContext` object, as show in <<ex-Defensive_Coding-TLS-Client-Context_For_Cert>>.
|
|
|
|
[[ex-Defensive_Coding-TLS-Client-Context_For_Cert]]
|
|
.Using a custom TLS trust manager with OpenJDK
|
|
====
|
|
|
|
[source,java]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-OpenJDK-Context_For_Cert.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
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.
|
|
|
|
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
|
|
`javax.net.ssl.X509ExtendedTrustManager`
|
|
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.
|
|
|
|
[[sect-Defensive_Coding-TLS-Client-NSS]]
|
|
=== Implementing TLS Clients With NSS
|
|
|
|
The following code shows how to implement a simple TLS client
|
|
using NSS. These instructions apply to NSS version 3.14 and
|
|
later. Versions before 3.14 need different initialization
|
|
code.
|
|
|
|
Keep in mind that the error handling needs to be improved
|
|
before the code can be used in production.
|
|
|
|
Using NSS needs several header files, as shown in
|
|
<<ex-Defensive_Coding-TLS-NSS-Includes>>.
|
|
|
|
[[ex-Defensive_Coding-TLS-NSS-Includes]]
|
|
.Include files for NSS
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-NSS-Includes.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
Initializing the NSS library is shown in <<ex-Defensive_Coding-TLS-NSS-Init>>. This
|
|
initialization procedure overrides global state. We only call
|
|
`NSS_SetDomesticPolicy` if there are no
|
|
strong ciphers available, assuming that it has already been
|
|
called otherwise. This avoids overriding the process-wide
|
|
cipher suite policy unnecessarily.
|
|
|
|
The simplest way to configured the trusted root certificates
|
|
involves loading the `libnssckbi.so` NSS
|
|
module with a call to the
|
|
`SECMOD_LoadUserModule` function. The root
|
|
certificates are compiled into this module. (The PEM module
|
|
for NSS, `libnsspem.so`, offers a way to
|
|
load trusted CA certificates from a file.)
|
|
|
|
[[ex-Defensive_Coding-TLS-NSS-Init]]
|
|
.Initializing the NSS library
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-NSS-Init.adoc[]
|
|
|
|
----
|
|
|
|
====
|
|
|
|
Some of the effects of the initialization can be reverted with
|
|
the following function calls:
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-NSS-Close.adoc[]
|
|
----
|
|
|
|
After NSS has been initialized, the TLS connection can be
|
|
created (<<ex-Defensive_Coding-TLS-Client-NSS-Connect>>). The
|
|
internal `PR_ImportTCPSocket` function is
|
|
used to turn the POSIX file descriptor
|
|
`sockfd` 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 *model* descriptor, which is
|
|
configured with the desired set of protocols. The model
|
|
descriptor is not needed anymore after TLS support has been
|
|
activated for the existing connection descriptor.
|
|
|
|
The call to `SSL_BadCertHook` can be
|
|
omitted if no mechanism to override certificate verification
|
|
is needed. The `bad_certificate` function
|
|
must check both the host name specified for the connection and
|
|
the certificate before granting the override.
|
|
|
|
Triggering the actual handshake requires three function calls,
|
|
`SSL_ResetHandshake`,
|
|
`SSL_SetURL`, and
|
|
`SSL_ForceHandshake`. (If
|
|
`SSL_ResetHandshake` is omitted,
|
|
`SSL_ForceHandshake` will succeed, but the
|
|
data will not be encrypted.) During the handshake, the
|
|
certificate is verified and matched against the host name.
|
|
|
|
[[ex-Defensive_Coding-TLS-Client-NSS-Connect]]
|
|
.Creating a TLS connection with NSS
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-NSS-Connect.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
After the connection has been established, <<ex-Defensive_Coding-TLS-NSS-Use>> shows how to use
|
|
the NSPR descriptor to communicate with the server.
|
|
|
|
[[ex-Defensive_Coding-TLS-NSS-Use]]
|
|
.Using NSS for sending and receiving data
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-NSS-Use.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
<<ex-Defensive_Coding-TLS-Client-NSS-Close>>
|
|
shows how to close the connection.
|
|
|
|
[[ex-Defensive_Coding-TLS-Client-NSS-Close]]
|
|
.Closing NSS client connections
|
|
====
|
|
|
|
[source,c]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-NSS-Close.adoc[]
|
|
|
|
----
|
|
|
|
====
|
|
|
|
[[sect-Defensive_Coding-TLS-Client-Python]]
|
|
=== Implementing TLS Clients With Python
|
|
|
|
The Python distribution provides a TLS implementation in the
|
|
`ssl` 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 <<sect-Defensive_Coding-TLS-OpenSSL>>.
|
|
|
|
[IMPORTANT]
|
|
====
|
|
|
|
Currently, most Python function which accept
|
|
`https://` URLs or otherwise implement
|
|
HTTPS support do not perform certificate validation at all.
|
|
(For example, this is true for the `httplib`
|
|
and `xmlrpclib` modules.) If you use
|
|
HTTPS, you should not use the built-in HTTP clients. The
|
|
`Curl` class in the `curl`
|
|
module, as provided by the `python-pycurl`
|
|
package implements proper certificate validation.
|
|
|
|
====
|
|
|
|
The `ssl` module currently does not perform
|
|
host name checking on the server certificate. <<ex-Defensive_Coding-TLS-Client-Python-check_host_name>>
|
|
shows how to implement certificate matching, using the parsed
|
|
certificate returned by `getpeercert`.
|
|
|
|
[[ex-Defensive_Coding-TLS-Client-Python-check_host_name]]
|
|
.Implementing TLS host name checking Python (without wildcard support)
|
|
====
|
|
|
|
[source,python]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-Python-check_host_name.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
To turn a regular, connected TCP socket into a TLS-enabled
|
|
socket, use the `ssl.wrap_socket` function.
|
|
The function call in <<ex-Defensive_Coding-TLS-Client-Python-Connect>>
|
|
provides additional arguments to override questionable
|
|
defaults in OpenSSL and in the Python module.
|
|
|
|
* `ciphers="HIGH:-aNULL:-eNULL:-PSK:RC4-SHA:RC4-MD5"`
|
|
selects relatively strong cipher suites with
|
|
certificate-based authentication. (The call to
|
|
`check_host_name` function provides
|
|
additional protection against anonymous cipher suites.)
|
|
|
|
* `ssl_version=ssl.PROTOCOL_TLSv1` disables
|
|
SSL 2.0 support. By default, the `ssl`
|
|
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.
|
|
|
|
* `cert_reqs=ssl.CERT_REQUIRED` turns on
|
|
certificate validation.
|
|
|
|
* `ca_certs='/etc/ssl/certs/ca-bundle.crt'`
|
|
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
|
|
`ssl` module.
|
|
|
|
The `ssl` module (and OpenSSL) perform
|
|
certificate validation, but the certificate must be compared
|
|
manually against the host name, by calling the
|
|
`check_host_name` defined above.
|
|
|
|
[[ex-Defensive_Coding-TLS-Client-Python-Connect]]
|
|
.Establishing a TLS client connection with Python
|
|
====
|
|
|
|
[source,python]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Client-Python-Connect.adoc[]
|
|
----
|
|
|
|
====
|
|
|
|
After the connection has been established, the TLS socket can
|
|
be used like a regular socket:
|
|
|
|
[source,python]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Python-Use.adoc[]
|
|
----
|
|
|
|
Closing the TLS socket is straightforward as well:
|
|
|
|
[source,python]
|
|
----
|
|
include::{partialsdir}/snippets/Features-TLS-Python-Close.adoc[]
|
|
----
|