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
1893 lines
No EOL
116 KiB
HTML
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> 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 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> 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> 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, &val, <span style="color:#080;font-weight:bold">sizeof</span>(val));
|
|
<span style="color:#080;font-weight:bold">if</span> (ret < <span style="color:#00D">0</span>) {
|
|
perror(<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">setsockopt(TCP_NODELAY)</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: %s: no error to report</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: %s: invalid blocking state %d</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: %s: TLS layer problem</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: %s: system call failed: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: %s: zero return</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">HIGH:MEDIUM</span><span style="color:#710">"</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">"</span><span style="color:#D20">AES128-GCM-SHA256</span><span style="color:#710">"</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">AES128-SHA256</span><span style="color:#710">"</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">AES256-SHA256</span><span style="color:#710">"</span></span>, <span style="color:#777">// strong ciphers</span>
|
|
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">AES128-SHA</span><span style="color:#710">"</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">AES256-SHA</span><span style="color:#710">"</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">"</span><span style="color:#D20">RC4-SHA</span><span style="color:#710">"</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">RC4-MD5</span><span style="color:#710">"</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">"</span><span style="color:#D20">DES-CBC3-SHA</span><span style="color:#710">"</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">DES-CBC3-MD5</span><span style="color:#710">"</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 < 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">"</span><span style="color:#D20">:</span><span style="color:#710">"</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">"</span><span style="color:#D20">SSL_connect</span><span style="color:#710">"</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">"</span><span style="color:#D20">peer certificate missing</span><span style="color:#710">"</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 && !certificate_validity_override(peercert)) {
|
|
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">SSL_connect: verify result: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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>
|
|
&& !certificate_host_name_override(peercert, host)) {
|
|
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">SSL certificate does not match host name</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</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">"</span></span>;
|
|
<span style="color:#080;font-weight:bold">if</span> (SSL_write(ssl, req, strlen(req)) < <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">"</span><span style="color:#D20">SSL_write</span><span style="color:#710">"</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 < <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">"</span><span style="color:#D20">SSL_read</span><span style="color:#710">"</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">"</span><span style="color:#D20">info: second SSL_shutdown returned zero</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">SSL_shutdown 2</span><span style="color:#710">"</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">"</span><span style="color:#D20">SSL_shutdown 1</span><span style="color:#710">"</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 (&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">"</span><span style="color:#D20">error: gnutls_certificate_allocate_credentials: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: no certificates found in system trust store</span><span style="color:#b0b">\n</span><span style="color:#710">"</span></span>);
|
|
exit(<span style="color:#00D">1</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">"</span><span style="color:#D20">error: gnutls_certificate_set_x509_system_trust: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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(&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">"</span><span style="color:#D20">error: gnutls_init: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">NORMAL</span><span style="color:#710">"</span></span>, &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">"</span><span style="color:#D20">error: gnutls_priority_set_direct: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</span></span>
|
|
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">error: at: </span><span style="color:#b0b">\"</span><span style="color:#D20">%s</span><span style="color:#b0b">\"</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: gnutls_credentials_set: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: gnutls_server_name_set: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: gnutls_handshake: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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’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, &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">"</span><span style="color:#D20">error: could not obtain peer certificate</span><span style="color:#b0b">\n</span><span style="color:#710">"</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, &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">"</span><span style="color:#D20">error: gnutls_certificate_verify_peers3: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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> && !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, &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">"</span><span style="color:#D20">error: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: certificate validation failed with code 0x%x</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</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">"</span></span>, host);
|
|
ret = gnutls_record_send(session, buf, strlen(buf));
|
|
<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">"</span><span style="color:#D20">error: gnutls_record_send: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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 < <span style="color:#00D">0</span>) {
|
|
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">error: gnutls_record_recv: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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 < <span style="color:#00D">0</span>) {
|
|
fprintf(stderr, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">error: gnutls_bye: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">TLSv1.2</span><span style="color:#710">"</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">SunJSSE</span><span style="color:#710">"</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">"</span><span style="color:#D20">TLSv1</span><span style="color:#710">"</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">SunJSSE</span><span style="color:#710">"</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><<span style="color:#0a8;font-weight:bold">String</span>> protocols = <span style="color:#080;font-weight:bold">new</span> <span style="color:#0a8;font-weight:bold">ArrayList</span><<span style="color:#0a8;font-weight:bold">String</span>>(
|
|
<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">"</span><span style="color:#D20">SSLv2Hello</span><span style="color:#710">"</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><<span style="color:#0a8;font-weight:bold">String</span>> ciphers = <span style="color:#080;font-weight:bold">new</span> <span style="color:#0a8;font-weight:bold">ArrayList</span><<span style="color:#0a8;font-weight:bold">String</span>>(
|
|
<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">"</span><span style="color:#D20">TLS_RSA_WITH_AES_128_CBC_SHA256</span><span style="color:#710">"</span></span>,
|
|
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">TLS_RSA_WITH_AES_256_CBC_SHA256</span><span style="color:#710">"</span></span>,
|
|
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">TLS_RSA_WITH_AES_256_CBC_SHA</span><span style="color:#710">"</span></span>,
|
|
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">TLS_RSA_WITH_AES_128_CBC_SHA</span><span style="color:#710">"</span></span>,
|
|
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">SSL_RSA_WITH_3DES_EDE_CBC_SHA</span><span style="color:#710">"</span></span>,
|
|
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">SSL_RSA_WITH_RC4_128_SHA1</span><span style="color:#710">"</span></span>,
|
|
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">SSL_RSA_WITH_RC4_128_MD5</span><span style="color:#710">"</span></span>,
|
|
<span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">TLS_EMPTY_RENEGOTIATION_INFO_SCSV</span><span style="color:#710">"</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">"</span><span style="color:#D20">HTTPS</span><span style="color:#710">"</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">"</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">"</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">"</span><span style="color:#D20">UTF-8</span><span style="color:#710">"</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">"</span><span style="color:#D20">info: accepting certificate: </span><span style="color:#710">"</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">"</span><span style="color:#D20">certificate rejected: </span><span style="color:#710">"</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">"</span><span style="color:#D20">TLSv1.2</span><span style="color:#710">"</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">SunJSSE</span><span style="color:#710">"</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">"</span><span style="color:#D20">TLSv1</span><span style="color:#710">"</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">SunJSSE</span><span style="color:#710">"</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"><prerror.h></span>
|
|
<span style="color:#579">#include</span> <span style="color:#B44;font-weight:bold"><prinit.h></span>
|
|
|
|
<span style="color:#777">// NSS include files</span>
|
|
<span style="color:#579">#include</span> <span style="color:#B44;font-weight:bold"><nss.h></span>
|
|
<span style="color:#579">#include</span> <span style="color:#B44;font-weight:bold"><pk11pub.h></span>
|
|
<span style="color:#579">#include</span> <span style="color:#B44;font-weight:bold"><secmod.h></span>
|
|
<span style="color:#579">#include</span> <span style="color:#B44;font-weight:bold"><ssl.h></span>
|
|
<span style="color:#579">#include</span> <span style="color:#B44;font-weight:bold"><sslproto.h></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">"</span><span style="color:#D20">sql:/etc/pki/nssdb</span><span style="color:#710">"</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#710">"</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#710">"</span></span>, <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: NSPR error code %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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, &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">"</span><span style="color:#D20">error: policy for cipher %u: error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">info: found cipher %x</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: NSS_SetDomesticPolicy: error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">library=libnssckbi.so name=</span><span style="color:#b0b">\"</span><span style="color:#D20">Root Certs</span><span style="color:#b0b">\"</span><span style="color:#710">"</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->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">"</span><span style="color:#D20">error: NSPR error code %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: NSPR error code %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: set SSL_ENABLE_SSL2 error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</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">"</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">"</span><span style="color:#D20">error: set SSL_ENABLE_DEFLATE error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: SSL_BadCertHook error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: SSL_ImportFD error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: SSL_ResetHandshake error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: SSL_SetURL error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: SSL_ForceHandshake error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</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">"</span></span>, host);
|
|
PRInt32 ret = PR_Write(nspr, buf, strlen(buf));
|
|
<span style="color:#080;font-weight:bold">if</span> (ret < <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">"</span><span style="color:#D20">error: PR_Write error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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 < <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">"</span><span style="color:#D20">error: PR_Read error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"</span><span style="color:#D20">error: PR_Read error %d: %s</span><span style="color:#b0b">\n</span><span style="color:#710">"</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">"""</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">"""</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">"</span><span style="color:#D20">subjectAltName</span><span style="color:#710">"</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">"</span><span style="color:#D20">subjectAltName</span><span style="color:#710">"</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">"</span><span style="color:#D20">DNS</span><span style="color:#710">"</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">"</span><span style="color:#D20">subject</span><span style="color:#710">"</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">"</span><span style="color:#D20">commonName</span><span style="color:#710">"</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">"</span><span style="color:#D20">HIGH:-aNULL:-eNULL:-PSK:RC4-SHA:RC4-MD5</span><span style="color:#710">"</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">"</span><span style="color:#D20">peer certificate does not match host name</span><span style="color:#710">"</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">"</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">"</span></span> + host + <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</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">"</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">®</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 »</a></p>
|
|
<p class="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> |