defensive-coding-guide/_package/main/master/en-US/features/Features-TLS.html
Brian (bex) Exelbierd 2e8934be40 Converted to AsciiBinder
This required moving files around in the repository and shifting
from a master.adoc structure to _topic_map.yml, etc.

README and Makefile modified slightly to reflect new build process
2018-02-08 13:08:40 +01:00

1893 lines
No EOL
116 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>Defensive Coding Guide | Defensive Coding Guide | Implementing Security Features | Transport Layer Security (TLS)</title>
<!-- Bootstrap -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<!-- Overpass Font -->
<link rel="stylesheet" href="https://overpass-30e2.kxcdn.com/overpass.css">
<link href="../../../master/_stylesheets/asciibinder.css" rel="stylesheet" />
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<link href="../../../master/_images/favicon32x32.png" rel="shortcut icon" type="text/css">
<!--[if IE]><link rel="shortcut icon" href="../../../master/_images/favicon.ico"><![endif]-->
<meta content="AsciiBinder" name="application-name">
</head>
<body>
<div class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="https://docs.fedoraproject.org/"><img alt="Fedora Documentation" src="../../../master/_images/fedora.svg"></a>
</div>
</div>
</div>
<div class="container">
<p class="toggle-nav visible-xs pull-left">
<button class="btn btn-default btn-sm" type="button" data-toggle="offcanvas">Toggle nav</button>
</p>
<ol class="breadcrumb">
<li class="sitename">
<a href="../../../index.html">Home</a>
</li>
<li class="hidden-xs active">
<a href="../../en-US/index.html">Defensive Coding Guide </a>
</li>
<li class="hidden-xs active">
<a href="../../en-US/index.html">Defensive Coding Guide</a>
</li>
<li class="hidden-xs active"><a href="../../en-US/features/Features-Authentication.html">Implementing Security Features</a></li>
<li class="hidden-xs active">
Transport Layer Security (TLS)
</li>
</ol>
<div class="row row-offcanvas row-offcanvas-left">
<div class="col-xs-8 col-sm-3 col-md-3 sidebar sidebar-offcanvas">
<ul class="nav nav-sidebar">
<li class="nav-header">
<a class="" href="#" data-toggle="collapse" data-target="#topicGroup0">
<span id="tgSpan0" class="fa fa-angle-down"></span>Defensive Coding Guide
</a>
<ul id="topicGroup0" class="collapse in list-unstyled">
<li><a class="" href="../../en-US/index.html">Book Information</a></li>
<li class="nav-header">
<a class="" href="#" data-toggle="collapse" data-target="#topicSubGroup-0-1">
<span id="sgSpan-0-1" class="fa fa-caret-right"></span>&nbsp;Programming Languages
</a>
<ul id="topicSubGroup-0-1" class="nav-tertiary list-unstyled collapse">
<li><a class="" href="../../en-US/programming-languages/C.html">The C Programming Language</a></li>
<li><a class="" href="../../en-US/programming-languages/CXX.html">The C++ Programming&nbsp;Language</a></li>
<li><a class="" href="../../en-US/programming-languages/Java.html">The Java Programming Language</a></li>
<li><a class="" href="../../en-US/programming-languages/Python.html">The Python Programming Language</a></li>
<li><a class="" href="../../en-US/programming-languages/Shell.html">Shell Programming and bash</a></li>
<li><a class="" href="../../en-US/programming-languages/Go.html">The Go Programming Language</a></li>
<li><a class="" href="../../en-US/programming-languages/Vala.html">The Vala Programming Language</a></li>
</ul>
</li>
<li class="nav-header">
<a class="" href="#" data-toggle="collapse" data-target="#topicSubGroup-0-2">
<span id="sgSpan-0-2" class="fa fa-caret-right"></span>&nbsp;Specific Programming Tasks
</a>
<ul id="topicSubGroup-0-2" class="nav-tertiary list-unstyled collapse">
<li><a class="" href="../../en-US/tasks/Tasks-Library_Design.html">Library Design</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Descriptors.html">File Descriptor Management</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-File_System.html">File System Manipulation</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Temporary_Files.html">Temporary Files</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Processes.html">Processes</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Serialization.html">Serialization and Deserialization</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Cryptography.html">Cryptography</a></li>
<li><a class="" href="../../en-US/tasks/Tasks-Packaging.html">RPM Packaging</a></li>
</ul>
</li>
<li class="nav-header">
<a class="" href="#" data-toggle="collapse" data-target="#topicSubGroup-0-3">
<span id="sgSpan-0-3" class="fa fa-caret-down"></span>&nbsp;Implementing Security Features
</a>
<ul id="topicSubGroup-0-3" class="nav-tertiary list-unstyled collapse in">
<li><a class="" href="../../en-US/features/Features-Authentication.html">Authentication and Authorization</a></li>
<li><a class=" active" href="../../en-US/features/Features-TLS.html">Transport Layer Security (TLS)</a></li>
<li><a class="" href="../../en-US/features/Features-HSM.html">Hardware Security Modules and Smart Cards</a></li>
</ul>
</li>
<li><a class="" href="../../en-US/Revision_History.html">Revision History</a></li>
</ul>
</li>
</ul>
</div>
<div class="col-xs-12 col-sm-9 col-md-9 main">
<div class="page-header">
<h2>Transport Layer Security (TLS)</h2>
</div>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>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.</p>
</div>
<div class="paragraph">
<p>When using any library, in addition to this guide, it is recommended to consult the
library' documentation.</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS">NSS documentation</a></p>
</li>
<li>
<p><a href="http://www.gnutls.org/manual/">GnuTLS documentation</a></p>
</li>
<li>
<p><a href="https://www.openssl.org/docs/">OpenSSL documentation</a></p>
</li>
<li>
<p><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html">OpenJDK documentation</a></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="sect-Defensive_Coding-TLS-Pitfalls"><a class="anchor" href="#sect-Defensive_Coding-TLS-Pitfalls"></a>Common Pitfalls</h2>
<div class="sectionbody">
<div class="paragraph">
<p>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.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>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.</p>
<div class="paragraph">
<p>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.</p>
</div>
</li>
<li>
<p>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.</p>
</li>
<li>
<p>The TLS handshake has very poor performance if the TCP Nagle
algorithm is active. You should switch on the
<code>TCP_NODELAY</code> socket option (at least for the
duration of the handshake), or use the Linux-specific
<code>TCP_CORK</code> option.</p>
<div id="ex-Defensive_Coding-TLS-Nagle" class="exampleblock">
<div class="title">Example 1. Deactivating the TCP Nagle algorithm</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c"><span style="color:#088;font-weight:bold">const</span> <span style="color:#0a8;font-weight:bold">int</span> val = <span style="color:#00D">1</span>;
<span style="color:#0a8;font-weight:bold">int</span> ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &amp;val, <span style="color:#080;font-weight:bold">sizeof</span>(val));
<span style="color:#080;font-weight:bold">if</span> (ret &lt; <span style="color:#00D">0</span>) {
perror(<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">setsockopt(TCP_NODELAY)</span><span style="color:#710">&quot;</span></span>);
exit(<span style="color:#00D">1</span>);
}</code></pre>
</div>
</div>
</div>
</div>
</li>
<li>
<p>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).</p>
</li>
<li>
<p>Both client and server should work towards an orderly
connection shutdown, that is send
<code>close_notify</code> 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).</p>
</li>
<li>
<p>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 <code>accept</code> 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.</p>
</li>
<li>
<p>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 <code>fork</code> function
calls (see <a href="#sect-Defensive_Coding-Tasks-Processes-Fork-Parallel">[sect-Defensive_Coding-Tasks-Processes-Fork-Parallel]</a>).</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="sect-Defensive_Coding-TLS-OpenSSL"><a class="anchor" href="#sect-Defensive_Coding-TLS-OpenSSL"></a>OpenSSL Pitfalls</h3>
<div class="paragraph">
<p>Some OpenSSL function use <strong>tri-state return
values</strong>. Correct error checking is extremely
important. Several functions return <code>int</code>
values with the following meaning:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The value <code>1</code> indicates success (for
example, a successful signature verification).</p>
</li>
<li>
<p>The value <code>0</code> indicates semantic
failure (for example, a signature verification which was
unsuccessful because the signing certificate was
self-signed).</p>
</li>
<li>
<p>The value <code>-1</code> indicates a low-level
error in the system, such as failure to allocate memory
using <code>malloc</code>.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>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.</p>
</div>
<div class="paragraph">
<p>Recovering precise error information is difficult.
<a href="#ex-Defensive_Coding-TLS-OpenSSL-Errors">Obtaining OpenSSL error codes</a>
shows how to obtain a more precise error code after a function
call on an <code>SSL</code> object has failed. However,
there are still cases where no detailed error information is
available (e.g., if <code>SSL_shutdown</code> fails
due to a connection teardown by the other end).</p>
</div>
<div id="ex-Defensive_Coding-TLS-OpenSSL-Errors" class="exampleblock">
<div class="title">Example 2. Obtaining OpenSSL error codes</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c"><span style="color:#088;font-weight:bold">static</span> <span style="color:#088;font-weight:bold">void</span> __attribute__((noreturn))
ssl_print_error_and_exit(SSL *ssl, <span style="color:#088;font-weight:bold">const</span> <span style="color:#0a8;font-weight:bold">char</span> *op, <span style="color:#0a8;font-weight:bold">int</span> ret)
{
<span style="color:#0a8;font-weight:bold">int</span> subcode = SSL_get_error(ssl, ret);
<span style="color:#080;font-weight:bold">switch</span> (subcode) {
<span style="color:#080;font-weight:bold">case</span> SSL_ERROR_NONE:
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: %s: no error to report</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>, op);
<span style="color:#080;font-weight:bold">break</span>;
<span style="color:#080;font-weight:bold">case</span> SSL_ERROR_WANT_READ:
<span style="color:#080;font-weight:bold">case</span> SSL_ERROR_WANT_WRITE:
<span style="color:#080;font-weight:bold">case</span> SSL_ERROR_WANT_X509_LOOKUP:
<span style="color:#080;font-weight:bold">case</span> SSL_ERROR_WANT_CONNECT:
<span style="color:#080;font-weight:bold">case</span> SSL_ERROR_WANT_ACCEPT:
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: %s: invalid blocking state %d</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>, op, subcode);
<span style="color:#080;font-weight:bold">break</span>;
<span style="color:#080;font-weight:bold">case</span> SSL_ERROR_SSL:
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: %s: TLS layer problem</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>, op);
<span style="color:#080;font-weight:bold">case</span> SSL_ERROR_SYSCALL:
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: %s: system call failed: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>, op, strerror(errno));
<span style="color:#080;font-weight:bold">break</span>;
<span style="color:#080;font-weight:bold">case</span> SSL_ERROR_ZERO_RETURN:
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: %s: zero return</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>, op);
}
exit(<span style="color:#00D">1</span>);
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>The <code>OPENSSL_config</code> 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.</p>
</div>
<div class="paragraph">
<p>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 <code>d2i_</code> and end in
<code>_fp</code> or <code>_bio</code> (e.g.,
<code>d2i_X509_fp</code> or
<code>d2i_X509_bio</code>). These decoders must not
be used for parsing data from untrusted sources; instead,
the variants without the <code>_fp</code> and
<code>_bio</code> (e.g.,
<code>d2i_X509</code>) shall be used. The BIO
variants have received considerably less testing and are not
very robust.</p>
</div>
<div class="paragraph">
<p>For the same reason, the OpenSSL command line tools (such as
<code class="command">openssl x509</code>) are generally generally less
robust than the actual library code. They use the BIO
functions internally, and not the more robust variants.</p>
</div>
<div class="paragraph">
<p>The command line tools do not always indicate failure in the
exit status of the <strong class="application">openssl</strong> process.
For instance, a verification failure in <code class="command">openssl
verify</code> result in an exit status of zero.</p>
</div>
<div class="paragraph">
<p>OpenSSL command-line commands, such as <code class="command">openssl
genrsa</code>, do not ensure that physical entropy is used
for key generation—they obtain entropy from
<code>/dev/urandom</code> and other sources, but not
from <code>/dev/random</code>. 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.</p>
</div>
<div class="paragraph">
<p>The OpenSSL server and client applications (<code class="command">openssl
s_client</code> and <code class="command">openssl s_server</code>)
are debugging tools and should <strong>never</strong> be
used as generic clients. For instance, the
<strong class="application">s_client</strong> tool reacts in a
surprising way to lines starting with <code>R</code> and
<code>Q</code>.</p>
</div>
<div class="paragraph">
<p>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.</p>
</div>
</div>
<div class="sect2">
<h3 id="sect-Defensive_Coding-TLS-Pitfalls-GnuTLS"><a class="anchor" href="#sect-Defensive_Coding-TLS-Pitfalls-GnuTLS"></a>GnuTLS Pitfalls</h3>
<div class="paragraph">
<p>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.</p>
</div>
</div>
<div class="sect2">
<h3 id="sect-Defensive_Coding-TLS-Pitfalls-OpenJDK"><a class="anchor" href="#sect-Defensive_Coding-TLS-Pitfalls-OpenJDK"></a>OpenJDK Pitfalls</h3>
<div class="paragraph">
<p>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.</p>
</div>
<div class="paragraph">
<p>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 <strong>unlimited
strength jurisdiction policy files</strong>. 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.</p>
</div>
<div class="paragraph">
<p>Some versions of OpenJDK use <code>/dev/random</code>
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
<code>/dev/random</code>.</p>
</div>
</div>
<div class="sect2">
<h3 id="sect-Defensive_Coding-TLS-Pitfalls-NSS"><a class="anchor" href="#sect-Defensive_Coding-TLS-Pitfalls-NSS"></a>NSS Pitfalls</h3>
<div class="paragraph">
<p>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.</p>
</div>
<div class="paragraph">
<p>If the NSPR descriptor is in an unexpected state, the
<code>SSL_ForceHandshake</code> function can succeed,
but no TLS handshake takes place, the peer is not
authenticated, and subsequent data is exchanged in the clear.</p>
</div>
<div class="paragraph">
<p>NSS disables itself if it detects that the process underwent a
<code>fork</code> after the library has been
initialized. This behavior is required by the PKCS#11 API
specification.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="sect-Defensive_Coding-TLS-Client"><a class="anchor" href="#sect-Defensive_Coding-TLS-Client"></a>TLS Clients</h2>
<div class="sectionbody">
<div class="paragraph">
<p>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.)</p>
</div>
<div class="ulist">
<ul>
<li>
<p>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 <code>update-ca-trust</code>
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.</p>
</li>
<li>
<p>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).</p>
</li>
<li>
<p>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.</p>
</li>
<li>
<p>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.)</p>
</li>
<li>
<p>The client must check that the configured or user-provided
server name matches the peer certificate provided by the
server.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>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.</p>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
<div class="paragraph">
<p>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.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect2">
<h3 id="implementation-tls-clients-with-openssl"><a class="anchor" href="#implementation-tls-clients-with-openssl"></a>Implementation TLS Clients With OpenSSL</h3>
<div class="paragraph">
<p>In the following code, the error handling is only exploratory.
Proper error handling is required for production use,
especially in libraries.</p>
</div>
<div class="paragraph">
<p>The OpenSSL library needs explicit initialization (see <a href="#ex-Defensive_Coding-TLS-OpenSSL-Init">OpenSSL library initialization</a>).</p>
</div>
<div id="ex-Defensive_Coding-TLS-OpenSSL-Init" class="exampleblock">
<div class="title">Example 3. OpenSSL library initialization</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c"><span style="color:#777">// The following call prints an error message and calls exit() if</span>
<span style="color:#777">// the OpenSSL configuration file is unreadable.</span>
OPENSSL_config(<span style="color:#069">NULL</span>);
<span style="color:#777">// Provide human-readable error messages.</span>
SSL_load_error_strings();
<span style="color:#777">// Register ciphers.</span>
SSL_library_init();</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>After that, a context object has to be created, which acts as
a factory for connection objects (<a href="#ex-Defensive_Coding-TLS-Client-OpenSSL-CTX">OpenSSL client context creation</a>). 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.</p>
</div>
<div id="ex-Defensive_Coding-TLS-Client-OpenSSL-CTX" class="exampleblock">
<div class="title">Example 4. OpenSSL client context creation</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c"><span style="color:#777">// Configure a client connection context. Send a hendshake for the</span>
<span style="color:#777">// highest supported TLS version, and disable compression.</span>
<span style="color:#088;font-weight:bold">const</span> SSL_METHOD *<span style="color:#088;font-weight:bold">const</span> req_method = SSLv23_client_method();
SSL_CTX *<span style="color:#088;font-weight:bold">const</span> ctx = SSL_CTX_new(req_method);
<span style="color:#080;font-weight:bold">if</span> (ctx == <span style="color:#069">NULL</span>) {
ERR_print_errors(bio_err);
exit(<span style="color:#00D">1</span>);
}
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION);
<span style="color:#777">// Adjust the ciphers list based on a whitelist. First enable all</span>
<span style="color:#777">// ciphers of at least medium strength, to get the list which is</span>
<span style="color:#777">// compiled into OpenSSL.</span>
<span style="color:#080;font-weight:bold">if</span> (SSL_CTX_set_cipher_list(ctx, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">HIGH:MEDIUM</span><span style="color:#710">&quot;</span></span>) != <span style="color:#00D">1</span>) {
ERR_print_errors(bio_err);
exit(<span style="color:#00D">1</span>);
}
{
<span style="color:#777">// Create a dummy SSL session to obtain the cipher list.</span>
SSL *ssl = SSL_new(ctx);
<span style="color:#080;font-weight:bold">if</span> (ssl == <span style="color:#069">NULL</span>) {
ERR_print_errors(bio_err);
exit(<span style="color:#00D">1</span>);
}
STACK_OF(SSL_CIPHER) *active_ciphers = SSL_get_ciphers(ssl);
<span style="color:#080;font-weight:bold">if</span> (active_ciphers == <span style="color:#069">NULL</span>) {
ERR_print_errors(bio_err);
exit(<span style="color:#00D">1</span>);
}
<span style="color:#777">// Whitelist of candidate ciphers.</span>
<span style="color:#088;font-weight:bold">static</span> <span style="color:#088;font-weight:bold">const</span> <span style="color:#0a8;font-weight:bold">char</span> *<span style="color:#088;font-weight:bold">const</span> candidates[] = {
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">AES128-GCM-SHA256</span><span style="color:#710">&quot;</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">AES128-SHA256</span><span style="color:#710">&quot;</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">AES256-SHA256</span><span style="color:#710">&quot;</span></span>, <span style="color:#777">// strong ciphers</span>
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">AES128-SHA</span><span style="color:#710">&quot;</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">AES256-SHA</span><span style="color:#710">&quot;</span></span>, <span style="color:#777">// strong ciphers, also in older versions</span>
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">RC4-SHA</span><span style="color:#710">&quot;</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">RC4-MD5</span><span style="color:#710">&quot;</span></span>, <span style="color:#777">// backwards compatibility, supposed to be weak</span>
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">DES-CBC3-SHA</span><span style="color:#710">&quot;</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">DES-CBC3-MD5</span><span style="color:#710">&quot;</span></span>, <span style="color:#777">// more backwards compatibility</span>
<span style="color:#069">NULL</span>
};
<span style="color:#777">// Actually selected ciphers.</span>
<span style="color:#0a8;font-weight:bold">char</span> ciphers[<span style="color:#00D">300</span>];
ciphers[<span style="color:#00D">0</span>] = <span style="color:#D20">'\0'</span>;
<span style="color:#080;font-weight:bold">for</span> (<span style="color:#088;font-weight:bold">const</span> <span style="color:#0a8;font-weight:bold">char</span> *<span style="color:#088;font-weight:bold">const</span> *c = candidates; *c; ++c) {
<span style="color:#080;font-weight:bold">for</span> (<span style="color:#0a8;font-weight:bold">int</span> i = <span style="color:#00D">0</span>; i &lt; sk_SSL_CIPHER_num(active_ciphers); ++i) {
<span style="color:#080;font-weight:bold">if</span> (strcmp(SSL_CIPHER_get_name(sk_SSL_CIPHER_value(active_ciphers, i)),
*c) == <span style="color:#00D">0</span>) {
<span style="color:#080;font-weight:bold">if</span> (*ciphers) {
strcat(ciphers, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">:</span><span style="color:#710">&quot;</span></span>);
}
strcat(ciphers, *c);
<span style="color:#080;font-weight:bold">break</span>;
}
}
}
SSL_free(ssl);
<span style="color:#777">// Apply final cipher list.</span>
<span style="color:#080;font-weight:bold">if</span> (SSL_CTX_set_cipher_list(ctx, ciphers) != <span style="color:#00D">1</span>) {
ERR_print_errors(bio_err);
exit(<span style="color:#00D">1</span>);
}
}
<span style="color:#777">// Load the set of trusted root certificates.</span>
<span style="color:#080;font-weight:bold">if</span> (!SSL_CTX_set_default_verify_paths(ctx)) {
ERR_print_errors(bio_err);
exit(<span style="color:#00D">1</span>);
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>A single context object can be used to create multiple
connection objects. It is safe to use the same
<code>SSL_CTX</code> object for creating connections
concurrently from multiple threads, provided that the
<code>SSL_CTX</code> object is not modified (e.g.,
callbacks must not be changed).</p>
</div>
<div class="paragraph">
<p>After creating the TCP socket and disabling the Nagle
algorithm (per <a href="#ex-Defensive_Coding-TLS-Nagle">Deactivating the TCP Nagle algorithm</a>), the actual
connection object needs to be created, as show in <a href="#ex-Defensive_Coding-TLS-Client-OpenSSL-CTX">OpenSSL client context creation</a>. If
the handshake started by <code>SSL_connect</code>
fails, the <code>ssl_print_error_and_exit</code>
function from <a href="#ex-Defensive_Coding-TLS-OpenSSL-Errors">Obtaining OpenSSL error codes</a> is called.</p>
</div>
<div class="paragraph">
<p>The <code>certificate_validity_override</code>
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.</p>
</div>
<div class="paragraph">
<p>The host name passed to the functions
<code>SSL_set_tlsext_host_name</code> and
<code>X509_check_host</code> must be the name that was
passed to <code>getaddrinfo</code> or a similar name
resolution function. No host name canonicalization must be
performed. The <code>X509_check_host</code> 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
<code>certificate_host_name_override</code> 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 <strong>and</strong> the host
name.</p>
</div>
<div id="ex-Defensive_Coding-TLS-Client-OpenSSL-Connect" class="exampleblock">
<div class="title">Example 5. Creating a client connection using OpenSSL</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c"><span style="color:#777">// Create the connection object.</span>
SSL *ssl = SSL_new(ctx);
<span style="color:#080;font-weight:bold">if</span> (ssl == <span style="color:#069">NULL</span>) {
ERR_print_errors(bio_err);
exit(<span style="color:#00D">1</span>);
}
SSL_set_fd(ssl, sockfd);
<span style="color:#777">// Enable the ServerNameIndication extension</span>
<span style="color:#080;font-weight:bold">if</span> (!SSL_set_tlsext_host_name(ssl, host)) {
ERR_print_errors(bio_err);
exit(<span style="color:#00D">1</span>);
}
<span style="color:#777">// Perform the TLS handshake with the server.</span>
ret = SSL_connect(ssl);
<span style="color:#080;font-weight:bold">if</span> (ret != <span style="color:#00D">1</span>) {
<span style="color:#777">// Error status can be 0 or negative.</span>
ssl_print_error_and_exit(ssl, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">SSL_connect</span><span style="color:#710">&quot;</span></span>, ret);
}
<span style="color:#777">// Obtain the server certificate.</span>
X509 *peercert = SSL_get_peer_certificate(ssl);
<span style="color:#080;font-weight:bold">if</span> (peercert == <span style="color:#069">NULL</span>) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">peer certificate missing</span><span style="color:#710">&quot;</span></span>);
exit(<span style="color:#00D">1</span>);
}
<span style="color:#777">// Check the certificate verification result. Allow an explicit</span>
<span style="color:#777">// certificate validation override in case verification fails.</span>
<span style="color:#0a8;font-weight:bold">int</span> verifystatus = SSL_get_verify_result(ssl);
<span style="color:#080;font-weight:bold">if</span> (verifystatus != X509_V_OK &amp;&amp; !certificate_validity_override(peercert)) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">SSL_connect: verify result: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
X509_verify_cert_error_string(verifystatus));
exit(<span style="color:#00D">1</span>);
}
<span style="color:#777">// Check if the server certificate matches the host name used to</span>
<span style="color:#777">// establish the connection.</span>
<span style="color:#777">// FIXME: Currently needs OpenSSL 1.1.</span>
<span style="color:#080;font-weight:bold">if</span> (X509_check_host(peercert, (<span style="color:#088;font-weight:bold">const</span> <span style="color:#0a8;font-weight:bold">unsigned</span> <span style="color:#0a8;font-weight:bold">char</span> *)host, strlen(host),
<span style="color:#00D">0</span>) != <span style="color:#00D">1</span>
&amp;&amp; !certificate_host_name_override(peercert, host)) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">SSL certificate does not match host name</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>);
exit(<span style="color:#00D">1</span>);
}
X509_free(peercert);</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>The connection object can be used for sending and receiving
data, as in <a href="#ex-Defensive_Coding-TLS-OpenSSL-Connection-Use">Using an OpenSSL connection to send and receive data</a>.
It is also possible to create a <code>BIO</code> object
and use the <code>SSL</code> object as the underlying
transport, using <code>BIO_set_ssl</code>.</p>
</div>
<div id="ex-Defensive_Coding-TLS-OpenSSL-Connection-Use" class="exampleblock">
<div class="title">Example 6. Using an OpenSSL connection to send and receive data</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c"><span style="color:#088;font-weight:bold">const</span> <span style="color:#0a8;font-weight:bold">char</span> *<span style="color:#088;font-weight:bold">const</span> req = <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">GET / HTTP/1.0</span><span style="color:#b0b">\r</span><span style="color:#b0b">\n</span><span style="color:#b0b">\r</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>;
<span style="color:#080;font-weight:bold">if</span> (SSL_write(ssl, req, strlen(req)) &lt; <span style="color:#00D">0</span>) {
ssl_print_error_and_exit(ssl, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">SSL_write</span><span style="color:#710">&quot;</span></span>, ret);
}
<span style="color:#0a8;font-weight:bold">char</span> buf[<span style="color:#00D">4096</span>];
ret = SSL_read(ssl, buf, <span style="color:#080;font-weight:bold">sizeof</span>(buf));
<span style="color:#080;font-weight:bold">if</span> (ret &lt; <span style="color:#00D">0</span>) {
ssl_print_error_and_exit(ssl, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">SSL_read</span><span style="color:#710">&quot;</span></span>, ret);
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>When it is time to close the connection, the
<code>SSL_shutdown</code> function needs to be called
twice for an orderly, synchronous connection termination
(<a href="#ex-Defensive_Coding-TLS-OpenSSL-Connection-Close">Closing an OpenSSL connection in an orderly fashion</a>).
This exchanges <code>close_notify</code> alerts with the
server. The additional logic is required to deal with an
unexpected <code>close_notify</code> from the server.
Note that is necessary to explicitly close the underlying
socket after the connection object has been freed.</p>
</div>
<div id="ex-Defensive_Coding-TLS-OpenSSL-Connection-Close" class="exampleblock">
<div class="title">Example 7. Closing an OpenSSL connection in an orderly fashion</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c"><span style="color:#777">// Send the close_notify alert.</span>
ret = SSL_shutdown(ssl);
<span style="color:#080;font-weight:bold">switch</span> (ret) {
<span style="color:#080;font-weight:bold">case</span> <span style="color:#00D">1</span>:
<span style="color:#777">// A close_notify alert has already been received.</span>
<span style="color:#080;font-weight:bold">break</span>;
<span style="color:#080;font-weight:bold">case</span> <span style="color:#00D">0</span>:
<span style="color:#777">// Wait for the close_notify alert from the peer.</span>
ret = SSL_shutdown(ssl);
<span style="color:#080;font-weight:bold">switch</span> (ret) {
<span style="color:#080;font-weight:bold">case</span> <span style="color:#00D">0</span>:
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">info: second SSL_shutdown returned zero</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>);
<span style="color:#080;font-weight:bold">break</span>;
<span style="color:#080;font-weight:bold">case</span> <span style="color:#00D">1</span>:
<span style="color:#080;font-weight:bold">break</span>;
<span style="color:#080;font-weight:bold">default</span>:
ssl_print_error_and_exit(ssl, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">SSL_shutdown 2</span><span style="color:#710">&quot;</span></span>, ret);
}
<span style="color:#080;font-weight:bold">break</span>;
<span style="color:#080;font-weight:bold">default</span>:
ssl_print_error_and_exit(ssl, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">SSL_shutdown 1</span><span style="color:#710">&quot;</span></span>, ret);
}
SSL_free(ssl);
close(sockfd);</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p><a href="#ex-Defensive_Coding-TLS-OpenSSL-Context-Close">Closing an OpenSSL connection in an orderly fashion</a> shows how
to deallocate the context object when it is no longer needed
because no further TLS connections will be established.</p>
</div>
<div id="ex-Defensive_Coding-TLS-OpenSSL-Context-Close" class="exampleblock">
<div class="title">Example 8. Closing an OpenSSL connection in an orderly fashion</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c">SSL_CTX_free(ctx);</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="sect-Defensive_Coding-TLS-Client-GnuTLS"><a class="anchor" href="#sect-Defensive_Coding-TLS-Client-GnuTLS"></a>Implementation TLS Clients With GnuTLS</h3>
<div class="paragraph">
<p>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.</p>
</div>
<div class="paragraph">
<p>Before setting up TLS connections, a credentials objects has
to be allocated and initialized with the set of trusted root
CAs (<a href="#ex-Defensive_Coding-TLS-Client-GNUTLS-Credentials">Initializing a GnuTLS credentials structure</a>).</p>
</div>
<div id="ex-Defensive_Coding-TLS-Client-GNUTLS-Credentials" class="exampleblock">
<div class="title">Example 9. Initializing a GnuTLS credentials structure</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c"><span style="color:#777">// Load the trusted CA certificates.</span>
gnutls_certificate_credentials_t cred = <span style="color:#069">NULL</span>;
<span style="color:#0a8;font-weight:bold">int</span> ret = gnutls_certificate_allocate_credentials (&amp;cred);
<span style="color:#080;font-weight:bold">if</span> (ret != GNUTLS_E_SUCCESS) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: gnutls_certificate_allocate_credentials: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
gnutls_strerror(ret));
exit(<span style="color:#00D">1</span>);
}
ret = gnutls_certificate_set_x509_system_trust(cred);
<span style="color:#080;font-weight:bold">if</span> (ret == <span style="color:#00D">0</span>) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: no certificates found in system trust store</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>);
exit(<span style="color:#00D">1</span>);
}
<span style="color:#080;font-weight:bold">if</span> (ret &lt; <span style="color:#00D">0</span>) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: gnutls_certificate_set_x509_system_trust: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
gnutls_strerror(ret));
exit(<span style="color:#00D">1</span>);
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>After the last TLS connection has been closed, this credentials
object should be freed:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c">gnutls_certificate_free_credentials(cred);</code></pre>
</div>
</div>
<div class="paragraph">
<p>During its lifetime, the credentials object can be used to
initialize TLS session objects from multiple threads, provided
that it is not changed.</p>
</div>
<div class="paragraph">
<p>Once the TCP connection has been established, the Nagle
algorithm should be disabled (see <a href="#ex-Defensive_Coding-TLS-Nagle">Deactivating the TCP Nagle algorithm</a>). 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 <a href="#ex-Defensive_Coding-TLS-Client-GNUTLS-Connect">Establishing a TLS client connection using GnuTLS</a>.</p>
</div>
<div id="ex-Defensive_Coding-TLS-Client-GNUTLS-Connect" class="exampleblock">
<div class="title">Example 10. Establishing a TLS client connection using GnuTLS</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c"><span style="color:#777">// Create the session object.</span>
gnutls_session_t session;
ret = gnutls_init(&amp;session, GNUTLS_CLIENT);
<span style="color:#080;font-weight:bold">if</span> (ret != GNUTLS_E_SUCCESS) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: gnutls_init: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
gnutls_strerror(ret));
exit(<span style="color:#00D">1</span>);
}
<span style="color:#777">// Configure the cipher preferences.</span>
<span style="color:#088;font-weight:bold">const</span> <span style="color:#0a8;font-weight:bold">char</span> *errptr = <span style="color:#069">NULL</span>;
ret = gnutls_priority_set_direct(session, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">NORMAL</span><span style="color:#710">&quot;</span></span>, &amp;errptr);
<span style="color:#080;font-weight:bold">if</span> (ret != GNUTLS_E_SUCCESS) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: gnutls_priority_set_direct: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: at: </span><span style="color:#b0b">\&quot;</span><span style="color:#D20">%s</span><span style="color:#b0b">\&quot;</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>, gnutls_strerror(ret), errptr);
exit(<span style="color:#00D">1</span>);
}
<span style="color:#777">// Install the trusted certificates.</span>
ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cred);
<span style="color:#080;font-weight:bold">if</span> (ret != GNUTLS_E_SUCCESS) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: gnutls_credentials_set: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
gnutls_strerror(ret));
exit(<span style="color:#00D">1</span>);
}
<span style="color:#777">// Associate the socket with the session object and set the server</span>
<span style="color:#777">// name.</span>
gnutls_transport_set_int(session, sockfd);
ret = gnutls_server_name_set(session, GNUTLS_NAME_DNS,
host, strlen(host));
<span style="color:#080;font-weight:bold">if</span> (ret != GNUTLS_E_SUCCESS) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: gnutls_server_name_set: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
gnutls_strerror(ret));
exit(<span style="color:#00D">1</span>);
}
<span style="color:#777">// Establish the session.</span>
ret = gnutls_handshake(session);
<span style="color:#080;font-weight:bold">if</span> (ret != GNUTLS_E_SUCCESS) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: gnutls_handshake: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
gnutls_strerror(ret));
exit(<span style="color:#00D">1</span>);
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>After the handshake has been completed, the server certificate
needs to be verified against the server&#8217;s hostname (<a href="#ex-Defensive_Coding-TLS-Client-GNUTLS-Verify">Verifying a server certificate using GnuTLS</a>). In
the example, the user-defined
<code>certificate_validity_override</code> 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.</p>
</div>
<div id="ex-Defensive_Coding-TLS-Client-GNUTLS-Verify" class="exampleblock">
<div class="title">Example 11. Verifying a server certificate using GnuTLS</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c"><span style="color:#777">// Obtain the server certificate chain. The server certificate</span>
<span style="color:#777">// itself is stored in the first element of the array.</span>
<span style="color:#0a8;font-weight:bold">unsigned</span> certslen = <span style="color:#00D">0</span>;
<span style="color:#088;font-weight:bold">const</span> gnutls_datum_t *<span style="color:#088;font-weight:bold">const</span> certs =
gnutls_certificate_get_peers(session, &amp;certslen);
<span style="color:#080;font-weight:bold">if</span> (certs == <span style="color:#069">NULL</span> || certslen == <span style="color:#00D">0</span>) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: could not obtain peer certificate</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>);
exit(<span style="color:#00D">1</span>);
}
<span style="color:#777">// Validate the certificate chain.</span>
<span style="color:#0a8;font-weight:bold">unsigned</span> status = (<span style="color:#0a8;font-weight:bold">unsigned</span>)-<span style="color:#00D">1</span>;
ret = gnutls_certificate_verify_peers3(session, host, &amp;status);
<span style="color:#080;font-weight:bold">if</span> (ret != GNUTLS_E_SUCCESS) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: gnutls_certificate_verify_peers3: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
gnutls_strerror(ret));
exit(<span style="color:#00D">1</span>);
}
<span style="color:#080;font-weight:bold">if</span> (status != <span style="color:#00D">0</span> &amp;&amp; !certificate_validity_override(certs[<span style="color:#00D">0</span>])) {
gnutls_datum_t msg;
<span style="color:#579">#if</span> GNUTLS_VERSION_AT_LEAST_3_1_4
<span style="color:#0a8;font-weight:bold">int</span> type = gnutls_certificate_type_get (session);
ret = gnutls_certificate_verification_status_print(status, type, &amp;out, <span style="color:#00D">0</span>);
<span style="color:#579">#else</span>
ret = -<span style="color:#00D">1</span>;
<span style="color:#579">#endif</span>
<span style="color:#080;font-weight:bold">if</span> (ret == <span style="color:#00D">0</span>) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>, msg.data);
gnutls_free(msg.data);
exit(<span style="color:#00D">1</span>);
} <span style="color:#080;font-weight:bold">else</span> {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: certificate validation failed with code 0x%x</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
status);
exit(<span style="color:#00D">1</span>);
}
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>An established TLS session can be used for sending and
receiving data, as in <a href="#ex-Defensive_Coding-TLS-GNUTLS-Use">Using a GnuTLS session</a>.</p>
</div>
<div id="ex-Defensive_Coding-TLS-GNUTLS-Use" class="exampleblock">
<div class="title">Example 12. Using a GnuTLS session</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c"><span style="color:#0a8;font-weight:bold">char</span> buf[<span style="color:#00D">4096</span>];
snprintf(buf, <span style="color:#080;font-weight:bold">sizeof</span>(buf), <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">GET / HTTP/1.0</span><span style="color:#b0b">\r</span><span style="color:#b0b">\n</span><span style="color:#D20">Host: %s</span><span style="color:#b0b">\r</span><span style="color:#b0b">\n</span><span style="color:#b0b">\r</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>, host);
ret = gnutls_record_send(session, buf, strlen(buf));
<span style="color:#080;font-weight:bold">if</span> (ret &lt; <span style="color:#00D">0</span>) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: gnutls_record_send: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>, gnutls_strerror(ret));
exit(<span style="color:#00D">1</span>);
}
ret = gnutls_record_recv(session, buf, <span style="color:#080;font-weight:bold">sizeof</span>(buf));
<span style="color:#080;font-weight:bold">if</span> (ret &lt; <span style="color:#00D">0</span>) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: gnutls_record_recv: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>, gnutls_strerror(ret));
exit(<span style="color:#00D">1</span>);
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>In order to shut down a connection in an orderly manner, you
should call the <code>gnutls_bye</code> function.
Finally, the session object can be deallocated using
<code>gnutls_deinit</code> (see <a href="#ex-Defensive_Coding-TLS-GNUTLS-Disconnect">Closing a GnuTLS session in an orderly fashion</a>).</p>
</div>
<div id="ex-Defensive_Coding-TLS-GNUTLS-Disconnect" class="exampleblock">
<div class="title">Example 13. Closing a GnuTLS session in an orderly fashion</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c"><span style="color:#777">// Initiate an orderly connection shutdown.</span>
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
<span style="color:#080;font-weight:bold">if</span> (ret &lt; <span style="color:#00D">0</span>) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: gnutls_bye: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>, gnutls_strerror(ret));
exit(<span style="color:#00D">1</span>);
}
<span style="color:#777">// Free the session object.</span>
gnutls_deinit(session);</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="sect-Defensive_Coding-TLS-Client-OpenJDK"><a class="anchor" href="#sect-Defensive_Coding-TLS-Client-OpenJDK"></a>Implementing TLS Clients With OpenJDK</h3>
<div class="paragraph">
<p>The examples below use the following cryptographic-related
classes:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span style="color:#080;font-weight:bold">import</span> <span style="color:#B44;font-weight:bold">java.security.NoSuchAlgorithmException</span>;
<span style="color:#080;font-weight:bold">import</span> <span style="color:#B44;font-weight:bold">java.security.NoSuchProviderException</span>;
<span style="color:#080;font-weight:bold">import</span> <span style="color:#B44;font-weight:bold">java.security.cert.CertificateEncodingException</span>;
<span style="color:#080;font-weight:bold">import</span> <span style="color:#B44;font-weight:bold">java.security.cert.CertificateException</span>;
<span style="color:#080;font-weight:bold">import</span> <span style="color:#B44;font-weight:bold">java.security.cert.X509Certificate</span>;
<span style="color:#080;font-weight:bold">import</span> <span style="color:#B44;font-weight:bold">javax.net.ssl.SSLContext</span>;
<span style="color:#080;font-weight:bold">import</span> <span style="color:#B44;font-weight:bold">javax.net.ssl.SSLParameters</span>;
<span style="color:#080;font-weight:bold">import</span> <span style="color:#B44;font-weight:bold">javax.net.ssl.SSLSocket</span>;
<span style="color:#080;font-weight:bold">import</span> <span style="color:#B44;font-weight:bold">javax.net.ssl.TrustManager</span>;
<span style="color:#080;font-weight:bold">import</span> <span style="color:#B44;font-weight:bold">javax.net.ssl.X509TrustManager</span>;
<span style="color:#080;font-weight:bold">import</span> <span style="color:#B44;font-weight:bold">sun.security.util.HostnameChecker</span>;</code></pre>
</div>
</div>
<div class="paragraph">
<p>If compatibility with OpenJDK 6 is required, it is necessary
to use the internal class
<code>sun.security.util.HostnameChecker</code>. (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
<code>setEndpointIdentificationAlgorithm</code> method
was added to the
<code>javax.net.ssl.SSLParameters</code> class,
providing an official way to implement host name checking.</p>
</div>
<div class="paragraph">
<p>TLS connections are established using an
<code>SSLContext</code> instance. With a properly
configured OpenJDK installation, the
<code>SunJSSE</code> provider uses the system-wide set
of trusted root certificate authorities, so no further
configuration is necessary. For backwards compatibility with
OpenJDK6, the <code>TLSv1</code> provider has to
be supported as a fall-back option. This is shown in <a href="#ex-Defensive_Coding-TLS-Client-OpenJDK-Context">Setting up an <code>SSLContext</code> for OpenJDK TLS clients</a>.</p>
</div>
<div id="ex-Defensive_Coding-TLS-Client-OpenJDK-Context" class="exampleblock">
<div class="title">Example 14. Setting up an <code>SSLContext</code> for OpenJDK TLS clients</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span style="color:#777">// Create the context. Specify the SunJSSE provider to avoid</span>
<span style="color:#777">// picking up third-party providers. Try the TLS 1.2 provider</span>
<span style="color:#777">// first, then fall back to TLS 1.0.</span>
<span style="color:#0a8;font-weight:bold">SSLContext</span> ctx;
<span style="color:#080;font-weight:bold">try</span> {
ctx = <span style="color:#0a8;font-weight:bold">SSLContext</span>.getInstance(<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">TLSv1.2</span><span style="color:#710">&quot;</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">SunJSSE</span><span style="color:#710">&quot;</span></span>);
} <span style="color:#080;font-weight:bold">catch</span> (<span style="color:#C00;font-weight:bold">NoSuchAlgorithmException</span> e) {
<span style="color:#080;font-weight:bold">try</span> {
ctx = <span style="color:#0a8;font-weight:bold">SSLContext</span>.getInstance(<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">TLSv1</span><span style="color:#710">&quot;</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">SunJSSE</span><span style="color:#710">&quot;</span></span>);
} <span style="color:#080;font-weight:bold">catch</span> (<span style="color:#C00;font-weight:bold">NoSuchAlgorithmException</span> e1) {
<span style="color:#777">// The TLS 1.0 provider should always be available.</span>
<span style="color:#080;font-weight:bold">throw</span> <span style="color:#080;font-weight:bold">new</span> <span style="color:#C00;font-weight:bold">AssertionError</span>(e1);
} <span style="color:#080;font-weight:bold">catch</span> (<span style="color:#C00;font-weight:bold">NoSuchProviderException</span> e1) {
<span style="color:#080;font-weight:bold">throw</span> <span style="color:#080;font-weight:bold">new</span> <span style="color:#C00;font-weight:bold">AssertionError</span>(e1);
}
} <span style="color:#080;font-weight:bold">catch</span> (<span style="color:#C00;font-weight:bold">NoSuchProviderException</span> e) {
<span style="color:#777">// The SunJSSE provider should always be available.</span>
<span style="color:#080;font-weight:bold">throw</span> <span style="color:#080;font-weight:bold">new</span> <span style="color:#C00;font-weight:bold">AssertionError</span>(e);
}
ctx.init(<span style="color:#069">null</span>, <span style="color:#069">null</span>, <span style="color:#069">null</span>);</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>In addition to the context, a TLS parameter object will be
needed which adjusts the cipher suites and protocols (<a href="#ex-Defensive_Coding-TLS-OpenJDK-Parameters">Setting up <code>SSLParameters</code> for TLS use with OpenJDK</a>). Like
the context, these parameters can be reused for multiple TLS
connections.</p>
</div>
<div id="ex-Defensive_Coding-TLS-OpenJDK-Parameters" class="exampleblock">
<div class="title">Example 15. Setting up <code>SSLParameters</code> for TLS use with OpenJDK</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span style="color:#777">// Prepare TLS parameters. These have to applied to every TLS</span>
<span style="color:#777">// socket before the handshake is triggered.</span>
SSLParameters params = ctx.getDefaultSSLParameters();
<span style="color:#777">// Do not send an SSL-2.0-compatible Client Hello.</span>
<span style="color:#0a8;font-weight:bold">ArrayList</span>&lt;<span style="color:#0a8;font-weight:bold">String</span>&gt; protocols = <span style="color:#080;font-weight:bold">new</span> <span style="color:#0a8;font-weight:bold">ArrayList</span>&lt;<span style="color:#0a8;font-weight:bold">String</span>&gt;(
<span style="color:#0a8;font-weight:bold">Arrays</span>.asList(params.getProtocols()));
protocols.remove(<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">SSLv2Hello</span><span style="color:#710">&quot;</span></span>);
params.setProtocols(protocols.toArray(<span style="color:#080;font-weight:bold">new</span> <span style="color:#0a8;font-weight:bold">String</span>[protocols.size()]));
<span style="color:#777">// Adjust the supported ciphers.</span>
<span style="color:#0a8;font-weight:bold">ArrayList</span>&lt;<span style="color:#0a8;font-weight:bold">String</span>&gt; ciphers = <span style="color:#080;font-weight:bold">new</span> <span style="color:#0a8;font-weight:bold">ArrayList</span>&lt;<span style="color:#0a8;font-weight:bold">String</span>&gt;(
<span style="color:#0a8;font-weight:bold">Arrays</span>.asList(params.getCipherSuites()));
ciphers.retainAll(<span style="color:#0a8;font-weight:bold">Arrays</span>.asList(
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">TLS_RSA_WITH_AES_128_CBC_SHA256</span><span style="color:#710">&quot;</span></span>,
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">TLS_RSA_WITH_AES_256_CBC_SHA256</span><span style="color:#710">&quot;</span></span>,
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">TLS_RSA_WITH_AES_256_CBC_SHA</span><span style="color:#710">&quot;</span></span>,
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">TLS_RSA_WITH_AES_128_CBC_SHA</span><span style="color:#710">&quot;</span></span>,
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">SSL_RSA_WITH_3DES_EDE_CBC_SHA</span><span style="color:#710">&quot;</span></span>,
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">SSL_RSA_WITH_RC4_128_SHA1</span><span style="color:#710">&quot;</span></span>,
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">SSL_RSA_WITH_RC4_128_MD5</span><span style="color:#710">&quot;</span></span>,
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">TLS_EMPTY_RENEGOTIATION_INFO_SCSV</span><span style="color:#710">&quot;</span></span>));
params.setCipherSuites(ciphers.toArray(<span style="color:#080;font-weight:bold">new</span> <span style="color:#0a8;font-weight:bold">String</span>[ciphers.size()]));</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>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:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">params.setEndpointIdentificationAlgorithm(<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">HTTPS</span><span style="color:#710">&quot;</span></span>);</code></pre>
</div>
</div>
<div class="paragraph">
<p>All application protocols can use the
<code>"HTTPS"</code> algorithm. (The algorithms have
minor differences with regard to wildcard handling, which
should not matter in practice.)</p>
</div>
<div class="paragraph">
<p><a href="#ex-Defensive_Coding-TLS-Client-OpenJDK-Connect">Establishing a TLS connection with OpenJDK</a>
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
<code>params</code>. (After this point, changes to
<code>params</code> will not affect this TLS socket.)
As mentioned initially, host name checking requires using an
internal API on OpenJDK 6.</p>
</div>
<div id="ex-Defensive_Coding-TLS-Client-OpenJDK-Connect" class="exampleblock">
<div class="title">Example 16. Establishing a TLS connection with OpenJDK</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span style="color:#777">// Create the socket and connect it at the TCP layer.</span>
<span style="color:#0a8;font-weight:bold">SSLSocket</span> socket = (<span style="color:#0a8;font-weight:bold">SSLSocket</span>) ctx.getSocketFactory()
.createSocket(host, port);
<span style="color:#777">// Disable the Nagle algorithm.</span>
socket.setTcpNoDelay(<span style="color:#069">true</span>);
<span style="color:#777">// Adjust ciphers and protocols.</span>
socket.setSSLParameters(params);
<span style="color:#777">// Perform the handshake.</span>
socket.startHandshake();
<span style="color:#777">// Validate the host name. The match() method throws</span>
<span style="color:#777">// CertificateException on failure.</span>
<span style="color:#0a8;font-weight:bold">X509Certificate</span> peer = (<span style="color:#0a8;font-weight:bold">X509Certificate</span>)
socket.getSession().getPeerCertificates()[<span style="color:#00D">0</span>];
<span style="color:#777">// This is the only way to perform host name checking on OpenJDK 6.</span>
HostnameChecker.getInstance(HostnameChecker.TYPE_TLS).match(
host, peer);</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Starting with OpenJDK 7, the last lines can be omitted,
provided that host name verification has been enabled by
calling the
<code>setEndpointIdentificationAlgorithm</code> method
on the <code>params</code> object (before it was applied
to the socket).</p>
</div>
<div class="paragraph">
<p>The TLS socket can be used as a regular socket, as shown in
<a href="#ex-Defensive_Coding-TLS-Client-OpenJDK-Use">Using a TLS client socket in OpenJDK</a>.</p>
</div>
<div id="ex-Defensive_Coding-TLS-Client-OpenJDK-Use" class="exampleblock">
<div class="title">Example 17. Using a TLS client socket in OpenJDK</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">socket.getOutputStream().write(<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">GET / HTTP/1.0</span><span style="color:#b0b">\r</span><span style="color:#b0b">\n</span><span style="color:#b0b">\r</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>
.getBytes(<span style="color:#0a8;font-weight:bold">Charset</span>.forName(<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">UTF-8</span><span style="color:#710">&quot;</span></span>)));
<span style="color:#339;font-weight:bold">byte</span><span style="color:#339;font-weight:bold">[]</span> buffer = <span style="color:#080;font-weight:bold">new</span> <span style="color:#339;font-weight:bold">byte</span>[<span style="color:#00D">4096</span>];
<span style="color:#339;font-weight:bold">int</span> count = socket.getInputStream().read(buffer);
<span style="color:#0a8;font-weight:bold">System</span>.out.write(buffer, <span style="color:#00D">0</span>, count);</code></pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="overriding-server-certificate-validation-with-openjdk-6"><a class="anchor" href="#overriding-server-certificate-validation-with-openjdk-6"></a>Overriding server certificate validation with OpenJDK 6</h4>
<div class="paragraph">
<p>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
<code>TrustManager</code> and
<code>SSLContext</code> objects have to be used for
different servers.</p>
</div>
<div class="paragraph">
<p>In the trust manager shown in <a href="#ex-Defensive_Coding-TLS-Client-MyTrustManager">A customer trust manager for OpenJDK TLS clients</a>,
the server certificate is identified by its SHA-256 hash.</p>
</div>
<div id="ex-Defensive_Coding-TLS-Client-MyTrustManager" class="exampleblock">
<div class="title">Example 18. A customer trust manager for OpenJDK TLS clients</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span style="color:#088;font-weight:bold">public</span> <span style="color:#339;font-weight:bold">class</span> <span style="color:#B06;font-weight:bold">MyTrustManager</span> <span style="color:#088;font-weight:bold">implements</span> <span style="color:#0a8;font-weight:bold">X509TrustManager</span> {
<span style="color:#088;font-weight:bold">private</span> <span style="color:#088;font-weight:bold">final</span> <span style="color:#339;font-weight:bold">byte</span><span style="color:#339;font-weight:bold">[]</span> certHash;
<span style="color:#088;font-weight:bold">public</span> MyTrustManager(<span style="color:#339;font-weight:bold">byte</span><span style="color:#339;font-weight:bold">[]</span> certHash) <span style="color:#088;font-weight:bold">throws</span> <span style="color:#C00;font-weight:bold">Exception</span> {
<span style="color:#950">this</span>.certHash = certHash;
}
<span style="color:#007">@Override</span>
<span style="color:#088;font-weight:bold">public</span> <span style="color:#339;font-weight:bold">void</span> checkClientTrusted(<span style="color:#0a8;font-weight:bold">X509Certificate</span><span style="color:#339;font-weight:bold">[]</span> chain, <span style="color:#0a8;font-weight:bold">String</span> authType)
<span style="color:#088;font-weight:bold">throws</span> <span style="color:#C00;font-weight:bold">CertificateException</span> {
<span style="color:#080;font-weight:bold">throw</span> <span style="color:#080;font-weight:bold">new</span> <span style="color:#C00;font-weight:bold">UnsupportedOperationException</span>();
}
<span style="color:#007">@Override</span>
<span style="color:#088;font-weight:bold">public</span> <span style="color:#339;font-weight:bold">void</span> checkServerTrusted(<span style="color:#0a8;font-weight:bold">X509Certificate</span><span style="color:#339;font-weight:bold">[]</span> chain,
<span style="color:#0a8;font-weight:bold">String</span> authType) <span style="color:#088;font-weight:bold">throws</span> <span style="color:#C00;font-weight:bold">CertificateException</span> {
<span style="color:#339;font-weight:bold">byte</span><span style="color:#339;font-weight:bold">[]</span> digest = getCertificateDigest(chain[<span style="color:#00D">0</span>]);
<span style="color:#0a8;font-weight:bold">String</span> digestHex = formatHex(digest);
<span style="color:#080;font-weight:bold">if</span> (<span style="color:#0a8;font-weight:bold">Arrays</span>.equals(digest, certHash)) {
<span style="color:#0a8;font-weight:bold">System</span>.err.println(<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">info: accepting certificate: </span><span style="color:#710">&quot;</span></span> + digestHex);
} <span style="color:#080;font-weight:bold">else</span> {
<span style="color:#080;font-weight:bold">throw</span> <span style="color:#080;font-weight:bold">new</span> <span style="color:#C00;font-weight:bold">CertificateException</span>(<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">certificate rejected: </span><span style="color:#710">&quot;</span></span> +
digestHex);
}
}
<span style="color:#007">@Override</span>
<span style="color:#088;font-weight:bold">public</span> <span style="color:#0a8;font-weight:bold">X509Certificate</span><span style="color:#339;font-weight:bold">[]</span> getAcceptedIssuers() {
<span style="color:#080;font-weight:bold">return</span> <span style="color:#080;font-weight:bold">new</span> <span style="color:#0a8;font-weight:bold">X509Certificate</span>[<span style="color:#00D">0</span>];
}
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>This trust manager has to be passed to the
<code>init</code> method of the
<code>SSLContext</code> object, as show in <a href="#ex-Defensive_Coding-TLS-Client-Context_For_Cert">Using a custom TLS trust manager with OpenJDK</a>.</p>
</div>
<div id="ex-Defensive_Coding-TLS-Client-Context_For_Cert" class="exampleblock">
<div class="title">Example 19. Using a custom TLS trust manager with OpenJDK</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span style="color:#0a8;font-weight:bold">SSLContext</span> ctx;
<span style="color:#080;font-weight:bold">try</span> {
ctx = <span style="color:#0a8;font-weight:bold">SSLContext</span>.getInstance(<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">TLSv1.2</span><span style="color:#710">&quot;</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">SunJSSE</span><span style="color:#710">&quot;</span></span>);
} <span style="color:#080;font-weight:bold">catch</span> (<span style="color:#C00;font-weight:bold">NoSuchAlgorithmException</span> e) {
<span style="color:#080;font-weight:bold">try</span> {
ctx = <span style="color:#0a8;font-weight:bold">SSLContext</span>.getInstance(<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">TLSv1</span><span style="color:#710">&quot;</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">SunJSSE</span><span style="color:#710">&quot;</span></span>);
} <span style="color:#080;font-weight:bold">catch</span> (<span style="color:#C00;font-weight:bold">NoSuchAlgorithmException</span> e1) {
<span style="color:#080;font-weight:bold">throw</span> <span style="color:#080;font-weight:bold">new</span> <span style="color:#C00;font-weight:bold">AssertionError</span>(e1);
} <span style="color:#080;font-weight:bold">catch</span> (<span style="color:#C00;font-weight:bold">NoSuchProviderException</span> e1) {
<span style="color:#080;font-weight:bold">throw</span> <span style="color:#080;font-weight:bold">new</span> <span style="color:#C00;font-weight:bold">AssertionError</span>(e1);
}
} <span style="color:#080;font-weight:bold">catch</span> (<span style="color:#C00;font-weight:bold">NoSuchProviderException</span> e) {
<span style="color:#080;font-weight:bold">throw</span> <span style="color:#080;font-weight:bold">new</span> <span style="color:#C00;font-weight:bold">AssertionError</span>(e);
}
MyTrustManager tm = <span style="color:#080;font-weight:bold">new</span> MyTrustManager(certHash);
ctx.init(<span style="color:#069">null</span>, <span style="color:#080;font-weight:bold">new</span> <span style="color:#0a8;font-weight:bold">TrustManager</span><span style="color:#339;font-weight:bold">[]</span> {tm}, <span style="color:#069">null</span>);</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>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.</p>
</div>
<div class="paragraph">
<p>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
<code>javax.net.ssl.X509ExtendedTrustManager</code>
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.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="sect-Defensive_Coding-TLS-Client-NSS"><a class="anchor" href="#sect-Defensive_Coding-TLS-Client-NSS"></a>Implementing TLS Clients With NSS</h3>
<div class="paragraph">
<p>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.</p>
</div>
<div class="paragraph">
<p>Keep in mind that the error handling needs to be improved
before the code can be used in production.</p>
</div>
<div class="paragraph">
<p>Using NSS needs several header files, as shown in
<a href="#ex-Defensive_Coding-TLS-NSS-Includes">Include files for NSS</a>.</p>
</div>
<div id="ex-Defensive_Coding-TLS-NSS-Includes" class="exampleblock">
<div class="title">Example 20. Include files for NSS</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c"><span style="color:#777">// NSPR include files</span>
<span style="color:#579">#include</span> <span style="color:#B44;font-weight:bold">&lt;prerror.h&gt;</span>
<span style="color:#579">#include</span> <span style="color:#B44;font-weight:bold">&lt;prinit.h&gt;</span>
<span style="color:#777">// NSS include files</span>
<span style="color:#579">#include</span> <span style="color:#B44;font-weight:bold">&lt;nss.h&gt;</span>
<span style="color:#579">#include</span> <span style="color:#B44;font-weight:bold">&lt;pk11pub.h&gt;</span>
<span style="color:#579">#include</span> <span style="color:#B44;font-weight:bold">&lt;secmod.h&gt;</span>
<span style="color:#579">#include</span> <span style="color:#B44;font-weight:bold">&lt;ssl.h&gt;</span>
<span style="color:#579">#include</span> <span style="color:#B44;font-weight:bold">&lt;sslproto.h&gt;</span>
<span style="color:#777">// Private API, no other way to turn a POSIX file descriptor into an</span>
<span style="color:#777">// NSPR handle.</span>
NSPR_API(PRFileDesc*) PR_ImportTCPSocket(<span style="color:#0a8;font-weight:bold">int</span>);</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Initializing the NSS library is shown in <a href="#ex-Defensive_Coding-TLS-NSS-Init">Initializing the NSS library</a>. This
initialization procedure overrides global state. We only call
<code>NSS_SetDomesticPolicy</code> 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.</p>
</div>
<div class="paragraph">
<p>The simplest way to configured the trusted root certificates
involves loading the <code>libnssckbi.so</code> NSS
module with a call to the
<code>SECMOD_LoadUserModule</code> function. The root
certificates are compiled into this module. (The PEM module
for NSS, <code>libnsspem.so</code>, offers a way to
load trusted CA certificates from a file.)</p>
</div>
<div id="ex-Defensive_Coding-TLS-NSS-Init" class="exampleblock">
<div class="title">Example 21. Initializing the NSS library</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c">PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, <span style="color:#00D">0</span>);
NSSInitContext *<span style="color:#088;font-weight:bold">const</span> ctx =
NSS_InitContext(<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">sql:/etc/pki/nssdb</span><span style="color:#710">&quot;</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#710">&quot;</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#710">&quot;</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#710">&quot;</span></span>, <span style="color:#069">NULL</span>,
NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
<span style="color:#080;font-weight:bold">if</span> (ctx == <span style="color:#069">NULL</span>) {
<span style="color:#088;font-weight:bold">const</span> PRErrorCode err = PR_GetError();
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: NSPR error code %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
err, PR_ErrorToName(err));
exit(<span style="color:#00D">1</span>);
}
<span style="color:#777">// Ciphers to enable.</span>
<span style="color:#088;font-weight:bold">static</span> <span style="color:#088;font-weight:bold">const</span> PRUint16 good_ciphers[] = {
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_RSA_WITH_AES_128_GCM_SHA256,
TLS_RSA_WITH_AES_256_GCM_SHA384,
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_RSA_WITH_AES_128_CBC_SHA,
TLS_RSA_WITH_AES_256_CBC_SHA,
SSL_RSA_WITH_3DES_EDE_CBC_SHA,
SSL_NULL_WITH_NULL_NULL <span style="color:#777">// sentinel</span>
};
<span style="color:#777">// Check if the current policy allows any strong ciphers. If it</span>
<span style="color:#777">// doesn't, set the cipher suite policy. This is not thread-safe</span>
<span style="color:#777">// and has global impact. Consequently, we only do it if absolutely</span>
<span style="color:#777">// necessary.</span>
<span style="color:#0a8;font-weight:bold">int</span> found_good_cipher = <span style="color:#00D">0</span>;
<span style="color:#080;font-weight:bold">for</span> (<span style="color:#088;font-weight:bold">const</span> PRUint16 *p = good_ciphers; *p != SSL_NULL_WITH_NULL_NULL;
++p) {
PRInt32 policy;
<span style="color:#080;font-weight:bold">if</span> (SSL_CipherPolicyGet(*p, &amp;policy) != SECSuccess) {
<span style="color:#088;font-weight:bold">const</span> PRErrorCode err = PR_GetError();
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: policy for cipher %u: error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
(<span style="color:#0a8;font-weight:bold">unsigned</span>)*p, err, PR_ErrorToName(err));
exit(<span style="color:#00D">1</span>);
}
<span style="color:#080;font-weight:bold">if</span> (policy == SSL_ALLOWED) {
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">info: found cipher %x</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>, (<span style="color:#0a8;font-weight:bold">unsigned</span>)*p);
found_good_cipher = <span style="color:#00D">1</span>;
<span style="color:#080;font-weight:bold">break</span>;
}
}
<span style="color:#080;font-weight:bold">if</span> (!found_good_cipher) {
<span style="color:#080;font-weight:bold">if</span> (NSS_SetDomesticPolicy() != SECSuccess) {
<span style="color:#088;font-weight:bold">const</span> PRErrorCode err = PR_GetError();
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: NSS_SetDomesticPolicy: error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
err, PR_ErrorToName(err));
exit(<span style="color:#00D">1</span>);
}
}
<span style="color:#777">// Initialize the trusted certificate store.</span>
<span style="color:#0a8;font-weight:bold">char</span> module_name[] = <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">library=libnssckbi.so name=</span><span style="color:#b0b">\&quot;</span><span style="color:#D20">Root Certs</span><span style="color:#b0b">\&quot;</span><span style="color:#710">&quot;</span></span>;
SECMODModule *module = SECMOD_LoadUserModule(module_name, <span style="color:#069">NULL</span>, PR_FALSE);
<span style="color:#080;font-weight:bold">if</span> (module == <span style="color:#069">NULL</span> || !module-&gt;loaded) {
<span style="color:#088;font-weight:bold">const</span> PRErrorCode err = PR_GetError();
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: NSPR error code %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
err, PR_ErrorToName(err));
exit(<span style="color:#00D">1</span>);
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Some of the effects of the initialization can be reverted with
the following function calls:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c">SECMOD_DestroyModule(module);
NSS_ShutdownContext(ctx);</code></pre>
</div>
</div>
<div class="paragraph">
<p>After NSS has been initialized, the TLS connection can be
created (<a href="#ex-Defensive_Coding-TLS-Client-NSS-Connect">Creating a TLS connection with NSS</a>). The
internal <code>PR_ImportTCPSocket</code> function is
used to turn the POSIX file descriptor
<code>sockfd</code> 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 <strong>model</strong> 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.</p>
</div>
<div class="paragraph">
<p>The call to <code>SSL_BadCertHook</code> can be
omitted if no mechanism to override certificate verification
is needed. The <code>bad_certificate</code> function
must check both the host name specified for the connection and
the certificate before granting the override.</p>
</div>
<div class="paragraph">
<p>Triggering the actual handshake requires three function calls,
<code>SSL_ResetHandshake</code>,
<code>SSL_SetURL</code>, and
<code>SSL_ForceHandshake</code>. (If
<code>SSL_ResetHandshake</code> is omitted,
<code>SSL_ForceHandshake</code> will succeed, but the
data will not be encrypted.) During the handshake, the
certificate is verified and matched against the host name.</p>
</div>
<div id="ex-Defensive_Coding-TLS-Client-NSS-Connect" class="exampleblock">
<div class="title">Example 22. Creating a TLS connection with NSS</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c"><span style="color:#777">// Wrap the POSIX file descriptor. This is an internal NSPR</span>
<span style="color:#777">// function, but it is very unlikely to change.</span>
PRFileDesc* nspr = PR_ImportTCPSocket(sockfd);
sockfd = -<span style="color:#00D">1</span>; <span style="color:#777">// Has been taken over by NSPR.</span>
<span style="color:#777">// Add the SSL layer.</span>
{
PRFileDesc *model = PR_NewTCPSocket();
PRFileDesc *newfd = SSL_ImportFD(<span style="color:#069">NULL</span>, model);
<span style="color:#080;font-weight:bold">if</span> (newfd == <span style="color:#069">NULL</span>) {
<span style="color:#088;font-weight:bold">const</span> PRErrorCode err = PR_GetError();
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: NSPR error code %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
err, PR_ErrorToName(err));
exit(<span style="color:#00D">1</span>);
}
model = newfd;
newfd = <span style="color:#069">NULL</span>;
<span style="color:#080;font-weight:bold">if</span> (SSL_OptionSet(model, SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess) {
<span style="color:#088;font-weight:bold">const</span> PRErrorCode err = PR_GetError();
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: set SSL_ENABLE_SSL2 error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
err, PR_ErrorToName(err));
exit(<span style="color:#00D">1</span>);
}
<span style="color:#080;font-weight:bold">if</span> (SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, PR_FALSE) != SECSuccess) {
<span style="color:#088;font-weight:bold">const</span> PRErrorCode err = PR_GetError();
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: set SSL_V2_COMPATIBLE_HELLO error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
err, PR_ErrorToName(err));
exit(<span style="color:#00D">1</span>);
}
<span style="color:#080;font-weight:bold">if</span> (SSL_OptionSet(model, SSL_ENABLE_DEFLATE, PR_FALSE) != SECSuccess) {
<span style="color:#088;font-weight:bold">const</span> PRErrorCode err = PR_GetError();
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: set SSL_ENABLE_DEFLATE error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
err, PR_ErrorToName(err));
exit(<span style="color:#00D">1</span>);
}
<span style="color:#777">// Allow overriding invalid certificate.</span>
<span style="color:#080;font-weight:bold">if</span> (SSL_BadCertHook(model, bad_certificate, (<span style="color:#0a8;font-weight:bold">char</span> *)host) != SECSuccess) {
<span style="color:#088;font-weight:bold">const</span> PRErrorCode err = PR_GetError();
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: SSL_BadCertHook error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
err, PR_ErrorToName(err));
exit(<span style="color:#00D">1</span>);
}
newfd = SSL_ImportFD(model, nspr);
<span style="color:#080;font-weight:bold">if</span> (newfd == <span style="color:#069">NULL</span>) {
<span style="color:#088;font-weight:bold">const</span> PRErrorCode err = PR_GetError();
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: SSL_ImportFD error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
err, PR_ErrorToName(err));
exit(<span style="color:#00D">1</span>);
}
nspr = newfd;
PR_Close(model);
}
<span style="color:#777">// Perform the handshake.</span>
<span style="color:#080;font-weight:bold">if</span> (SSL_ResetHandshake(nspr, PR_FALSE) != SECSuccess) {
<span style="color:#088;font-weight:bold">const</span> PRErrorCode err = PR_GetError();
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: SSL_ResetHandshake error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
err, PR_ErrorToName(err));
exit(<span style="color:#00D">1</span>);
}
<span style="color:#080;font-weight:bold">if</span> (SSL_SetURL(nspr, host) != SECSuccess) {
<span style="color:#088;font-weight:bold">const</span> PRErrorCode err = PR_GetError();
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: SSL_SetURL error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
err, PR_ErrorToName(err));
exit(<span style="color:#00D">1</span>);
}
<span style="color:#080;font-weight:bold">if</span> (SSL_ForceHandshake(nspr) != SECSuccess) {
<span style="color:#088;font-weight:bold">const</span> PRErrorCode err = PR_GetError();
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: SSL_ForceHandshake error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
err, PR_ErrorToName(err));
exit(<span style="color:#00D">1</span>);
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>After the connection has been established, <a href="#ex-Defensive_Coding-TLS-NSS-Use">Using NSS for sending and receiving data</a> shows how to use
the NSPR descriptor to communicate with the server.</p>
</div>
<div id="ex-Defensive_Coding-TLS-NSS-Use" class="exampleblock">
<div class="title">Example 23. Using NSS for sending and receiving data</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c"><span style="color:#0a8;font-weight:bold">char</span> buf[<span style="color:#00D">4096</span>];
snprintf(buf, <span style="color:#080;font-weight:bold">sizeof</span>(buf), <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">GET / HTTP/1.0</span><span style="color:#b0b">\r</span><span style="color:#b0b">\n</span><span style="color:#D20">Host: %s</span><span style="color:#b0b">\r</span><span style="color:#b0b">\n</span><span style="color:#b0b">\r</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>, host);
PRInt32 ret = PR_Write(nspr, buf, strlen(buf));
<span style="color:#080;font-weight:bold">if</span> (ret &lt; <span style="color:#00D">0</span>) {
<span style="color:#088;font-weight:bold">const</span> PRErrorCode err = PR_GetError();
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: PR_Write error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
err, PR_ErrorToName(err));
exit(<span style="color:#00D">1</span>);
}
ret = PR_Read(nspr, buf, <span style="color:#080;font-weight:bold">sizeof</span>(buf));
<span style="color:#080;font-weight:bold">if</span> (ret &lt; <span style="color:#00D">0</span>) {
<span style="color:#088;font-weight:bold">const</span> PRErrorCode err = PR_GetError();
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: PR_Read error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
err, PR_ErrorToName(err));
exit(<span style="color:#00D">1</span>);
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p><a href="#ex-Defensive_Coding-TLS-Client-NSS-Close">Closing NSS client connections</a>
shows how to close the connection.</p>
</div>
<div id="ex-Defensive_Coding-TLS-Client-NSS-Close" class="exampleblock">
<div class="title">Example 24. Closing NSS client connections</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="c"><span style="color:#777">// Send close_notify alert.</span>
<span style="color:#080;font-weight:bold">if</span> (PR_Shutdown(nspr, PR_SHUTDOWN_BOTH) != PR_SUCCESS) {
<span style="color:#088;font-weight:bold">const</span> PRErrorCode err = PR_GetError();
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">error: PR_Read error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>,
err, PR_ErrorToName(err));
exit(<span style="color:#00D">1</span>);
}
<span style="color:#777">// Closes the underlying POSIX file descriptor, too.</span>
PR_Close(nspr);</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="sect-Defensive_Coding-TLS-Client-Python"><a class="anchor" href="#sect-Defensive_Coding-TLS-Client-Python"></a>Implementing TLS Clients With Python</h3>
<div class="paragraph">
<p>The Python distribution provides a TLS implementation in the
<code>ssl</code> 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 <a href="#sect-Defensive_Coding-TLS-OpenSSL">OpenSSL Pitfalls</a>.</p>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Currently, most Python function which accept
<code>https://</code> URLs or otherwise implement
HTTPS support do not perform certificate validation at all.
(For example, this is true for the <code>httplib</code>
and <code>xmlrpclib</code> modules.) If you use
HTTPS, you should not use the built-in HTTP clients. The
<code>Curl</code> class in the <code>curl</code>
module, as provided by the <code>python-pycurl</code>
package implements proper certificate validation.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The <code>ssl</code> module currently does not perform
host name checking on the server certificate. <a href="#ex-Defensive_Coding-TLS-Client-Python-check_host_name">Implementing TLS host name checking Python (without wildcard support)</a>
shows how to implement certificate matching, using the parsed
certificate returned by <code>getpeercert</code>.</p>
</div>
<div id="ex-Defensive_Coding-TLS-Client-Python-check_host_name" class="exampleblock">
<div class="title">Example 25. Implementing TLS host name checking Python (without wildcard support)</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="python"><span style="color:#080;font-weight:bold">def</span> <span style="color:#06B;font-weight:bold">check_host_name</span>(peercert, name):
<span style="color:#D42"><span style="color:black">&quot;&quot;&quot;</span><span>Simple certificate/host name checker. Returns True if the</span><span>
</span><span> certificate matches, False otherwise. Does not support</span><span>
</span><span> wildcards.</span><span style="color:black">&quot;&quot;&quot;</span></span>
<span style="color:#777"># Check that the peer has supplied a certificate.</span>
<span style="color:#777"># None/{} is not acceptable.</span>
<span style="color:#080;font-weight:bold">if</span> <span style="color:#080;font-weight:bold">not</span> peercert:
<span style="color:#080;font-weight:bold">return</span> <span style="color:#069">False</span>
<span style="color:#080;font-weight:bold">if</span> peercert.has_key(<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">subjectAltName</span><span style="color:#710">&quot;</span></span>):
<span style="color:#080;font-weight:bold">for</span> typ, val <span style="color:#080;font-weight:bold">in</span> peercert[<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">subjectAltName</span><span style="color:#710">&quot;</span></span>]:
<span style="color:#080;font-weight:bold">if</span> typ == <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">DNS</span><span style="color:#710">&quot;</span></span> <span style="color:#080;font-weight:bold">and</span> val == name:
<span style="color:#080;font-weight:bold">return</span> <span style="color:#069">True</span>
<span style="color:#080;font-weight:bold">else</span>:
<span style="color:#777"># Only check the subject DN if there is no subject alternative</span>
<span style="color:#777"># name.</span>
cn = <span style="color:#069">None</span>
<span style="color:#080;font-weight:bold">for</span> attr, val <span style="color:#080;font-weight:bold">in</span> peercert[<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">subject</span><span style="color:#710">&quot;</span></span>]:
<span style="color:#777"># Use most-specific (last) commonName attribute.</span>
<span style="color:#080;font-weight:bold">if</span> attr == <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">commonName</span><span style="color:#710">&quot;</span></span>:
cn = val
<span style="color:#080;font-weight:bold">if</span> cn <span style="color:#080;font-weight:bold">is</span> <span style="color:#080;font-weight:bold">not</span> <span style="color:#069">None</span>:
<span style="color:#080;font-weight:bold">return</span> cn == name
<span style="color:#080;font-weight:bold">return</span> <span style="color:#069">False</span></code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>To turn a regular, connected TCP socket into a TLS-enabled
socket, use the <code>ssl.wrap_socket</code> function.
The function call in <a href="#ex-Defensive_Coding-TLS-Client-Python-Connect">Establishing a TLS client connection with Python</a>
provides additional arguments to override questionable
defaults in OpenSSL and in the Python module.</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>ciphers="HIGH:-aNULL:-eNULL:-PSK:RC4-SHA:RC4-MD5"</code>
selects relatively strong cipher suites with
certificate-based authentication. (The call to
<code>check_host_name</code> function provides
additional protection against anonymous cipher suites.)</p>
</li>
<li>
<p><code>ssl_version=ssl.PROTOCOL_TLSv1</code> disables
SSL 2.0 support. By default, the <code>ssl</code>
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.</p>
</li>
<li>
<p><code>cert_reqs=ssl.CERT_REQUIRED</code> turns on
certificate validation.</p>
</li>
<li>
<p><code>ca_certs='/etc/ssl/certs/ca-bundle.crt'</code>
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
<code>ssl</code> module.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The <code>ssl</code> module (and OpenSSL) perform
certificate validation, but the certificate must be compared
manually against the host name, by calling the
<code>check_host_name</code> defined above.</p>
</div>
<div id="ex-Defensive_Coding-TLS-Client-Python-Connect" class="exampleblock">
<div class="title">Example 26. Establishing a TLS client connection with Python</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="python">sock = ssl.wrap_socket(sock,
ciphers=<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">HIGH:-aNULL:-eNULL:-PSK:RC4-SHA:RC4-MD5</span><span style="color:#710">&quot;</span></span>,
ssl_version=ssl.PROTOCOL_TLSv1,
cert_reqs=ssl.CERT_REQUIRED,
ca_certs=<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">'</span><span style="color:#D20">/etc/ssl/certs/ca-bundle.crt</span><span style="color:#710">'</span></span>)
<span style="color:#777"># getpeercert() triggers the handshake as a side effect.</span>
<span style="color:#080;font-weight:bold">if</span> <span style="color:#080;font-weight:bold">not</span> check_host_name(sock.getpeercert(), host):
<span style="color:#080;font-weight:bold">raise</span> <span style="color:#C00;font-weight:bold">IOError</span>(<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">peer certificate does not match host name</span><span style="color:#710">&quot;</span></span>)</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>After the connection has been established, the TLS socket can
be used like a regular socket:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="python">sock.write(<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#D20">GET / HTTP/1.1</span><span style="color:#b0b">\r</span><span style="color:#b0b">\n</span><span style="color:#D20">Host: </span><span style="color:#710">&quot;</span></span> + host + <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">&quot;</span><span style="color:#b0b">\r</span><span style="color:#b0b">\n</span><span style="color:#b0b">\r</span><span style="color:#b0b">\n</span><span style="color:#710">&quot;</span></span>)
<span style="color:#080;font-weight:bold">print</span> sock.read()</code></pre>
</div>
</div>
<div class="paragraph">
<p>Closing the TLS socket is straightforward as well:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="python">sock.close()</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="bottom" class="text-muted py-3" >
<div class="foot">
<div class="container">
<div class="row footerlinks">
<div class="col-sm-3 col-xs-6 widget">
<h3 class="widget-title">About</h3>
<div class="widget-body">
<dl>
<dd><a href="https://fedoraproject.org/wiki/Overview">About Fedora</a></dd>
<dd><a href="https://getfedora.org/en/sponsors">Sponsors</a></dd>
<dd><a href="https://fedoramagazine.org">Fedora Magazine</a></dd>
<dd><a href="https://fedoraproject.org/wiki/Legal:Main#Legal">Legal</a></dd>
</dl>
<ul class="list-inline">
<li>
<a href="https://www.facebook.com/TheFedoraProject" class="btn-social btn-outline"><i class="fa fa-fw fa-facebook"></i></a>
</li>
<li>
<a href="https://plus.google.com/112917221531140868607" class="btn-social btn-outline"><i class="fa fa-fw fa-google-plus"></i></a>
</li>
<li>
<a href="https://twitter.com/fedora" class="btn-social btn-outline"><i class="fa fa-fw fa-twitter"></i></a>
</li>
</ul>
</div>
</div>
<div class="col-sm-3 col-xs-6 widget">
<h3 class="widget-title uppercase">Download</h3>
<div class="widget-body">
<dl>
<dd><a href="https://getfedora.org/en/workstation/download">Get Fedora Workstation</a></dd>
<dd><a href="https://getfedora.org/en/server/download">Get Fedora Server</a></dd>
<dd><a href="https://getfedora.org/en/atomic/download">Get Fedora Atomic</a></dd>
<dd><a href="https://spins.fedoraproject.org">Fedora Spins</a></dd>
<dd><a href="https://labs.fedoraproject.org">Fedora Labs</a></dd>
<dd><a href="https://arm.fedoraproject.org">Fedora ARM<span class="sup">&reg;</span></a></dd>
<dd><a href="https://alt.fedoraproject.org/">Alternative Downloads</a></dd>
</dl>
</div>
</div>
<div class="col-sm-3 col-xs-6 widget">
<h3 class="widget-title">Support</h3>
<div class="widget-body">
<dl>
<dd><a href="https://fedoraproject.org/wiki/Communicating_and_getting_help">Get Help</a></dd>
<dd><a href="https://ask.fedoraproject.org/">Ask Fedora</a></dd>
<dd><a href="https://fedoraproject.org/wiki/Common_F27_bugs">Common Bugs</a></dd>
<dd><a href="https://developer.fedoraproject.org/">Fedora Developer Portal</a></dd>
<dd><a href="https://docs.fedoraproject.org/f27/install-guide/index.html">Installation Guide</a></dd>
</dl>
</div>
</div>
<div class="col-sm-3 col-xs-6 widget">
<h3 class="widget-title">Join</h3>
<div class="widget-body">
<dl>
<dd><a href="https://fedoraproject.org/wiki/Join">Join Fedora</a></dd>
<dd><a href="http://fedoraplanet.org">Planet Fedora</a></dd>
<dd><a href="https://fedoraproject.org/wiki/SIGs">Fedora SIGs</a></dd>
<dd><a href="https://admin.fedoraproject.org/accounts/">Fedora Account System</a></dd>
<dd><a href="https://fedoracommunity.org/">Fedora Community</a></dd>
</dl>
</div>
</div>
</div> <!-- /row of widgets -->
<div class="row">
<div class="col-md-2">
<div class="widget-body">
<a href="https://www.redhat.com/"><img class="rh-logo" src="../../../master/_images/redhat-logo.png" alt="Red Hat Logo" /></a>
</div>
</div>
<div class="col-md-7">
<div class="widget-body">
<p class="sponsor">Fedora is sponsored by Red Hat.</p>
<p class="sponsor"><a href="https://www.redhat.com/en/technologies/linux-platforms/articles/relationship-between-fedora-and-rhel">Learn more about the relationship between Red Hat and Fedora &raquo;</a></p>
<p class="copy">&copy; 2017 Red Hat, Inc. and others. Please send any comments or corrections to the <a href="https://pagure.io/fedora-docs/docs-fp-o">documentation team</a></p>
</div>
</div>
</div> <!-- /row of widgets -->
</div>
</div>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="../../../master/_javascripts/bootstrap-offcanvas.js" type="text/javascript"></script>
<script type="text/javascript">
/*<![CDATA[*/
$(document).ready(function() {
$("[id^='topicGroup']").on('show.bs.collapse', function (event) {
if (!($(event.target).attr('id').match(/^topicSubGroup/))) {
$(this).parent().find("[id^='tgSpan']").toggleClass("fa-angle-right fa-angle-down");
}
});
$("[id^='topicGroup']").on('hide.bs.collapse', function (event) {
if (!($(event.target).attr('id').match(/^topicSubGroup/))) {
$(this).parent().find("[id^='tgSpan']").toggleClass("fa-angle-right fa-angle-down");
}
});
$("[id^='topicSubGroup']").on('show.bs.collapse', function () {
$(this).parent().find("[id^='sgSpan']").toggleClass("fa-caret-right fa-caret-down");
});
$("[id^='topicSubGroup']").on('hide.bs.collapse', function () {
$(this).parent().find("[id^='sgSpan']").toggleClass("fa-caret-right fa-caret-down");
});
});
/*]]>*/
</script>
</body>
</html>