aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl')
-rw-r--r--lib/ssl/Makefile16
-rw-r--r--lib/ssl/doc/src/Makefile4
-rw-r--r--lib/ssl/doc/src/book.xml3
-rw-r--r--lib/ssl/doc/src/create_certs.xml148
-rw-r--r--lib/ssl/doc/src/insidecover.xml14
-rw-r--r--lib/ssl/doc/src/licenses.xml156
-rw-r--r--lib/ssl/doc/src/notes.xml2
-rw-r--r--lib/ssl/doc/src/refman.xml3
-rw-r--r--lib/ssl/doc/src/ssl.xml33
-rw-r--r--lib/ssl/doc/src/ssl_app.xml155
-rw-r--r--lib/ssl/doc/src/ssl_distribution.xml8
-rw-r--r--lib/ssl/doc/src/ssl_protocol.xml431
-rw-r--r--lib/ssl/doc/src/ssl_session_cache_api.xml158
-rw-r--r--lib/ssl/doc/src/usersguide.xml20
-rw-r--r--lib/ssl/doc/src/using_ssl.xml149
-rw-r--r--lib/ssl/doc/src/using_ssl.xmlsrc113
-rw-r--r--lib/ssl/src/ssl.appup.src2
-rw-r--r--lib/ssl/src/ssl.erl117
-rw-r--r--lib/ssl/src/ssl_alert.erl25
-rw-r--r--lib/ssl/src/ssl_app.erl12
-rw-r--r--lib/ssl/src/ssl_certificate.erl61
-rw-r--r--lib/ssl/src/ssl_certificate_db.erl51
-rw-r--r--lib/ssl/src/ssl_cipher.erl81
-rw-r--r--lib/ssl/src/ssl_cipher.hrl8
-rw-r--r--lib/ssl/src/ssl_connection.erl361
-rw-r--r--lib/ssl/src/ssl_handshake.erl169
-rw-r--r--lib/ssl/src/ssl_internal.hrl24
-rw-r--r--lib/ssl/src/ssl_manager.erl110
-rw-r--r--lib/ssl/src/ssl_record.erl117
-rw-r--r--lib/ssl/src/ssl_session.erl32
-rw-r--r--lib/ssl/src/ssl_session_cache.erl45
-rw-r--r--lib/ssl/src/ssl_ssl3.erl15
-rw-r--r--lib/ssl/src/ssl_sup.erl7
-rw-r--r--lib/ssl/src/ssl_tls1.erl16
-rw-r--r--lib/ssl/test/erl_make_certs.erl34
-rw-r--r--lib/ssl/test/make_certs.erl16
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl108
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl267
-rw-r--r--lib/ssl/test/ssl_test_lib.erl32
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl4
-rw-r--r--lib/ssl/vsn.mk43
41 files changed, 1522 insertions, 1648 deletions
diff --git a/lib/ssl/Makefile b/lib/ssl/Makefile
index b8b51270c9..8c9d78d4bc 100644
--- a/lib/ssl/Makefile
+++ b/lib/ssl/Makefile
@@ -24,21 +24,11 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
#
# Macros
#
-ifeq ($(findstring win32,$(TARGET)),win32)
-ifeq ($(HOST_OS),)
-HOST_OS := $(shell $(ERL_TOP)/erts/autoconf/config.guess)
-endif
-ifeq ($(findstring solaris,$(HOST_OS)),solaris)
-SKIP_BUILDING_BINARIES := true
-endif
-else
-SKIP_BUILDING_BINARIES := false
-endif
-ifeq ($(SKIP_BUILDING_BINARIES), true)
SUB_DIRECTORIES = src c_src doc/src
-else
-SUB_DIRECTORIES = src c_src doc/src examples/certs examples/src
+
+ifeq ($(CROSS_COMPILING),no)
+SUB_DIRECTORIES += examples/certs examples/src
endif
include vsn.mk
diff --git a/lib/ssl/doc/src/Makefile b/lib/ssl/doc/src/Makefile
index d6788c1633..3119d37af0 100644
--- a/lib/ssl/doc/src/Makefile
+++ b/lib/ssl/doc/src/Makefile
@@ -37,7 +37,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
# Target Specs
# ----------------------------------------------------
XML_APPLICATION_FILES = refman.xml
-XML_REF3_FILES = ssl.xml old_ssl.xml
+XML_REF3_FILES = ssl.xml old_ssl.xml ssl_session_cache_api.xml
XML_REF6_FILES = ssl_app.xml
XML_PART_FILES = release_notes.xml usersguide.xml
@@ -45,9 +45,7 @@ XML_CHAPTER_FILES = \
ssl_protocol.xml \
using_ssl.xml \
pkix_certs.xml \
- create_certs.xml \
ssl_distribution.xml \
- licenses.xml \
notes.xml
BOOK_FILES = book.xml
diff --git a/lib/ssl/doc/src/book.xml b/lib/ssl/doc/src/book.xml
index 9122addb74..85d6b56b26 100644
--- a/lib/ssl/doc/src/book.xml
+++ b/lib/ssl/doc/src/book.xml
@@ -28,9 +28,6 @@
<rev>A</rev>
<file>book.sgml</file>
</header>
- <insidecover>
- <include file="insidecover"></include>
- </insidecover>
<pagetext>SSL Application</pagetext>
<preamble>
<contents level="2"></contents>
diff --git a/lib/ssl/doc/src/create_certs.xml b/lib/ssl/doc/src/create_certs.xml
deleted file mode 100644
index 79cc8a0537..0000000000
--- a/lib/ssl/doc/src/create_certs.xml
+++ /dev/null
@@ -1,148 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2003</year><year>2009</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- </legalnotice>
-
- <title>Creating Certificates</title>
- <prepared>UAB/F/P Peter H&ouml;gfeldt</prepared>
- <docno></docno>
- <date>2003-06-16</date>
- <rev>A</rev>
- <file>create_certs.xml</file>
- </header>
- <p>Here we consider the creation of example certificates.
- </p>
-
- <section>
- <title>The openssl Command</title>
- <p>The <c>openssl</c> command is a utility that comes with the
- OpenSSL distribution. It provides a variety of subcommands. Each
- subcommand is invoked as</p>
- <code type="none"><![CDATA[
- openssl subcmd <options and arguments> ]]></code>
- <p>where <c>subcmd</c> denotes the subcommand in question.
- </p>
- <p>We shall use the following subcommands to create certificates for
- the purpose of testing Erlang/OTP SSL:
- </p>
- <list type="bulleted">
- <item><em>req</em> to create certificate requests and a
- self-signed certificates,
- </item>
- <item><em>ca</em> to create certificates from certificate requests.</item>
- </list>
- <p>We create the following certificates:
- </p>
- <list type="bulleted">
- <item>the <em>erlangCA</em> root certificate (a self-signed
- certificate), </item>
- <item>the <em>otpCA</em> certificate signed by the <em>erlangCA</em>, </item>
- <item>a client certificate signed by the <em>otpCA</em>, and</item>
- <item>a server certificate signed by the <em>otpCA</em>.</item>
- </list>
-
- <section>
- <title>The openssl configuration file</title>
- <p>An <c>openssl</c> configuration file consist of a number of
- sections, where each section starts with one line containing
- <c>[ section_name ]</c>, where <c>section_name</c> is the name
- of the section. The first section of the file is either
- unnamed, or is named <c>[ default ]</c>. For further details
- see the OpenSSL config(5) manual page.
- </p>
- <p>The required sections for the subcommands we are going to
- use are as follows:
- </p>
- <table>
- <row>
- <cell align="left" valign="middle">subcommand</cell>
- <cell align="left" valign="middle">required/default section</cell>
- <cell align="left" valign="middle">override command line option</cell>
- <cell align="left" valign="middle">configuration file option</cell>
- </row>
- <row>
- <cell align="left" valign="middle">req</cell>
- <cell align="left" valign="middle">[req]</cell>
- <cell align="left" valign="middle">-</cell>
- <cell align="left" valign="middle"><c>-config FILE</c></cell>
- </row>
- <row>
- <cell align="left" valign="middle">ca</cell>
- <cell align="left" valign="middle">[ca]</cell>
- <cell align="left" valign="middle"><c>-name section</c></cell>
- <cell align="left" valign="middle"><c>-config FILE</c></cell>
- </row>
- <tcaption>openssl subcommands to use</tcaption>
- </table>
- </section>
-
- <section>
- <title>Creating the Erlang root CA</title>
- <p>The Erlang root CA is created with the command</p>
- <code type="none">
- openssl req -new -x509 -config /some/path/req.cnf \\
- -keyout /some/path/key.pem -out /some/path/cert.pem </code>
- <p>where the option <c>-new</c> indicates that we want to create
- a new certificate request and the option <c>-x509</c> implies
- that a self-signed certificate is created.
- </p>
- </section>
-
- <section>
- <title>Creating the OTP CA</title>
- <p>The OTP CA is created by first creating a certificate request
- with the command</p>
- <code type="none">
- openssl req -new -config /some/path/req.cnf \\
- -keyout /some/path/key.pem -out /some/path/req.pem </code>
- <p>and the ask the Erlang CA to sign it:</p>
- <code type="none">
- openssl ca -batch -notext -config /some/path/req.cnf \\
- -extensions ca_cert -in /some/path/req.pem -out /some/path/cert.pem </code>
- <p>where the option <c>-extensions</c> refers to a section in the
- configuration file saying that it should create a CA certificate,
- and not a plain user certificate.
- </p>
- <p>The <c>client</c> and <c>server</c> certificates are created
- similarly, except that the option <c>-extensions</c> then has the
- value <c>user_cert</c>.
- </p>
- </section>
- </section>
-
- <section>
- <title>An Example</title>
- <p>The following module <c>create_certs</c> is used by the Erlang/OTP
- SSL application for generating certificates to be used in tests. The
- source code is also found in <c>ssl-X.Y.Z/examples/certs/src</c>.
- </p>
- <p>The purpose of the <c>create_certs:all/1</c> function is to make
- it possible to provide from the <c>erl</c> command line, the
- full path name of the <c>openssl</c> command.
- </p>
- <p>Note that the module creates temporary OpenSSL configuration files
- for the <c>req</c> and <c>ca</c> subcommands.
- </p>
- <codeinclude file="../../examples/certs/src/make_certs.erl" tag="" type="erl"></codeinclude>
- </section>
-</chapter>
-
-
diff --git a/lib/ssl/doc/src/insidecover.xml b/lib/ssl/doc/src/insidecover.xml
deleted file mode 100644
index 4f3f5e5951..0000000000
--- a/lib/ssl/doc/src/insidecover.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE bookinsidecover SYSTEM "bookinsidecover.dtd">
-
-<bookinsidecover>
-The Erlang/OTP SSL application includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/). Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. <br></br>
-This product includes cryptographic software written by Eric Young ([email protected]). This product includes software written by Tim Hudson ([email protected]). Copyright (C) 1995-1998 Eric Young ([email protected]). All rights reserved. <br></br>
-For further OpenSSL and SSLeay license information se the chapter <bold>Licenses</bold>
-. <vfill></vfill>
- <br></br>
- <tt>http://www.erlang.org</tt>
- <br></br>
-</bookinsidecover>
-
-
diff --git a/lib/ssl/doc/src/licenses.xml b/lib/ssl/doc/src/licenses.xml
deleted file mode 100644
index 0969f9ad6e..0000000000
--- a/lib/ssl/doc/src/licenses.xml
+++ /dev/null
@@ -1,156 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2003</year><year>2009</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- </legalnotice>
-
- <title>Licenses</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <docno></docno>
- <date>2003-05-26</date>
- <rev>A</rev>
- <file>licenses.xml</file>
- </header>
- <p> <marker id="licenses"></marker>
-This chapter contains in extenso versions
- of the OpenSSL and SSLeay licenses.
- </p>
-
- <section>
- <title>OpenSSL License</title>
- <code type="none">
-/* ====================================================================
- * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * ([email protected]). This product includes software written by Tim
- * Hudson ([email protected]).
- *
- */ </code>
- </section>
-
- <section>
- <title>SSLeay License</title>
- <code type="none">
-/* Copyright (C) 1995-1998 Eric Young ([email protected])
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young ([email protected]).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson ([email protected]).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young ([email protected])"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson ([email protected])"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */ </code>
- </section>
-</chapter>
-
-
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 151b685941..95e968aa22 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -819,7 +819,7 @@
<title>Fixed Bugs and Malfunctions</title>
<list type="bulleted">
<item>
- <p>When a file descriptor was marked for closing, and and
+ <p>When a file descriptor was marked for closing, and
end-of-file condition had already been detected, the file
descriptor was never closed.</p>
<p>Own Id: OTP-5093 Aux Id: seq8806 </p>
diff --git a/lib/ssl/doc/src/refman.xml b/lib/ssl/doc/src/refman.xml
index 9658e229eb..68f84660f3 100644
--- a/lib/ssl/doc/src/refman.xml
+++ b/lib/ssl/doc/src/refman.xml
@@ -45,7 +45,8 @@
</description>
<xi:include href="ssl_app.xml"/>
<xi:include href="ssl.xml"/>
- <xi:include href="old_ssl.xml"/>
+ <xi:include href="old_ssl.xml"/>
+ <xi:include href="ssl_session_cache_api.xml"/>
</application>
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 75aa8f2fe9..def61bcf03 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -21,13 +21,6 @@
</legalnotice>
<title>ssl</title>
- <prepared>Ingela Anderton Andin</prepared>
- <responsible>Ingela Anderton Andin</responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date>2003-03-25</date>
- <rev></rev>
<file>ssl.xml</file>
</header>
<module>ssl</module>
@@ -185,8 +178,17 @@ end
{bad_cert, cert_expired}, {bad_cert, invalid_issuer},
{bad_cert, invalid_signature}, {bad_cert, name_not_permitted},
{bad_cert, cert_revoked} (not implemented yet),
- {bad_cert, unknown_critical_extension} or {bad_cert, term()} (Will
- be relevant later when an option is added for the user to be able to verify application specific extensions.)
+ {bad_cert, unknown_critical_extension} or {bad_cert, term()}
+ </item>
+
+
+ <tag>{validate_extensions_fun, fun()}</tag>
+ <item>
+ This options makes it possible to supply a fun to validate
+ possible application specific certificate extensions
+ during the certificat path validation. This option
+ will be better documented onec the public_key API is more
+ mature.
</item>
<tag>{depth, integer()}</tag>
@@ -231,7 +233,8 @@ end
</item>
<tag>{ssl_imp, ssl_imp()}</tag>
- <item>Specify which ssl implementation you want to use.
+ <item>Specify which ssl implementation you want to use. Defaults to
+ new.
</item>
<tag>{reuse_sessions, boolean()}</tag>
@@ -248,6 +251,15 @@ end
certificate, Compression is an enumeration integer
and CipherSuite of type ciphersuite().
</item>
+
+ <tag>{secure_renegotiate, boolean()}</tag>
+ <item>Specifies if to reject renegotiation attempt that does
+ not live up to RFC 5746. By default secure_renegotiate is
+ set to false e.i. secure renegotiation will be used if possible
+ but it will fallback to unsecure renegotiation if the peer
+ does not support RFC 5746.
+ </item>
+
</taglist>
</section>
@@ -414,7 +426,6 @@ end
<type>
<v>Socket = sslsocket()</v>
<v>Cert = binary()</v>
- <v>Subject = term()</v>
</type>
<desc>
<p>The peer certificate is returned as a DER encoded binary.
diff --git a/lib/ssl/doc/src/ssl_app.xml b/lib/ssl/doc/src/ssl_app.xml
index fac2053532..2ba6f48611 100644
--- a/lib/ssl/doc/src/ssl_app.xml
+++ b/lib/ssl/doc/src/ssl_app.xml
@@ -22,38 +22,11 @@
</legalnotice>
<title>ssl</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <responsible>Peter H&ouml;gfeldt</responsible>
- <docno></docno>
- <approved>Peter H&ouml;gfeldt</approved>
- <checked>Peter H&ouml;gfeldt</checked>
- <date>2005-03-10</date>
- <rev>E</rev>
<file>ssl_app.sgml</file>
</header>
<app>ssl</app>
- <appsummary>The SSL Application</appsummary>
- <description>
- <p>The Secure Socket Layer (SSL) application provides secure
- socket communication over TCP/IP. Note that this documentation
- is mainly valid for the old ssl implementation and will
- be replaced in a future release.
- </p>
- </description>
-
- <section>
- <title>Warning</title>
- <p>In previous versions of Erlang/OTP SSL it was advised, as a
- work-around, to set the operating system environment variable
- <c>SSL_CERT_FILE</c> to point at a file containing CA
- certificates. That variable is no longer needed, and is not
- recognised by Erlang/OTP SSL any more.
- </p>
- <p>However, the OpenSSL package does interpret that environment
- variable. Hence a setting of that variable might have
- unpredictable effects on the Erlang/OTP SSL application. It is
- therefore adviced to not used that environment variable at all.</p>
- </section>
+ <appsummary>The SSL application provides secure communication over
+ sockets.</appsummary>
<section>
<title>Environment</title>
@@ -63,115 +36,43 @@
</p>
<p>Note that the environment parameters can be set on the command line,
for instance,</p>
- <p><c>erl ... -ssl protocol_version '[sslv2,sslv3]' ...</c>.
+ <p><c>erl ... -ssl protocol_version '[sslv3, tlsv1]' ...</c>.
</p>
<taglist>
- <tag><c><![CDATA[ephemeral_rsa = true | false <optional>]]></c></tag>
+ <tag><c><![CDATA[protocol_version = [sslv3|tlsv1] <optional>]]></c>.</tag>
<item>
- <p>Enables all SSL servers (those that listen and accept)
- to use ephemeral RSA key generation when a clients connect with
- weak handshake cipher specifications, that need equally weak
- ciphers from the server (i.e. obsolete restrictions on export
- ciphers). Default is <c>false</c>.
- </p>
+ <p>Protocol that will be supported by started clients and
+ servers. If this option is not set it will default to all
+ protocols currently supported by the erlang ssl application.
+ Note that this option may be overridden by the version option
+ to ssl:connect/[2,3] and ssl:listen/2.
+ </p>
</item>
- <tag><c><![CDATA[debug = true | false <optional>]]></c></tag>
- <item>
- <p>Causes debug information to be written to standard
- output. Default is <c>false</c>.
- </p>
- </item>
- <tag><c><![CDATA[debugdir = path() | false <optional>]]></c></tag>
- <item>
- <p>Causes debug information output controlled by <c>debug</c>
- and <c>msgdebug</c> to be printed to a file named
- <c><![CDATA[ssl_esock.<pid>.log]]></c> in the directory specified by
- <c>debugdir</c>, where <c><![CDATA[<pid>]]></c> is the operating system
- specific textual representation of the process identifier
- of the external port program of the SSL application. Default
- is <c>false</c>, i.e. no log file is produced.
- </p>
- </item>
- <tag><c><![CDATA[msgdebug = true | false <optional>]]></c></tag>
- <item>
- <p>Sets <c>debug = true</c> and causes also the contents
- of low level messages to be printed to standard output.
- Default is <c>false</c>.
- </p>
- </item>
- <tag><c><![CDATA[port_program = string() | false <optional>]]></c></tag>
- <item>
- <p>Name of port program. The default is <c>ssl_esock</c>.
- </p>
- </item>
- <tag><c><![CDATA[protocol_version = [sslv2|sslv3|tlsv1] <optional>]]></c>.</tag>
+
+ <tag><c><![CDATA[session_lifetime = integer() <optional>]]></c></tag>
<item>
- <p>Name of protocols to use. If this option is not set,
- all protocols are assumed, i.e. the default value is
- <c>[sslv2, sslv3, tlsv1]</c>.
- </p>
+ <p>The lifetime of session data in seconds.
+ </p>
</item>
- <tag><c><![CDATA[proxylsport = integer() | false <optional>]]></c></tag>
+
+ <tag><c><![CDATA[session_cb = atom() <optional>]]></c></tag>
<item>
- <p>Define the port number of the listen port of the
- SSL port program. Almost never is this option needed.
+ <p>
+ Name of session cache callback module that implements
+ the ssl_session_cache_api behavior, defaults to
+ ssl_session_cache.erl.
</p>
</item>
- <tag><c><![CDATA[proxylsbacklog = integer() | false <optional>]]></c></tag>
+
+ <tag><c><![CDATA[session_cb_init_args = list() <optional>]]></c></tag>
<item>
- <p>Set the listen queue size of the listen port of the
- SSL port program. The default is 128.
- </p>
+ <p>
+ List of arguments to the init function in session cache
+ callback module, defaults to [].
+ </p>
</item>
- </taglist>
- </section>
-
- <section>
- <title>OpenSSL libraries</title>
- <p>The current implementation of the Erlang SSL application is
- based on the <em>OpenSSL</em> package version 0.9.7 or higher.
- There are source and binary releases on the web.
- </p>
- <p>Source releases of OpenSSL can be downloaded from the <url href="http://www.openssl.org">OpenSSL</url> project home page,
- or mirror sites listed there.
- </p>
- <p>The same URL also contains links to some compiled binaries and
- libraries of OpenSSL (see the <c>Related/Binaries</c> menu) of
- which the <url href="http://www.shininglightpro.com/search.php?searchname=Win32+OpenSSL">Shining Light Productions Win32 and OpenSSL</url> pages are of
- interest for the Win32 user.
- </p>
- <p>For some Unix flavours there are binary packages available
- on the net.
- </p>
- <p>If you cannot find a suitable binary OpenSSL package, you
- have to fetch an OpenSSL source release and compile it.
- </p>
- <p>You then have to compile and install the libraries
- <c>libcrypto.so</c> and <c>libssl.so</c> (Unix), or the
- libraries <c>libeay32.dll</c> and <c>ssleay32.dll</c> (Win32).
- </p>
- <p>For Unix The <c>ssl_esock</c> port program is delivered linked
- to OpenSSL libraries in <c>/usr/local/lib</c>, but the default
- dynamic linking will also accept libraries in <c>/lib</c> and
- <c>/usr/lib</c>.
- </p>
- <p>If that is not applicable to the particular Unix operating
- system used, the example <c>Makefile</c> in the SSL
- <c>priv/obj</c> directory, should be used as a guide to
- relinking the final version of the port program.
- </p>
- <p>For <c>Win32</c> it is only required that the libraries can be
- found from the <c>PATH</c> environment variable, or that they
- reside in the appropriate <c>SYSTEM32</c> directory; hence no
- particular relinking is need. Hence no example <c>Makefile</c>
- for Win32 is provided.</p>
- </section>
- <section>
- <title>Restrictions</title>
- <p>Users must be aware of export restrictions and patent rights
- concerning cryptographic software.
- </p>
+ </taglist>
</section>
<section>
@@ -180,5 +81,3 @@
</section>
</appref>
-
-
diff --git a/lib/ssl/doc/src/ssl_distribution.xml b/lib/ssl/doc/src/ssl_distribution.xml
index c743cd67a3..4067fb8a22 100644
--- a/lib/ssl/doc/src/ssl_distribution.xml
+++ b/lib/ssl/doc/src/ssl_distribution.xml
@@ -32,7 +32,13 @@
<file>ssl_distribution.xml</file>
</header>
<p>This chapter describes how the Erlang distribution can use
- SSL to get additional verification and security.</p>
+ SSL to get additional verification and security.
+
+ <note><p>Note this
+ documentation is written for the old ssl implementation and
+ will be updated for the new one once this functionallity is
+ supported by the new implementation.</p></note>
+ </p>
<section>
<title>Introduction</title>
diff --git a/lib/ssl/doc/src/ssl_protocol.xml b/lib/ssl/doc/src/ssl_protocol.xml
index 3dc2332795..726b9a4eeb 100644
--- a/lib/ssl/doc/src/ssl_protocol.xml
+++ b/lib/ssl/doc/src/ssl_protocol.xml
@@ -13,337 +13,138 @@
compliance with the License. You should have received a copy of the
Erlang Public License along with this software. If not, it can be
retrieved online at http://www.erlang.org/.
-
+
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
the License for the specific language governing rights and limitations
under the License.
-
+
</legalnotice>
- <title>The SSL Protocol</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <docno></docno>
- <date>2003-04-28</date>
- <rev>PA2</rev>
+ <title>Transport Layer Security (TLS) and its predecessor, Secure Socket Layer (SSL)</title>
<file>ssl_protocol.xml</file>
</header>
- <p>Here we provide a short introduction to the SSL protocol. We only
- consider those part of the protocol that are important from a
- programming point of view.
- </p>
- <p>For a very good general introduction to SSL and TLS see the book
- <cite id="rescorla"></cite>.
- </p>
- <p><em>Outline:</em></p>
- <list type="bulleted">
- <item>Two types of connections - connection: handshake, data transfer, and
- shutdown -
- SSL/TLS protocol - server must have certificate - what the the
- server sends to the client - client may verify the server -
- server may ask client for certificate - what the client sends to
- the server - server may then verify the client - verification -
- certificate chains - root certificates - public keys - key
- agreement - purpose of certificate - references</item>
- </list>
+
+ <p>The erlang ssl application currently supports SSL 3.0 and TLS 1.0
+ RFC 2246, and will in the future also support later versions of TLS.
+ SSL 2.0 is not supported.
+ </p>
- <section>
- <title>SSL Connections</title>
- <p>The SSL protocol is implemented on top of the TCP/IP protocol.
- From an endpoint view it also has the same type of connections
- as that protocol, almost always created by calls to socket
- interface functions <em>listen</em>, <em>accept</em> and
- <em>connect</em>. The endpoints are <em>servers</em> and
- <em>clients</em>.
- </p>
- <p>A <em>server</em><em>listen</em>s for connections on a
- specific address and port. This is done once. The server then
- <em>accept</em>s each connections on that same address and
- port. This is typically done indefinitely many times.
- </p>
- <p>A <em>client</em> connects to a server on a specific address
- and port. For each purpose this is done once.
- </p>
- <p>For a plain TCP/IP connection the establishment of a connection
- (through an accept or a connect) is followed by data transfer between
- the client and server, finally ended by a connection close.
- </p>
- <p>An SSL connection also consists of data transfer and connection
- close, However, the data transfer contains encrypted data, and
- in order to establish the encryption parameters, the data
- transfer is preceded by an SSL <em>handshake</em>. In this
- handshake the server plays a dominant role, and the main
- instrument used in achieving a valid SSL connection is the
- server's <em>certificate</em>. We consider certificates in the
- next section, and the SSL handshake in a subsequent section.</p>
- </section>
+ <p>By default erlang ssl is run over the TCP/IP protocol even
+ though you could plug in an other reliable transport protocol
+ with the same API as gen_tcp.</p>
+
+ <p>If a client and server wants to use an upgrade mechanism, such as
+ defined by RFC2817, to upgrade a regular TCP/IP connection to a ssl
+ connection the erlang ssl API supports this. This can be useful for
+ things such as supporting HTTP and HTTPS on the same port and
+ implementing virtual hosting.
+ </p>
<section>
- <title>Certificates</title>
- <p>A certificate is similar to a driver's license, or a
- passport. The holder of the certificate is called the
- <em>subject</em>. First of all the certificate identifies the
- subject in terms of the name of the subject, its postal address,
- country name, company name (if applicable), etc.
- </p>
- <p>Although a driver's license is always issued by a well-known and
- distinct authority, a certificate may have an <em>issuer</em>
- that is not so well-known. Therefore a certificate also always
- contains information on the issuer of the certificate. That
- information is of the same type as the information on the
- subject. The issuer of a certificate also signs the certificate
- with a <em>digital signature</em> (the signature is an inherent
- part of the certificate), which allow others to verify that the
- issuer really is the issuer of the certificate.
- </p>
- <p>Now that a certificate can be checked by verifying the
- signature of the issuer, the question is how to trust the
- issuer. The answer to this question is to require that there is
- a certificate for the issuer as well. That issuer has in turn an
- issuer, which must also have a certificate, and so on. This
- <em>certificate chain</em> has to have en end, which then must
- be a certificate that is trusted by other means. We shall cover
- this problem of <em>authentication</em> in a subsequent
- section.
- </p>
+ <title>Security overview</title>
+
+ <p>To achive authentication and privacy the client and server will
+ perform a TLS Handshake procedure before transmitting or receiving
+ any data. During the handshake they agree on a protocol version and
+ cryptographic algorithms, they generate shared secrets using public
+ key cryptographics and optionally authenticate each other with
+ digital certificates.</p>
</section>
-
+
<section>
- <title>Encryption Algorithms</title>
- <p>An encryption algorithm is a mathematical algorithm for
- encryption and decryption of messages (arrays of bytes,
- say). The algorithm as such is always required to be publicly
- known, otherwise its strength cannot be evaluated, and hence it
- cannot be used reliably. The secrecy of an encrypted message is
- not achieved by the secrecy of the algorithm used, but by the
- secrecy of the <em>keys</em> used as input to the encryption and
- decryption algorithms. For an account of cryptography in general
- see <cite id="schneier"></cite>.
- </p>
- <p>There are two classes of encryption algorithms: <em>symmetric key</em> algorithms and <em>public key</em> algorithms. Both
- types of algorithms are used in the SSL protocol.
- </p>
- <p>In the sequel we assume holders of keys keep them secret (except
- public keys) and that they in that sense are trusted. How a
- holder of a secret key is proved to be the one it claims to be
- is a question of <em>authentication</em>, which, in the context
- of the SSL protocol, is described in a section further below.
- </p>
-
- <section>
- <title>Symmetric Key Algorithms</title>
- <p>A <em>symmetric key</em> algorithm has one key only. The key
- is used for both encryption and decryption. Obviously the key
- of a symmetric key algorithm must always be kept secret by the
- users of the key. DES is an example of a symmetric key
- algorithm.
- </p>
- <p>Symmetric key algorithms are fast compared to public key
- algorithms. They are therefore typically used for encrypting
- bulk data.
- </p>
- </section>
-
- <section>
- <title>Public Key Algorithms</title>
- <p>A <em>public key</em> algorithm has two keys. Any of the two
- keys can be used for encryption. A message encrypted with one
- of the keys, can only be decrypted with the other key. One of
- the keys is public (known to the world), while the other key
- is private (i.e. kept secret) by the owner of the two keys.
- </p>
- <p>RSA is an example of a public key algorithm.
- </p>
- <p>Public key algorithms are slow compared to symmetric key
- algorithms, and they are therefore seldom used for bulk data
- encryption. They are therefore only used in cases where the
- fact that one key is public and the other is private, provides
- features that cannot be provided by symmetric algorithms.
- </p>
- </section>
-
- <section>
- <title>Digital Signature Algorithms</title>
- <p>An interesting feature of a public key algorithm is that its
- public and private keys can both be used for encryption.
- Anyone can use the public key to encrypt a message, and send
- that message to the owner of the private key, and be sure of
- that only the holder of the private key can decrypt the
- message.
- </p>
- <p>On the other hand, the owner of the private key can encrypt a
- message with the private key, thus obtaining an encrypted
- message that can decrypted by anyone having the public key.
- </p>
- <p>The last approach can be used as a digital signature
- algorithm. The holder of the private key signs an array of
- bytes by performing a specified well-known <em>message digest algorithm</em> to compute a hash of the array, encrypts the
- hash value with its private key, an then presents the original
- array, the name of the digest algorithm, and the encryption of
- the hash value as a <em>signed array of bytes</em>.
- </p>
- <p>Now anyone having the public key, can decrypt the encrypted
- hash value with that key, compute the hash with the specified
- digest algorithm, and check that the hash values compare equal
- in order to verify that the original array was indeed signed
- by the holder of the private key.
- </p>
- <p>What we have accounted for so far is by no means all that can
- be said about digital signatures (see <cite id="schneier"></cite>for
- further details).
- </p>
- </section>
-
- <section>
- <title>Message Digests Algorithms</title>
- <p>A message digest algorithm is a hash function that accepts
- an array bytes of arbitrary but finite length of input, and
- outputs an array of bytes of fixed length. Such an algorithm
- is also required to be very hard to invert.
- </p>
- <p>MD5 (16 bytes output) and SHA1 (20 bytes output) are examples
- of message digest algorithms.
- </p>
- </section>
+ <title>Data Privacy and Integrity</title>
+
+ <p>A <em>symmetric key</em> algorithm has one key only. The key is
+ used for both encryption and decryption. These algoritms are fast
+ compared to public key algorithms (using two keys, a public and a
+ private one) and are therefore typically used for encrypting bulk
+ data.
+ </p>
+
+ <p>The keys for the symmetric encryption are generated uniquely
+ for each connection and are based on a secret negotiated
+ in the TLS handshake. </p>
+
+ <p>The TLS handsake protocol and data transfer is run on top of
+ the TLS Record Protocol that uses a keyed-hash MAC (Message
+ Authenticity Code), or HMAC, to protect the message's data
+ integrity. From the TLS RFC "A Message Authentication Code is a
+ one-way hash computed from a message and some secret data. It is
+ difficult to forge without knowing the secret data. Its purpose is
+ to detect if the message has been altered."
+ </p>
+
</section>
- <section>
- <title>SSL Handshake</title>
- <p>The main purpose of the handshake performed before an an SSL
- connection is established is to negotiate the encryption
- algorithm and key to be used for the bulk data transfer between
- the client and the server. We are writing <em>the</em> key,
- since the algorithm to choose for bulk encryption one of the
- symmetric algorithms.
- </p>
- <p>There is thus only one key to agree upon, and obviously that
- key has to be kept secret between the client and the server. To
- obtain that the handshake has to be encrypted as well.
- </p>
- <p>The SSL protocol requires that the server always sends its
- certificate to the client in the beginning of the handshake. The
- client then retrieves the server's public key from the
- certificate, which means that the client can use the server's
- public key to encrypt messages to the server, and the server can
- decrypt those messages with its private key. Similarly, the
- server can encrypt messages to the client with its private key,
- and the client can decrypt messages with the server's public
- key. It is thus is with the server's public and private keys
- that messages in the handshake are encrypted and decrypted, and
- hence the key agreed upon for symmetric encryption of bulk data
- can be kept secret (there are more things to consider to really
- keep it secret, see <cite id="rescorla"></cite>).
- </p>
- <p>The above indicates that the server does not care who is
- connecting, and that only the client has the possibility to
- properly identify the server based on the server's certificate.
- That is indeed true in the minimal use of the protocol, but it
- is possible to instruct the server to request the certificate of
- the client, in order to have a means to identify the client, but
- it is by no means required to establish an SSL connection.
- </p>
- <p>If a server request the client certificate, it verifies, as a
- part of the protocol, that the client really holds the private
- key of the certificate by sending the client a string of bytes
- to encrypt with its private key, which the server then decrypts
- with the client's public key, the result of which is compared
- with the original string of bytes (a similar procedure is always
- performed by the client when it has received the server's
- certificate).
- </p>
- <p>The way clients and servers <em>authenticate</em> each other,
- i.e. proves that their respective peers are what they claim to
- be, is the topic of the next section.
- </p>
- </section>
+ <section>
+ <title>Digital Certificates</title>
+ <p>A certificate is similar to a driver's license, or a
+ passport. The holder of the certificate is called the
+ <em>subject</em>. The certificate is signed
+ with the private key of the issuer of the certificate. A chain
+ of trust is build by having the issuer in its turn being
+ certified by an other certificate and so on until you reach the
+ so called root certificate that is self signed e.i. issued
+ by itself.</p>
+
+ <p>Certificates are issued by <em>certification
+ authorities</em> (<em>CA</em>s) only. There are a handful of
+ top CAs in the world that issue root certificates. You can
+ examine the certificates of several of them by clicking
+ through the menus of your web browser.
+ </p>
+ </section>
+
+ <section>
+ <title>Authentication of Sender</title>
+
+ <p>Authentication of the sender is done by public key path
+ validation as defined in RFC 3280. Simplified that means that
+ each certificate in the certificate chain is issued by the one
+ before, the certificates attributes are valid ones, and the
+ root cert is a trusted cert that is present in the trusted
+ certs database kept by the peer.</p>
+
+ <p>The server will always send a certificate chain as part of
+ the TLS handshake, but the client will only send one if
+ the server requests it. If the client does not have
+ an appropriate certificate it may send an "empty" certificate
+ to the server.</p>
+
+ <p>The client may choose to accept some path evaluation errors
+ for instance a web browser may ask the user if they want to
+ accept an unknown CA root certificate. The server, if it request
+ a certificate, will on the other hand not accept any path validation
+ errors. It is configurable if the server should accept
+ or reject an "empty" certificate as response to
+ a certificate request.</p>
+ </section>
+
+ <section>
+ <title>TLS Sessions</title>
+
+ <p>From the TLS RFC "A TLS session is an association between a
+ client and a server. Sessions are created by the handshake
+ protocol. Sessions define a set of cryptographic security
+ parameters, which can be shared among multiple
+ connections. Sessions are used to avoid the expensive negotiation
+ of new security parameters for each connection."</p>
- <section>
- <title>Authentication</title>
- <p>As we have already seen the reception of a certificate from a
- peer is not enough to prove that the peer is authentic. More
- certificates are needed, and we have to consider how certificates
- are issued and on what grounds.
- </p>
- <p>Certificates are issued by <em>certification authorities</em>
- (<em>CA</em>s) only. They issue certificates both for other CAs
- and ordinary users (which are not CAs).
- </p>
- <p>Certain CAs are <em>top CAs</em>, i.e. they do not have a
- certificate issued by another CA. Instead they issue their own
- certificate, where the subject and issuer part of the
- certificate are identical (such a certificate is called a
- self-signed certificate). A top CA has to be well-known, and has
- to have a publicly available policy telling on what grounds it
- issues certificates.
- </p>
- <p>There are a handful of top CAs in the world. You can examine the
- certificates of several of them by clicking through the menus of
- your web browser.
- </p>
- <p>A top CA typically issues certificates for other CAs, called
- <em>intermediate CAs</em>, but possibly also to ordinary users. Thus
- the certificates derivable from a top CA constitute a tree, where
- the leaves of the tree are ordinary user certificates.
- </p>
- <p>A <em>certificate chain</em> is an ordered sequence of
- certificates, <c>C1, C2, ..., Cn</c>, say, where <c>C1</c> is a
- top CA certificate, and where <c>Cn</c> is an ordinary user
- certificate, and where the holder of <c>C1</c> is the issuer of
- <c>C2</c>, the holder of <c>C2</c> is the issuer of <c>C3</c>,
- ..., and the holder of <c>Cn-1</c> is the issuer of <c>Cn</c>,
- the ordinary user certificate. The holders of <c>C2, C3, ..., Cn-1</c> are then intermediate CAs.
- </p>
- <p>Now to verify that a certificate chain is unbroken we have to
- take the public key from each certificate <c>Ck</c>, and apply
- that key to decrypt the signature of certificate <c>Ck-1</c>,
- thus obtaining the message digest computed by the holder of the
- <c>Ck</c> certificate, compute the real message digest of the
- <c>Ck-1</c> certificate and compare the results. If they compare
- equal the link of the chain between <c>Ck</c> and <c>Ck-1</c> is
- considered to unbroken. This is done for each link k = 1, 2,
- ..., n-1. If all links are found to be unbroken, the user
- certificate <c>Cn</c> is considered authenticated.
- </p>
+ <p>Session data is by default kept by the ssl application in a
+ memory storage hence session data will be lost at application
+ restart or takeover. Users may define their own callback module
+ to handle session data storage if persistent data storage is
+ required. Session data will also be invalidated after 24 hours
+ from it was saved, for security reasons. It is of course
+ possible to configure the amount of time the session data should be
+ saved.</p>
- <section>
- <title>Trusted Certificates</title>
- <p>Now that there is a way to authenticate a certificate by
- checking that all links of a certificate chain are unbroken,
- the question is how you can be sure to trust the certificates
- in the chain, and in particular the top CA certificate of the
- chain.
- </p>
- <p>To provide an answer to that question consider the
- perspective of a client, which have just received the
- certificate of the server. In order to authenticate the server
- the client has to construct a certificate chain and to prove
- that the chain is unbroken. The client has to have a set of CA
- certificates (top CA or intermediate CA certificates) not
- obtained from the server, but obtained by other means. Those
- certificates are kept <c>locally</c> by the client, and are
- trusted by the client.
- </p>
- <p>More specifically, the client does not really have to have
- top CA certificates in its local storage. In order to
- authenticate a server it is sufficient for the client to
- posses the trusted certificate of the issuer of the server
- certificate.
- </p>
- <p>Now that is not the whole story. A server can send an
- (incomplete) certificate chain to its client, and then the
- task of the client is to construct a certificate chain that
- begins with a trusted certificate and ends with the server's
- certificate. (A client can also send a chain to its server,
- provided the server requested the client's certificate.)
- </p>
- <p>All this means that an unbroken certificate chain begins with
- a trusted certificate (top CA or not), and ends with the peer
- certificate. That is the end of the chain is obtained from the
- peer, but the beginning of the chain is obtained from local
- storage, which is considered trusted.
- </p>
- </section>
- </section>
-</chapter>
+ <p>Ssl clients will by default try to reuse an available session,
+ ssl servers will by default agree to reuse sessions when clients
+ ask to do so.</p>
+
+ </section>
+ </chapter>
diff --git a/lib/ssl/doc/src/ssl_session_cache_api.xml b/lib/ssl/doc/src/ssl_session_cache_api.xml
new file mode 100644
index 0000000000..7b70c6cf34
--- /dev/null
+++ b/lib/ssl/doc/src/ssl_session_cache_api.xml
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1999</year><year>2010</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+ <title>ssl</title>
+ <file>ssl_session_cache_api.xml</file>
+ </header>
+ <module>ssl_session_cache_api</module>
+ <modulesummary>Defines the API for the TLS session cache so
+ that the datastorge scheme can be replaced by
+ defining a new callback module implementing this API.</modulesummary>
+
+ <section>
+ <title>Common Data Types</title>
+
+ <p>The following data types are used in the functions below:
+ </p>
+
+ <p><c>cache_ref() = opaque()</c></p>
+
+ <p><c>key() = {partialkey(), session_id()}</c></p>
+
+ <p><c>partialkey() = opaque()</c></p>
+
+ <p><c>session_id() = binary()</c></p>
+
+ <p><c>session() = opaque()</c></p>
+
+ </section>
+
+ <funcs>
+
+ <func>
+ <name>delete(Cache, Key) -> _</name>
+ <fsummary></fsummary>
+ <type>
+ <v> Cache = cache_ref()</v>
+ <v> Key = key()</v>
+ </type>
+ <desc>
+ <p> Delets a cache entry. Will only be called from the cache
+ handling process.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>foldl(Fun, Acc0, Cache) -> Acc</name>
+ <fsummary></fsummary>
+ <type>
+ <v></v>
+ </type>
+ <desc>
+ <p>Calls Fun(Elem, AccIn) on successive elements of the
+ cache, starting with AccIn == Acc0. Fun/2 must return a new
+ accumulator which is passed to the next call. The function returns
+ the final value of the accumulator. Acc0 is returned if the cache is
+ empty.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>init() -> opaque() </name>
+ <fsummary>Return cache reference</fsummary>
+ <type>
+ <v></v>
+ </type>
+ <desc>
+ <p>Performes possible initializations of the cache and returns
+ a reference to it that will be used as parameter to the other
+ api functions. Will be called by the cache handling processes
+ init function, hence puting the same requierments on it as
+ a normal process init function.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>lookup(Cache, Key) -> Entry</name>
+ <fsummary> Looks up a cach entry.</fsummary>
+ <type>
+ <v> Cache = cache_ref()</v>
+ <v> Key = key()</v>
+ <v> Entry = session() | undefined </v>
+ </type>
+ <desc>
+ <p>Looks up a cach entry. Should be callable from any
+ process.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>select_session(Cache, PartialKey) -> [session()]</name>
+ <fsummary>>Selects sessions that could be reused.</fsummary>
+ <type>
+ <v> Cache = cache_ref()</v>
+ <v> PartialKey = partialkey()</v>
+ <v> Session = session()</v>
+ </type>
+ <desc>
+ <p>Selects sessions that could be reused. Should be callable
+ from any process.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>terminate(Cache) -> _</name>
+ <fsummary>Called by the process that handles the cache when it
+ is aboute to terminat.</fsummary>
+ <type>
+ <v>Cache = term() - as returned by init/0</v>
+ </type>
+ <desc>
+ <p>Takes care of possible cleanup that is needed when the
+ cache handling process terminates.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>update(Cache, Key, Session) -> _</name>
+ <fsummary> Caches a new session or updates a already cached one.</fsummary>
+ <type>
+ <v> Cache = cache_ref()</v>
+ <v> Key = key()</v>
+ <v> Session = session()</v>
+ </type>
+ <desc>
+ <p> Caches a new session or updates a already cached one. Will
+ only be called from the cache handling process.
+ </p>
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
diff --git a/lib/ssl/doc/src/usersguide.xml b/lib/ssl/doc/src/usersguide.xml
index 76ee13dd23..6528c00a0b 100644
--- a/lib/ssl/doc/src/usersguide.xml
+++ b/lib/ssl/doc/src/usersguide.xml
@@ -23,35 +23,17 @@
<title>SSL User's Guide</title>
<prepared>OTP Team</prepared>
- <docno></docno>
<date>2003-05-26</date>
- <rev>B</rev>
<file>usersguide.sgml</file>
</header>
<description>
<p>The <em>SSL</em> application provides secure communication over
- sockets. Note that this users guide was written for
- the old ssl implementation that is now being phased out and
- will be replaced by a new guide in a future release.
- </p>
- <p>This product includes software developed by the OpenSSL Project for
- use in the OpenSSL Toolkit (http://www.openssl.org/).
- </p>
- <p>This product includes cryptographic software written by Eric Young
- </p>
- <p>This product includes software written by Tim Hudson
- </p>
- <p>For full OpenSSL and SSLeay license texts, see <seealso marker="licenses#licenses">Licenses</seealso>.
+ sockets.
</p>
</description>
<xi:include href="ssl_protocol.xml"/>
<xi:include href="using_ssl.xml"/>
- <xi:include href="pkix_certs.xml"/>
- <xi:include href="create_certs.xml"/>
<xi:include href="ssl_distribution.xml"/>
- <xi:include href="licenses.xml"/>
</part>
diff --git a/lib/ssl/doc/src/using_ssl.xml b/lib/ssl/doc/src/using_ssl.xml
new file mode 100644
index 0000000000..4bdd8f97b4
--- /dev/null
+++ b/lib/ssl/doc/src/using_ssl.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2003</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Using the SSL API</title>
+ <file>using_ssl.xml</file>
+ </header>
+
+ <section>
+ <title>General information</title>
+ <p>To see relevant version information for ssl you can
+ call ssl:versions/0</p>
+
+ <p>To see all supported cipher suites
+ call ssl:cipher_suites/0. Note that available cipher suites
+ for a connection will depend on your certificate. It is also
+ possible to specify a specific cipher suite(s) that you
+ want your connection to use. Default is to use the strongest
+ available.</p>
+
+ </section>
+
+ <section>
+ <title>Setting up connections</title>
+
+ <p>Here follows some small example of how to set up client/server connections
+ using the erlang shell. The returned value of the sslsocket has been abbreviated with
+ <c>[...]</c> as it can be fairly large and is opaque.</p>
+
+ <section>
+ <title>Minmal example</title>
+
+ <note><p> The minimal setup is not the most secure setup of ssl.</p>
+ </note>
+
+ <p> Start server side</p>
+ <code type="erl">1 server> ssl:start().
+ok</code>
+
+ <p>Create a ssl listen socket</p>
+ <code type="erl">2 server> {ok, ListenSocket} =
+ssl:listen(9999, [{certfile, "cert.pem"}, {keyfile, "key.pem"},{reuseaddr, true}]).
+{ok,{sslsocket, [...]}}</code>
+
+ <p>Do a transport accept on the ssl listen socket</p>
+ <code type="erl">3 server> {ok, Socket} = ssl:transport_accept(ListenSocket).
+{ok,{sslsocket, [...]}}</code>
+
+ <p>Start client side</p>
+ <code type="erl">1 client> ssl:start().
+ok</code>
+
+ <code type="erl">2 client> {ok, Socket} = ssl:connect("localhost", 9999, [], infinity).
+{ok,{sslsocket, [...]}}</code>
+
+ <p>Do the ssl handshake</p>
+ <code type="erl">4 server> ok = ssl:ssl_accept(Socket).
+ok</code>
+
+ <p>Send a messag over ssl</p>
+ <code type="erl">5 server> ssl:send(Socket, "foo").
+ok</code>
+
+ <p>Flush the shell message queue to see that we got the message
+ sent on the server side</p>
+ <code type="erl">3 client> flush().
+Shell got {ssl,{sslsocket,[...]},"foo"}
+ok</code>
+ </section>
+
+ <section>
+ <title>Upgrade example</title>
+
+ <note><p> To upgrade a TCP/IP connection to a ssl connection the
+ client and server have to aggre to do so. Agreement
+ may be accompliced by using a protocol such the one used by HTTP
+ specified in RFC 2817.</p> </note>
+
+ <p>Start server side</p>
+ <code type="erl">1 server> ssl:start().
+ok</code>
+
+ <p>Create a normal tcp listen socket</p>
+ <code type="erl">2 server> {ok, ListenSocket} = gen_tcp:listen(9999, [{reuseaddr, true}]).
+{ok, #Port&lt;0.475&gt;}</code>
+
+ <p>Accept client connection</p>
+ <code type="erl">3 server> {ok, Socket} = gen_tcp:accept(ListenSocket).
+{ok, #Port&lt;0.476&gt;}</code>
+
+ <p>Start client side</p>
+ <code type="erl">1 client> ssl:start().
+ok</code>
+
+ <code type="erl">2 client> {ok, Socket} = gen_tcp:connect("localhost", 9999, [], infinity).</code>
+
+ <p>Make sure active is set to false before trying
+ to upgrade a connection to a ssl connection, otherwhise
+ ssl handshake messages may be deliverd to the wrong process.</p>
+ <code type="erl">4 server> inet:setopts(Socket, [{active, false}]).
+ok</code>
+
+ <p>Do the ssl handshake.</p>
+ <code type="erl">5 server> {ok, SSLSocket} = ssl:ssl_accept(Socket, [{cacertfile, "cacerts.pem"},
+{certfile, "cert.pem"}, {keyfile, "key.pem"}]).
+{ok,{sslsocket,[...]}}</code>
+
+ <p> Upgrade to a ssl connection. Note that the client and server
+ must agree upon the upgrade and the server must call
+ ssl:accept/2 before the client calls ssl:connect/3.</p>
+ <code type="erl">3 client>{ok, SSLSocket} = ssl:connect(Socket, [{cacertfile, "cacerts.pem"},
+{certfile, "cert.pem"}, {keyfile, "key.pem"}], infinity).
+{ok,{sslsocket,[...]}}</code>
+
+ <p>Send a messag over ssl</p>
+ <code type="erl">4 client> ssl:send(SSLSocket, "foo").
+ok</code>
+
+ <p>Set active true on the ssl socket</p>
+ <code type="erl">4 server> ssl:setopts(SSLSocket, [{active, true}]).
+ok</code>
+
+ <p>Flush the shell message queue to see that we got the message
+ sent on the client side</p>
+ <code type="erl">5 server> flush().
+Shell got {ssl,{sslsocket,[...]},"foo"}
+ok</code>
+ </section>
+ </section>
+ </chapter>
diff --git a/lib/ssl/doc/src/using_ssl.xmlsrc b/lib/ssl/doc/src/using_ssl.xmlsrc
deleted file mode 100644
index ba74dcfef4..0000000000
--- a/lib/ssl/doc/src/using_ssl.xmlsrc
+++ /dev/null
@@ -1,113 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2003</year><year>2009</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- </legalnotice>
-
- <title>Using the SSL application</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <docno></docno>
- <date>2003-04-23</date>
- <rev>PA2</rev>
- <file>using_ssl.xml</file>
- </header>
- <p>Here we provide an introduction to using the Erlang/OTP SSL
- application, which is accessed through the <c>ssl</c> interface
- module.
- </p>
- <p>We also present example code in the Erlang module
- <c>client_server</c>, also provided in the directory
- <c>ssl-X.Y.Z/examples</c>, with source code in <c>src</c> and the
- compiled module in <c>ebin</c> of that directory.
- </p>
-
- <section>
- <title>The ssl Module</title>
- <p>The <c>ssl</c> module provides the user interface to the Erlang/OTP
- SSL application. The interface functions provided are very similar
- to those provided by the <c>gen_tcp</c> and <c>inet</c> modules.
- </p>
- <p>Servers use the interface functions <c>listen</c> and
- <c>accept</c>. The <c>listen</c> function specifies a TCP port
- to to listen to, and each call to the <c>accept</c> function
- establishes an incoming connection.
- </p>
- <p>Clients use the <c>connect</c> function which specifies the address
- and port of a server to connect to, and a successful call establishes
- such a connection.
- </p>
- <p>The <c>listen</c> and <c>connect</c> functions have almost all
- the options that the corresponding functions in <c>gen_tcp/</c> have,
- but there are also additional options specific to the SSL protocol.
- </p>
- <p>The most important SSL specific option is the <c>cacertfile</c>
- option which specifies a local file containing trusted CA
- certificates which are and used for peer authentication. This
- option is used by clients and servers in case they want to
- authenticate their peers.
- </p>
- <p>The <c>certfile</c> option specifies a local path to a file
- containing the certificate of the holder of the connection
- endpoint. In case of a server endpoint this option is mandatory
- since the contents of the sever certificate is needed in the
- the handshake preceding the establishment of a connection.
- </p>
- <p>Similarly, the <c>keyfile</c> option points to a local file
- containing the private key of the holder of the endpoint. If the
- <c>certfile</c> option is present, this option has to be
- specified as well, unless the private key is provided in the
- same file as specified by the <c>certfile</c> option (a
- certificate and a private key can thus coexist in the same file).
- </p>
- <p>The <c>verify</c> option specifies how the peer should be verified:
- </p>
- <taglist>
- <tag>0</tag>
- <item>Do not verify the peer,</item>
- <tag>1</tag>
- <item>Verify peer,</item>
- <tag>2</tag>
- <item>Verify peer, fail the verification if the peer has no
- certificate. </item>
- </taglist>
- <p>The <c>depth</c> option specifies the maximum length of the
- verification certificate chain. Depth = 0 means the peer
- certificate, depth = 1 the CA certificate, depth = 2 the next CA
- certificate etc. If the verification process does not find a
- trusted CA certificate within the maximum length, the verification
- fails.
- </p>
- <p>The <c>ciphers</c> option specifies which ciphers to use (a
- string of colon separated cipher names). To obtain a list of
- available ciphers, evaluate the <c>ssl:ciphers/0</c> function
- (the SSL application has to be running).
- </p>
- </section>
-
- <section>
- <title>A Client-Server Example</title>
- <p>Here is a simple client server example.
- </p>
- <codeinclude file="../../examples/src/client_server.erl" tag="" type="erl"></codeinclude>
- </section>
-</chapter>
-
-
-
diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src
index 65f23e2f74..88cd73be74 100644
--- a/lib/ssl/src/ssl.appup.src
+++ b/lib/ssl/src/ssl.appup.src
@@ -1,6 +1,7 @@
%% -*- erlang -*-
{"%VSN%",
[
+ {"4.0", [{restart_application, ssl}]},
{"3.11.1", [{restart_application, ssl}]},
{"3.11", [{restart_application, ssl}]},
{"3.10", [{restart_application, ssl}]},
@@ -15,6 +16,7 @@
{"3.10.9", [{restart_application, ssl}]}
],
[
+ {"4.0", [{restart_application, ssl}]},
{"3.11.1", [{restart_application, ssl}]},
{"3.11", [{restart_application, ssl}]},
{"3.10", [{restart_application, ssl}]},
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 35d27713b8..6e26f05c3d 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -34,10 +34,12 @@
%% Should be deprecated as soon as old ssl is removed
%%-deprecated({pid, 1, next_major_release}).
+-deprecated({peercert, 2, next_major_release}).
-include("ssl_int.hrl").
-include("ssl_internal.hrl").
-include("ssl_record.hrl").
+-include("ssl_cipher.hrl").
-include_lib("public_key/include/public_key.hrl").
@@ -49,11 +51,11 @@
}).
%%--------------------------------------------------------------------
-%% Function: start([, Type]) -> ok
+-spec start() -> ok.
+-spec start(permanent | transient | temporary) -> ok.
%%
-%% Type = permanent | transient | temporary
-%%
-%% Description: Starts the ssl application. Default type
+%% Description: Utility function that starts the ssl,
+%% crypto and public_key applications. Default type
%% is temporary. see application(3)
%%--------------------------------------------------------------------
start() ->
@@ -67,7 +69,7 @@ start(Type) ->
application:start(ssl, Type).
%%--------------------------------------------------------------------
-%% Function: stop() -> ok
+-spec stop() -> ok.
%%
%% Description: Stops the ssl application.
%%--------------------------------------------------------------------
@@ -75,7 +77,9 @@ stop() ->
application:stop(ssl).
%%--------------------------------------------------------------------
-%% Function: connect(Address, Port, Options[, Timeout]) -> {ok, Socket}
+-spec connect(host() | port(), list()) -> {ok, #sslsocket{}}.
+-spec connect(host() | port(), list() | port_num(), timeout() | list()) -> {ok, #sslsocket{}}.
+-spec connect(host() | port(), port_num(), list(), timeout()) -> {ok, #sslsocket{}}.
%%
%% Description: Connect to a ssl server.
%%--------------------------------------------------------------------
@@ -101,13 +105,13 @@ connect(Socket, SslOptions0, Timeout) when is_port(Socket) ->
{error, Reason}
end;
-connect(Address, Port, Options) ->
- connect(Address, Port, Options, infinity).
+connect(Host, Port, Options) ->
+ connect(Host, Port, Options, infinity).
-connect(Address, Port, Options0, Timeout) ->
+connect(Host, Port, Options0, Timeout) ->
case proplists:get_value(ssl_imp, Options0, new) of
new ->
- new_connect(Address, Port, Options0, Timeout);
+ new_connect(Host, Port, Options0, Timeout);
old ->
%% Allow the option reuseaddr to be present
%% so that new and old ssl can be run by the same
@@ -115,13 +119,14 @@ connect(Address, Port, Options0, Timeout) ->
%% that hardcodes reuseaddr to true in its portprogram.
Options1 = proplists:delete(reuseaddr, Options0),
Options = proplists:delete(ssl_imp, Options1),
- old_connect(Address, Port, Options, Timeout);
+ old_connect(Host, Port, Options, Timeout);
Value ->
{error, {eoptions, {ssl_imp, Value}}}
end.
%%--------------------------------------------------------------------
-%% Function: listen(Port, Options) -> {ok, ListenSock} | {error, Reason}
+-spec listen(port_num(), list()) ->{ok, #sslsocket{}} | {error, reason()}.
+
%%
%% Description: Creates a ssl listen socket.
%%--------------------------------------------------------------------
@@ -144,7 +149,8 @@ listen(Port, Options0) ->
end.
%%--------------------------------------------------------------------
-%% Function: transport_accept(ListenSocket[, Timeout]) -> {ok, Socket}.
+-spec transport_accept(#sslsocket{}) -> {ok, #sslsocket{}}.
+-spec transport_accept(#sslsocket{}, timeout()) -> {ok, #sslsocket{}}.
%%
%% Description: Performs transport accept on a ssl listen socket
%%--------------------------------------------------------------------
@@ -182,8 +188,8 @@ transport_accept(#sslsocket{} = ListenSocket, Timeout) ->
ssl_broker:transport_accept(Pid, ListenSocket, Timeout).
%%--------------------------------------------------------------------
-%% Function: ssl_accept(ListenSocket[, Timeout]) -> {ok, Socket} |
-%% {error, Reason}
+-spec ssl_accept(#sslsocket{}) -> {ok, #sslsocket{}} | {error, reason()}.
+-spec ssl_accept(#sslsocket{}, timeout()) -> {ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Performs accept on a ssl listen socket. e.i. performs
%% ssl handshake.
@@ -210,14 +216,14 @@ ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) ->
{ok, #config{cb=CbInfo,ssl=SslOpts, emulated=EmOpts}} ->
{ok, Port} = inet:port(Socket),
ssl_connection:ssl_accept(Port, Socket,
- {SslOpts, EmOpts},
- self(), CbInfo, Timeout)
+ {SslOpts, EmOpts},
+ self(), CbInfo, Timeout)
catch
Error = {error, _Reason} -> Error
end.
%%--------------------------------------------------------------------
-%% Function: close() -> ok
+-spec close(#sslsocket{}) -> term().
%%
%% Description: Close a ssl connection
%%--------------------------------------------------------------------
@@ -230,7 +236,7 @@ close(Socket = #sslsocket{}) ->
ssl_broker:close(Socket).
%%--------------------------------------------------------------------
-%% Function: send(Socket, Data) -> ok | {error, Reason}
+-spec send(#sslsocket{}, iolist()) -> ok | {error, reason()}.
%%
%% Description: Sends data over the ssl connection
%%--------------------------------------------------------------------
@@ -242,7 +248,8 @@ send(#sslsocket{} = Socket, Data) ->
ssl_broker:send(Socket, Data).
%%--------------------------------------------------------------------
-%% Function: recv(Socket, Length [,Timeout]) -> {ok, Data} | {error, reason}
+-spec recv(#sslsocket{}, integer()) -> {ok, binary()| list()} | {error, reason()}.
+-spec recv(#sslsocket{}, integer(), timeout()) -> {ok, binary()| list()} | {error, reason()}.
%%
%% Description: Receives data when active = false
%%--------------------------------------------------------------------
@@ -256,8 +263,8 @@ recv(Socket = #sslsocket{}, Length, Timeout) ->
ssl_broker:recv(Socket, Length, Timeout).
%%--------------------------------------------------------------------
-%% Function: controlling_process(Socket, NewOwner) -> ok | {error, Reason}
-%%
+-spec controlling_process(#sslsocket{}, pid()) -> ok | {error, reason()}.
+%%
%% Description: Changes process that receives the messages when active = true
%% or once.
%%--------------------------------------------------------------------
@@ -270,11 +277,8 @@ controlling_process(Socket, NewOwner) when is_pid(NewOwner) ->
ssl_broker:controlling_process(Socket, NewOwner).
%%--------------------------------------------------------------------
-%% Function: connection_info(Socket) -> {ok, {Protocol, CipherSuite}} |
-%% {error, Reason}
-%% Protocol = sslv3 | tlsv1 | tlsv1.1
-%% CipherSuite = {KeyExchange, Chipher, Hash, Exportable}
-%%
+-spec connection_info(#sslsocket{}) -> {ok, {tls_atom_version(), erl_cipher_suite()}} |
+ {error, reason()}.
%%
%% Description: Returns ssl protocol and cipher used for the connection
%%--------------------------------------------------------------------
@@ -286,9 +290,9 @@ connection_info(#sslsocket{} = Socket) ->
ssl_broker:connection_info(Socket).
%%--------------------------------------------------------------------
-%% Function: peercert(Socket[, Opts]) -> {ok, Cert} | {error, Reason}
+-spec peercert(#sslsocket{}) ->{ok, der_cert()} | {error, reason()}.
%%
-%% Description:
+%% Description: Returns the peercert.
%%--------------------------------------------------------------------
peercert(Socket) ->
peercert(Socket, []).
@@ -323,7 +327,7 @@ decode_peercert(BinCert, Opts) ->
{ok, BinCert}
end.
-select_part(otp, {ok, Cert}, Opts) ->
+select_part(otp, Cert, Opts) ->
case lists:member(subject, Opts) of
true ->
TBS = Cert#'OTPCertificate'.tbsCertificate,
@@ -332,7 +336,7 @@ select_part(otp, {ok, Cert}, Opts) ->
{ok, Cert}
end;
-select_part(plain, {ok, Cert}, Opts) ->
+select_part(plain, Cert, Opts) ->
case lists:member(subject, Opts) of
true ->
TBS = Cert#'Certificate'.tbsCertificate,
@@ -342,9 +346,9 @@ select_part(plain, {ok, Cert}, Opts) ->
end.
%%--------------------------------------------------------------------
-%% Function: peername(Socket) -> {ok, {Address, Port}} | {error, Reason}
+-spec peername(#sslsocket{}) -> {ok, {tuple(), port_num()}} | {error, reason()}.
%%
-%% Description:
+%% Description: same as inet:peername/1.
%%--------------------------------------------------------------------
peername(#sslsocket{fd = new_ssl, pid = Pid}) ->
ssl_connection:peername(Pid);
@@ -354,9 +358,10 @@ peername(#sslsocket{} = Socket) ->
ssl_broker:peername(Socket).
%%--------------------------------------------------------------------
-%% Function: cipher_suites() ->
-%%
-%% Description:
+-spec cipher_suites() -> [erl_cipher_suite()].
+-spec cipher_suites(erlang | openssl) -> [erl_cipher_suite()] | [string()].
+
+%% Description: Returns all supported cipher suites.
%%--------------------------------------------------------------------
cipher_suites() ->
cipher_suites(erlang).
@@ -370,7 +375,7 @@ cipher_suites(openssl) ->
[ssl_cipher:openssl_suite_name(S) || S <- ssl_cipher:suites(Version)].
%%--------------------------------------------------------------------
-%% Function: getopts(Socket, OptTags) -> {ok, Options} | {error, Reason}
+-spec getopts(#sslsocket{}, [atom()]) -> {ok, [{atom(), term()}]}| {error, reason()}.
%%
%% Description:
%%--------------------------------------------------------------------
@@ -383,7 +388,7 @@ getopts(#sslsocket{} = Socket, Options) ->
ssl_broker:getopts(Socket, Options).
%%--------------------------------------------------------------------
-%% Function: setopts(Socket, Options) -> ok | {error, Reason}
+-spec setopts(#sslsocket{}, [{atom(), term()}]) -> ok | {error, reason()}.
%%
%% Description:
%%--------------------------------------------------------------------
@@ -398,8 +403,8 @@ setopts(#sslsocket{} = Socket, Options) ->
ssl_broker:setopts(Socket, Options).
%%---------------------------------------------------------------
-%% Function: shutdown(Socket, How) -> ok | {error, Reason}
-%%
+-spec shutdown(#sslsocket{}, read | write | read_write) -> ok | {error, reason()}.
+%%
%% Description: Same as gen_tcp:shutdown/2
%%--------------------------------------------------------------------
shutdown(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _, _}}}, fd = new_ssl}, How) ->
@@ -408,8 +413,8 @@ shutdown(#sslsocket{pid = Pid, fd = new_ssl}, How) ->
ssl_connection:shutdown(Pid, How).
%%--------------------------------------------------------------------
-%% Function: sockname(Socket) -> {ok, {Address, Port}} | {error, Reason}
-%%
+-spec sockname(#sslsocket{}) -> {ok, {tuple(), port_num()}} | {error, reason()}.
+%%
%% Description: Same as inet:sockname/1
%%--------------------------------------------------------------------
sockname(#sslsocket{fd = new_ssl, pid = {ListenSocket, _}}) ->
@@ -423,9 +428,9 @@ sockname(#sslsocket{} = Socket) ->
ssl_broker:sockname(Socket).
%%---------------------------------------------------------------
-%% Function: seed(Data) -> ok | {error, edata}
+-spec seed(term()) ->term().
%%
-%% Description:
+%% Description: Only used by old ssl.
%%--------------------------------------------------------------------
%% TODO: crypto:seed ?
seed(Data) ->
@@ -433,20 +438,17 @@ seed(Data) ->
ssl_server:seed(Data).
%%---------------------------------------------------------------
-%% Function: session_id(Socket) -> {ok, PropList} | {error, Reason}
+-spec session_info(#sslsocket{}) -> {ok, list()} | {error, reason()}.
%%
-%% Description:
+%% Description: Returns list of session info currently [{session_id, session_id(),
+%% {cipher_suite, cipher_suite()}]
%%--------------------------------------------------------------------
session_info(#sslsocket{pid = Pid, fd = new_ssl}) ->
ssl_connection:session_info(Pid).
%%---------------------------------------------------------------
-%% Function: versions() -> [{SslAppVer, SupportedSslVer, AvailableSslVsn}]
-%%
-%% SslAppVer = string() - t.ex: ssl-4.0
-%% SupportedSslVer = [SslVer]
-%% AvailableSslVsn = [SSLVer]
-%% SSLVer = sslv3 | tlsv1 | 'tlsv1.1'
+-spec versions() -> [{ssl_app, string()} | {supported, [tls_atom_version()]} |
+ {available, [tls_atom_version()]}].
%%
%% Description: Returns a list of relevant versions.
%%--------------------------------------------------------------------
@@ -457,6 +459,11 @@ versions() ->
[{ssl_app, ?VSN}, {supported, SupportedVsns}, {available, AvailableVsns}].
+%%---------------------------------------------------------------
+-spec renegotiate(#sslsocket{}) -> ok | {error, reason()}.
+%%
+%% Description:
+%%--------------------------------------------------------------------
renegotiate(#sslsocket{pid = Pid, fd = new_ssl}) ->
ssl_connection:renegotiation(Pid).
@@ -660,7 +667,7 @@ validate_option(secure_renegotiate, Value) when Value == true;
Value == false ->
Value;
validate_option(renegotiate_at, Value) when is_integer(Value) ->
- min(Value, ?DEFAULT_RENEGOTIATE_AT);
+ erlang:min(Value, ?DEFAULT_RENEGOTIATE_AT);
validate_option(debug, Value) when is_list(Value); Value == true ->
Value;
@@ -890,10 +897,6 @@ version() ->
end,
{ok, {SSLVsn, CompVsn, LibVsn}}.
-min(N,M) when N < M ->
- N;
-min(_, M) ->
- M.
%% Only used to remove exit messages from old ssl
%% First is a nonsense clause to provide some
diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl
index db9a883654..eb1228afa4 100644
--- a/lib/ssl/src/ssl_alert.erl
+++ b/lib/ssl/src/ssl_alert.erl
@@ -32,6 +32,17 @@
-export([alert_txt/1, reason_code/2]).
+%%====================================================================
+%% Internal application API
+%%====================================================================
+%%--------------------------------------------------------------------
+-spec reason_code(#alert{}, client | server) -> closed | esslconnect |
+ esslaccept | string().
+%%
+%% Description: Returns the error reason that will be returned to the
+%% user.
+%%--------------------------------------------------------------------
+
reason_code(#alert{description = ?CLOSE_NOTIFY}, _) ->
closed;
reason_code(#alert{description = ?HANDSHAKE_FAILURE}, client) ->
@@ -41,10 +52,19 @@ reason_code(#alert{description = ?HANDSHAKE_FAILURE}, server) ->
reason_code(#alert{description = Description}, _) ->
description_txt(Description).
+%%--------------------------------------------------------------------
+-spec alert_txt(#alert{}) -> string().
+%%
+%% Description: Returns the error string for given alert.
+%%--------------------------------------------------------------------
+
alert_txt(#alert{level = Level, description = Description, where = {Mod,Line}}) ->
Mod ++ ":" ++ integer_to_list(Line) ++ ":" ++
level_txt(Level) ++" "++ description_txt(Description).
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
level_txt(?WARNING) ->
"Warning:";
level_txt(?FATAL) ->
@@ -96,8 +116,3 @@ description_txt(?USER_CANCELED) ->
"user canceled";
description_txt(?NO_RENEGOTIATION) ->
"no renegotiation".
-
-
-
-
-
diff --git a/lib/ssl/src/ssl_app.erl b/lib/ssl/src/ssl_app.erl
index 6ca1c42631..8d50fd7bdb 100644
--- a/lib/ssl/src/ssl_app.erl
+++ b/lib/ssl/src/ssl_app.erl
@@ -27,14 +27,16 @@
-export([start/2, stop/1]).
-%% start/2(Type, StartArgs) -> {ok, Pid} | {ok, Pid, State} |
-%% {error, Reason}
-%%
+%%--------------------------------------------------------------------
+-spec start(normal | {takeover, node()} | {failover, node()}, list()) ->
+ ignore | {ok, pid()} | {error, term()}.
+%%--------------------------------------------------------------------
start(_Type, _StartArgs) ->
ssl_sup:start_link().
-%% stop(State) -> void()
-%%
+%--------------------------------------------------------------------
+-spec stop(term())-> ok.
+%%--------------------------------------------------------------------
stop(_State) ->
ok.
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 9aa31ae8a4..917e75157b 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -46,9 +46,17 @@
%% Internal application API
%%====================================================================
+%%--------------------------------------------------------------------
+-spec trusted_cert_and_path([der_cert()], certdb_ref(), boolean()) ->
+ {der_cert(), [der_cert()], list()}.
+%%
+%% Description: Extracts the root cert (if not presents tries to
+%% look it up, if not found {bad_cert, unknown_ca} will be added verification
+%% errors. Returns {RootCert, Path, VerifyErrors}
+%%--------------------------------------------------------------------
trusted_cert_and_path(CertChain, CertDbRef, Verify) ->
[Cert | RestPath] = lists:reverse(CertChain),
- {ok, OtpCert} = public_key:pkix_decode_cert(Cert, otp),
+ OtpCert = public_key:pkix_decode_cert(Cert, otp),
IssuerAnPath =
case public_key:pkix_is_self_signed(OtpCert) of
true ->
@@ -84,19 +92,31 @@ trusted_cert_and_path(CertChain, CertDbRef, Verify) ->
end
end.
-
+%%--------------------------------------------------------------------
+-spec certificate_chain(undefined | binary(), certdb_ref()) ->
+ {error, no_cert} | {ok, [der_cert()]}.
+%%
+%% Description: Return the certificate chain to send to peer.
+%%--------------------------------------------------------------------
certificate_chain(undefined, _CertsDbRef) ->
{error, no_cert};
certificate_chain(OwnCert, CertsDbRef) ->
- {ok, ErlCert} = public_key:pkix_decode_cert(OwnCert, otp),
+ ErlCert = public_key:pkix_decode_cert(OwnCert, otp),
certificate_chain(ErlCert, OwnCert, CertsDbRef, [OwnCert]).
-
+%%--------------------------------------------------------------------
+-spec file_to_certificats(string()) -> [der_cert()].
+%%
+%% Description: Return list of DER encoded certificates.
+%%--------------------------------------------------------------------
file_to_certificats(File) ->
{ok, List} = ssl_manager:cache_pem_file(File),
- [Bin || {cert, Bin, not_encrypted} <- List].
-
-
-%% Validates ssl/tls specific extensions
+ [Bin || {'Certificate', Bin, not_encrypted} <- List].
+%%--------------------------------------------------------------------
+-spec validate_extensions([#'Extension'{}], term(), [#'Extension'{}],
+ boolean(), list(), client | server) -> {[#'Extension'{}], term(), list()}.
+%%
+%% Description: Validates ssl/tls specific extensions
+%%--------------------------------------------------------------------
validate_extensions([], ValidationState, UnknownExtensions, _, AccErr, _) ->
{UnknownExtensions, ValidationState, AccErr};
@@ -119,21 +139,42 @@ validate_extensions([Extension | Rest], ValidationState, UnknownExtensions,
validate_extensions(Rest, ValidationState, [Extension | UnknownExtensions],
Verify, AccErr, Role).
+%%--------------------------------------------------------------------
+-spec is_valid_key_usage(list(), term()) -> boolean().
+%%
+%% Description: Checks if Use is a valid key usage.
+%%--------------------------------------------------------------------
is_valid_key_usage(KeyUse, Use) ->
lists:member(Use, KeyUse).
- select_extension(_, []) ->
+%%--------------------------------------------------------------------
+-spec select_extension(term(), list()) -> undefined | #'Extension'{}.
+%%
+%% Description: Selects the extension identified by Id if present in
+%% a list of extensions.
+%%--------------------------------------------------------------------
+select_extension(_, []) ->
undefined;
select_extension(Id, [#'Extension'{extnID = Id} = Extension | _]) ->
Extension;
select_extension(Id, [_ | Extensions]) ->
select_extension(Id, Extensions).
+%%--------------------------------------------------------------------
+-spec extensions_list(asn1_NOVALUE | list()) -> list().
+%%
+%% Description: Handles that
+%%--------------------------------------------------------------------
extensions_list(asn1_NOVALUE) ->
[];
extensions_list(Extensions) ->
Extensions.
+%%--------------------------------------------------------------------
+-spec signature_type(term()) -> rsa | dsa .
+%%
+%% Description:
+%%--------------------------------------------------------------------
signature_type(RSA) when RSA == ?sha1WithRSAEncryption;
RSA == ?md5WithRSAEncryption ->
rsa;
@@ -178,7 +219,7 @@ certificate_chain(CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned) ->
case ssl_manager:lookup_trusted_cert(CertsDbRef,
SerialNr, Issuer) of
{ok, {IssuerCert, ErlCert}} ->
- {ok, ErlCert} = public_key:pkix_decode_cert(IssuerCert, otp),
+ ErlCert = public_key:pkix_decode_cert(IssuerCert, otp),
certificate_chain(ErlCert, IssuerCert,
CertsDbRef, [IssuerCert | Chain]);
_ ->
diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl
index b8c3c6f6b7..00d3079cb3 100644
--- a/lib/ssl/src/ssl_certificate_db.erl
+++ b/lib/ssl/src/ssl_certificate_db.erl
@@ -22,7 +22,7 @@
%%----------------------------------------------------------------------
-module(ssl_certificate_db).
-
+-include("ssl_internal.hrl").
-include_lib("public_key/include/public_key.hrl").
-export([create/0, remove/1, add_trusted_certs/3,
@@ -34,8 +34,7 @@
%%====================================================================
%%--------------------------------------------------------------------
-%% Function: create() -> Db
-%% Db = term() - Reference to the crated database
+-spec create() -> certdb_ref().
%%
%% Description: Creates a new certificate db.
%% Note: lookup_trusted_cert/3 may be called from any process but only
@@ -47,8 +46,7 @@ create() ->
ets:new(ssl_pid_to_file, [bag, private])].
%%--------------------------------------------------------------------
-%% Function: delete(Db) -> _
-%% Db = Database refererence as returned by create/0
+-spec remove(certdb_ref()) -> term().
%%
%% Description: Removes database db
%%--------------------------------------------------------------------
@@ -56,11 +54,9 @@ remove(Dbs) ->
lists:foreach(fun(Db) -> true = ets:delete(Db) end, Dbs).
%%--------------------------------------------------------------------
-%% Function: lookup_trusted_cert(Ref, SerialNumber, Issuer) -> {BinCert,DecodedCert}
-%% Ref = ref()
-%% SerialNumber = integer()
-%% Issuer = {rdnSequence, IssuerAttrs}
-%% BinCert = binary()
+-spec lookup_trusted_cert(reference(), serialnumber(), issuer()) ->
+ undefined | {ok, {der_cert(), #'OTPCertificate'{}}}.
+
%%
%% Description: Retrives the trusted certificate identified by
%% <SerialNumber, Issuer>. Ref is used as it is specified
@@ -78,11 +74,7 @@ lookup_cached_certs(File) ->
ets:lookup(certificate_db_name(), {file, File}).
%%--------------------------------------------------------------------
-%% Function: add_trusted_certs(Pid, File, Db) -> {ok, Ref}
-%% Pid = pid()
-%% File = string()
-%% Db = Database refererence as returned by create/0
-%% Ref = ref()
+-spec add_trusted_certs(pid(), string(), certdb_ref()) -> {ok, certdb_ref()}.
%%
%% Description: Adds the trusted certificates from file <File> to the
%% runtime database. Returns Ref that should be handed to lookup_trusted_cert
@@ -103,18 +95,20 @@ add_trusted_certs(Pid, File, [CertsDb, FileToRefDb, PidToFileDb]) ->
{ok, Ref}.
%%--------------------------------------------------------------------
-%% Function: cache_pem_file(Pid, File, Db) -> FileContent
+-spec cache_pem_file(pid(), string(), certdb_ref()) -> term().
%%
%% Description: Cache file as binary in DB
%%--------------------------------------------------------------------
cache_pem_file(Pid, File, [CertsDb, _FileToRefDb, PidToFileDb]) ->
- Res = {ok, Content} = public_key:pem_to_der(File),
+ {ok, PemBin} = file:read_file(File),
+ Content = public_key:pem_decode(PemBin),
insert({file, File}, Content, CertsDb),
insert(Pid, File, PidToFileDb),
- Res.
+ {ok, Content}.
%%--------------------------------------------------------------------
-%% Function: remove_trusted_certs(Pid, Db) -> _
+-spec remove_trusted_certs(pid(), certdb_ref()) -> term().
+
%%
%% Description: Removes trusted certs originating from
%% the file associated to Pid from the runtime database.
@@ -144,15 +138,13 @@ remove_trusted_certs(Pid, [CertsDb, FileToRefDb, PidToFileDb]) ->
end.
%%--------------------------------------------------------------------
-%% Function: issuer_candidate() -> {Key, Candidate} | no_more_candidates
+-spec issuer_candidate(no_candidate | cert_key() | {file, term()}) ->
+ {cert_key(),{der_cert(), #'OTPCertificate'{}}} | no_more_candidates.
%%
-%% Candidate
-%%
-%%
%% Description: If a certificat does not define its issuer through
%% the extension 'ce-authorityKeyIdentifier' we can
%% try to find the issuer in the database over known
-%% certificates.
+%% certificates.
%%--------------------------------------------------------------------
issuer_candidate(no_candidate) ->
Db = certificate_db_name(),
@@ -211,14 +203,15 @@ remove_certs(Ref, CertsDb) ->
ets:match_delete(CertsDb, {{Ref, '_', '_'}, '_'}).
add_certs_from_file(File, Ref, CertsDb) ->
- Decode = fun(Cert) ->
- {ok, ErlCert} = public_key:pkix_decode_cert(Cert, otp),
+ Add = fun(Cert) ->
+ ErlCert = public_key:pkix_decode_cert(Cert, otp),
TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate,
SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber,
- Issuer = public_key:pkix_normalize_general_name(
+ Issuer = public_key:pkix_normalize_name(
TBSCertificate#'OTPTBSCertificate'.issuer),
insert({Ref, SerialNumber, Issuer}, {Cert,ErlCert}, CertsDb)
end,
- {ok,Der} = public_key:pem_to_der(File),
- [Decode(Cert) || {cert, Cert, not_encrypted} <- Der].
+ {ok, PemBin} = file:read_file(File),
+ PemEntries = public_key:pem_decode(PemBin),
+ [Add(Cert) || {'Certificate', Cert, not_encrypted} <- PemEntries].
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 2a71df8ee1..8230149304 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -40,11 +40,8 @@
-compile(inline).
%%--------------------------------------------------------------------
-%% Function: security_parameters(CipherSuite, SecParams) ->
-%% #security_parameters{}
-%%
-%% CipherSuite - as defined in ssl_cipher.hrl
-%% SecParams - #security_parameters{}
+-spec security_parameters(cipher_suite(), #security_parameters{}) ->
+ #security_parameters{}.
%%
%% Description: Returns a security parameters record where the
%% cipher values has been updated according to <CipherSuite>
@@ -63,15 +60,11 @@ security_parameters(CipherSuite, SecParams) ->
hash_size = hash_size(Hash)}.
%%--------------------------------------------------------------------
-%% Function: cipher(Method, CipherState, Mac, Data) ->
-%% {Encrypted, UpdateCipherState}
-%%
-%% Method - integer() (as defined in ssl_cipher.hrl)
-%% CipherState, UpdatedCipherState - #cipher_state{}
-%% Data, Encrypted - binary()
+-spec cipher(cipher_enum(), #cipher_state{}, binary(), binary()) ->
+ {binary(), #cipher_state{}}.
%%
-%% Description: Encrypts the data and the mac using method, updating
-%% the cipher state
+%% Description: Encrypts the data and the MAC using chipher described
+%% by cipher_enum() and updating the cipher state
%%-------------------------------------------------------------------
cipher(?NULL, CipherState, <<>>, Fragment) ->
GenStreamCipherList = [Fragment, <<>>],
@@ -125,15 +118,11 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0,
{T, CS0#cipher_state{iv=NextIV}}.
%%--------------------------------------------------------------------
-%% Function: decipher(Method, CipherState, Mac, Data, Version) ->
-%% {Decrypted, UpdateCipherState}
-%%
-%% Method - integer() (as defined in ssl_cipher.hrl)
-%% CipherState, UpdatedCipherState - #cipher_state{}
-%% Data, Encrypted - binary()
+-spec decipher(cipher_enum(), integer(), #cipher_state{}, binary(), tls_version()) ->
+ {binary(), binary(), #cipher_state{}} | #alert{}.
%%
-%% Description: Decrypts the data and the mac using method, updating
-%% the cipher state
+%% Description: Decrypts the data and the MAC using cipher described
+%% by cipher_enum() and updating the cipher state.
%%-------------------------------------------------------------------
decipher(?NULL, _HashSz, CipherState, Fragment, _) ->
{Fragment, <<>>, CipherState};
@@ -192,10 +181,7 @@ block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
end.
%%--------------------------------------------------------------------
-%% Function: suites(Version) -> [Suite]
-%%
-%% Version = version()
-%% Suite = binary() from ssl_cipher.hrl
+-spec suites(tls_version()) -> [cipher_suite()].
%%
%% Description: Returns a list of supported cipher suites.
%%--------------------------------------------------------------------
@@ -205,19 +191,9 @@ suites({3, N}) when N == 1; N == 2 ->
ssl_tls1:suites().
%%--------------------------------------------------------------------
-%% Function: suite_definition(CipherSuite) ->
-%% {KeyExchange, Cipher, Hash}
-%%
-%%
-%% CipherSuite - as defined in ssl_cipher.hrl
-%% KeyExchange - rsa | dh_anon | dhe_dss | dhe_rsa | kerb5
-%%
-%% Cipher - null | rc4_128 | idea_cbc | des_cbc | '3des_ede_cbc'
-%% des40_cbc | aes_128_cbc | aes_256_cbc
-%% Hash - null | md5 | sha
+-spec suite_definition(cipher_suite()) -> erl_cipher_suite().
%%
-%% Description: Returns a security parameters tuple where the
-%% cipher values has been updated according to <CipherSuite>
+%% Description: Return erlang cipher suite definition.
%% Note: Currently not supported suites are commented away.
%% They should be supported or removed in the future.
%%-------------------------------------------------------------------
@@ -261,6 +237,12 @@ suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) ->
suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) ->
{dhe_rsa, aes_256_cbc, sha}.
+%%--------------------------------------------------------------------
+-spec suite(erl_cipher_suite()) -> cipher_suite().
+%%
+%% Description: Return TLS cipher suite definition.
+%%--------------------------------------------------------------------
+
%% TLS v1.1 suites
%%suite({rsa, null, md5}) ->
%% ?TLS_RSA_WITH_NULL_MD5;
@@ -309,7 +291,11 @@ suite({dhe_rsa, aes_256_cbc, sha}) ->
%% suite({dh_anon, aes_256_cbc, sha}) ->
%% ?TLS_DH_anon_WITH_AES_256_CBC_SHA.
-
+%%--------------------------------------------------------------------
+-spec openssl_suite(openssl_cipher_suite()) -> cipher_suite().
+%%
+%% Description: Return TLS cipher suite definition.
+%%--------------------------------------------------------------------
%% translate constants <-> openssl-strings
openssl_suite("DHE-RSA-AES256-SHA") ->
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
@@ -339,7 +325,11 @@ openssl_suite("EDH-RSA-DES-CBC-SHA") ->
?TLS_DHE_RSA_WITH_DES_CBC_SHA;
openssl_suite("DES-CBC-SHA") ->
?TLS_RSA_WITH_DES_CBC_SHA.
-
+%%--------------------------------------------------------------------
+-spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite().
+%%
+%% Description: Return openssl cipher suite name.
+%%-------------------------------------------------------------------
openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) ->
"DHE-RSA-AES256-SHA";
openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) ->
@@ -372,10 +362,15 @@ openssl_suite_name(?TLS_RSA_WITH_DES_CBC_SHA) ->
openssl_suite_name(Cipher) ->
suite_definition(Cipher).
+%%--------------------------------------------------------------------
+-spec filter(undefined | binary(), [cipher_suite()]) -> [cipher_suite()].
+%%
+%% Description: .
+%%-------------------------------------------------------------------
filter(undefined, Ciphers) ->
Ciphers;
filter(DerCert, Ciphers) ->
- {ok, OtpCert} = public_key:pkix_decode_cert(DerCert, otp),
+ OtpCert = public_key:pkix_decode_cert(DerCert, otp),
SigAlg = OtpCert#'OTPCertificate'.signatureAlgorithm,
case ssl_certificate:signature_type(SigAlg#'SignatureAlgorithm'.algorithm) of
rsa ->
@@ -511,6 +506,12 @@ generic_stream_cipher_from_bin(T, HashSz) ->
is_correct_padding(_, {3, 0}) ->
true;
+%% For interoperability reasons we do not check the padding in TLS 1.0 as it
+%% is not strictly required and breaks interopability with for instance
+%% Google.
+is_correct_padding(_, {3, 1}) ->
+ true;
+%% Padding must be check in TLS 1.1 and after
is_correct_padding(#generic_block_cipher{padding_length = Len, padding = Padding}, _) ->
list_to_binary(lists:duplicate(Len, Len)) == Padding.
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl
index 80fe527f45..8bd68cc190 100644
--- a/lib/ssl/src/ssl_cipher.hrl
+++ b/lib/ssl/src/ssl_cipher.hrl
@@ -26,6 +26,14 @@
-ifndef(ssl_cipher).
-define(ssl_cipher, true).
+-type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc'
+ | aes_128_cbc | aes_256_cbc.
+-type hash() :: null | sha | md5.
+-type erl_cipher_suite() :: {key_algo(), cipher(), hash()}.
+-type cipher_suite() :: binary().
+-type cipher_enum() :: integer().
+-type openssl_cipher_suite() :: string().
+
%%% SSL cipher protocol %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-define(CHANGE_CIPHER_SPEC_PROTO, 1). % _PROTO to not clash with
% SSL record protocol
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 07fa101ed4..76422155a5 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -98,12 +98,17 @@
#'DHParameter'{prime = ?DEFAULT_DIFFIE_HELLMAN_PRIME,
base = ?DEFAULT_DIFFIE_HELLMAN_GENERATOR}).
+-type state_name() :: hello | abbreviated | certify | cipher | connection.
+-type gen_fsm_state_return() :: {next_state, state_name(), #state{}} |
+ {next_state, state_name(), #state{}, timeout()} |
+ {stop, term(), #state{}}.
+
%%====================================================================
%% Internal application API
%%====================================================================
%%--------------------------------------------------------------------
-%% Function: send(Pid, Data) -> ok | {error, Reason}
+-spec send(pid(), iolist()) -> ok | {error, reason()}.
%%
%% Description: Sends data over the ssl connection
%%--------------------------------------------------------------------
@@ -112,15 +117,17 @@ send(Pid, Data) ->
erlang:iolist_to_binary(Data)}, infinity).
%%--------------------------------------------------------------------
-%% Function: recv(Socket, Length Timeout) -> {ok, Data} | {error, reason}
+-spec recv(pid(), integer(), timeout()) ->
+ {ok, binary() | list()} | {error, reason()}.
%%
%% Description: Receives data when active = false
%%--------------------------------------------------------------------
recv(Pid, Length, Timeout) ->
sync_send_all_state_event(Pid, {recv, Length}, Timeout).
%%--------------------------------------------------------------------
-%% Function: : connect(Host, Port, Socket, Options,
-%% User, CbInfo, Timeout) -> {ok, Socket}
+-spec connect(host(), port_num(), port(), {#ssl_options{}, #socket_options{}},
+ pid(), tuple(), timeout()) ->
+ {ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Connect to a ssl server.
%%--------------------------------------------------------------------
@@ -132,8 +139,9 @@ connect(Host, Port, Socket, Options, User, CbInfo, Timeout) ->
{error, ssl_not_started}
end.
%%--------------------------------------------------------------------
-%% Function: accept(Port, Socket, Opts, User,
-%% CbInfo, Timeout) -> {ok, Socket} | {error, Reason}
+-spec ssl_accept(port_num(), port(), {#ssl_options{}, #socket_options{}},
+ pid(), tuple(), timeout()) ->
+ {ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Performs accept on a ssl listen socket. e.i. performs
%% ssl handshake.
@@ -147,7 +155,7 @@ ssl_accept(Port, Socket, Opts, User, CbInfo, Timeout) ->
end.
%%--------------------------------------------------------------------
-%% Function: handshake(SslSocket, Timeout) -> ok | {error, Reason}
+-spec handshake(#sslsocket{}, timeout()) -> ok | {error, reason()}.
%%
%% Description: Starts ssl handshake.
%%--------------------------------------------------------------------
@@ -159,7 +167,8 @@ handshake(#sslsocket{pid = Pid}, Timeout) ->
Error
end.
%--------------------------------------------------------------------
-%% Function: socket_control(Pid) -> {ok, SslSocket} | {error, Reason}
+-spec socket_control(port(), pid(), atom()) ->
+ {ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Set the ssl process to own the accept socket
%%--------------------------------------------------------------------
@@ -172,7 +181,7 @@ socket_control(Socket, Pid, CbModule) ->
end.
%%--------------------------------------------------------------------
-%% Function: close() -> ok
+-spec close(pid()) -> ok | {error, reason()}.
%%
%% Description: Close a ssl connection
%%--------------------------------------------------------------------
@@ -185,7 +194,7 @@ close(ConnectionPid) ->
end.
%%--------------------------------------------------------------------
-%% Function: shutdown(Socket, How) -> ok | {error, Reason}
+-spec shutdown(pid(), atom()) -> ok | {error, reason()}.
%%
%% Description: Same as gen_tcp:shutdown/2
%%--------------------------------------------------------------------
@@ -193,7 +202,7 @@ shutdown(ConnectionPid, How) ->
sync_send_all_state_event(ConnectionPid, {shutdown, How}).
%%--------------------------------------------------------------------
-%% Function: new_user(ConnectionPid, User) -> ok | {error, Reason}
+-spec new_user(pid(), pid()) -> ok | {error, reason()}.
%%
%% Description: Changes process that receives the messages when active = true
%% or once.
@@ -201,28 +210,28 @@ shutdown(ConnectionPid, How) ->
new_user(ConnectionPid, User) ->
sync_send_all_state_event(ConnectionPid, {new_user, User}).
%%--------------------------------------------------------------------
-%% Function: sockname(ConnectionPid) -> {ok, {Address, Port}} | {error, Reason}
+-spec sockname(pid()) -> {ok, {tuple(), port_num()}} | {error, reason()}.
%%
%% Description: Same as inet:sockname/1
%%--------------------------------------------------------------------
sockname(ConnectionPid) ->
sync_send_all_state_event(ConnectionPid, sockname).
%%--------------------------------------------------------------------
-%% Function: peername(ConnectionPid) -> {ok, {Address, Port}} | {error, Reason}
+-spec peername(pid()) -> {ok, {tuple(), port_num()}} | {error, reason()}.
%%
%% Description: Same as inet:peername/1
%%--------------------------------------------------------------------
peername(ConnectionPid) ->
sync_send_all_state_event(ConnectionPid, peername).
%%--------------------------------------------------------------------
-%% Function: get_opts(ConnectionPid, OptTags) -> {ok, Options} | {error, Reason}
+-spec get_opts(pid(), list()) -> {ok, list()} | {error, reason()}.
%%
%% Description: Same as inet:getopts/2
%%--------------------------------------------------------------------
get_opts(ConnectionPid, OptTags) ->
sync_send_all_state_event(ConnectionPid, {get_opts, OptTags}).
%%--------------------------------------------------------------------
-%% Function: setopts(Socket, Options) -> ok | {error, Reason}
+-spec set_opts(pid(), list()) -> ok | {error, reason()}.
%%
%% Description: Same as inet:setopts/2
%%--------------------------------------------------------------------
@@ -230,8 +239,7 @@ set_opts(ConnectionPid, Options) ->
sync_send_all_state_event(ConnectionPid, {set_opts, Options}).
%%--------------------------------------------------------------------
-%% Function: info(ConnectionPid) -> {ok, {Protocol, CipherSuite}} |
-%% {error, Reason}
+-spec info(pid()) -> {ok, {atom(), tuple()}} | {error, reason()}.
%%
%% Description: Returns ssl protocol and cipher used for the connection
%%--------------------------------------------------------------------
@@ -239,7 +247,7 @@ info(ConnectionPid) ->
sync_send_all_state_event(ConnectionPid, info).
%%--------------------------------------------------------------------
-%% Function: session_info(ConnectionPid) -> {ok, PropList} | {error, Reason}
+-spec session_info(pid()) -> {ok, list()} | {error, reason()}.
%%
%% Description: Returns info about the ssl session
%%--------------------------------------------------------------------
@@ -247,7 +255,7 @@ session_info(ConnectionPid) ->
sync_send_all_state_event(ConnectionPid, session_info).
%%--------------------------------------------------------------------
-%% Function: peercert(ConnectionPid) -> {ok, Cert} | {error, Reason}
+-spec peer_certificate(pid()) -> {ok, binary()| undefined} | {error, reason()}.
%%
%% Description: Returns the peer cert
%%--------------------------------------------------------------------
@@ -255,7 +263,7 @@ peer_certificate(ConnectionPid) ->
sync_send_all_state_event(ConnectionPid, peer_certificate).
%%--------------------------------------------------------------------
-%% Function: renegotiation(ConnectionPid) -> ok | {error, Reason}
+-spec renegotiation(pid()) -> ok | {error, reason()}.
%%
%% Description: Starts a renegotiation of the ssl session.
%%--------------------------------------------------------------------
@@ -267,7 +275,8 @@ renegotiation(ConnectionPid) ->
%%====================================================================
%%--------------------------------------------------------------------
-%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
+-spec start_link(atom(), host(), port_num(), port(), list(), pid(), tuple()) ->
+ {ok, pid()} | ignore | {error, reason()}.
%%
%% Description: Creates a gen_fsm process which calls Module:init/1 to
%% initialize. To ensure a synchronized start-up procedure, this function
@@ -281,10 +290,10 @@ start_link(Role, Host, Port, Socket, Options, User, CbInfo) ->
%% gen_fsm callbacks
%%====================================================================
%%--------------------------------------------------------------------
-%% Function: init(Args) -> {ok, StateName, State} |
-%% {ok, StateName, State, Timeout} |
-%% ignore |
-%% {stop, StopReason}
+-spec init(list()) -> {ok, state_name(), #state{}} | {stop, term()}.
+%% Possible return values not used now.
+%% | {ok, state_name(), #state{}, timeout()} |
+%% ignore
%% Description:Whenever a gen_fsm is started using gen_fsm:start/[3,4] or
%% gen_fsm:start_link/3,4, this function is called by the new process to
%% initialize.
@@ -309,11 +318,7 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options,
end.
%%--------------------------------------------------------------------
-%% Function:
-%% state_name(Event, State) -> {next_state, NextStateName, NextState}|
-%% {next_state, NextStateName,
-%% NextState, Timeout} |
-%% {stop, Reason, NewState}
+%% -spec state_name(event(), #state{}) -> gen_fsm_state_return()
%%
%% Description:There should be one instance of this function for each
%% possible state name. Whenever a gen_fsm receives an event sent
@@ -322,6 +327,9 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options,
%% the event. It is also called if a timeout occurs.
%%
%%--------------------------------------------------------------------
+-spec hello(start | #hello_request{} | #client_hello{} | #server_hello{} | term(),
+ #state{}) -> gen_fsm_state_return().
+%%--------------------------------------------------------------------
hello(start, #state{host = Host, port = Port, role = client,
ssl_options = SslOpts,
transport_cb = Transport, socket = Socket,
@@ -359,49 +367,30 @@ hello(#hello_request{}, #state{role = client} = State0) ->
hello(#server_hello{cipher_suite = CipherSuite,
compression_method = Compression} = Hello,
- #state{session = Session0 = #session{session_id = OldId},
+ #state{session = #session{session_id = OldId},
connection_states = ConnectionStates0,
role = client,
negotiated_version = ReqVersion,
- host = Host, port = Port,
renegotiation = {Renegotiation, _},
- ssl_options = SslOptions,
- session_cache = Cache,
- session_cache_cb = CacheCb} = State0) ->
+ ssl_options = SslOptions} = State0) ->
case ssl_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
- {Version, NewId, ConnectionStates1} ->
+ {Version, NewId, ConnectionStates} ->
{KeyAlgorithm, _, _} =
ssl_cipher:suite_definition(CipherSuite),
PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm),
- State1 = State0#state{key_algorithm = KeyAlgorithm,
- negotiated_version = Version,
- connection_states = ConnectionStates1,
- premaster_secret = PremasterSecret},
+ State = State0#state{key_algorithm = KeyAlgorithm,
+ negotiated_version = Version,
+ connection_states = ConnectionStates,
+ premaster_secret = PremasterSecret},
case ssl_session:is_new(OldId, NewId) of
true ->
- Session = Session0#session{session_id = NewId,
- cipher_suite = CipherSuite,
- compression_method = Compression},
- {Record, State} = next_record(State1#state{session = Session}),
- next_state(certify, Record, State);
+ handle_new_session(NewId, CipherSuite, Compression, State);
false ->
- Session = CacheCb:lookup(Cache, {{Host, Port}, NewId}),
- case ssl_handshake:master_secret(Version, Session,
- ConnectionStates1, client) of
- {_, ConnectionStates2} ->
- {Record, State} =
- next_record(State1#state{
- connection_states = ConnectionStates2,
- session = Session}),
- next_state(abbreviated, Record, State);
- #alert{} = Alert ->
- handle_own_alert(Alert, Version, hello, State1),
- {stop, normal, State1}
- end
+ handle_resumed_session(NewId, State#state{connection_states = ConnectionStates})
end;
#alert{} = Alert ->
handle_own_alert(Alert, ReqVersion, hello, State0),
@@ -431,7 +420,10 @@ hello(Hello = #client_hello{client_version = ClientVersion},
hello(Msg, State) ->
handle_unexpected_message(Msg, hello, State).
-
+%%--------------------------------------------------------------------
+-spec abbreviated(#hello_request{} | #finished{} | term(),
+ #state{}) -> gen_fsm_state_return().
+%%--------------------------------------------------------------------
abbreviated(#hello_request{}, State0) ->
{Record, State} = next_record(State0),
next_state(hello, Record, State);
@@ -477,6 +469,11 @@ abbreviated(#finished{verify_data = Data} = Finished,
abbreviated(Msg, State) ->
handle_unexpected_message(Msg, abbreviated, State).
+%%--------------------------------------------------------------------
+-spec certify(#hello_request{} | #certificate{} | #server_key_exchange{} |
+ #certificate_request{} | #server_hello_done{} | #client_key_exchange{} | term(),
+ #state{}) -> gen_fsm_state_return().
+%%--------------------------------------------------------------------
certify(#hello_request{}, State0) ->
{Record, State} = next_record(State0),
next_state(hello, Record, State);
@@ -646,6 +643,10 @@ certify(#client_key_exchange{exchange_keys = #client_diffie_hellman_public{
certify(Msg, State) ->
handle_unexpected_message(Msg, certify, State).
+%%--------------------------------------------------------------------
+-spec cipher(#hello_request{} | #certificate_verify{} | #finished{} | term(),
+ #state{}) -> gen_fsm_state_return().
+%%--------------------------------------------------------------------
cipher(#hello_request{}, State0) ->
{Record, State} = next_record(State0),
next_state(hello, Record, State);
@@ -676,31 +677,14 @@ cipher(#finished{verify_data = Data} = Finished,
role = Role,
session = #session{master_secret = MasterSecret}
= Session0,
- tls_handshake_hashes = Hashes0,
- connection_states = ConnectionStates0} = State) ->
+ tls_handshake_hashes = Hashes0} = State) ->
case ssl_handshake:verify_connection(Version, Finished,
opposite_role(Role),
MasterSecret, Hashes0) of
verified ->
Session = register_session(Role, Host, Port, Session0),
- case Role of
- client ->
- ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0),
- next_state_connection(cipher, ack_connection(State#state{session = Session,
- connection_states = ConnectionStates}));
- server ->
- ConnectionStates1 = ssl_record:set_client_verify_data(current_read, Data, ConnectionStates0),
- {ConnectionStates, Hashes} =
- finalize_handshake(State#state{
- connection_states = ConnectionStates1,
- session = Session}, cipher),
- next_state_connection(cipher, ack_connection(State#state{connection_states =
- ConnectionStates,
- session = Session,
- tls_handshake_hashes =
- Hashes}))
- end;
+ cipher_role(Role, Data, Session, State);
#alert{} = Alert ->
handle_own_alert(Alert, Version, cipher, State),
{stop, normal, State}
@@ -709,7 +693,10 @@ cipher(#finished{verify_data = Data} = Finished,
cipher(Msg, State) ->
handle_unexpected_message(Msg, cipher, State).
-
+%%--------------------------------------------------------------------
+-spec connection(#hello_request{} | #client_hello{} | term(),
+ #state{}) -> gen_fsm_state_return().
+%%--------------------------------------------------------------------
connection(#hello_request{}, #state{host = Host, port = Port,
socket = Socket,
ssl_options = SslOpts,
@@ -736,30 +723,24 @@ connection(#client_hello{} = Hello, #state{role = server} = State) ->
connection(Msg, State) ->
handle_unexpected_message(Msg, connection, State).
%%--------------------------------------------------------------------
-%% Function:
-%% handle_event(Event, StateName, State) -> {next_state, NextStateName,
-%% NextState} |
-%% {next_state, NextStateName,
-%% NextState, Timeout} |
-%% {stop, Reason, NewState}
+-spec handle_event(term(), state_name(), #state{}) -> term().
+%% As it is not currently used gen_fsm_state_return() makes
+%% dialyzer unhappy!
+%%
%% Description: Whenever a gen_fsm receives an event sent using
%% gen_fsm:send_all_state_event/2, this function is called to handle
-%% the event.
+%% the event. Not currently used!
%%--------------------------------------------------------------------
handle_event(_Event, StateName, State) ->
{next_state, StateName, State}.
%%--------------------------------------------------------------------
-%% Function:
-%% handle_sync_event(Event, From, StateName,
-%% State) -> {next_state, NextStateName, NextState} |
-%% {next_state, NextStateName, NextState,
-%% Timeout} |
-%% {reply, Reply, NextStateName, NextState}|
-%% {reply, Reply, NextStateName, NextState,
-%% Timeout} |
-%% {stop, Reason, NewState} |
-%% {stop, Reason, Reply, NewState}
+-spec handle_sync_event(term(), from(), state_name(), #state{}) ->
+ gen_fsm_state_return() |
+ {reply, reply(), state_name(), #state{}} |
+ {reply, reply(), state_name(), #state{}, timeout()} |
+ {stop, reason(), reply(), #state{}}.
+%%
%% Description: Whenever a gen_fsm receives an event sent using
%% gen_fsm:sync_send_all_state_event/2,3, this function is called to handle
%% the event.
@@ -936,11 +917,11 @@ handle_sync_event(peer_certificate, _, StateName,
{reply, {ok, Cert}, StateName, State}.
%%--------------------------------------------------------------------
-%% Function:
-%% handle_info(Info,StateName,State)-> {next_state, NextStateName, NextState}|
-%% {next_state, NextStateName, NextState,
-%% Timeout} |
-%% {stop, Reason, NewState}
+-spec handle_info(msg(),state_name(), #state{}) ->
+ {next_state, state_name(), #state{}}|
+ {next_state, state_name(), #state{}, timeout()} |
+ {stop, reason(), #state{}}.
+%%
%% Description: This function is called by a gen_fsm when it receives any
%% other message than a synchronous or asynchronous event
%% (or a system message).
@@ -1000,7 +981,8 @@ handle_info(Msg, StateName, State) ->
{next_state, StateName, State}.
%%--------------------------------------------------------------------
-%% Function: terminate(Reason, StateName, State) -> void()
+-spec terminate(reason(), state_name(), #state{}) -> term().
+%%
%% Description:This function is called by a gen_fsm when it is about
%% to terminate. It should be the opposite of Module:init/1 and do any
%% necessary cleaning up. When it returns, the gen_fsm terminates with
@@ -1027,7 +1009,8 @@ terminate(_Reason, _StateName, #state{transport_cb = Transport,
Transport:close(Socket).
%%--------------------------------------------------------------------
-%% Function:
+-spec code_change(term(), state_name(), #state{}, list()) -> {ok, state_name(), #state{}}.
+%%
%% code_change(OldVsn, StateName, State, Extra) -> {ok, StateName, NewState}
%% Description: Convert process state when code is changed
%%--------------------------------------------------------------------
@@ -1039,24 +1022,17 @@ code_change(_OldVsn, StateName, State, _Extra) ->
%%--------------------------------------------------------------------
start_fsm(Role, Host, Port, Socket, Opts, User, {CbModule, _,_, _} = CbInfo,
Timeout) ->
- case ssl_connection_sup:start_child([Role, Host, Port, Socket,
- Opts, User, CbInfo]) of
- {ok, Pid} ->
- case socket_control(Socket, Pid, CbModule) of
- {ok, SslSocket} ->
- case handshake(SslSocket, Timeout) of
- ok ->
- {ok, SslSocket};
- {error, Reason} ->
- {error, Reason}
- end;
- {error, Reason} ->
- {error, Reason}
- end;
- {error, Reason} ->
- {error, Reason}
+ try
+ {ok, Pid} = ssl_connection_sup:start_child([Role, Host, Port, Socket,
+ Opts, User, CbInfo]),
+ {ok, SslSocket} = socket_control(Socket, Pid, CbModule),
+ ok = handshake(SslSocket, Timeout),
+ {ok, SslSocket}
+ catch
+ error:{badmatch, {error, _} = Error} ->
+ Error
end.
-
+
ssl_init(SslOpts, Role) ->
{ok, CertDbRef, CacheRef, OwnCert} = init_certificates(SslOpts, Role),
PrivateKey =
@@ -1067,20 +1043,22 @@ ssl_init(SslOpts, Role) ->
init_certificates(#ssl_options{cacertfile = CACertFile,
certfile = CertFile}, Role) ->
+ {ok, CertDbRef, CacheRef} =
+ try
+ {ok, _, _} = ssl_manager:connection_init(CACertFile, Role)
+ catch
+ Error:Reason ->
+ handle_file_error(?LINE, Error, Reason, CACertFile, ecacertfile,
+ erlang:get_stacktrace())
+ end,
+ init_certificates(CertDbRef, CacheRef, CertFile, Role).
- case ssl_manager:connection_init(CACertFile, Role) of
- {ok, CertDbRef, CacheRef} ->
- init_certificates(CertDbRef, CacheRef, CertFile, Role);
- {error, Reason} ->
- handle_file_error(?LINE, error, Reason, CACertFile, ecacertfile,
- erlang:get_stacktrace())
- end.
init_certificates(CertDbRef, CacheRef, CertFile, client) ->
try
[OwnCert] = ssl_certificate:file_to_certificats(CertFile),
{ok, CertDbRef, CacheRef, OwnCert}
- catch _E:_R ->
+ catch _Error:_Reason ->
{ok, CertDbRef, CacheRef, undefined}
end;
@@ -1097,15 +1075,15 @@ init_certificates(CertDbRef, CacheRef, CertFile, server) ->
init_private_key(undefined, "", _Password, client) ->
undefined;
init_private_key(undefined, KeyFile, Password, _) ->
- case ssl_manager:cache_pem_file(KeyFile) of
- {ok, List} ->
- [Der] = [Der || Der = {PKey, _ , _} <- List,
- PKey =:= rsa_private_key orelse
- PKey =:= dsa_private_key],
- {ok, Decoded} = public_key:decode_private_key(Der,Password),
- Decoded;
- {error, Reason} ->
- handle_file_error(?LINE, error, Reason, KeyFile, ekeyfile,
+ try
+ {ok, List} = ssl_manager:cache_pem_file(KeyFile),
+ [PemEntry] = [PemEntry || PemEntry = {PKey, _ , _} <- List,
+ PKey =:= 'RSAPrivateKey' orelse
+ PKey =:= 'DSAPrivateKey'],
+ public_key:pem_entry_decode(PemEntry, Password)
+ catch
+ Error:Reason ->
+ handle_file_error(?LINE, Error, Reason, KeyFile, ekeyfile,
erlang:get_stacktrace())
end;
@@ -1117,6 +1095,7 @@ handle_file_error(Line, Error, {badmatch, Reason}, File, Throw, Stack) ->
handle_file_error(Line, Error, Reason, File, Throw, Stack) ->
file_error(Line, Error, Reason, File, Throw, Stack).
+-spec(file_error/6 :: (_,_,_,_,_,_) -> no_return()).
file_error(Line, Error, Reason, File, Throw, Stack) ->
Report = io_lib:format("SSL: ~p: ~p:~p ~s~n ~p~n",
[Line, Error, Reason, File, Stack]),
@@ -1128,17 +1107,18 @@ init_diffie_hellman(_, client) ->
init_diffie_hellman(undefined, _) ->
?DEFAULT_DIFFIE_HELLMAN_PARAMS;
init_diffie_hellman(DHParamFile, server) ->
- case ssl_manager:cache_pem_file(DHParamFile) of
- {ok, List} ->
- case [Der || Der = {dh_params, _ , _} <- List] of
- [Der] ->
- {ok, Decoded} = public_key:decode_dhparams(Der),
- Decoded;
- [] ->
- ?DEFAULT_DIFFIE_HELLMAN_PARAMS
- end;
- {error, Reason} ->
- handle_file_error(?LINE, error, Reason, DHParamFile, edhfile, erlang:get_stacktrace())
+ try
+ {ok, List} = ssl_manager:cache_pem_file(DHParamFile),
+ case [Entry || Entry = {'DHParameter', _ , _} <- List] of
+ [Entry] ->
+ public_key:pem_entry_decode(Entry);
+ [] ->
+ ?DEFAULT_DIFFIE_HELLMAN_PARAMS
+ end
+ catch
+ Error:Reason ->
+ handle_file_error(?LINE, Error, Reason,
+ DHParamFile, edhfile, erlang:get_stacktrace())
end.
sync_send_all_state_event(FsmPid, Event) ->
@@ -1207,7 +1187,7 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
tls_handshake_hashes = Hashes1};
ignore ->
State;
- #alert{} = Alert ->
+ #alert{} = Alert ->
handle_own_alert(Alert, Version, certify, State)
end;
@@ -1215,18 +1195,19 @@ verify_client_cert(#state{client_certificate_requested = false} = State) ->
State.
do_server_hello(Type, #state{negotiated_version = Version,
- session = Session,
+ session = #session{session_id = SessId} = Session,
connection_states = ConnectionStates0,
renegotiation = {Renegotiation, _}}
= State0) when is_atom(Type) ->
+
ServerHello =
- ssl_handshake:server_hello(Session#session.session_id, Version,
+ ssl_handshake:server_hello(SessId, Version,
ConnectionStates0, Renegotiation),
State1 = server_hello(ServerHello, State0),
case Type of
new ->
- do_server_hello(ServerHello, State1);
+ new_server_hello(ServerHello, State1);
resumed ->
ConnectionStates1 = State1#state.connection_states,
case ssl_handshake:master_secret(Version, Session,
@@ -1245,9 +1226,9 @@ do_server_hello(Type, #state{negotiated_version = Version,
handle_own_alert(Alert, Version, hello, State1),
{stop, normal, State1}
end
- end;
+ end.
-do_server_hello(#server_hello{cipher_suite = CipherSuite,
+new_server_hello(#server_hello{cipher_suite = CipherSuite,
compression_method = Compression,
session_id = SessionId},
#state{session = Session0,
@@ -1267,6 +1248,33 @@ do_server_hello(#server_hello{cipher_suite = CipherSuite,
{stop, normal, State0}
end.
+handle_new_session(NewId, CipherSuite, Compression, #state{session = Session0} = State0) ->
+ Session = Session0#session{session_id = NewId,
+ cipher_suite = CipherSuite,
+ compression_method = Compression},
+ {Record, State} = next_record(State0#state{session = Session}),
+ next_state(certify, Record, State).
+
+handle_resumed_session(SessId, #state{connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ host = Host, port = Port,
+ session_cache = Cache,
+ session_cache_cb = CacheCb} = State0) ->
+ Session = CacheCb:lookup(Cache, {{Host, Port}, SessId}),
+ case ssl_handshake:master_secret(Version, Session,
+ ConnectionStates0, client) of
+ {_, ConnectionStates1} ->
+ {Record, State} =
+ next_record(State0#state{
+ connection_states = ConnectionStates1,
+ session = Session}),
+ next_state(abbreviated, Record, State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, hello, State0),
+ {stop, normal, State0}
+ end.
+
+
client_certify_and_key_exchange(#state{negotiated_version = Version} =
State0) ->
try do_client_certify_and_key_exchange(State0) of
@@ -1345,7 +1353,7 @@ certify_server(#state{transport_cb = Transport,
key_exchange(#state{role = server, key_algorithm = rsa} = State) ->
State;
key_exchange(#state{role = server, key_algorithm = Algo,
- diffie_hellman_params = Params,
+ diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params,
private_key = PrivateKey,
connection_states = ConnectionStates0,
negotiated_version = Version,
@@ -1354,11 +1362,9 @@ key_exchange(#state{role = server, key_algorithm = Algo,
transport_cb = Transport
} = State)
when Algo == dhe_dss;
- Algo == dhe_dss_export;
- Algo == dhe_rsa;
- Algo == dhe_rsa_export ->
+ Algo == dhe_rsa ->
- Keys = public_key:gen_key(Params),
+ Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]),
ConnectionState =
ssl_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
@@ -1402,9 +1408,7 @@ key_exchange(#state{role = client,
socket = Socket, transport_cb = Transport,
tls_handshake_hashes = Hashes0} = State)
when Algorithm == dhe_dss;
- Algorithm == dhe_dss_export;
- Algorithm == dhe_rsa;
- Algorithm == dhe_rsa_export ->
+ Algorithm == dhe_rsa ->
Msg = ssl_handshake:key_exchange(client, {dh, DhPubKey}),
{BinMsg, ConnectionStates1, Hashes1} =
encode_handshake(Msg, Version, ConnectionStates0, Hashes0),
@@ -1412,6 +1416,8 @@ key_exchange(#state{role = client,
State#state{connection_states = ConnectionStates1,
tls_handshake_hashes = Hashes1}.
+-spec(rsa_key_exchange/2 :: (_,_) -> no_return()).
+
rsa_key_exchange(PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
when Algorithm == ?rsaEncryption;
Algorithm == ?md2WithRSAEncryption;
@@ -1542,9 +1548,24 @@ verify_dh_params(Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) ->
false
end;
verify_dh_params(Signed, Hash, {?'id-dsa', PublicKey, PublicKeyParams}) ->
- public_key:verify_signature(Hash, none, Signed, PublicKey, PublicKeyParams).
+ public_key:verify(Hash, none, Signed, {PublicKey, PublicKeyParams}).
+cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} = State) ->
+ ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0),
+ next_state_connection(cipher, ack_connection(State#state{session = Session,
+ connection_states = ConnectionStates}));
+
+cipher_role(server, Data, Session, #state{connection_states = ConnectionStates0} = State) ->
+ ConnectionStates1 = ssl_record:set_client_verify_data(current_read, Data, ConnectionStates0),
+ {ConnectionStates, Hashes} =
+ finalize_handshake(State#state{connection_states = ConnectionStates1,
+ session = Session}, cipher),
+ next_state_connection(cipher, ack_connection(State#state{connection_states =
+ ConnectionStates,
+ session = Session,
+ tls_handshake_hashes =
+ Hashes})).
encode_alert(#alert{} = Alert, Version, ConnectionStates) ->
?DBG_TERM(Alert),
ssl_record:encode_alert_record(Alert, Version, ConnectionStates).
@@ -1554,7 +1575,7 @@ encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) ->
ssl_record:encode_change_cipher_spec(Version, ConnectionStates).
encode_handshake(HandshakeRec, Version, ConnectionStates, Hashes) ->
- encode_handshake(HandshakeRec, undefined, Version,
+ encode_handshake(HandshakeRec, null, Version,
ConnectionStates, Hashes).
encode_handshake(HandshakeRec, SigAlg, Version, ConnectionStates0, Hashes0) ->
@@ -1717,11 +1738,13 @@ format_packet_error(#socket_options{active = _, mode = Mode}, Data) ->
format_reply(binary, _, N, Data) when N > 0 -> % Header mode
header(N, Data);
-format_reply(binary, _, _, Data) -> Data;
-format_reply(list, Packet, _, Data) when is_integer(Packet); Packet == raw ->
- binary_to_list(Data);
+format_reply(binary, _, _, Data) ->
+ Data;
+format_reply(list, Packet, _, Data)
+ when Packet == http; Packet == {http, headers}; Packet == http_bin; Packet == {http_bin, headers} ->
+ Data;
format_reply(list, _,_, Data) ->
- Data.
+ binary_to_list(Data).
header(0, <<>>) ->
<<>>;
@@ -2145,7 +2168,7 @@ renegotiate(#state{role = server,
negotiated_version = Version,
connection_states = ConnectionStates0} = State0) ->
HelloRequest = ssl_handshake:hello_request(),
- Frag = ssl_handshake:encode_handshake(HelloRequest, Version, undefined),
+ Frag = ssl_handshake:encode_handshake(HelloRequest, Version, null),
Hs0 = ssl_handshake:init_hashes(),
{BinMsg, ConnectionStates} =
ssl_record:encode_handshake(Frag, Version, ConnectionStates0),
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index f7e3e392ec..3d831eae02 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -42,16 +42,17 @@
encode_handshake/3, init_hashes/0,
update_hashes/2, decrypt_premaster_secret/2]).
+-type tls_handshake() :: #client_hello{} | #server_hello{} |
+ #server_hello_done{} | #certificate{} | #certificate_request{} |
+ #client_key_exchange{} | #finished{} | #certificate_verify{} |
+ #hello_request{}.
+
%%====================================================================
%% Internal application API
%%====================================================================
%%--------------------------------------------------------------------
-%% Function: client_hello(Host, Port, ConnectionStates, SslOpts, Cert, Renegotiation) ->
-%% #client_hello{}
-%% Host
-%% Port
-%% ConnectionStates = #connection_states{}
-%% SslOpts = #ssl_options{}
+-spec client_hello(host(), port_num(), #connection_states{},
+ #ssl_options{}, binary(), boolean()) -> #client_hello{}.
%%
%% Description: Creates a client hello message.
%%--------------------------------------------------------------------
@@ -65,7 +66,7 @@ client_hello(Host, Port, ConnectionStates, #ssl_options{versions = Versions,
Version = ssl_record:highest_protocol_version(lists:map(Fun, Versions)),
Pending = ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
- Ciphers = available_suites(Cert, UserSuites, Version),
+ Ciphers = available_suites(UserSuites, Version),
Id = ssl_manager:client_session_id(Host, Port, SslOpts),
@@ -79,13 +80,8 @@ client_hello(Host, Port, ConnectionStates, #ssl_options{versions = Versions,
}.
%%--------------------------------------------------------------------
-%% Function: server_hello(SessionId, Version,
-%% ConnectionStates, Renegotiation) -> #server_hello{}
-%% SessionId
-%% Version
-%% ConnectionStates
-%% Renegotiation
-%%
+-spec server_hello(session_id(), tls_version(), #connection_states{},
+ boolean()) -> #server_hello{}.
%%
%% Description: Creates a server hello message.
%%--------------------------------------------------------------------
@@ -103,7 +99,7 @@ server_hello(SessionId, Version, ConnectionStates, Renegotiation) ->
}.
%%--------------------------------------------------------------------
-%% Function: hello_request() -> #hello_request{}
+-spec hello_request() -> #hello_request{}.
%%
%% Description: Creates a hello request message sent by server to
%% trigger renegotiation.
@@ -112,15 +108,12 @@ hello_request() ->
#hello_request{}.
%%--------------------------------------------------------------------
-%% Function: hello(Hello, Info, Renegotiation) ->
-%% {Version, Id, NewConnectionStates} |
-%% #alert{}
-%%
-%% Hello = #client_hello{} | #server_hello{}
-%% Info = ConnectionStates | {Port, #ssl_options{}, Session,
-%% Cahce, CahceCb, ConnectionStates}
-%% ConnectionStates = #connection_states{}
-%% Renegotiation = boolean()
+-spec hello(#server_hello{} | #client_hello{}, #ssl_options{},
+ #connection_states{} | {port_num(), #session{}, cache_ref(),
+ atom(), #connection_states{}, binary()},
+ boolean()) -> {tls_version(), session_id(), #connection_states{}}|
+ {tls_version(), {resumed | new, #session{}},
+ #connection_states{}} | #alert{}.
%%
%% Description: Handles a recieved hello message
%%--------------------------------------------------------------------
@@ -183,12 +176,9 @@ hello(#client_hello{client_version = ClientVersion, random = Random,
end.
%%--------------------------------------------------------------------
-%% Function: certify(Certs, CertDbRef, MaxPathLen) ->
-%% {PeerCert, PublicKeyInfo} | #alert{}
-%%
-%% Certs = #certificate{}
-%% CertDbRef = reference()
-%% MaxPathLen = integer() | nolimit
+-spec certify(#certificate{}, term(), integer() | nolimit,
+ verify_peer | verify_none, fun(), fun(),
+ client | server) -> {der_cert(), public_key_info()} | #alert{}.
%%
%% Description: Handles a certificate handshake message
%%--------------------------------------------------------------------
@@ -244,10 +234,7 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbRef,
end.
%%--------------------------------------------------------------------
-%% Function: certificate(OwnCert, CertDbRef, Role) -> #certificate{}
-%%
-%% OwnCert = binary()
-%% CertDbRef = term() as returned by ssl_certificate_db:create()
+-spec certificate(der_cert(), term(), client | server) -> #certificate{} | #alert{}.
%%
%% Description: Creates a certificate message.
%%--------------------------------------------------------------------
@@ -273,10 +260,10 @@ certificate(OwnCert, CertDbRef, server) ->
end.
%%--------------------------------------------------------------------
-%% Function: client_certificate_verify(Cert, ConnectionStates) ->
-%% #certificate_verify{} | ignore
-%% Cert = #'OTPcertificate'{}
-%% ConnectionStates = #connection_states{}
+-spec client_certificate_verify(undefined | der_cert(), binary(),
+ tls_version(), key_algo(), private_key(),
+ {{binary(), binary()},{binary(), binary()}}) ->
+ #certificate_verify{} | ignore | #alert{}.
%%
%% Description: Creates a certificate_verify message, called by the client.
%%--------------------------------------------------------------------
@@ -298,10 +285,9 @@ client_certificate_verify(OwnCert, MasterSecret, Version, Algorithm,
end.
%%--------------------------------------------------------------------
-%% Function: certificate_verify(Signature, PublicKeyInfo) -> valid | #alert{}
-%%
-%% Signature = binary()
-%% PublicKeyInfo = {Algorithm, PublicKey, PublicKeyParams}
+%% -spec certificate_verify(binary(), public_key_info(), tls_version(),
+%% binary(), key_algo(),
+%% {_, {binary(), binary()}}) -> valid | #alert{}.
%%
%% Description: Checks that the certificate_verify message is valid.
%%--------------------------------------------------------------------
@@ -320,13 +306,19 @@ certificate_verify(Signature, {_, PublicKey, _}, Version,
end;
certificate_verify(Signature, {_, PublicKey, PublicKeyParams}, Version,
MasterSecret, dhe_dss = Algorithm, {_, Hashes0}) ->
- Hashes = calc_certificate_verify(Version, MasterSecret,
- Algorithm, Hashes0),
- public_key:verify_signature(Hashes, sha, Signature, PublicKey, PublicKeyParams).
+ Hashes = calc_certificate_verify(Version, MasterSecret,
+ Algorithm, Hashes0),
+ case public_key:verify(Hashes, none, Signature, {PublicKey, PublicKeyParams}) of
+ true ->
+ valid;
+ false ->
+ ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE)
+ end.
+
%%--------------------------------------------------------------------
-%% Function: certificate_request(ConnectionStates, CertDbRef) ->
-%% #certificate_request{}
+-spec certificate_request(#connection_states{}, certdb_ref()) ->
+ #certificate_request{}.
%%
%% Description: Creates a certificate_request message, called by the server.
%%--------------------------------------------------------------------
@@ -342,11 +334,12 @@ certificate_request(ConnectionStates, CertDbRef) ->
}.
%%--------------------------------------------------------------------
-%% Function: key_exchange(Role, Secret, Params) ->
-%% #client_key_exchange{} | #server_key_exchange{}
-%%
-%% Secret -
-%% Params -
+-spec key_exchange(client | server,
+ {premaster_secret, binary(), public_key_info()} |
+ {dh, binary()} |
+ {dh, {binary(), binary()}, #'DHParameter'{}, key_algo(),
+ binary(), binary(), private_key()}) ->
+ #client_key_exchange{} | #server_key_exchange{}.
%%
%% Description: Creates a keyexchange message.
%%--------------------------------------------------------------------
@@ -382,15 +375,9 @@ key_exchange(server, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
signed_params = Signed}.
%%--------------------------------------------------------------------
-%% Function: master_secret(Version, Session/PremasterSecret,
-%% ConnectionStates, Role) ->
-%% {MasterSecret, NewConnectionStates} | #alert{}
-%% Version = #protocol_version{}
-%% Session = #session{} (session contains master secret)
-%% PremasterSecret = binary()
-%% ConnectionStates = #connection_states{}
-%% Role = client | server
-%%
+-spec master_secret(tls_version(), #session{} | binary(), #connection_states{},
+ client | server) -> {binary(), #connection_states{}} | #alert{}.
+%%
%% Description: Sets or calculates the master secret and calculate keys,
%% updating the pending connection states. The Mastersecret and the update
%% connection states are returned or an alert if the calculation fails.
@@ -427,9 +414,8 @@ master_secret(Version, PremasterSecret, ConnectionStates, Role) ->
end.
%%--------------------------------------------------------------------
-%% Function: finished(Version, Role, MacSecret, Hashes) -> #finished{}
-%%
-%% ConnectionStates = #connection_states{}
+-spec finished(tls_version(), client | server, binary(), {{binary(), binary()},_}) ->
+ #finished{}.
%%
%% Description: Creates a handshake finished message
%%-------------------------------------------------------------------
@@ -438,15 +424,8 @@ finished(Version, Role, MasterSecret, {Hashes, _}) -> % use the current hashes
calc_finished(Version, Role, MasterSecret, Hashes)}.
%%--------------------------------------------------------------------
-%% Function: verify_connection(Finished, Role,
-%% MasterSecret, Hashes) -> verified | #alert{}
-%%
-%% Finished = #finished{}
-%% Role = client | server - the role of the process that sent the finished
-%% message.
-%% MasterSecret = binary()
-%% Hashes = binary() - {md5_hash, sha_hash}
-%%
+-spec verify_connection(tls_version(), #finished{}, client | server, binary(),
+ {_, {binary(), binary()}}) -> verified | #alert{}.
%%
%% Description: Checks the ssl handshake finished message to verify
%% the connection.
@@ -462,17 +441,18 @@ verify_connection(Version, #finished{verify_data = Data},
_E ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)
end.
-
+%%--------------------------------------------------------------------
+-spec server_hello_done() -> #server_hello_done{}.
+%%
+%% Description: Creates a server hello done message.
+%%--------------------------------------------------------------------
server_hello_done() ->
#server_hello_done{}.
%%--------------------------------------------------------------------
-%% Function: encode_handshake(HandshakeRec) -> BinHandshake
-%% HandshakeRec = #client_hello | #server_hello{} | server_hello_done |
-%% #certificate{} | #client_key_exchange{} | #finished{} |
-%% #client_certify_request{}
+-spec encode_handshake(tls_handshake(), tls_version(), key_algo()) -> iolist().
%%
-%% encode a handshake packet to binary
+%% Description: Encode a handshake packet to binary
%%--------------------------------------------------------------------
encode_handshake(Package, Version, KeyAlg) ->
SigAlg = sig_alg(KeyAlg),
@@ -481,12 +461,11 @@ encode_handshake(Package, Version, KeyAlg) ->
[MsgType, ?uint24(Len), Bin].
%%--------------------------------------------------------------------
-%% Function: get_tls_handshake(Data, Buffer) -> Result
-%% Result = {[#handshake{}], [Raw], NewBuffer}
-%% Data = Buffer = NewBuffer = Raw = binary()
+-spec get_tls_handshake(binary(), binary() | iolist(), key_algo(), tls_version()) ->
+ {[tls_handshake()], binary()}.
%%
%% Description: Given buffered and new data from ssl_record, collects
-%% and returns it as a list of #handshake, also returns leftover
+%% and returns it as a list of handshake messages, also returns leftover
%% data.
%%--------------------------------------------------------------------
get_tls_handshake(Data, <<>>, KeyAlg, Version) ->
@@ -495,6 +474,9 @@ get_tls_handshake(Data, Buffer, KeyAlg, Version) ->
get_tls_handshake_aux(list_to_binary([Buffer, Data]),
KeyAlg, Version, []).
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
get_tls_handshake_aux(<<?BYTE(Type), ?UINT24(Length),
Body:Length/binary,Rest/binary>>, KeyAlg,
Version, Acc) ->
@@ -504,9 +486,6 @@ get_tls_handshake_aux(<<?BYTE(Type), ?UINT24(Length),
get_tls_handshake_aux(Data, _KeyAlg, _Version, Acc) ->
{lists:reverse(Acc), Data}.
-%%--------------------------------------------------------------------
-%%% Internal functions
-%%--------------------------------------------------------------------
verify_bool(verify_peer) ->
true;
verify_bool(verify_none) ->
@@ -547,13 +526,16 @@ select_session(Hello, Port, Session, Version,
{resumed, CacheCb:lookup(Cache, {Port, SessionId})}
end.
-available_suites(Cert, UserSuites, Version) ->
+available_suites(UserSuites, Version) ->
case UserSuites of
[] ->
- ssl_cipher:filter(Cert, ssl_cipher:suites(Version));
+ ssl_cipher:suites(Version);
_ ->
- ssl_cipher:filter(Cert, UserSuites)
+ UserSuites
end.
+
+available_suites(ServerCert, UserSuites, Version) ->
+ ssl_cipher:filter(ServerCert, available_suites(UserSuites, Version)).
cipher_suites(Suites, false) ->
[?TLS_EMPTY_RENEGOTIATION_INFO_SCSV | Suites];
@@ -1065,9 +1047,10 @@ certificate_authorities(CertDbRef) ->
Authorities = certificate_authorities_from_db(CertDbRef),
Enc = fun(#'OTPCertificate'{tbsCertificate=TBSCert}) ->
OTPSubj = TBSCert#'OTPTBSCertificate'.subject,
- Subj = public_key:pkix_transform(OTPSubj, encode),
- {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj),
- DNEncodedBin = iolist_to_binary(DNEncoded),
+ DNEncodedBin = public_key:pkix_encode('Name', OTPSubj, otp),
+ %%Subj = public_key:pkix_transform(OTPSubj, encode),
+ %% {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj),
+ %% DNEncodedBin = iolist_to_binary(DNEncoded),
DNEncodedLen = byte_size(DNEncodedBin),
<<?UINT16(DNEncodedLen), DNEncodedBin/binary>>
end,
@@ -1091,7 +1074,7 @@ digitally_signed(Hash, #'RSAPrivateKey'{} = Key) ->
public_key:encrypt_private(Hash, Key,
[{rsa_pad, rsa_pkcs1_padding}]);
digitally_signed(Hash, #'DSAPrivateKey'{} = Key) ->
- public_key:sign(none, Hash, Key).
+ public_key:sign(Hash, none, Key).
calc_master_secret({3,0}, PremasterSecret, ClientRandom, ServerRandom) ->
ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom);
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index fdc0c33750..337403531e 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -23,6 +23,8 @@
-ifndef(ssl_internal).
-define(ssl_internal, true).
+-include_lib("public_key/include/public_key.hrl").
+
%% basic binary constructors
-define(BOOLEAN(X), X:8/unsigned-big-integer).
-define(BYTE(X), X:8/unsigned-big-integer).
@@ -88,6 +90,28 @@
active = true
}).
+-type reason() :: term().
+-type reply() :: term().
+-type msg() :: term().
+-type from() :: term().
+-type host() :: string() | tuple().
+-type port_num() :: integer().
+-type session_id() :: 0 | binary().
+-type tls_version() :: {integer(), integer()}.
+-type tls_atom_version() :: sslv3 | tlsv1.
+-type cache_ref() :: term().
+-type certdb_ref() :: term().
+-type key_algo() :: null | rsa | dhe_rsa | dhe_dss.
+-type enum_algo() :: integer().
+-type public_key() :: #'RSAPublicKey'{} | integer().
+-type public_key_params() :: #'Dss-Parms'{} | term().
+-type public_key_info() :: {enum_algo(), public_key(), public_key_params()}.
+-type der_cert() :: binary().
+-type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{}.
+-type issuer() :: tuple().
+-type serialnumber() :: integer().
+-type cert_key() :: {reference(), integer(), issuer()}.
+
-endif. % -ifdef(ssl_internal).
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index 19bdcfa1f5..459dcefb79 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -24,10 +24,13 @@
-module(ssl_manager).
-behaviour(gen_server).
+-include("ssl_internal.hrl").
+
%% Internal application API
--export([start_link/0, start_link/1,
+-export([start_link/1,
connection_init/2, cache_pem_file/1,
- lookup_trusted_cert/3, issuer_candidate/1, client_session_id/3, server_session_id/3,
+ lookup_trusted_cert/3, issuer_candidate/1, client_session_id/3,
+ server_session_id/3,
register_session/2, register_session/3, invalidate_session/2,
invalidate_session/3]).
@@ -58,21 +61,25 @@
%% API
%%====================================================================
%%--------------------------------------------------------------------
-%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
+-spec start_link(list()) -> {ok, pid()} | ignore | {error, term()}.
+%%
%% Description: Starts the server
%%--------------------------------------------------------------------
-start_link() ->
- gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
start_link(Opts) ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [Opts], []).
%%--------------------------------------------------------------------
-%% Function:
-%% Description:
+-spec connection_init(string(), client | server) -> {ok, reference(), cache_ref()}.
+%%
+%% Description: Do necessary initializations for a new connection.
%%--------------------------------------------------------------------
connection_init(TrustedcertsFile, Role) ->
call({connection_init, TrustedcertsFile, Role}).
-
+%%--------------------------------------------------------------------
+-spec cache_pem_file(string()) -> {ok, term()}.
+%%
+%% Description: Cach a pem file and
+%%--------------------------------------------------------------------
cache_pem_file(File) ->
case ssl_certificate_db:lookup_cached_certs(File) of
[{_,Content}] ->
@@ -80,48 +87,54 @@ cache_pem_file(File) ->
[] ->
call({cache_pem, File})
end.
-
-%%--------------------------------------------------------------------
-%% Function:
-%% Description:
%%--------------------------------------------------------------------
+-spec lookup_trusted_cert(reference(), serialnumber(), issuer()) ->
+ undefined |
+ {ok, {der_cert(), #'OTPCertificate'{}}}.
+%%
+%% Description: Lookup the trusted cert with Key = {reference(),
+%% serialnumber(), issuer()}.
+%% --------------------------------------------------------------------
lookup_trusted_cert(Ref, SerialNumber, Issuer) ->
ssl_certificate_db:lookup_trusted_cert(Ref, SerialNumber, Issuer).
-
%%--------------------------------------------------------------------
-%% Function:
-%% Description:
+-spec issuer_candidate(cert_key() | no_candidate) ->
+ {cert_key(), {der_cert(), #'OTPCertificate'{}}} | no_more_candidates.
+%%
+%% Description: Return next issuer candidate.
%%--------------------------------------------------------------------
issuer_candidate(PrevCandidateKey) ->
ssl_certificate_db:issuer_candidate(PrevCandidateKey).
-
%%--------------------------------------------------------------------
-%% Function:
-%% Description:
+-spec client_session_id(host(), port_num(), #ssl_options{}) -> session_id().
+%%
+%% Description: Select a session id for the client.
%%--------------------------------------------------------------------
client_session_id(Host, Port, SslOpts) ->
call({client_session_id, Host, Port, SslOpts}).
-
+
%%--------------------------------------------------------------------
-%% Function:
-%% Description:
+-spec server_session_id(host(), port_num(), #ssl_options{}) -> session_id().
+%%
+%% Description: Select a session id for the server.
%%--------------------------------------------------------------------
server_session_id(Port, SuggestedSessionId, SslOpts) ->
call({server_session_id, Port, SuggestedSessionId, SslOpts}).
%%--------------------------------------------------------------------
-%% Function:
-%% Description:
+-spec register_session(host(), port_num(), #session{}) -> ok.
+%%
+%% Description: Make the session available for reuse.
%%--------------------------------------------------------------------
register_session(Host, Port, Session) ->
cast({register_session, Host, Port, Session}).
register_session(Port, Session) ->
cast({register_session, Port, Session}).
-
%%--------------------------------------------------------------------
-%% Function:
-%% Description:
+-spec invalidate_session(host(), port_num(), #session{}) -> ok.
+%%
+%% Description: Make the session unavilable for reuse.
%%--------------------------------------------------------------------
invalidate_session(Host, Port, Session) ->
cast({invalidate_session, Host, Port, Session}).
@@ -134,10 +147,10 @@ invalidate_session(Port, Session) ->
%%====================================================================
%%--------------------------------------------------------------------
-%% Function: init(Args) -> {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
+-spec init(list()) -> {ok, #state{}}.
+%% Possible return values not used now.
+%% | {ok, #state{}, timeout()} | ignore | {stop, term()}.
+%%
%% Description: Initiates the server
%%--------------------------------------------------------------------
init([Opts]) ->
@@ -156,12 +169,14 @@ init([Opts]) ->
session_validation_timer = Timer}}.
%%--------------------------------------------------------------------
-%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
-%% {reply, Reply, State, Timeout} |
-%% {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, Reply, State} |
-%% {stop, Reason, State}
+-spec handle_call(msg(), from(), #state{}) -> {reply, reply(), #state{}}.
+%% Possible return values not used now.
+%% {reply, reply(), #state{}, timeout()} |
+%% {noreply, #state{}} |
+%% {noreply, #state{}, timeout()} |
+%% {stop, reason(), reply(), #state{}} |
+%% {stop, reason(), #state{}}.
+%%
%% Description: Handling call messages
%%--------------------------------------------------------------------
handle_call({{connection_init, "", _Role}, Pid}, _From,
@@ -207,9 +222,11 @@ handle_call({{cache_pem, File},Pid}, _, State = #state{certificate_db = Db}) ->
{reply, {error, Reason}, State}
end.
%%--------------------------------------------------------------------
-%% Function: handle_cast(Msg, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State}
+-spec handle_cast(msg(), #state{}) -> {noreply, #state{}}.
+%% Possible return values not used now.
+%% | {noreply, #state{}, timeout()} |
+%% {stop, reason(), #state{}}.
+%%
%% Description: Handling cast messages
%%--------------------------------------------------------------------
handle_cast({register_session, Host, Port, Session},
@@ -243,9 +260,11 @@ handle_cast({invalidate_session, Port, #session{session_id = ID}},
{noreply, State}.
%%--------------------------------------------------------------------
-%% Function: handle_info(Info, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State}
+-spec handle_info(msg(), #state{}) -> {noreply, #state{}}.
+%% Possible return values not used now.
+%% |{noreply, #state{}, timeout()} |
+%% {stop, reason(), #state{}}.
+%%
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
handle_info(validate_sessions, #state{session_cache_cb = CacheCb,
@@ -278,7 +297,8 @@ handle_info(_Info, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
-%% Function: terminate(Reason, State) -> void()
+-spec terminate(reason(), #state{}) -> term().
+%%
%% Description: This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any necessary
%% cleaning up. When it returns, the gen_server terminates with Reason.
@@ -294,7 +314,8 @@ terminate(_Reason, #state{certificate_db = Db,
ok.
%%--------------------------------------------------------------------
-%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
+-spec code_change(term(), #state{}, list()) -> {ok, #state{}}.
+%%
%% Description: Convert process state when code is changed
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
@@ -339,4 +360,3 @@ session_validation({{{Host, Port}, _}, Session}, LifeTime) ->
session_validation({{Port, _}, Session}, LifeTime) ->
validate_session(Port, Session, LifeTime),
LifeTime.
-
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 6b7cffaa7d..acd0d49c19 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -66,10 +66,9 @@
%%====================================================================
%% Internal application API
%%====================================================================
+
%%--------------------------------------------------------------------
-%% Function: init_connection_states(Role) -> #connection_states{}
-%% Role = client | server
-%% Random = binary()
+-spec init_connection_states(client | server) -> #connection_states{}.
%%
%% Description: Creates a connection_states record with appropriate
%% values for the initial SSL connection setup.
@@ -85,9 +84,8 @@ init_connection_states(Role) ->
}.
%%--------------------------------------------------------------------
-%% Function: current_connection_state(States, Type) -> #connection_state{}
-%% States = #connection_states{}
-%% Type = read | write
+-spec current_connection_state(#connection_states{}, read | write) ->
+ #connection_state{}.
%%
%% Description: Returns the instance of the connection_state record
%% that is currently defined as the current conection state.
@@ -100,9 +98,8 @@ current_connection_state(#connection_states{current_write = Current},
Current.
%%--------------------------------------------------------------------
-%% Function: pending_connection_state(States, Type) -> #connection_state{}
-%% States = #connection_states{}
-%% Type = read | write
+-spec pending_connection_state(#connection_states{}, read | write) ->
+ #connection_state{}.
%%
%% Description: Returns the instance of the connection_state record
%% that is currently defined as the pending conection state.
@@ -115,14 +112,11 @@ pending_connection_state(#connection_states{pending_write = Pending},
Pending.
%%--------------------------------------------------------------------
-%% Function: update_security_params(Params, States) ->
-%% #connection_states{}
-%% Params = #security_parameters{}
-%% States = #connection_states{}
+-spec update_security_params(#security_parameters{}, #security_parameters{},
+ #connection_states{}) -> #connection_states{}.
%%
%% Description: Creates a new instance of the connection_states record
-%% where the pending states gets its security parameters
-%% updated to <Params>.
+%% where the pending states gets its security parameters updated.
%%--------------------------------------------------------------------
update_security_params(ReadParams, WriteParams, States =
#connection_states{pending_read = Read,
@@ -135,14 +129,10 @@ update_security_params(ReadParams, WriteParams, States =
WriteParams}
}.
%%--------------------------------------------------------------------
-%% Function: set_mac_secret(ClientWriteMacSecret,
-%% ServerWriteMacSecret, Role, States) ->
-%% #connection_states{}
-%% MacSecret = binary()
-%% States = #connection_states{}
-%% Role = server | client
+-spec set_mac_secret(binary(), binary(), client | server,
+ #connection_states{}) -> #connection_states{}.
%%
-%% update the mac_secret field in pending connection states
+%% Description: update the mac_secret field in pending connection states
%%--------------------------------------------------------------------
set_mac_secret(ClientWriteMacSecret, ServerWriteMacSecret, client, States) ->
set_mac_secret(ServerWriteMacSecret, ClientWriteMacSecret, States);
@@ -159,12 +149,9 @@ set_mac_secret(ReadMacSecret, WriteMacSecret,
%%--------------------------------------------------------------------
-%% Function: set_master_secret(MasterSecret, States) ->
-%% #connection_states{}
-%% MacSecret =
-%% States = #connection_states{}
+-spec set_master_secret(binary(), #connection_states{}) -> #connection_states{}.
%%
-%% Set master_secret in pending connection states
+%% Description: Set master_secret in pending connection states
%%--------------------------------------------------------------------
set_master_secret(MasterSecret,
States = #connection_states{pending_read = Read,
@@ -180,12 +167,9 @@ set_master_secret(MasterSecret,
States#connection_states{pending_read = Read1, pending_write = Write1}.
%%--------------------------------------------------------------------
-%% Function: set_renegotiation_flag(Flag, States) ->
-%% #connection_states{}
-%% Flag = boolean()
-%% States = #connection_states{}
+-spec set_renegotiation_flag(boolean(), #connection_states{}) -> #connection_states{}.
%%
-%% Set master_secret in pending connection states
+%% Description: Set secure_renegotiation in pending connection states
%%--------------------------------------------------------------------
set_renegotiation_flag(Flag, #connection_states{
current_read = CurrentRead0,
@@ -203,13 +187,11 @@ set_renegotiation_flag(Flag, #connection_states{
pending_write = PendingWrite}.
%%--------------------------------------------------------------------
-%% Function: set_client_verify_data(State, Data, States) ->
-%% #connection_states{}
-%% State = atom()
-%% Data = binary()
-%% States = #connection_states{}
+-spec set_client_verify_data(current_read | current_write | current_both,
+ binary(), #connection_states{})->
+ #connection_states{}.
%%
-%% Set verify data in connection states.
+%% Description: Set verify data in connection states.
%%--------------------------------------------------------------------
set_client_verify_data(current_read, Data,
#connection_states{current_read = CurrentRead0,
@@ -235,15 +217,12 @@ set_client_verify_data(current_both, Data,
CurrentWrite = CurrentWrite0#connection_state{client_verify_data = Data},
ConnectionStates#connection_states{current_read = CurrentRead,
current_write = CurrentWrite}.
-
%%--------------------------------------------------------------------
-%% Function: set_server_verify_data(State, Data, States) ->
-%% #connection_states{}
-%% State = atom()
-%% Data = binary()
-%% States = #connection_states{}
+-spec set_server_verify_data(current_read | current_write | current_both,
+ binary(), #connection_states{})->
+ #connection_states{}.
%%
-%% Set verify data in pending connection states.
+%% Description: Set verify data in pending connection states.
%%--------------------------------------------------------------------
set_server_verify_data(current_write, Data,
#connection_states{pending_read = PendingRead0,
@@ -273,10 +252,8 @@ set_server_verify_data(current_both, Data,
current_write = CurrentWrite}.
%%--------------------------------------------------------------------
-%% Function: activate_pending_connection_state(States, Type) ->
-%% #connection_states{}
-%% States = #connection_states{}
-%% Type = read | write
+-spec activate_pending_connection_state(#connection_states{}, read | write) ->
+ #connection_states{}.
%%
%% Description: Creates a new instance of the connection_states record
%% where the pending state of <Type> has been activated.
@@ -308,11 +285,9 @@ activate_pending_connection_state(States =
}.
%%--------------------------------------------------------------------
-%% Function: set_pending_cipher_state(States, ClientState,
-%% ServerState, Role) ->
-%% #connection_states{}
-%% ClientState = ServerState = #cipher_state{}
-%% States = #connection_states{}
+-spec set_pending_cipher_state(#connection_states{}, #cipher_state{},
+ #cipher_state{}, client | server) ->
+ #connection_states{}.
%%
%% Description: Set the cipher state in the specified pending connection state.
%%--------------------------------------------------------------------
@@ -331,12 +306,10 @@ set_pending_cipher_state(#connection_states{pending_read = Read,
pending_write = Write#connection_state{cipher_state = ClientState}}.
%%--------------------------------------------------------------------
-%% Function: get_tls_record(Data, Buffer) -> Result
-%% Result = {[#tls_compressed{}], NewBuffer}
-%% Data = Buffer = NewBuffer = binary()
-%%
-%% Description: given old buffer and new data from TCP, packs up a records
-%% and returns it as a list of #tls_compressed, also returns leftover
+-spec get_tls_records(binary(), binary()) -> {[binary()], binary()} | #alert{}.
+%%
+%% Description: Given old buffer and new data from TCP, packs up a records
+%% and returns it as a list of tls_compressed binaries also returns leftover
%% data
%%--------------------------------------------------------------------
get_tls_records(Data, <<>>) ->
@@ -399,8 +372,8 @@ get_tls_records_aux(Data, Acc) ->
{lists:reverse(Acc), Data}.
%%--------------------------------------------------------------------
-%% Function: protocol_version(Version) -> #protocol_version{}
-%% Version = atom()
+-spec protocol_version(tls_atom_version() | tls_version()) ->
+ tls_version() | tls_atom_version().
%%
%% Description: Creates a protocol version record from a version atom
%% or vice versa.
@@ -420,8 +393,7 @@ protocol_version({3, 1}) ->
protocol_version({3, 0}) ->
sslv3.
%%--------------------------------------------------------------------
-%% Function: protocol_version(Version1, Version2) -> #protocol_version{}
-%% Version1 = Version2 = #protocol_version{}
+-spec lowest_protocol_version(tls_version(), tls_version()) -> tls_version().
%%
%% Description: Lowes protocol version of two given versions
%%--------------------------------------------------------------------
@@ -436,8 +408,7 @@ lowest_protocol_version(Version = {M,_},
lowest_protocol_version(_,Version) ->
Version.
%%--------------------------------------------------------------------
-%% Function: protocol_version(Versions) -> #protocol_version{}
-%% Versions = [#protocol_version{}]
+-spec highest_protocol_version([tls_version()]) -> tls_version().
%%
%% Description: Highest protocol version present in a list
%%--------------------------------------------------------------------
@@ -459,9 +430,8 @@ highest_protocol_version(_, [Version | Rest]) ->
highest_protocol_version(Version, Rest).
%%--------------------------------------------------------------------
-%% Function: supported_protocol_versions() -> Versions
-%% Versions = [#protocol_version{}]
-%%
+-spec supported_protocol_versions() -> [tls_version()].
+%%
%% Description: Protocol versions supported
%%--------------------------------------------------------------------
supported_protocol_versions() ->
@@ -487,8 +457,7 @@ supported_protocol_versions([_|_] = Vsns) ->
Vsns.
%%--------------------------------------------------------------------
-%% Function: is_acceptable_version(Version) -> true | false
-%% Version = #protocol_version{}
+-spec is_acceptable_version(tls_version()) -> boolean().
%%
%% Description: ssl version 2 is not acceptable security risks are too big.
%%--------------------------------------------------------------------
@@ -499,7 +468,7 @@ is_acceptable_version(_) ->
false.
%%--------------------------------------------------------------------
-%% Function: compressions() -> binary()
+-spec compressions() -> [binary()].
%%
%% Description: return a list of compressions supported (currently none)
%%--------------------------------------------------------------------
@@ -507,8 +476,8 @@ compressions() ->
[?byte(?NULL)].
%%--------------------------------------------------------------------
-%% Function: decode_cipher_text(CipherText, ConnectionStates0) ->
-%% {Plain, ConnectionStates}
+-spec decode_cipher_text(#ssl_tls{}, #connection_states{}) ->
+ {#ssl_tls{}, #connection_states{}}| #alert{}.
%%
%% Description: Decode cipher text
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl
index bcb10daf69..6db13e5b7a 100644
--- a/lib/ssl/src/ssl_session.erl
+++ b/lib/ssl/src/ssl_session.erl
@@ -32,11 +32,10 @@
-define(GEN_UNIQUE_ID_MAX_TRIES, 10).
+-type seconds() :: integer().
+
%%--------------------------------------------------------------------
-%% Function: is_new(ClientSuggestedId, ServerDecidedId) -> true | false
-%%
-%% ClientSuggestedId = binary()
-%% ServerDecidedId = binary()
+-spec is_new(session_id(), session_id()) -> boolean().
%%
%% Description: Checks if the session id decided by the server is a
%% new or resumed sesion id.
@@ -45,17 +44,11 @@ is_new(<<>>, _) ->
true;
is_new(SessionId, SessionId) ->
false;
-is_new(_, _) ->
+is_new(_ClientSuggestion, _ServerDecision) ->
true.
%%--------------------------------------------------------------------
-%% Function: id(ClientInfo, Cache, CacheCb) -> SessionId
-%%
-%% ClientInfo = {HostIP, Port, SslOpts}
-%% HostIP = ipadress()
-%% Port = integer()
-%% CacheCb = atom()
-%% SessionId = binary()
+-spec id({host(), port_num(), #ssl_options{}}, cache_ref(), atom()) -> binary().
%%
%% Description: Should be called by the client side to get an id
%% for the client hello message.
@@ -69,14 +62,8 @@ id(ClientInfo, Cache, CacheCb) ->
end.
%%--------------------------------------------------------------------
-%% Function: id(Port, SuggestedSessionId, ReuseFun, CacheCb,
-%% SecondLifeTime) -> SessionId
-%%
-%% Port = integer()
-%% SuggestedSessionId = SessionId = binary()
-%% ReuseFun = fun(SessionId, PeerCert, Compression, CipherSuite) ->
-%% true | false
-%% CacheCb = atom()
+-spec id(port_num(), binary(), #ssl_options{}, cache_ref(),
+ atom(), seconds()) -> binary().
%%
%% Description: Should be called by the server side to get an id
%% for the server hello message.
@@ -95,10 +82,7 @@ id(Port, SuggestedSessionId, #ssl_options{reuse_sessions = ReuseEnabled,
new_id(Port, ?GEN_UNIQUE_ID_MAX_TRIES, Cache, CacheCb)
end.
%%--------------------------------------------------------------------
-%% Function: valid_session(Session, LifeTime) -> true | false
-%%
-%% Session = #session{}
-%% LifeTime = integer() - seconds
+-spec valid_session(#session{}, seconds()) -> boolean().
%%
%% Description: Check that the session has not expired
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/ssl_session_cache.erl b/lib/ssl/src/ssl_session_cache.erl
index 1f2d1fc7d3..823bf7acfa 100644
--- a/lib/ssl/src/ssl_session_cache.erl
+++ b/lib/ssl/src/ssl_session_cache.erl
@@ -22,13 +22,16 @@
-behaviour(ssl_session_cache_api).
+-include("ssl_handshake.hrl").
+-include("ssl_internal.hrl").
+
-export([init/1, terminate/1, lookup/2, update/3, delete/2, foldl/3,
select_session/2]).
+-type key() :: {{host(), port_num()}, session_id()} | {port_num(), session_id()}.
+
%%--------------------------------------------------------------------
-%% Function: init() -> Cache
-%%
-%% Cache - Reference to the cash (opaque)
+-spec init(list()) -> cache_ref(). %% Returns reference to the cache (opaque)
%%
%% Description: Return table reference. Called by ssl_manager process.
%%--------------------------------------------------------------------
@@ -36,9 +39,7 @@ init(_) ->
ets:new(cache_name(), [set, protected]).
%%--------------------------------------------------------------------
-%% Function: terminate(Cache) ->
-%%
-%% Cache - as returned by create/0
+-spec terminate(cache_ref()) -> any(). %%
%%
%% Description: Handles cache table at termination of ssl manager.
%%--------------------------------------------------------------------
@@ -46,9 +47,7 @@ terminate(Cache) ->
ets:delete(Cache).
%%--------------------------------------------------------------------
-%% Function: lookup(Cache, Key) -> Session | undefined
-%% Cache - as returned by create/0
-%% Session = #session{}
+-spec lookup(cache_ref(), key()) -> #session{} | undefined.
%%
%% Description: Looks up a cach entry. Should be callable from any
%% process.
@@ -62,9 +61,7 @@ lookup(Cache, Key) ->
end.
%%--------------------------------------------------------------------
-%% Function: update(Cache, Key, Session) -> _
-%% Cache - as returned by create/0
-%% Session = #session{}
+-spec update(cache_ref(), key(), #session{}) -> any().
%%
%% Description: Caches a new session or updates a already cached one.
%% Will only be called from the ssl_manager process.
@@ -73,11 +70,7 @@ update(Cache, Key, Session) ->
ets:insert(Cache, {Key, Session}).
%%--------------------------------------------------------------------
-%% Function: delete(Cache, HostIP, Port, Id) -> _
-%% Cache - as returned by create/0
-%% HostIP = Host = string() | ipadress()
-%% Port = integer()
-%% Id =
+-spec delete(cache_ref(), key()) -> any().
%%
%% Description: Delets a cache entry.
%% Will only be called from the ssl_manager process.
@@ -86,28 +79,19 @@ delete(Cache, Key) ->
ets:delete(Cache, Key).
%%--------------------------------------------------------------------
-%% Function: foldl(Fun, Acc0, Cache) -> Acc
-%%
-%% Fun - fun()
-%% Acc0 - term()
-%% Cache - cache_ref()
-%%
+-spec foldl(fun(), term(), cache_ref()) -> term().
%%
%% Description: Calls Fun(Elem, AccIn) on successive elements of the
%% cache, starting with AccIn == Acc0. Fun/2 must return a new
%% accumulator which is passed to the next call. The function returns
-%% the final value of the accumulator. Acc0 is returned if the cache is
-%% empty.
-%% Should be callable from any process
+%% the final value of the accumulator. Acc0 is returned if the cache
+%% is empty.Should be callable from any process
%%--------------------------------------------------------------------
foldl(Fun, Acc0, Cache) ->
ets:foldl(Fun, Acc0, Cache).
%%--------------------------------------------------------------------
-%% Function: select_session(Cache, PartialKey) -> [Sessions]
-%%
-%% Cache - as returned by create/0
-%% PartialKey - opaque Key = {PartialKey, SessionId}
+-spec select_session(cache_ref(), {host(), port_num()} | port_num()) -> [#session{}].
%%
%% Description: Selects a session that could be reused. Should be callable
%% from any process.
@@ -119,6 +103,5 @@ select_session(Cache, PartialKey) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-
cache_name() ->
ssl_otp_session_cache.
diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl
index 88b801d46b..1add203fb0 100644
--- a/lib/ssl/src/ssl_ssl3.erl
+++ b/lib/ssl/src/ssl_ssl3.erl
@@ -38,6 +38,8 @@
%% Internal application API
%%====================================================================
+-spec master_secret(binary(), binary(), binary()) -> binary().
+
master_secret(PremasterSecret, ClientRandom, ServerRandom) ->
?DBG_HEX(PremasterSecret),
?DBG_HEX(ClientRandom),
@@ -57,6 +59,8 @@ master_secret(PremasterSecret, ClientRandom, ServerRandom) ->
?DBG_HEX(B),
B.
+-spec finished(client | server, binary(), {binary(), binary()}) -> binary().
+
finished(Role, MasterSecret, {MD5Hash, SHAHash}) ->
%% draft-ietf-tls-ssl-version3-00 - 5.6.9 Finished
%% struct {
@@ -75,6 +79,8 @@ finished(Role, MasterSecret, {MD5Hash, SHAHash}) ->
SHA = handshake_hash(?SHA, MasterSecret, Sender, SHAHash),
<<MD5/binary, SHA/binary>>.
+-spec certificate_verify(key_algo(), binary(), {binary(), binary()}) -> binary().
+
certificate_verify(Algorithm, MasterSecret, {MD5Hash, SHAHash})
when Algorithm == rsa; Algorithm == dhe_rsa ->
%% md5_hash
@@ -94,6 +100,8 @@ certificate_verify(dhe_dss, MasterSecret, {_, SHAHash}) ->
%% SHA(handshake_messages + master_secret + pad_1));
handshake_hash(?SHA, MasterSecret, undefined, SHAHash).
+-spec mac_hash(integer(), binary(), integer(), integer(), integer(), binary()) -> binary().
+
mac_hash(Method, Mac_write_secret, Seq_num, Type, Length, Fragment) ->
%% draft-ietf-tls-ssl-version3-00 - 5.2.3.1
%% hash(MAC_write_secret + pad_2 +
@@ -113,6 +121,11 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, Length, Fragment) ->
?DBG_HEX(Mac),
Mac.
+-spec setup_keys(binary(), binary(), binary(),
+ integer(), integer(), term(), integer()) ->
+ {binary(), binary(), binary(),
+ binary(), binary(), binary()}.
+
setup_keys(MasterSecret, ServerRandom, ClientRandom, HS, KML, _EKML, IVS) ->
KeyBlock = generate_keyblock(MasterSecret, ServerRandom, ClientRandom,
2*(HS+KML+IVS)),
@@ -136,6 +149,8 @@ setup_keys(MasterSecret, ServerRandom, ClientRandom, HS, KML, _EKML, IVS) ->
{ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
ServerWriteKey, ClientIV, ServerIV}.
+-spec suites() -> [cipher_suite()].
+
suites() ->
[
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
diff --git a/lib/ssl/src/ssl_sup.erl b/lib/ssl/src/ssl_sup.erl
index b7cb5c3ab3..316ed8a4e9 100644
--- a/lib/ssl/src/ssl_sup.erl
+++ b/lib/ssl/src/ssl_sup.erl
@@ -32,14 +32,17 @@
%%%=========================================================================
%%% API
%%%=========================================================================
+
+-spec start_link() -> {ok, pid()} | ignore | {error, term()}.
+
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
-%% init([]) -> {ok, {SupFlags, [ChildSpec]}}
-%%
+-spec init([]) -> {ok, {SupFlags :: tuple(), [ChildSpec :: tuple()]}}.
+
init([]) ->
%% OLD ssl - moved start to ssl.erl only if old
%% ssl is acctualy run!
diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl
index 70db632835..d1bc0730ba 100644
--- a/lib/ssl/src/ssl_tls1.erl
+++ b/lib/ssl/src/ssl_tls1.erl
@@ -36,6 +36,8 @@
%% Internal application API
%%====================================================================
+-spec master_secret(binary(), binary(), binary()) -> binary().
+
master_secret(PreMasterSecret, ClientRandom, ServerRandom) ->
%% RFC 2246 & 4346 - 8.1 %% master_secret = PRF(pre_master_secret,
%% "master secret", ClientHello.random +
@@ -43,6 +45,8 @@ master_secret(PreMasterSecret, ClientRandom, ServerRandom) ->
prf(PreMasterSecret, <<"master secret">>,
[ClientRandom, ServerRandom], 48).
+-spec finished(client | server, binary(), {binary(), binary()}) -> binary().
+
finished(Role, MasterSecret, {MD5Hash, SHAHash}) ->
%% RFC 2246 & 4346 - 7.4.9. Finished
%% struct {
@@ -56,6 +60,7 @@ finished(Role, MasterSecret, {MD5Hash, SHAHash}) ->
SHA = hash_final(?SHA, SHAHash),
prf(MasterSecret, finished_label(Role), [MD5, SHA], 12).
+-spec certificate_verify(key_algo(), {binary(), binary()}) -> binary().
certificate_verify(Algorithm, {MD5Hash, SHAHash}) when Algorithm == rsa;
Algorithm == dhe_rsa ->
@@ -65,7 +70,11 @@ certificate_verify(Algorithm, {MD5Hash, SHAHash}) when Algorithm == rsa;
certificate_verify(dhe_dss, {_, SHAHash}) ->
hash_final(?SHA, SHAHash).
-
+
+-spec setup_keys(binary(), binary(), binary(), integer(),
+ integer(), integer()) -> {binary(), binary(), binary(),
+ binary(), binary(), binary()}.
+
setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize,
KeyMatLen, IVSize) ->
%% RFC 2246 - 6.3. Key calculation
@@ -112,6 +121,9 @@ setup_keys(MasterSecret, ServerRandom, ClientRandom, HashSize,
%% {ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
%% ServerWriteKey, undefined, undefined}.
+-spec mac_hash(integer(), binary(), integer(), integer(), tls_version(),
+ integer(), binary()) -> binary().
+
mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
Length, Fragment) ->
%% RFC 2246 & 4346 - 6.2.3.1.
@@ -132,6 +144,8 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
?DBG_HEX(Mac),
Mac.
+-spec suites() -> [cipher_suite()].
+
suites() ->
[
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl
index 1d2cea6c72..c9db0d3851 100644
--- a/lib/ssl/test/erl_make_certs.erl
+++ b/lib/ssl/test/erl_make_certs.erl
@@ -56,7 +56,7 @@
make_cert(Opts) ->
SubjectPrivateKey = get_key(Opts),
{TBSCert, IssuerKey} = make_tbs(SubjectPrivateKey, Opts),
- Cert = public_key:sign(TBSCert, IssuerKey),
+ Cert = public_key:pkix_sign(TBSCert, IssuerKey),
true = verify_signature(Cert, IssuerKey, undef), %% verify that the keys where ok
{Cert, encode_key(SubjectPrivateKey)}.
@@ -66,8 +66,9 @@ make_cert(Opts) ->
%% @end
%%--------------------------------------------------------------------
write_pem(Dir, FileName, {Cert, Key = {_,_,not_encrypted}}) when is_binary(Cert) ->
- ok = public_key:der_to_pem(filename:join(Dir, FileName ++ ".pem"), [{cert, Cert, not_encrypted}]),
- ok = public_key:der_to_pem(filename:join(Dir, FileName ++ "_key.pem"), [Key]).
+ ok = ssl_test_lib:der_to_pem(filename:join(Dir, FileName ++ ".pem"),
+ [{'Certificate', Cert, not_encrypted}]),
+ ok = ssl_test_lib:der_to_pem(filename:join(Dir, FileName ++ "_key.pem"), [Key]).
%%--------------------------------------------------------------------
%% @doc Creates a rsa key (OBS: for testing only)
@@ -94,18 +95,14 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
%% @spec (::binary(), ::tuple()) -> ::boolean()
%% @end
%%--------------------------------------------------------------------
-verify_signature(DerEncodedCert, DerKey, KeyParams) ->
+verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
Key = decode_key(DerKey),
case Key of
#'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} ->
- public_key:verify_signature(DerEncodedCert,
- #'RSAPublicKey'{modulus=Mod, publicExponent=Exp},
- 'NULL');
+ public_key:pkix_verify(DerEncodedCert,
+ #'RSAPublicKey'{modulus=Mod, publicExponent=Exp});
#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
- public_key:verify_signature(DerEncodedCert, Y, #'Dss-Parms'{p=P, q=Q, g=G});
-
- _ ->
- public_key:verify_signature(DerEncodedCert, Key, KeyParams)
+ public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}})
end.
%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -132,19 +129,18 @@ decode_key(#'RSAPrivateKey'{} = Key,_) ->
Key;
decode_key(#'DSAPrivateKey'{} = Key,_) ->
Key;
-decode_key(Der = {_,_,_}, Pw) ->
- {ok, Key} = public_key:decode_private_key(Der, Pw),
- Key;
-decode_key(FileOrDer, Pw) ->
- {ok, [KeyInfo]} = public_key:pem_to_der(FileOrDer),
+decode_key(PemEntry = {_,_,_}, Pw) ->
+ public_key:pem_entry_decode(PemEntry, Pw);
+decode_key(PemBin, Pw) ->
+ [KeyInfo] = public_key:pem_decode(PemBin),
decode_key(KeyInfo, Pw).
encode_key(Key = #'RSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key),
- {rsa_private_key, list_to_binary(Der), not_encrypted};
+ {'RSAPrivateKey', list_to_binary(Der), not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {dsa_private_key, list_to_binary(Der), not_encrypted}.
+ {'DSAPrivateKey', list_to_binary(Der), not_encrypted}.
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
@@ -178,7 +174,7 @@ issuer(Opts, SubjectKey) ->
end.
issuer_der(Issuer) ->
- {ok, Decoded} = public_key:pkix_decode_cert(Issuer, otp),
+ Decoded = public_key:pkix_decode_cert(Issuer, otp),
#'OTPCertificate'{tbsCertificate=Tbs} = Decoded,
#'OTPTBSCertificate'{subject=Subject} = Tbs,
Subject.
diff --git a/lib/ssl/test/make_certs.erl b/lib/ssl/test/make_certs.erl
index 0cdf33c3e2..3c18a905b4 100644
--- a/lib/ssl/test/make_certs.erl
+++ b/lib/ssl/test/make_certs.erl
@@ -90,8 +90,10 @@ enduser(Root, OpenSSLCmd, CA, User) ->
KeyFile = filename:join([UsrRoot, "key.pem"]),
ReqFile = filename:join([UsrRoot, "req.pem"]),
create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile),
- CertFile = filename:join([UsrRoot, "cert.pem"]),
- sign_req(Root, OpenSSLCmd, CA, "user_cert", ReqFile, CertFile).
+ CertFileAllUsage = filename:join([UsrRoot, "cert.pem"]),
+ sign_req(Root, OpenSSLCmd, CA, "user_cert", ReqFile, CertFileAllUsage),
+ CertFileDigitalSigOnly = filename:join([UsrRoot, "digital_signature_only_cert.pem"]),
+ sign_req(Root, OpenSSLCmd, CA, "user_cert_digital_signature_only", ReqFile, CertFileDigitalSigOnly).
collect_certs(Root, CAs, Users) ->
Bins = lists:foldr(
@@ -255,6 +257,7 @@ ca_cnf(CA) ->
"RANDFILE = $dir/private/RAND\n"
"\n"
"x509_extensions = user_cert\n"
+ "unique_subject = no\n"
"default_days = 3600\n"
"default_md = sha1\n"
"preserve = no\n"
@@ -279,6 +282,15 @@ ca_cnf(CA) ->
"issuerAltName = issuer:copy\n"
"\n"
+ "[user_cert_digital_signature_only]\n"
+ "basicConstraints = CA:false\n"
+ "keyUsage = digitalSignature\n"
+ "subjectKeyIdentifier = hash\n"
+ "authorityKeyIdentifier = keyid,issuer:always\n"
+ "subjectAltName = email:copy\n"
+ "issuerAltName = issuer:copy\n"
+ "\n"
+
"[ca_cert]\n"
"basicConstraints = critical,CA:true\n"
"keyUsage = cRLSign, keyCertSign\n"
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 8a1b90ed98..53142250e8 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -233,7 +233,8 @@ all(suite) ->
server_renegotiate_reused_session, client_no_wrap_sequence_number,
server_no_wrap_sequence_number, extended_key_usage,
validate_extensions_fun, no_authority_key_identifier,
- invalid_signature_client, invalid_signature_server, cert_expired
+ invalid_signature_client, invalid_signature_server, cert_expired,
+ client_with_cert_cipher_suites_handshake
].
%% Test cases starts here.
@@ -578,8 +579,8 @@ peercert(Config) when is_list(Config) ->
{options, ClientOpts}]),
CertFile = proplists:get_value(certfile, ServerOpts),
- {ok, [{cert, BinCert, _}]} = public_key:pem_to_der(CertFile),
- {ok, ErlCert} = public_key:pkix_decode_cert(BinCert, otp),
+ [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile),
+ ErlCert = public_key:pkix_decode_cert(BinCert, otp),
ServerMsg = {{error, no_peercert}, {error, no_peercert}},
ClientMsg = {{ok, BinCert}, {ok, ErlCert}},
@@ -2525,35 +2526,35 @@ extended_key_usage(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile),
- {ok, Key} = public_key:decode_private_key(KeyInfo),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = public_key:pem_entry_decode(KeyEntry),
ServerCertFile = proplists:get_value(certfile, ServerOpts),
NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"),
- {ok, [{cert, ServerDerCert, _}]} = public_key:pem_to_der(ServerCertFile),
- {ok, ServerOTPCert} = public_key:pkix_decode_cert(ServerDerCert, otp),
+ [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
+ ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp),
ServerExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']},
ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate,
ServerExtensions = ServerOTPTbsCert#'OTPTBSCertificate'.extensions,
NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions =
[ServerExtKeyUsageExt |
ServerExtensions]},
- NewServerDerCert = public_key:sign(NewServerOTPTbsCert, Key),
- public_key:der_to_pem(NewServerCertFile, [{cert, NewServerDerCert, not_encrypted}]),
+ NewServerDerCert = public_key:pkix_sign(NewServerOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
ClientCertFile = proplists:get_value(certfile, ClientOpts),
NewClientCertFile = filename:join(PrivDir, "client/new_cert.pem"),
- {ok, [{cert, ClientDerCert, _}]} = public_key:pem_to_der(ClientCertFile),
- {ok, ClientOTPCert} = public_key:pkix_decode_cert(ClientDerCert, otp),
+ [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
+ ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp),
ClientExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-clientAuth']},
ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
ClientExtensions = ClientOTPTbsCert#'OTPTBSCertificate'.extensions,
NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions =
[ClientExtKeyUsageExt |
ClientExtensions]},
- NewClientDerCert = public_key:sign(NewClientOTPTbsCert, Key),
- public_key:der_to_pem(NewClientCertFile, [{cert, NewClientDerCert, not_encrypted}]),
+ NewClientDerCert = public_key:pkix_sign(NewClientOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]),
NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)],
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -2621,13 +2622,13 @@ no_authority_key_identifier(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile),
- {ok, Key} = public_key:decode_private_key(KeyInfo),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = public_key:pem_entry_decode(KeyEntry),
CertFile = proplists:get_value(certfile, ServerOpts),
NewCertFile = filename:join(PrivDir, "server/new_cert.pem"),
- {ok, [{cert, DerCert, _}]} = public_key:pem_to_der(CertFile),
- {ok, OTPCert} = public_key:pkix_decode_cert(DerCert, otp),
+ [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(CertFile),
+ OTPCert = public_key:pkix_decode_cert(DerCert, otp),
OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate,
Extensions = OTPTbsCert#'OTPTBSCertificate'.extensions,
NewExtensions = delete_authority_key_extension(Extensions, []),
@@ -2635,8 +2636,8 @@ no_authority_key_identifier(Config) when is_list(Config) ->
test_server:format("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]),
- NewDerCert = public_key:sign(NewOTPTbsCert, Key),
- public_key:der_to_pem(NewCertFile, [{cert, NewDerCert, not_encrypted}]),
+ NewDerCert = public_key:pkix_sign(NewOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]),
NewServerOpts = [{certfile, NewCertFile} | proplists:delete(certfile, ServerOpts)],
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -2679,16 +2680,16 @@ invalid_signature_server(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
KeyFile = filename:join(PrivDir, "server/key.pem"),
- {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile),
- {ok, Key} = public_key:decode_private_key(KeyInfo),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = public_key:pem_entry_decode(KeyEntry),
ServerCertFile = proplists:get_value(certfile, ServerOpts),
NewServerCertFile = filename:join(PrivDir, "server/invalid_cert.pem"),
- {ok, [{cert, ServerDerCert, _}]} = public_key:pem_to_der(ServerCertFile),
- {ok, ServerOTPCert} = public_key:pkix_decode_cert(ServerDerCert, otp),
+ [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
+ ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp),
ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate,
- NewServerDerCert = public_key:sign(ServerOTPTbsCert, Key),
- public_key:der_to_pem(NewServerCertFile, [{cert, NewServerDerCert, not_encrypted}]),
+ NewServerDerCert = public_key:pkix_sign(ServerOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -2719,16 +2720,16 @@ invalid_signature_client(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
KeyFile = filename:join(PrivDir, "client/key.pem"),
- {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile),
- {ok, Key} = public_key:decode_private_key(KeyInfo),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = public_key:pem_entry_decode(KeyEntry),
ClientCertFile = proplists:get_value(certfile, ClientOpts),
NewClientCertFile = filename:join(PrivDir, "client/invalid_cert.pem"),
- {ok, [{cert, ClientDerCert, _}]} = public_key:pem_to_der(ClientCertFile),
- {ok, ClientOTPCert} = public_key:pkix_decode_cert(ClientDerCert, otp),
+ [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
+ ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp),
ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
- NewClientDerCert = public_key:sign(ClientOTPTbsCert, Key),
- public_key:der_to_pem(NewClientCertFile, [{cert, NewClientDerCert, not_encrypted}]),
+ NewClientDerCert = public_key:pkix_sign(ClientOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]),
NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)],
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -2796,13 +2797,13 @@ cert_expired(Config) when is_list(Config) ->
PrivDir = ?config(priv_dir, Config),
KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- {ok, [KeyInfo]} = public_key:pem_to_der(KeyFile),
- {ok, Key} = public_key:decode_private_key(KeyInfo),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = public_key:pem_entry_decode(KeyEntry),
ServerCertFile = proplists:get_value(certfile, ServerOpts),
NewServerCertFile = filename:join(PrivDir, "server/expired_cert.pem"),
- {ok, [{cert, DerCert, _}]} = public_key:pem_to_der(ServerCertFile),
- {ok, OTPCert} = public_key:pkix_decode_cert(DerCert, otp),
+ [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
+ OTPCert = public_key:pkix_decode_cert(DerCert, otp),
OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate,
{Year, Month, Day} = date(),
@@ -2825,8 +2826,8 @@ cert_expired(Config) when is_list(Config) ->
[OTPTbsCert#'OTPTBSCertificate'.validity, NewValidity]),
NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{validity = NewValidity},
- NewServerDerCert = public_key:sign(NewOTPTbsCert, Key),
- public_key:der_to_pem(NewServerCertFile, [{cert, NewServerDerCert, not_encrypted}]),
+ NewServerDerCert = public_key:pkix_sign(NewOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -2849,6 +2850,39 @@ two_digits_str(N) ->
lists:flatten(io_lib:format("~p", [N])).
%%--------------------------------------------------------------------
+
+client_with_cert_cipher_suites_handshake(doc) ->
+ ["Test that client with a certificate without keyEncipherment usage "
+ " extension can connect to a server with restricted cipher suites "];
+
+client_with_cert_cipher_suites_handshake(suite) ->
+ [];
+
+client_with_cert_cipher_suites_handshake(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_verification_opts_digital_signature_only, Config),
+ ServerOpts = ?config(server_verification_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE,
+ send_recv_result_active, []}},
+ {options, [{active, true},
+ {ciphers, ssl_test_lib:rsa_non_signed_suites()}
+ | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ send_recv_result_active, []}},
+ {options, [{active, true}
+ | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
send_recv_result(Socket) ->
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index 1b8754afe9..9553241ad4 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -145,14 +145,19 @@ all(suite) ->
packet_baddata_passive, packet_baddata_active,
packet_size_passive, packet_size_active,
packet_cdr_decode,
+ packet_cdr_decode_list,
packet_http_decode,
packet_http_decode_list,
packet_http_bin_decode_multi,
packet_line_decode,
- packet_asn1_decode,
+ packet_line_decode_list,
+ packet_asn1_decode,
+ packet_asn1_decode_list,
packet_tpkt_decode,
+ packet_tpkt_decode_list,
%packet_fcgi_decode,
packet_sunrm_decode,
+ packet_sunrm_decode_list,
header_decode_one_byte,
header_decode_two_bytes,
header_decode_two_bytes_one_sent,
@@ -1429,7 +1434,7 @@ packet_size_passive(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
packet_cdr_decode(doc) ->
- ["Test setting the packet option {packet, cdr}"];
+ ["Test setting the packet option {packet, cdr}, {mode, binary}"];
packet_cdr_decode(suite) ->
[];
packet_cdr_decode(Config) when is_list(Config) ->
@@ -1463,8 +1468,44 @@ packet_cdr_decode(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
+packet_cdr_decode_list(doc) ->
+ ["Test setting the packet option {packet, cdr} {mode, list}"];
+packet_cdr_decode_list(suite) ->
+ [];
+packet_cdr_decode_list(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ %% A valid cdr packet
+ Data = [71,73,79,80,1,2,2,1,0,0,0,41,0,0,0,0,0,0,0,0,0,0,0,1,78,
+ 69,79,0,0,0,0,2,0,10,0,0,0,0,0,0,0,0,0,18,0,0,0,0,0,0,0,4,49],
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, server_packet_decode,
+ [Data]}},
+ {options, [{active, true}, list,
+ {packet, cdr}|ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, client_packet_decode,
+ [Data]}},
+ {options, [{active, true}, {packet, cdr},
+ list | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
packet_http_decode(doc) ->
- ["Test setting the packet option {packet, http} {mode, binary}"];
+ ["Test setting the packet option {packet, http} {mode, binary} "
+ "(Body will be binary http strings are lists)"];
packet_http_decode(suite) ->
[];
@@ -1485,7 +1526,7 @@ packet_http_decode(Config) when is_list(Config) ->
{from, self()},
{mfa, {?MODULE, server_http_decode,
[Response]}},
- {options, [{active, true}, binary,
+ {options, [{active, true},binary,
{packet, http} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
@@ -1494,7 +1535,7 @@ packet_http_decode(Config) when is_list(Config) ->
{from, self()},
{mfa, {?MODULE, client_http_decode,
[Request]}},
- {options, [{active, true}, binary,
+ {options, [{active, true}, binary,
{packet, http} |
ClientOpts]}]),
@@ -1548,7 +1589,8 @@ client_http_decode(Socket, HttpRequest) ->
%%--------------------------------------------------------------------
packet_http_decode_list(doc) ->
- ["Test setting the packet option {packet, http}, {mode, list}"];
+ ["Test setting the packet option {packet, http}, {mode, list}"
+ "(Body will be litst too)"];
packet_http_decode_list(suite) ->
[];
packet_http_decode_list(Config) when is_list(Config) ->
@@ -1697,7 +1739,7 @@ client_http_bin_decode(_, _, _) ->
ok.
%%--------------------------------------------------------------------
packet_line_decode(doc) ->
- ["Test setting the packet option {packet, line}"];
+ ["Test setting the packet option {packet, line}, {mode, binary}"];
packet_line_decode(suite) ->
[];
packet_line_decode(Config) when is_list(Config) ->
@@ -1731,30 +1773,44 @@ packet_line_decode(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
-server_line_packet_decode(Socket, Lines) ->
- receive
- {ssl, Socket, <<"Line ends here.\n">>} -> ok;
- Other1 -> exit({?LINE, Other1})
- end,
- receive
- {ssl, Socket, <<"Now it is a new line.\n">>} -> ok;
- Other2 -> exit({?LINE, Other2})
- end,
- ok = ssl:send(Socket, Lines).
+packet_line_decode_list(doc) ->
+ ["Test setting the packet option {packet, line}, {mode, list}"];
+packet_line_decode_list(suite) ->
+ [];
+packet_line_decode_list(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = lists:flatten(io_lib:format("Line ends here.~n"
+ "Now it is a new line.~n", [])),
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE,
+ server_line_packet_decode,
+ [Data]}},
+ {options, [{active, true}, list,
+ {packet, line}|ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ client_line_packet_decode,
+ [Data]}},
+ {options, [{active, true},
+ {packet, line},
+ list | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
-client_line_packet_decode(Socket, Lines) ->
- <<P1:10/binary, P2/binary>> = Lines,
- ok = ssl:send(Socket, P1),
- ok = ssl:send(Socket, P2),
- receive
- {ssl, Socket, <<"Line ends here.\n">>} -> ok;
- Other1 -> exit({?LINE, Other1})
- end,
- receive
- {ssl, Socket, <<"Now it is a new line.\n">>} -> ok;
- Other2 -> exit({?LINE, Other2})
- end.
%%--------------------------------------------------------------------
@@ -1770,7 +1826,7 @@ packet_asn1_decode(Config) when is_list(Config) ->
File = proplists:get_value(certfile, ServerOpts),
%% A valid asn1 BER packet (DER is stricter BER)
- {ok,[{cert, Data, _}]} = public_key:pem_to_der(File),
+ [{'Certificate', Data, _}] = ssl_test_lib:pem_to_der(File),
Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
{from, self()},
@@ -1794,6 +1850,44 @@ packet_asn1_decode(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
+packet_asn1_decode_list(doc) ->
+ ["Test setting the packet option {packet, asn1}"];
+packet_asn1_decode_list(suite) ->
+ [];
+packet_asn1_decode_list(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ File = proplists:get_value(certfile, ServerOpts),
+
+ %% A valid asn1 BER packet (DER is stricter BER)
+ [{'Certificate', BinData, _}] = ssl_test_lib:pem_to_der(File),
+
+ Data = binary_to_list(BinData),
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, server_packet_decode,
+ [Data]}},
+ {options, [{active, true}, list,
+ {packet, asn1}|ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, client_packet_decode,
+ [Data]}},
+ {options, [{active, true}, {packet, asn1},
+ list | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
packet_tpkt_decode(doc) ->
["Test setting the packet option {packet, tpkt}"];
packet_tpkt_decode(suite) ->
@@ -1826,6 +1920,38 @@ packet_tpkt_decode(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+packet_tpkt_decode_list(doc) ->
+ ["Test setting the packet option {packet, tpkt}"];
+packet_tpkt_decode_list(suite) ->
+ [];
+packet_tpkt_decode_list(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = binary_to_list(list_to_binary(add_tpkt_header("TPKT data"))),
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, server_packet_decode,
+ [Data]}},
+ {options, [{active, true}, list,
+ {packet, tpkt}|ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, client_packet_decode,
+ [Data]}},
+ {options, [{active, true}, {packet, tpkt},
+ list | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
@@ -1895,6 +2021,39 @@ packet_sunrm_decode(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+packet_sunrm_decode_list(doc) ->
+ ["Test setting the packet option {packet, sunrm}"];
+packet_sunrm_decode_list(suite) ->
+ [];
+packet_sunrm_decode_list(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = binary_to_list(list_to_binary([<<11:32>>, "Hello world"])),
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, server_packet_decode,
+ [Data]}},
+ {options, [{active, true}, list,
+ {packet, sunrm}|ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, client_packet_decode,
+ [Data]}},
+ {options, [{active, true}, {packet, sunrm},
+ list | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
header_decode_one_byte(doc) ->
@@ -2155,8 +2314,14 @@ server_packet_decode(Socket, Packet) ->
end,
ok = ssl:send(Socket, Packet).
-client_packet_decode(Socket, Packet) ->
+client_packet_decode(Socket, Packet) when is_binary(Packet)->
<<P1:10/binary, P2/binary>> = Packet,
+ client_packet_decode(Socket, P1, P2, Packet);
+client_packet_decode(Socket, [Head | Tail] = Packet) ->
+ client_packet_decode(Socket, [Head], Tail, Packet).
+
+client_packet_decode(Socket, P1, P2, Packet) ->
+ test_server:format("Packet: ~p ~n", [Packet]),
ok = ssl:send(Socket, P1),
ok = ssl:send(Socket, P2),
receive
@@ -2176,7 +2341,7 @@ server_header_decode(Socket, Packet, Result) ->
end,
ok = ssl:send(Socket, Packet),
receive
- {ssl, Socket, Result} -> ok;
+ {ssl, Socket, Result} -> ok;
Other2 -> exit({?LINE, Other2})
end,
ok = ssl:send(Socket, Packet).
@@ -2192,6 +2357,44 @@ client_header_decode(Socket, Packet, Result) ->
{ssl, Socket, Result} -> ok;
Other2 -> exit({?LINE, Other2})
end.
+
+server_line_packet_decode(Socket, Packet) when is_binary(Packet) ->
+ [L1, L2] = string:tokens(binary_to_list(Packet), "\n"),
+ server_line_packet_decode(Socket, list_to_binary(L1 ++ "\n"), list_to_binary(L2 ++ "\n"), Packet);
+server_line_packet_decode(Socket, Packet) ->
+ [L1, L2] = string:tokens(Packet, "\n"),
+ server_line_packet_decode(Socket, L1 ++ "\n", L2 ++ "\n", Packet).
+
+server_line_packet_decode(Socket, L1, L2, Packet) ->
+ receive
+ {ssl, Socket, L1} -> ok;
+ Other1 -> exit({?LINE, Other1})
+ end,
+ receive
+ {ssl, Socket, L2} -> ok;
+ Other2 -> exit({?LINE, Other2})
+ end,
+ ok = ssl:send(Socket, Packet).
+
+client_line_packet_decode(Socket, Packet) when is_binary(Packet)->
+ <<P1:10/binary, P2/binary>> = Packet,
+ [L1, L2] = string:tokens(binary_to_list(Packet), "\n"),
+ client_line_packet_decode(Socket, P1, P2, list_to_binary(L1 ++ "\n"), list_to_binary(L2 ++ "\n"));
+client_line_packet_decode(Socket, [Head | Tail] = Packet) ->
+ [L1, L2] = string:tokens(Packet, "\n"),
+ client_line_packet_decode(Socket, [Head], Tail, L1 ++ "\n", L2 ++ "\n").
+
+client_line_packet_decode(Socket, P1, P2, L1, L2) ->
+ ok = ssl:send(Socket, P1),
+ ok = ssl:send(Socket, P2),
+ receive
+ {ssl, Socket, L1} -> ok;
+ Other1 -> exit({?LINE, Other1})
+ end,
+ receive
+ {ssl, Socket, L2} -> ok;
+ Other2 -> exit({?LINE, Other2})
+ end.
add_tpkt_header(Data) when is_binary(Data) ->
L = size(Data) + 4,
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 40715dbf30..c7ff015034 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -268,6 +268,8 @@ cert_options(Config) ->
"client", "cacerts.pem"]),
ClientCertFile = filename:join([?config(priv_dir, Config),
"client", "cert.pem"]),
+ ClientCertFileDigitalSignatureOnly = filename:join([?config(priv_dir, Config),
+ "client", "digital_signature_only_cert.pem"]),
ServerCaCertFile = filename:join([?config(priv_dir, Config),
"server", "cacerts.pem"]),
ServerCertFile = filename:join([?config(priv_dir, Config),
@@ -292,6 +294,10 @@ cert_options(Config) ->
{certfile, ClientCertFile},
{keyfile, ClientKeyFile},
{ssl_imp, new}]},
+ {client_verification_opts_digital_signature_only, [{cacertfile, ClientCaCertFile},
+ {certfile, ClientCertFileDigitalSignatureOnly},
+ {keyfile, ClientKeyFile},
+ {ssl_imp, new}]},
{server_opts, [{ssl_imp, new},{reuseaddr, true},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
{server_verification_opts, [{ssl_imp, new},{reuseaddr, true},
@@ -325,6 +331,10 @@ make_dsa_cert(Config) ->
[{server_dsa_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
+ {server_dsa_verify_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ServerCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {verify, verify_peer}]},
{client_dsa_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ClientCaCertFile},
{certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
@@ -342,9 +352,9 @@ make_dsa_cert_files(RoleStr, Config) ->
KeyFile = filename:join([?config(priv_dir, Config),
RoleStr, "dsa_key.pem"]),
- public_key:der_to_pem(CaCertFile, [{cert, CaCert, not_encrypted}]),
- public_key:der_to_pem(CertFile, [{cert, Cert, not_encrypted}]),
- public_key:der_to_pem(KeyFile, [CertKey]),
+ der_to_pem(CaCertFile, [{'Certificate', CaCert, not_encrypted}]),
+ der_to_pem(CertFile, [{'Certificate', Cert, not_encrypted}]),
+ der_to_pem(KeyFile, [CertKey]),
{CaCertFile, CertFile, KeyFile}.
start_upgrade_server(Args) ->
@@ -567,6 +577,14 @@ rsa_suites() ->
end,
ssl:cipher_suites()).
+rsa_non_signed_suites() ->
+ lists:filter(fun({rsa, _, _}) ->
+ true;
+ (_) ->
+ false
+ end,
+ ssl:cipher_suites()).
+
dsa_suites() ->
lists:filter(fun({dhe_dss, _, _}) ->
true;
@@ -597,3 +615,11 @@ openssl_dsa_suites() ->
true
end
end, Ciphers).
+
+pem_to_der(File) ->
+ {ok, PemBin} = file:read_file(File),
+ public_key:pem_decode(PemBin).
+
+der_to_pem(File, Entries) ->
+ PemBin = public_key:pem_encode(Entries),
+ file:write_file(File, PemBin).
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index d2a4ca8db5..75cfce0052 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -309,7 +309,7 @@ tls1_erlang_server_openssl_client_dsa_cert(suite) ->
tls1_erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ClientOpts = ?config(client_dsa_opts, Config),
- ServerOpts = ?config(server_dsa_opts, Config),
+ ServerOpts = ?config(server_dsa_verify_opts, Config),
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
@@ -398,7 +398,7 @@ ssl3_erlang_server_openssl_client_dsa_cert(suite) ->
ssl3_erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ClientOpts = ?config(client_dsa_opts, Config),
- ServerOpts = ?config(server_dsa_opts, Config),
+ ServerOpts = ?config(server_dsa_verify_opts, Config),
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index 74b1cf4c78..6c40a4529c 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -17,45 +17,4 @@
# %CopyrightEnd%
#
-SSL_VSN = 4.0
-
-TICKETS = OTP-8587\
- OTP-8695
-
-#TICKETS = OTP-8679 \
-# OTP-7047 \
-# OTP-7049 \
-# OTP-8568 \
-# OTP-8588
-
-#TICKETS_3.11 = OTP-8517 \
-# OTP-7046 \
-# OTP-8557 \
-# OTP-8560 \
-# OTP-8545 \
-# OTP-8554
-
-#TICKETS_3.10.9 = OTP-8510
-
-#TICKETS_3.10.8 = OTP-8372 OTP-8441 OTP-8459
-#TICKETS_3.10.7 = OTP-8260 OTP-8218 OTP-8250
-
-#TICKETS_3.10.6 = OTP-8275
-
-#TICKETS_3.10.5 = OTP-8224 OTP-8244
-
-#TICKETS_3.10.4 = OTP-8137
-
-#TICKETS_3.10.3 = OTP-8011
-#TICKETS_3.10.2 = OTP-7963
-
-# TICKETS_3.10.1 = OTP-7878 \
-# OTP-7656 \
-# OTP-7870 \
-# OTP-7871
-
-# TICKETS_3.10 = OTP-7258 \
-# OTP-6894 \
-# OTP-7037 \
-# OTP-7039 \
-# OTP-7150
+SSL_VSN = 4.0.1