aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssl')
-rw-r--r--lib/ssl/Makefile6
-rw-r--r--lib/ssl/doc/src/ssl.xml286
-rw-r--r--lib/ssl/doc/src/ssl_distribution.xml10
-rw-r--r--lib/ssl/doc/src/ssl_protocol.xml12
-rw-r--r--lib/ssl/doc/src/ssl_session_cache_api.xml20
-rw-r--r--lib/ssl/examples/certs/Makefile41
-rw-r--r--lib/ssl/examples/certs/Makefile.in80
-rw-r--r--lib/ssl/examples/certs/ebin/.gitignore0
-rw-r--r--lib/ssl/examples/certs/etc/client/cacerts.pem34
-rw-r--r--lib/ssl/examples/certs/etc/client/cert.pem17
-rw-r--r--lib/ssl/examples/certs/etc/client/key.pem16
-rw-r--r--lib/ssl/examples/certs/etc/erlangCA/cert.pem17
-rw-r--r--lib/ssl/examples/certs/etc/otpCA/cert.pem17
-rw-r--r--lib/ssl/examples/certs/etc/server/cacerts.pem34
-rw-r--r--lib/ssl/examples/certs/etc/server/cert.pem17
-rw-r--r--lib/ssl/examples/certs/etc/server/key.pem16
-rw-r--r--lib/ssl/examples/certs/rnd/RANDbin512 -> 0 bytes
-rw-r--r--lib/ssl/examples/certs/src/make_certs.erl297
-rw-r--r--lib/ssl/src/ssl.erl121
-rw-r--r--lib/ssl/src/ssl_certificate.erl86
-rw-r--r--lib/ssl/src/ssl_certificate_db.erl27
-rw-r--r--lib/ssl/src/ssl_connection.erl44
-rw-r--r--lib/ssl/src/ssl_handshake.erl138
-rw-r--r--lib/ssl/src/ssl_internal.hrl5
-rw-r--r--lib/ssl/src/ssl_manager.erl10
-rw-r--r--lib/ssl/src/ssl_session.erl4
-rw-r--r--lib/ssl/test/erl_make_certs.erl51
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl265
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl66
-rw-r--r--lib/ssl/test/ssl_test_lib.erl2
-rw-r--r--lib/ssl/vsn.mk19
31 files changed, 998 insertions, 760 deletions
diff --git a/lib/ssl/Makefile b/lib/ssl/Makefile
index 8c9d78d4bc..daad7dc3e6 100644
--- a/lib/ssl/Makefile
+++ b/lib/ssl/Makefile
@@ -25,11 +25,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
# Macros
#
-SUB_DIRECTORIES = src c_src doc/src
-
-ifeq ($(CROSS_COMPILING),no)
-SUB_DIRECTORIES += examples/certs examples/src
-endif
+SUB_DIRECTORIES = src c_src doc/src examples/certs examples/src
include vsn.mk
VSN = $(SSL_VSN)
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index def61bcf03..d5b7253ef3 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
@@ -69,10 +69,13 @@
</p>
<p> <c>ssloption() = {verify, verify_type()} |
+ {verify_fun, {fun(), term()}} |
{fail_if_no_peer_cert, boolean()}
{depth, integer()} |
- {certfile, path()} | {keyfile, path()} | {password, string()} |
- {cacertfile, path()} | {dhfile, path()} | {ciphers, ciphers()} |
+ {cert, der_bin()}| {certfile, path()} |
+ {key, der_bin()} | {keyfile, path()} | {password, string()} |
+ {cacerts, [der_bin()]} | {cacertfile, path()} |
+ |{dh, der_bin()} | {dhfile, path()} | {ciphers, ciphers()} |
{ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | {reuse_session, fun()}
</c></p>
@@ -91,6 +94,8 @@
<p><c>verify_type() = verify_none | verify_peer</c></p>
<p><c>path() = string() - representing a file path.</c></p>
+
+ <p><c>der_bin() = binary() -Asn1 DER encoded entity as an erlang binary.</c></p>
<p><c>host() = hostname() | ipaddress()</c></p>
@@ -121,115 +126,52 @@
<p><c>ssl_imp() = new | old - default is new.</c></p>
</section>
-
-<section>
- <title>SSL OPTION DESCRIPTIONS</title>
+
+ <section>
+ <title>SSL OPTION DESCRIPTIONS - COMMON for SERVER and CLIENT</title>
+
+ <p>Options described here are options that are have the same
+ meaning in the client and the server.
+ </p>
<taglist>
- <tag>{verify, verify_type()}</tag>
- <item> If <c>verify_none</c> is specified x509-certificate
- path validation errors at the client side
- will not automatically cause the connection to fail, as
- it will if the verify type is <c>verify_peer</c>. See also
- the option verify_fun.
- Servers only do the path validation if <c>verify_peer</c> is set to
- true, as it then will
- send a certificate request to
- the client (this message is not sent if the verify option is
- <c>verify_none</c>) and you may then also want to specify
- the option <c>fail_if_no_peer_cert</c>.
- </item>
- <tag>{fail_if_no_peer_cert, boolean()}</tag>
- <item>Used together with {verify, verify_peer} by a ssl server.
- If set to true,
- the server will fail if the client does not have a certificate
- to send, e.i sends a empty certificate, if set to false it will
- only fail if the client sends a invalid certificate (an empty
- certificate is considered valid).
- </item>
+ <tag>{cert, der_bin()}</tag>
+ <item> The DER encoded users certificate. If this option
+ is supplied it will override the certfile option.</item>
- <tag>{verify_fun, fun(ErrorList) -> boolean()}</tag>
- <item>Used by the ssl client to determine if
- x509-certificate path validations errors are acceptable or
- if the connection should fail. Defaults to:
-
-<code>
-fun(ErrorList) ->
- case lists:foldl(fun({bad_cert,unknown_ca}, Acc) ->
- Acc;
- (Other, Acc) ->
- [Other | Acc]
- end, [], ErrorList) of
- [] ->
- true;
- [_|_] ->
- false
- end
-end
-</code>
- I.e. by default if the only error found was that the CA-certificate
- holder was unknown this will be accepted.
-
- Possible errors in the error list are:
- {bad_cert, cert_expired}, {bad_cert, invalid_issuer},
- {bad_cert, invalid_signature}, {bad_cert, name_not_permitted},
- {bad_cert, unknown_ca},
- {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()}
- </item>
-
+ <tag>{certfile, path()}</tag>
+ <item>Path to a file containing the user's certificate.</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>{key, der_bin()}</tag>
+ <item> The DER encoded users private key. If this option
+ is supplied it will override the keyfile option.</item>
- <tag>{depth, integer()}</tag>
- <item>Specifies the maximum
- verification depth, i.e. how far in a chain of certificates the
- verification process can proceed before the verification is
- considered to fail. Peer certificate = 0, CA certificate = 1,
- higher level CA certificate = 2, etc. The value 2 thus means
- that a chain can at most contain peer cert, CA cert, next CA
- cert, and an additional CA cert. The default value is 1.
- </item>
-
- <tag>{certfile, path()}</tag>
- <item>Path to a file containing the
- user's certificate. Optional for clients but note
- that some servers requires that the client can certify
- itself. </item>
<tag>{keyfile, path()}</tag>
<item>Path to file containing user's
private PEM encoded key. As PEM-files may contain several
entries this option defaults to the same file as given by
certfile option.</item>
+
<tag>{password, string()}</tag>
<item>String containing the user's password.
Only used if the private keyfile is password protected.
</item>
+
+ <tag>{cacerts, [der_bin()]}</tag>
+ <item> The DER encoded trusted certificates. If this option
+ is supplied it will override the cacertfile option.</item>
+
<tag>{cacertfile, path()}</tag>
<item>Path to file containing PEM encoded
CA certificates (trusted certificates used for verifying a peer
certificate). May be omitted if you do not want to verify
the peer.</item>
- <tag>{dhfile, path()}</tag>
- <item>Path to file containing PEM encoded Diffie Hellman parameters,
- for the server to use if a cipher suite using Diffie Hellman key exchange
- is negotiated. If not specified hardcode parameters will be used.
- </item>
-
<tag>{ciphers, ciphers()}</tag>
- <item>The function <c>ciphers_suites/0</c> can
- be used to find all available ciphers.
+ <item>The cipher suites that should be supported. The function
+ <c>ciphers_suites/0</c> can be used to find all available
+ ciphers.
</item>
<tag>{ssl_imp, ssl_imp()}</tag>
@@ -237,13 +179,153 @@ end
new.
</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 i.e. secure renegotiation will be used if possible
+ but it will fallback to unsecure renegotiation if the peer
+ does not support RFC 5746.
+ </item>
+
+ <tag>{depth, integer()}</tag>
+ <item>Specifies the maximum
+ verification depth, i.e. how far in a chain of certificates the
+ verification process can proceed before the verification is
+ considered to fail. Peer certificate = 0, CA certificate = 1,
+ higher level CA certificate = 2, etc. The value 2 thus means
+ that a chain can at most contain peer cert, CA cert, next CA
+ cert, and an additional CA cert. The default value is 1.
+ </item>
+
+ <tag>{verify_fun, {Verifyfun :: fun(), InitialUserState :: term()}}</tag>
+ <item>
+ <p>The verification fun should be defined as:</p>
+
+ <code>
+fun(OtpCert :: #'OtpCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
+ {extension, #'Extension'{}}, InitialUserState :: term()) ->
+ {valid, UserState :: term()} | {fail, Reason :: term()} |
+ {unknown, UserState :: term()}.
+ </code>
+
+ <p>The verify fun will be called during the X509-path
+ validation when an error or an extension unknown to the ssl
+ application is encountered. Additionally it will be called
+ when a certificate is considered valid by the path validation
+ to allow access to each certificate in the path to the user
+ application.
+ See
+ <seealso marker="public_key:application">public_key(3)</seealso>
+ for definition of #'OtpCertificate'{} and #'Extension'{}.</p>
+
+ <p>If the verify callback fun returns {fail, Reason}, the
+ verification process is immediately stopped and an alert is
+ sent to the peer and the TLS/SSL handshake is terminated. If
+ the verify callback fun returns {valid, UserState}, the
+ verification process is continued. If the verify callback fun
+ always returns {valid, UserState}, the TLS/SSL handshake will
+ not be terminated with respect to verification failures and
+ the connection will be established. If called with an
+ extension unknown to the user application the return value
+ {unknown, UserState} should be used.</p>
+
+ <p>The default verify_fun option in verify_peer mode:</p>
+
+ <code>
+{fun(_,{bad_cert, _} = Reason, _) ->
+ {fail, Reason};
+ (_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, UserState) ->
+ {valid, UserState}
+ end, []}
+ </code>
+
+ <p>The default verify_fun option in verify_none mode:</p>
+
+ <code>
+{fun(_,{bad_cert, unknown_ca}, UserState) ->
+ {valid, UserState};
+ (_,{bad_cert, _} = Reason, _) ->
+ {fail, Reason};
+ (_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, UserState) ->
+ {valid, UserState}
+ end, []}
+ </code>
+
+<p>Possible path validation errors: </p>
+
+<p> {bad_cert, cert_expired}, {bad_cert, invalid_issuer}, {bad_cert, invalid_signature}, {bad_cert, unknown_ca}, {bad_cert, name_not_permitted}, {bad_cert, missing_basic_constraint}, {bad_cert, invalid_key_usage}</p>
+ </item>
+
+ </taglist>
+
+ </section>
+
+ <section>
+ <title>SSL OPTION DESCRIPTIONS - CLIENT SIDE</title>
+
+ <p>Option described here are client specific or has a slightly different
+ meaning in the client than in the server.</p>
+
+ <taglist>
+ <tag>{verify, verify_type()}</tag>
+ <item> In verify_none mode the x509-path validation error {bad_cert, unknown_ca}
+ will automatically be accepted. See also the verify_fun option.
+ </item>
<tag>{reuse_sessions, boolean()}</tag>
- <item>Specifies if ssl sessions should be reused
- when possible.
+ <item>Specifies if client should try to reuse sessions
+ when possible.
</item>
- <tag>{reuse_session, fun(SuggestedSessionId,
- PeerCert, Compression, CipherSuite) -> boolean()}</tag>
+ </taglist>
+ </section>
+
+ <section>
+ <title>SSL OPTION DESCRIPTIONS - SERVER SIDE</title>
+
+ <p>Option described here are server specific or has a slightly different
+ meaning in the server than in the client.</p>
+
+ <taglist>
+
+ <tag>{dh, der_bin()}</tag>
+ <item>The DER encoded Diffie Hellman parameters. If this option
+ is supplied it will override the dhfile option.
+ </item>
+
+ <tag>{dhfile, path()}</tag>
+ <item>Path to file containing PEM encoded Diffie Hellman parameters,
+ for the server to use if a cipher suite using Diffie Hellman key exchange
+ is negotiated. If not specified default parameters will be used.
+ </item>
+
+ <tag>{verify, verify_type()}</tag>
+ <item>Servers only do the x509-path validation in verify_peer
+ mode, as it then will send a certificate request to the client
+ (this message is not sent if the verify option is verify_none)
+ and you may then also want to specify the option
+ fail_if_no_peer_cert.
+ </item>
+
+ <tag>{fail_if_no_peer_cert, boolean()}</tag>
+ <item>Used together with {verify, verify_peer} by a ssl server.
+ If set to true, the server will fail if the client does not have
+ a certificate to send, i.e. sends a empty certificate, if set to
+ false it will only fail if the client sends a invalid
+ certificate (an empty certificate is considered valid).
+ </item>
+
+ <tag>{reuse_sessions, boolean()}</tag>
+ <item>Specifies if the server should agree to reuse sessions
+ when the clients request to do so. See also the reuse_session
+ option.
+ </item>
+
+ <tag>{reuse_session, fun(SuggestedSessionId,
+ PeerCert, Compression, CipherSuite) -> boolean()}</tag>
<item>Enables the ssl server to have a local policy
for deciding if a session should be reused or not,
only meaning full if <c>reuse_sessions</c> is set to true.
@@ -252,14 +334,6 @@ end
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>
@@ -316,7 +390,7 @@ end
<v>Reason = term()</v>
</type>
<desc> <p>Upgrades a gen_tcp, or equivalent,
- connected socket to a ssl socket e.i performs the
+ connected socket to a ssl socket i.e. performs the
client-side ssl handshake.</p>
</desc>
</func>
@@ -559,12 +633,12 @@ end
</type>
<desc>
<p> Upgrades a gen_tcp, or
- equivalent, socket to a ssl socket e.i performs the
+ equivalent, socket to a ssl socket i.e. performs the
ssl server-side handshake.</p>
- <p><note>Note that the listen socket should be in {active, false} mode
+ <p><warning>Note that the listen socket should be in {active, false} mode
before telling the client that the server is ready to upgrade
and calling this function, otherwise the upgrade may
- or may not succeed depending on timing.</note></p>
+ or may not succeed depending on timing.</warning></p>
</desc>
</func>
diff --git a/lib/ssl/doc/src/ssl_distribution.xml b/lib/ssl/doc/src/ssl_distribution.xml
index 4067fb8a22..7bcc12eb5f 100644
--- a/lib/ssl/doc/src/ssl_distribution.xml
+++ b/lib/ssl/doc/src/ssl_distribution.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
- <year>2000</year><year>2009</year>
+ <year>2000</year><year>2010</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -36,7 +36,7 @@
<note><p>Note this
documentation is written for the old ssl implementation and
- will be updated for the new one once this functionallity is
+ will be updated for the new one once this functionality is
supported by the new implementation.</p></note>
</p>
@@ -55,7 +55,7 @@
all participating Erlang nodes in a distributed system must use
this distribution module.</p>
<p>The security depends on how the connections are set up, one can
- use key files or certificates to just get a crypted
+ use key files or certificates to just get a encrypted
connection. One can also make the SSL package verify the
certificates of other nodes to get additional security.
Cookies are however always used as they can be used to
@@ -179,7 +179,7 @@ Eshell V5.0 (abort with ^G)
<c>certfile</c> can (and usually needs to) be specified as
<c>client_certfile</c> and <c>server_certfile</c>. The
<c>client_certfile</c> is used when the distribution initiates a
- connection to another node and the <c>server_cerfile</c> is used
+ connection to another node and the <c>server_certfile</c> is used
when accepting a connection from a remote node. </p>
<p>The command line argument for specifying the SSL options is named
<c>-ssl_dist_opt</c> and should be followed by an even number of
diff --git a/lib/ssl/doc/src/ssl_protocol.xml b/lib/ssl/doc/src/ssl_protocol.xml
index 726b9a4eeb..6936408881 100644
--- a/lib/ssl/doc/src/ssl_protocol.xml
+++ b/lib/ssl/doc/src/ssl_protocol.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
<header>
<copyright>
- <year>2003</year><year>2009</year>
+ <year>2003</year><year>2010</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -44,7 +44,7 @@
<section>
<title>Security overview</title>
- <p>To achive authentication and privacy the client and server will
+ <p>To achieve 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
@@ -56,7 +56,7 @@
<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
+ used for both encryption and decryption. These algorithms 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.
@@ -66,7 +66,7 @@
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
+ <p>The TLS handshake 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
@@ -85,7 +85,7 @@
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
+ so called root certificate that is self signed i.e. issued
by itself.</p>
<p>Certificates are issued by <em>certification
diff --git a/lib/ssl/doc/src/ssl_session_cache_api.xml b/lib/ssl/doc/src/ssl_session_cache_api.xml
index 7b70c6cf34..e0b07961fb 100644
--- a/lib/ssl/doc/src/ssl_session_cache_api.xml
+++ b/lib/ssl/doc/src/ssl_session_cache_api.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
@@ -25,7 +25,7 @@
</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
+ that the data storage scheme can be replaced by
defining a new callback module implementing this API.</modulesummary>
<section>
@@ -56,7 +56,7 @@
<v> Key = key()</v>
</type>
<desc>
- <p> Delets a cache entry. Will only be called from the cache
+ <p> Deletes a cache entry. Will only be called from the cache
handling process.
</p>
</desc>
@@ -85,10 +85,10 @@
<v></v>
</type>
<desc>
- <p>Performes possible initializations of the cache and returns
+ <p>Performs 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
+ init function, hence putting the same requirements on it as
a normal process init function.
</p>
</desc>
@@ -96,16 +96,16 @@
<func>
<name>lookup(Cache, Key) -> Entry</name>
- <fsummary> Looks up a cach entry.</fsummary>
+ <fsummary> Looks up a cache 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>
+ <p>Looks up a cache entry. Should be callable from any
+ process.
+ </p>
</desc>
</func>
@@ -127,7 +127,7 @@
<func>
<name>terminate(Cache) -> _</name>
<fsummary>Called by the process that handles the cache when it
- is aboute to terminat.</fsummary>
+ is about to terminate.</fsummary>
<type>
<v>Cache = term() - as returned by init/0</v>
</type>
diff --git a/lib/ssl/examples/certs/Makefile b/lib/ssl/examples/certs/Makefile
index 121fcc6950..b811b461dc 100644
--- a/lib/ssl/examples/certs/Makefile
+++ b/lib/ssl/examples/certs/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2009. All Rights Reserved.
+# Copyright Ericsson AB 2003-2010. All Rights Reserved.
#
# 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
@@ -21,4 +21,41 @@
# Invoke with GNU make or clearmake -C gnu.
#
-include $(ERL_TOP)/make/run_make.mk
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN=$(SSL_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/ssl-$(VSN)
+
+TARGET_FILES=
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+debug opt: $(TARGET_FILES)
+
+clean:
+ rm -fr $(TARGET_FILES) *~ *.beam
+
+docs:
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/examples/certs
+ tar cf - etc | \
+ (cd $(RELSYSDIR)/examples/certs; tar xf -)
+ chmod -f -R ug+rw $(RELSYSDIR)/examples
+release_docs_spec:
diff --git a/lib/ssl/examples/certs/Makefile.in b/lib/ssl/examples/certs/Makefile.in
deleted file mode 100644
index 4ea7aaf6dc..0000000000
--- a/lib/ssl/examples/certs/Makefile.in
+++ /dev/null
@@ -1,80 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2003-2009. All Rights Reserved.
-#
-# 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.
-#
-# %CopyrightEnd%
-#
-
-#
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-include ../../vsn.mk
-VSN=$(SSL_VSN)
-
-RELSYSDIR = $(RELEASE_PATH)/lib/ssl-$(VSN)
-
-EBIN = ebin
-ETC = etc
-SRC = src
-
-OPENSSL_CMD = @OPENSSL_CMD@
-
-# We are generating more files than in the following list, but we take
-# there existence as successful execution of make rules
-
-PEMS = cacerts.pem cert.pem key.pem
-
-PEMFILES = $(PEMS:%=$(ETC)/client/%) $(PEMS:%=$(ETC)/server/%)
-
-debug opt: $(PEMFILES)
-
-$(PEMFILES): done
-
-done: $(EBIN)/make_certs.beam
- erl -noinput -pa $(EBIN) -run make_certs all $(OPENSSL_CMD) \
- -s erlang halt
- echo >done
-
-$(EBIN)/make_certs.beam: $(SRC)/make_certs.erl
- cd src; erlc -W -o ../$(EBIN) make_certs.erl
-
-clean:
- rm -fr $(EBIN)/* $(SRC)/*~ $(SRC)/*.beam $(ETC) done \
- stderr.txt erl_crash.dump *~
-
-docs:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/examples/certs
- tar cf - Makefile ebin etc rnd src | \
- (cd $(RELSYSDIR)/examples/certs; tar xf -)
- chmod -f -R ug+rw $(RELSYSDIR)/examples
-
-release_docs_spec:
-
-
-
-
-
-
-
-
diff --git a/lib/ssl/examples/certs/ebin/.gitignore b/lib/ssl/examples/certs/ebin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/ssl/examples/certs/ebin/.gitignore
+++ /dev/null
diff --git a/lib/ssl/examples/certs/etc/client/cacerts.pem b/lib/ssl/examples/certs/etc/client/cacerts.pem
new file mode 100644
index 0000000000..cb19d3d41e
--- /dev/null
+++ b/lib/ssl/examples/certs/etc/client/cacerts.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIICizCCAfSgAwIBAgIFdMMs9fEwDQYJKoZIhvcNAQEFBQAwfTERMA8GA1UEAxMI
+ZXJsYW5nQ0ExIDAeBgkqhkiG9w0BCQEWEXRlc3RlckBlcmxhbmcub3JnMRIwEAYD
+VQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYTAlNFMQ8wDQYDVQQKEwZlcmxhbmcxFDAS
+BgNVBAsTC3Rlc3RpbmcgZGVwMCIYDzIwMTAwOTAxMDAwMDAwWhgPMjAyNTA4Mjgw
+MDAwMDBaMH0xETAPBgNVBAMTCGVybGFuZ0NBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0
+ZXJAZXJsYW5nLm9yZzESMBAGA1UEBxMJU3RvY2tob2xtMQswCQYDVQQGEwJTRTEP
+MA0GA1UEChMGZXJsYW5nMRQwEgYDVQQLEwt0ZXN0aW5nIGRlcDCBnzANBgkqhkiG
+9w0BAQEFAAOBjQAwgYkCgYEAgmHw2xApZqdzZOOPTzwHr1hRYd1OqbLOsXbAq6kJ
+Kuu+qe5jAlMF3vnUhiHomuZeNZVJe3SP+JfBt3BHMjm2CLChCuNgfctKURMlEc/L
+xo8fO1Jk9MD5mbG2Utx3m3gM6Liwt9fHVABlCTyB6/jXrK1tYpEG5CrwUXyy8Htl
+jHECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAl
+0tMEXWPgzXTpDuNmuKh6aGq9CuExUuEXXQQWPThzEuluA3aHFmObziQlMY1+KeO1
+AL0kpx0Yhvju/rfAJ+OF6MMni6hJoKlYTVml+fCY89A3nmY1rJHJavjHp0OIPGxh
+4Sr+EcjROkqe8jE0DmbwmM6lzpwSJscxte+V6HvGRw==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICiDCCAfGgAwIBAgIFSHyFNTEwDQYJKoZIhvcNAQEFBQAwfTERMA8GA1UEAxMI
+ZXJsYW5nQ0ExIDAeBgkqhkiG9w0BCQEWEXRlc3RlckBlcmxhbmcub3JnMRIwEAYD
+VQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYTAlNFMQ8wDQYDVQQKEwZlcmxhbmcxFDAS
+BgNVBAsTC3Rlc3RpbmcgZGVwMCIYDzIwMTAwOTAxMDAwMDAwWhgPMjAyNTA4Mjgw
+MDAwMDBaMHoxDjAMBgNVBAMTBW90cENBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0ZXJA
+ZXJsYW5nLm9yZzESMBAGA1UEBxMJU3RvY2tob2xtMQswCQYDVQQGEwJTRTEPMA0G
+A1UEChMGZXJsYW5nMRQwEgYDVQQLEwt0ZXN0aW5nIGRlcDCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAjEt9iy365+mTialKDKb3l2QPg71yavJA1ZC6aGC14X7x
+KCm1FhUYsVKOlWjmC1VYJiCS01gvKqMXiogreHJGM93E+URlKkOm9kmOWQwLfFb8
+JLzafPi3/8TUdjl8UuIDHyPsoQiM2ZBDUVWezfl+CBsTYFO3U4Lqf9OKbCxTF78C
+AwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAv6vHw
+wK3MvxzlhDJIx7rUasOYJDZJyOt71KdOKeA7+ocbvDIblmV7sTbe3oQNqbSATZ6H
+RUqHZdPhKIZ9wjEBSKdBTL8rc0TvbztMvd+i0rkTCL/bspQYchA2zCcjgkWqpaN4
+OhOjQR1+9/ntmaU/r5Ca7KmrXEf5XSQIGLSMag==
+-----END CERTIFICATE-----
+
diff --git a/lib/ssl/examples/certs/etc/client/cert.pem b/lib/ssl/examples/certs/etc/client/cert.pem
new file mode 100644
index 0000000000..a2f53aaf82
--- /dev/null
+++ b/lib/ssl/examples/certs/etc/client/cert.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIIChzCCAfCgAwIBAgIGAIsapa8BMA0GCSqGSIb3DQEBBQUAMHoxDjAMBgNVBAMT
+BW90cENBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0ZXJAZXJsYW5nLm9yZzESMBAGA1UE
+BxMJU3RvY2tob2xtMQswCQYDVQQGEwJTRTEPMA0GA1UEChMGZXJsYW5nMRQwEgYD
+VQQLEwt0ZXN0aW5nIGRlcDAiGA8yMDEwMDkwMTAwMDAwMFoYDzIwMjUwODI4MDAw
+MDAwWjB7MQ8wDQYDVQQDEwZjbGllbnQxIDAeBgkqhkiG9w0BCQEWEXRlc3RlckBl
+cmxhbmcub3JnMRIwEAYDVQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYTAlNFMQ8wDQYD
+VQQKEwZlcmxhbmcxFDASBgNVBAsTC3Rlc3RpbmcgZGVwMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQCTFBPkOO98fDY3j6MIxIGKp+rampfIay50Lx4+EnCnRSSV
+wC+n0VVmP7V5SGFJpuXJzN0hvqPUWOOjiMTNlNRaGy0pqu2oMXWAPLOxHWL1wT53
+h2Zr3FUNU/N0Rvnkttse1KZJ9uYCLKUiuXXsv2rR62nH3OhRIiBHSAcSv0NRWwID
+AQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAG8t6f1A
+PF7xayGxtUpG2r6W5ETylC3ZIKPS2kfJk9aYi7AZNTp7/xTU6SgqvFBN8aBPzxCD
+4jHrSNC8DSb4X1x9uimarb6qdZDHEdij+DRAd2eygJHZxEf7+8B4Fx34thQeU9hZ
+S1Izke5AlsyFMkvB7h0anE4k9BfuU70vl6v5
+-----END CERTIFICATE-----
+
diff --git a/lib/ssl/examples/certs/etc/client/key.pem b/lib/ssl/examples/certs/etc/client/key.pem
new file mode 100644
index 0000000000..4d55b08f4c
--- /dev/null
+++ b/lib/ssl/examples/certs/etc/client/key.pem
@@ -0,0 +1,16 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQCTFBPkOO98fDY3j6MIxIGKp+rampfIay50Lx4+EnCnRSSVwC+n
+0VVmP7V5SGFJpuXJzN0hvqPUWOOjiMTNlNRaGy0pqu2oMXWAPLOxHWL1wT53h2Zr
+3FUNU/N0Rvnkttse1KZJ9uYCLKUiuXXsv2rR62nH3OhRIiBHSAcSv0NRWwIDAQAB
+AoGACdIVYe/LTeydUihtInC8lZ2QuPgJmoBNocRjqJFipEihoL4scHAx25n1bBvB
+I0HZphffzBkGp28oBAtl2LRPWXqu527unc/RWRfLMqSK1xNSq1DxD1a30zkrZPna
+QiV65vEJuNSJTtlDy/Zqc/BVZXCpxWlzYQedZgkmf0Qse8ECQQCmaz02Yur8zC9f
+eSQKU5OSzGw3bSIumEzziCfHdTheK6MEoccf5TCAyLXhZwA7QlKja4tFXfeyVxws
+/LlnUJN9AkEA4j+xnOeYUyGKXL5i+BAbnqpI4MzPiq+IoCYkaRlD/wAws24r5HNI
+ZQmEHWqD/NNzOf/A2XuyLtMiTGJPW/DftwJBAKKpJP6Ytuh6xz8BUCnLwO12Y7vV
+LtjuQiCzD3aUa5EYA9HOMqxJPxxRkf0LyR0i2VUkE8+sZiPpov+R0cJa7p0CQQCj
+40GUiArGRSiF7/+e84QeVfl+pb29F1QftiFv5DZmFEwy3Z572KpbTh5edJbxYHY6
+UDHxGHJFCvnwXNJhpkVXAkBJqfEfiMJ3Q/E5Gpf3sQizacouW92iiN8ojlF1oB80
+t34RysJH7SgI3gdMhTribCo2UUaV0StjR6yodPN+TB2J
+-----END RSA PRIVATE KEY-----
+
diff --git a/lib/ssl/examples/certs/etc/erlangCA/cert.pem b/lib/ssl/examples/certs/etc/erlangCA/cert.pem
new file mode 100644
index 0000000000..c4386494dc
--- /dev/null
+++ b/lib/ssl/examples/certs/etc/erlangCA/cert.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICizCCAfSgAwIBAgIFdMMs9fEwDQYJKoZIhvcNAQEFBQAwfTERMA8GA1UEAxMI
+ZXJsYW5nQ0ExIDAeBgkqhkiG9w0BCQEWEXRlc3RlckBlcmxhbmcub3JnMRIwEAYD
+VQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYTAlNFMQ8wDQYDVQQKEwZlcmxhbmcxFDAS
+BgNVBAsTC3Rlc3RpbmcgZGVwMCIYDzIwMTAwOTAxMDAwMDAwWhgPMjAyNTA4Mjgw
+MDAwMDBaMH0xETAPBgNVBAMTCGVybGFuZ0NBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0
+ZXJAZXJsYW5nLm9yZzESMBAGA1UEBxMJU3RvY2tob2xtMQswCQYDVQQGEwJTRTEP
+MA0GA1UEChMGZXJsYW5nMRQwEgYDVQQLEwt0ZXN0aW5nIGRlcDCBnzANBgkqhkiG
+9w0BAQEFAAOBjQAwgYkCgYEAgmHw2xApZqdzZOOPTzwHr1hRYd1OqbLOsXbAq6kJ
+Kuu+qe5jAlMF3vnUhiHomuZeNZVJe3SP+JfBt3BHMjm2CLChCuNgfctKURMlEc/L
+xo8fO1Jk9MD5mbG2Utx3m3gM6Liwt9fHVABlCTyB6/jXrK1tYpEG5CrwUXyy8Htl
+jHECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAl
+0tMEXWPgzXTpDuNmuKh6aGq9CuExUuEXXQQWPThzEuluA3aHFmObziQlMY1+KeO1
+AL0kpx0Yhvju/rfAJ+OF6MMni6hJoKlYTVml+fCY89A3nmY1rJHJavjHp0OIPGxh
+4Sr+EcjROkqe8jE0DmbwmM6lzpwSJscxte+V6HvGRw==
+-----END CERTIFICATE-----
+
diff --git a/lib/ssl/examples/certs/etc/otpCA/cert.pem b/lib/ssl/examples/certs/etc/otpCA/cert.pem
new file mode 100644
index 0000000000..8610621695
--- /dev/null
+++ b/lib/ssl/examples/certs/etc/otpCA/cert.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICiDCCAfGgAwIBAgIFSHyFNTEwDQYJKoZIhvcNAQEFBQAwfTERMA8GA1UEAxMI
+ZXJsYW5nQ0ExIDAeBgkqhkiG9w0BCQEWEXRlc3RlckBlcmxhbmcub3JnMRIwEAYD
+VQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYTAlNFMQ8wDQYDVQQKEwZlcmxhbmcxFDAS
+BgNVBAsTC3Rlc3RpbmcgZGVwMCIYDzIwMTAwOTAxMDAwMDAwWhgPMjAyNTA4Mjgw
+MDAwMDBaMHoxDjAMBgNVBAMTBW90cENBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0ZXJA
+ZXJsYW5nLm9yZzESMBAGA1UEBxMJU3RvY2tob2xtMQswCQYDVQQGEwJTRTEPMA0G
+A1UEChMGZXJsYW5nMRQwEgYDVQQLEwt0ZXN0aW5nIGRlcDCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAjEt9iy365+mTialKDKb3l2QPg71yavJA1ZC6aGC14X7x
+KCm1FhUYsVKOlWjmC1VYJiCS01gvKqMXiogreHJGM93E+URlKkOm9kmOWQwLfFb8
+JLzafPi3/8TUdjl8UuIDHyPsoQiM2ZBDUVWezfl+CBsTYFO3U4Lqf9OKbCxTF78C
+AwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAv6vHw
+wK3MvxzlhDJIx7rUasOYJDZJyOt71KdOKeA7+ocbvDIblmV7sTbe3oQNqbSATZ6H
+RUqHZdPhKIZ9wjEBSKdBTL8rc0TvbztMvd+i0rkTCL/bspQYchA2zCcjgkWqpaN4
+OhOjQR1+9/ntmaU/r5Ca7KmrXEf5XSQIGLSMag==
+-----END CERTIFICATE-----
+
diff --git a/lib/ssl/examples/certs/etc/server/cacerts.pem b/lib/ssl/examples/certs/etc/server/cacerts.pem
new file mode 100644
index 0000000000..cb19d3d41e
--- /dev/null
+++ b/lib/ssl/examples/certs/etc/server/cacerts.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIICizCCAfSgAwIBAgIFdMMs9fEwDQYJKoZIhvcNAQEFBQAwfTERMA8GA1UEAxMI
+ZXJsYW5nQ0ExIDAeBgkqhkiG9w0BCQEWEXRlc3RlckBlcmxhbmcub3JnMRIwEAYD
+VQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYTAlNFMQ8wDQYDVQQKEwZlcmxhbmcxFDAS
+BgNVBAsTC3Rlc3RpbmcgZGVwMCIYDzIwMTAwOTAxMDAwMDAwWhgPMjAyNTA4Mjgw
+MDAwMDBaMH0xETAPBgNVBAMTCGVybGFuZ0NBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0
+ZXJAZXJsYW5nLm9yZzESMBAGA1UEBxMJU3RvY2tob2xtMQswCQYDVQQGEwJTRTEP
+MA0GA1UEChMGZXJsYW5nMRQwEgYDVQQLEwt0ZXN0aW5nIGRlcDCBnzANBgkqhkiG
+9w0BAQEFAAOBjQAwgYkCgYEAgmHw2xApZqdzZOOPTzwHr1hRYd1OqbLOsXbAq6kJ
+Kuu+qe5jAlMF3vnUhiHomuZeNZVJe3SP+JfBt3BHMjm2CLChCuNgfctKURMlEc/L
+xo8fO1Jk9MD5mbG2Utx3m3gM6Liwt9fHVABlCTyB6/jXrK1tYpEG5CrwUXyy8Htl
+jHECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAl
+0tMEXWPgzXTpDuNmuKh6aGq9CuExUuEXXQQWPThzEuluA3aHFmObziQlMY1+KeO1
+AL0kpx0Yhvju/rfAJ+OF6MMni6hJoKlYTVml+fCY89A3nmY1rJHJavjHp0OIPGxh
+4Sr+EcjROkqe8jE0DmbwmM6lzpwSJscxte+V6HvGRw==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICiDCCAfGgAwIBAgIFSHyFNTEwDQYJKoZIhvcNAQEFBQAwfTERMA8GA1UEAxMI
+ZXJsYW5nQ0ExIDAeBgkqhkiG9w0BCQEWEXRlc3RlckBlcmxhbmcub3JnMRIwEAYD
+VQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYTAlNFMQ8wDQYDVQQKEwZlcmxhbmcxFDAS
+BgNVBAsTC3Rlc3RpbmcgZGVwMCIYDzIwMTAwOTAxMDAwMDAwWhgPMjAyNTA4Mjgw
+MDAwMDBaMHoxDjAMBgNVBAMTBW90cENBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0ZXJA
+ZXJsYW5nLm9yZzESMBAGA1UEBxMJU3RvY2tob2xtMQswCQYDVQQGEwJTRTEPMA0G
+A1UEChMGZXJsYW5nMRQwEgYDVQQLEwt0ZXN0aW5nIGRlcDCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAjEt9iy365+mTialKDKb3l2QPg71yavJA1ZC6aGC14X7x
+KCm1FhUYsVKOlWjmC1VYJiCS01gvKqMXiogreHJGM93E+URlKkOm9kmOWQwLfFb8
+JLzafPi3/8TUdjl8UuIDHyPsoQiM2ZBDUVWezfl+CBsTYFO3U4Lqf9OKbCxTF78C
+AwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAv6vHw
+wK3MvxzlhDJIx7rUasOYJDZJyOt71KdOKeA7+ocbvDIblmV7sTbe3oQNqbSATZ6H
+RUqHZdPhKIZ9wjEBSKdBTL8rc0TvbztMvd+i0rkTCL/bspQYchA2zCcjgkWqpaN4
+OhOjQR1+9/ntmaU/r5Ca7KmrXEf5XSQIGLSMag==
+-----END CERTIFICATE-----
+
diff --git a/lib/ssl/examples/certs/etc/server/cert.pem b/lib/ssl/examples/certs/etc/server/cert.pem
new file mode 100644
index 0000000000..f26adb7f5c
--- /dev/null
+++ b/lib/ssl/examples/certs/etc/server/cert.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIIChzCCAfCgAwIBAgIGANUxXM9BMA0GCSqGSIb3DQEBBQUAMHoxDjAMBgNVBAMT
+BW90cENBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0ZXJAZXJsYW5nLm9yZzESMBAGA1UE
+BxMJU3RvY2tob2xtMQswCQYDVQQGEwJTRTEPMA0GA1UEChMGZXJsYW5nMRQwEgYD
+VQQLEwt0ZXN0aW5nIGRlcDAiGA8yMDEwMDkwMTAwMDAwMFoYDzIwMjUwODI4MDAw
+MDAwWjB7MQ8wDQYDVQQDEwZzZXJ2ZXIxIDAeBgkqhkiG9w0BCQEWEXRlc3RlckBl
+cmxhbmcub3JnMRIwEAYDVQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYTAlNFMQ8wDQYD
+VQQKEwZlcmxhbmcxFDASBgNVBAsTC3Rlc3RpbmcgZGVwMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQCf4Htxr99lLs5W8QQw7jdakqyAkIjOW4aqH8sr4va4SvZ9
+Adq67k8jMHefCVZo+F8x4cwsBgB4aWzFIGBnvFTi6YsH27XW7f9O9IPCej8fdhRZ
+4UAtNHa253buOWpDGla2JmIdkmfFvXFJycMIKbG5tYilVXoWKBMKmCwWaXz0nQID
+AQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAGF5Pfwk
+QDdwJup/mVITPxbBls4Yl7anDooUQsq8066lA1g54H/PRfXscGkyCFGh1ifXvf1L
+psMRoBAdDHL/wSJplk3rRavkC94eBgnTFZmfKL6844g1j53yameiYL8IEVExYMBg
+/XGyc0qwq57WT8B/K4aElrvlBlQ0wF3wN54M
+-----END CERTIFICATE-----
+
diff --git a/lib/ssl/examples/certs/etc/server/key.pem b/lib/ssl/examples/certs/etc/server/key.pem
new file mode 100644
index 0000000000..c1392ca557
--- /dev/null
+++ b/lib/ssl/examples/certs/etc/server/key.pem
@@ -0,0 +1,16 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQCf4Htxr99lLs5W8QQw7jdakqyAkIjOW4aqH8sr4va4SvZ9Adq6
+7k8jMHefCVZo+F8x4cwsBgB4aWzFIGBnvFTi6YsH27XW7f9O9IPCej8fdhRZ4UAt
+NHa253buOWpDGla2JmIdkmfFvXFJycMIKbG5tYilVXoWKBMKmCwWaXz0nQIDAQAB
+AoGAQIlma0r6W6bcRj4+Wd4fXCFvHuq5Psu1fYEeC5Yvz8761xVjjSfbrDHJZ9pm
+FjOEgedK+s5lbDXqYVyjbdyZSugStBRocSmbG8SQHcAsxR2ZIkNzX2hYzB+lslWo
+T3YJojDyB134O7XJznCu+ZFXP86jyJ1JT6k6a+OIHcwnJ+ECQQDYn57dY4Px3mEd
+VBLStN3YkRF5oFyT+xk7IaKeLLB6n4gCnoVbBoHut7PFbPYPzoNzEwPk3MQKDIHb
+Kig3S5CpAkEAvPA1VmoJWAlN6kUi+F2L8HXEArzE8x7vwdsslrwMKUe4dFS+ZC/7
+5iDOaxcZ7TYkCgwzBt341++DCgP6j3fY1QJBALB6AcOcwi52m6l4B8mu3ZkEPjdX
+BHTuONTqhv/TqoaLlxODL2NDvvDKqeMp7KBd/srt79swW2lQXS4+fvrlTdkCQQCm
+zxj4O1QWkthkfje6ubSkTwUIOatUzrp1F9GNH2dJRtX2dx9FCwxGCC7WY6XzRXqa
+GF0wsedSllbGD+82nWQlAkAicMGqCqRq4hKR/cVmFatOqKVWCVkx6OFF2FhuiI5Z
+h5eIOPGCt8dVRs1P9DNSld/D98Sfm65m85z8BtXovvYV
+-----END RSA PRIVATE KEY-----
+
diff --git a/lib/ssl/examples/certs/rnd/RAND b/lib/ssl/examples/certs/rnd/RAND
deleted file mode 100644
index 70997bd01f..0000000000
--- a/lib/ssl/examples/certs/rnd/RAND
+++ /dev/null
Binary files differ
diff --git a/lib/ssl/examples/certs/src/make_certs.erl b/lib/ssl/examples/certs/src/make_certs.erl
index c374836568..fe267bed28 100644
--- a/lib/ssl/examples/certs/src/make_certs.erl
+++ b/lib/ssl/examples/certs/src/make_certs.erl
@@ -1,261 +1,48 @@
-%% The purpose of this module is to create example certificates for
-%% testing.
-%% Run it as:
-%%
-%% erl -noinput -run make_certs all "/path/to/openssl" -s erlang halt
-%%
+%% The purpose of this module is to log how the example certs where created,
+%% it requires erl_make_certs found in the test directory.
-module(make_certs).
--export([all/0, all/1]).
-
--record(dn, {commonName,
- organizationalUnitName = "Erlang OTP",
- organizationName = "Ericsson AB",
- localityName = "Stockholm",
- countryName = "SE",
- emailAddress = "[email protected]"}).
+-export([all/0]).
all() ->
- all(["openssl"]).
-
-all([OpenSSLCmd]) ->
- Root = filename:dirname(filename:dirname((code:which(?MODULE)))),
- %% io:fwrite("Root : ~s~n", [Root]),
- NRoot = filename:join([Root, "etc"]),
- file:make_dir(NRoot),
- create_rnd(Root, "etc"), % For all requests
- rootCA(NRoot, OpenSSLCmd, "erlangCA"),
- intermediateCA(NRoot, OpenSSLCmd, "otpCA", "erlangCA"),
- endusers(NRoot, OpenSSLCmd, "otpCA", ["client", "server"]),
- collect_certs(NRoot, ["erlangCA", "otpCA"], ["client", "server"]),
- remove_rnd(Root, "etc").
-
-rootCA(Root, OpenSSLCmd, Name) ->
- create_ca_dir(Root, Name, ca_cnf(Name)),
- DN = #dn{commonName = Name},
- create_self_signed_cert(Root, OpenSSLCmd, Name, req_cnf(DN)),
- ok.
-
-intermediateCA(Root, OpenSSLCmd, CA, ParentCA) ->
- CA = "otpCA",
- create_ca_dir(Root, CA, ca_cnf(CA)),
- CARoot = filename:join([Root, CA]),
- DN = #dn{commonName = CA},
- CnfFile = filename:join([CARoot, "req.cnf"]),
- file:write_file(CnfFile, req_cnf(DN)),
- KeyFile = filename:join([CARoot, "private", "key.pem"]),
- ReqFile = filename:join([CARoot, "req.pem"]),
- create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile),
- CertFile = filename:join([CARoot, "cert.pem"]),
- sign_req(Root, OpenSSLCmd, ParentCA, "ca_cert", ReqFile, CertFile).
-
-endusers(Root, OpenSSLCmd, CA, Users) ->
- lists:foreach(fun(User) -> enduser(Root, OpenSSLCmd, CA, User) end, Users).
-
-enduser(Root, OpenSSLCmd, CA, User) ->
- UsrRoot = filename:join([Root, User]),
- file:make_dir(UsrRoot),
- CnfFile = filename:join([UsrRoot, "req.cnf"]),
- DN = #dn{commonName = User},
- file:write_file(CnfFile, req_cnf(DN)),
- 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).
-
-collect_certs(Root, CAs, Users) ->
- Bins = lists:foldr(
- fun(CA, Acc) ->
- File = filename:join([Root, CA, "cert.pem"]),
- {ok, Bin} = file:read_file(File),
- [Bin, "\n" | Acc]
- end, [], CAs),
- lists:foreach(
- fun(User) ->
- File = filename:join([Root, User, "cacerts.pem"]),
- file:write_file(File, Bins)
- end, Users).
-
-create_self_signed_cert(Root, OpenSSLCmd, CAName, Cnf) ->
- CARoot = filename:join([Root, CAName]),
- CnfFile = filename:join([CARoot, "req.cnf"]),
- file:write_file(CnfFile, Cnf),
- KeyFile = filename:join([CARoot, "private", "key.pem"]),
- CertFile = filename:join([CARoot, "cert.pem"]),
- Cmd = [OpenSSLCmd, " req"
- " -new"
- " -x509"
- " -config ", CnfFile,
- " -keyout ", KeyFile,
- " -out ", CertFile],
- Env = [{"ROOTDIR", Root}],
- cmd(Cmd, Env).
-
-create_ca_dir(Root, CAName, Cnf) ->
- CARoot = filename:join([Root, CAName]),
- file:make_dir(CARoot),
- create_dirs(CARoot, ["certs", "crl", "newcerts", "private"]),
- create_rnd(Root, filename:join([CAName, "private"])),
- create_files(CARoot, [{"serial", "01\n"},
- {"index.txt", ""},
- {"ca.cnf", Cnf}]).
-
-create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile) ->
- Cmd = [OpenSSLCmd, " req"
- " -new"
- " -config ", CnfFile,
- " -keyout ", KeyFile,
- " -out ", ReqFile],
- Env = [{"ROOTDIR", Root}],
- cmd(Cmd, Env).
-
-sign_req(Root, OpenSSLCmd, CA, CertType, ReqFile, CertFile) ->
- CACnfFile = filename:join([Root, CA, "ca.cnf"]),
- Cmd = [OpenSSLCmd, " ca"
- " -batch"
- " -notext"
- " -config ", CACnfFile,
- " -extensions ", CertType,
- " -in ", ReqFile,
- " -out ", CertFile],
- Env = [{"ROOTDIR", Root}],
- cmd(Cmd, Env).
+ LongTime = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())+15*365),
+ Validity = {date(), LongTime},
+ Subject = [{email, "[email protected]"},
+ {city, "Stockholm"},
+ {country, "SE"},
+ {org, "erlang"},
+ {org_unit, "testing dep"}],
+
+ RootCa = erl_make_certs:make_cert([{validity, Validity}, {subject, [{name, "erlangCA"}|Subject]}]),
+ ImedCa = erl_make_certs:make_cert([{issuer, RootCa}, {validity, Validity},
+ {subject, [{name, "otpCA"}|Subject]}]),
+ ClientCa = erl_make_certs:make_cert([{issuer, ImedCa}, {validity, Validity},
+ {subject, [{name, "client"}|Subject]}]),
+ ServerCa = erl_make_certs:make_cert([{issuer, ImedCa}, {validity, Validity},
+ {subject, [{name, "server"}|Subject]}]),
+
+ Root0 = filename:dirname(filename:dirname((code:which(?MODULE)))),
+ Root = filename:join([Root0, "etc"]), file:make_dir(Root),
+ CaPath = filename:join([Root, "erlangCA"]), file:make_dir(CaPath),
+ IPath = filename:join([Root, "otpCA"]), file:make_dir(IPath),
+ CPath = filename:join([Root, "client"]), file:make_dir(CPath),
+ SPath = filename:join([Root, "server"]), file:make_dir(SPath),
+
+ erl_make_certs:write_pem(CaPath,"cert", RootCa),
+ erl_make_certs:write_pem(IPath, "cert", ImedCa),
+
+ {ok, CaBin0} = file:read_file(filename:join(CaPath, "cert.pem")),
+ {ok, CaBin1} = file:read_file(filename:join(IPath, "cert.pem")),
+ CaBin = <<CaBin0/binary, CaBin1/binary>>,
+
+ erl_make_certs:write_pem(CPath, "cert", ClientCa),
+ ok = file:write_file(filename:join(CPath, "cacerts.pem"), CaBin),
+ erl_make_certs:write_pem(SPath, "cert", ServerCa),
+ ok = file:write_file(filename:join(SPath, "cacerts.pem"), CaBin),
-%%
-%% Misc
-%%
-
-create_dirs(Root, Dirs) ->
- lists:foreach(fun(Dir) ->
- file:make_dir(filename:join([Root, Dir])) end,
- Dirs).
-
-create_files(Root, NameContents) ->
- lists:foreach(
- fun({Name, Contents}) ->
- file:write_file(filename:join([Root, Name]), Contents) end,
- NameContents).
-
-create_rnd(Root, Dir) ->
- From = filename:join([Root, "rnd", "RAND"]),
- To = filename:join([Root, Dir, "RAND"]),
- file:copy(From, To).
-
-remove_rnd(Root, Dir) ->
- File = filename:join([Root, Dir, "RAND"]),
- file:delete(File).
-
-cmd(Cmd, Env) ->
- FCmd = lists:flatten(Cmd),
- Port = open_port({spawn, FCmd}, [stream, eof, exit_status,
- {env, Env}]),
- eval_cmd(Port).
-
-eval_cmd(Port) ->
- receive
- {Port, {data, _}} ->
- eval_cmd(Port);
- {Port, eof} ->
- ok
- end,
- receive
- {Port, {exit_status, Status}} when Status /= 0 ->
- %% io:fwrite("exit status: ~w~n", [Status]),
- erlang:halt(Status)
- after 0 ->
- ok
- end.
-
-%%
-%% Contents of configuration files
-%%
-
-req_cnf(DN) ->
- ["# Purpose: Configuration for requests (end users and CAs)."
- "\n"
- "ROOTDIR = $ENV::ROOTDIR\n"
- "\n"
-
- "[req]\n"
- "input_password = secret\n"
- "output_password = secret\n"
- "default_bits = 1024\n"
- "RANDFILE = $ROOTDIR/RAND\n"
- "encrypt_key = no\n"
- "default_md = sha1\n"
- "#string_mask = pkix\n"
- "x509_extensions = ca_ext\n"
- "prompt = no\n"
- "distinguished_name= name\n"
- "\n"
-
- "[name]\n"
- "commonName = ", DN#dn.commonName, "\n"
- "organizationalUnitName = ", DN#dn.organizationalUnitName, "\n"
- "organizationName = ", DN#dn.organizationName, "\n"
- "localityName = ", DN#dn.localityName, "\n"
- "countryName = ", DN#dn.countryName, "\n"
- "emailAddress = ", DN#dn.emailAddress, "\n"
- "\n"
-
- "[ca_ext]\n"
- "basicConstraints = critical, CA:true\n"
- "keyUsage = cRLSign, keyCertSign\n"
- "subjectKeyIdentifier = hash\n"
- "subjectAltName = email:copy\n"].
-
-
-ca_cnf(CA) ->
- ["# Purpose: Configuration for CAs.\n"
- "\n"
- "ROOTDIR = $ENV::ROOTDIR\n"
- "default_ca = ca\n"
- "\n"
-
- "[ca]\n"
- "dir = $ROOTDIR/", CA, "\n"
- "certs = $dir/certs\n"
- "crl_dir = $dir/crl\n"
- "database = $dir/index.txt\n"
- "new_certs_dir = $dir/newcerts\n"
- "certificate = $dir/cert.pem\n"
- "serial = $dir/serial\n"
- "crl = $dir/crl.pem\n"
- "private_key = $dir/private/key.pem\n"
- "RANDFILE = $dir/private/RAND\n"
- "\n"
- "x509_extensions = user_cert\n"
- "default_days = 3600\n"
- "default_md = sha1\n"
- "preserve = no\n"
- "policy = policy_match\n"
- "\n"
-
- "[policy_match]\n"
- "commonName = supplied\n"
- "organizationalUnitName = optional\n"
- "organizationName = match\n"
- "countryName = match\n"
- "localityName = match\n"
- "emailAddress = supplied\n"
- "\n"
-
- "[user_cert]\n"
- "basicConstraints = CA:false\n"
- "keyUsage = nonRepudiation, digitalSignature, keyEncipherment\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"
- "subjectKeyIdentifier = hash\n"
- "authorityKeyIdentifier = keyid:always,issuer:always\n"
- "subjectAltName = email:copy\n"
- "issuerAltName = issuer:copy\n"].
-
+ file:delete(filename:join(CaPath, "cert_key.pem")),
+ file:delete(filename:join(IPath, "cert_key.pem")),
+ file:rename(filename:join(CPath, "cert_key.pem"), filename:join(CPath, "key.pem")),
+ file:rename(filename:join(SPath, "cert_key.pem"), filename:join(SPath, "key.pem")),
+ ok.
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 6e26f05c3d..12dffb413c 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -80,6 +80,7 @@ stop() ->
-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.
%%--------------------------------------------------------------------
@@ -375,7 +376,7 @@ cipher_suites(openssl) ->
[ssl_cipher:openssl_suite_name(S) || S <- ssl_cipher:suites(Version)].
%%--------------------------------------------------------------------
--spec getopts(#sslsocket{}, [atom()]) -> {ok, [{atom(), term()}]}| {error, reason()}.
+-spec getopts(#sslsocket{}, [atom()]) -> {ok, [{atom(), term()}]}| {error, reason()}.
%%
%% Description:
%%--------------------------------------------------------------------
@@ -522,59 +523,66 @@ old_listen(Port, Options) ->
{ok, Pid} = ssl_broker:start_broker(listener),
ssl_broker:listen(Pid, Port, Options).
-handle_options(Opts0, Role) ->
+handle_options(Opts0, _Role) ->
Opts = proplists:expand([{binary, [{mode, binary}]},
{list, [{mode, list}]}], Opts0),
ReuseSessionFun = fun(_, _, _, _) -> true end,
- AcceptBadCa = fun({bad_cert,unknown_ca}, Acc) -> Acc;
- (Other, Acc) -> [Other | Acc]
- end,
-
- VerifyFun =
- fun(ErrorList) ->
- case lists:foldl(AcceptBadCa, [], ErrorList) of
- [] -> true;
- [_|_] -> false
- end
- end,
-
- UserFailIfNoPeerCert = validate_option(fail_if_no_peer_cert,
- proplists:get_value(fail_if_no_peer_cert, Opts, false)),
-
- {Verify, FailIfNoPeerCert, CaCertDefault} =
+ VerifyNoneFun =
+ {fun(_,{bad_cert, unknown_ca}, UserState) ->
+ {valid, UserState};
+ (_,{bad_cert, _} = Reason, _) ->
+ {fail, Reason};
+ (_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, UserState) ->
+ {valid, UserState}
+ end, []},
+
+ UserFailIfNoPeerCert = handle_option(fail_if_no_peer_cert, Opts, false),
+ UserVerifyFun = handle_option(verify_fun, Opts, undefined),
+ CaCerts = handle_option(cacerts, Opts, undefined),
+
+ {Verify, FailIfNoPeerCert, CaCertDefault, VerifyFun} =
%% Handle 0, 1, 2 for backwards compatibility
case proplists:get_value(verify, Opts, verify_none) of
0 ->
- {verify_none, false, ca_cert_default(verify_none, Role)};
+ {verify_none, false,
+ ca_cert_default(verify_none, VerifyNoneFun, CaCerts), VerifyNoneFun};
1 ->
- {verify_peer, false, ca_cert_default(verify_peer, Role)};
+ {verify_peer, false,
+ ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
2 ->
- {verify_peer, true, ca_cert_default(verify_peer, Role)};
+ {verify_peer, true,
+ ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
verify_none ->
- {verify_none, false, ca_cert_default(verify_none, Role)};
+ {verify_none, false,
+ ca_cert_default(verify_none, VerifyNoneFun, CaCerts), VerifyNoneFun};
verify_peer ->
- {verify_peer, UserFailIfNoPeerCert, ca_cert_default(verify_peer, Role)};
+ {verify_peer, UserFailIfNoPeerCert,
+ ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
Value ->
throw({error, {eoptions, {verify, Value}}})
- end,
+ end,
CertFile = handle_option(certfile, Opts, ""),
SSLOptions = #ssl_options{
versions = handle_option(versions, Opts, []),
verify = validate_option(verify, Verify),
- verify_fun = handle_option(verify_fun, Opts, VerifyFun),
+ verify_fun = VerifyFun,
fail_if_no_peer_cert = FailIfNoPeerCert,
verify_client_once = handle_option(verify_client_once, Opts, false),
- validate_extensions_fun = handle_option(validate_extensions_fun, Opts, undefined),
depth = handle_option(depth, Opts, 1),
+ cert = handle_option(cert, Opts, undefined),
certfile = CertFile,
- keyfile = handle_option(keyfile, Opts, CertFile),
key = handle_option(key, Opts, undefined),
+ keyfile = handle_option(keyfile, Opts, CertFile),
password = handle_option(password, Opts, ""),
+ cacerts = CaCerts,
cacertfile = handle_option(cacertfile, Opts, CaCertDefault),
+ dh = handle_option(dh, Opts, undefined),
dhfile = handle_option(dhfile, Opts, undefined),
ciphers = handle_option(ciphers, Opts, []),
%% Server side option
@@ -586,10 +594,10 @@ handle_options(Opts0, Role) ->
},
CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}),
- SslOptions = [versions, verify, verify_fun, validate_extensions_fun,
+ SslOptions = [versions, verify, verify_fun,
fail_if_no_peer_cert, verify_client_once,
- depth, certfile, keyfile,
- key, password, cacertfile, dhfile, ciphers,
+ depth, cert, certfile, key, keyfile,
+ password, cacerts, cacertfile, dh, dhfile, ciphers,
debug, reuse_session, reuse_sessions, ssl_imp,
cb_info, renegotiate_at, secure_renegotiate],
@@ -613,7 +621,23 @@ validate_option(ssl_imp, Value) when Value == new; Value == old ->
validate_option(verify, Value)
when Value == verify_none; Value == verify_peer ->
Value;
-validate_option(verify_fun, Value) when is_function(Value) ->
+validate_option(verify_fun, undefined) ->
+ undefined;
+%% Backwards compatibility
+validate_option(verify_fun, Fun) when is_function(Fun) ->
+ {fun(_,{bad_cert, _} = Reason, OldFun) ->
+ case OldFun([Reason]) of
+ true ->
+ {valid, OldFun};
+ false ->
+ {fail, Reason}
+ end;
+ (_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, UserState) ->
+ {valid, UserState}
+ end, Fun};
+validate_option(verify_fun, {Fun, _} = Value) when is_function(Fun) ->
Value;
validate_option(fail_if_no_peer_cert, Value)
when Value == true; Value == false ->
@@ -621,29 +645,38 @@ validate_option(fail_if_no_peer_cert, Value)
validate_option(verify_client_once, Value)
when Value == true; Value == false ->
Value;
-
-validate_option(validate_extensions_fun, Value) when Value == undefined; is_function(Value) ->
- Value;
validate_option(depth, Value) when is_integer(Value),
Value >= 0, Value =< 255->
Value;
+validate_option(cert, Value) when Value == undefined;
+ is_binary(Value) ->
+ Value;
validate_option(certfile, Value) when is_list(Value) ->
Value;
+
+validate_option(key, undefined) ->
+ undefined;
+validate_option(key, {KeyType, Value}) when is_binary(Value),
+ KeyType == rsa;
+ KeyType == dsa ->
+ {KeyType, Value};
validate_option(keyfile, Value) when is_list(Value) ->
Value;
-validate_option(key, Value) when Value == undefined;
- is_tuple(Value) ->
- %% element(1, Value)=='RSAPrivateKey' ->
- Value;
validate_option(password, Value) when is_list(Value) ->
Value;
+validate_option(cacerts, Value) when Value == undefined;
+ is_list(Value) ->
+ Value;
%% certfile must be present in some cases otherwhise it can be set
%% to the empty string.
validate_option(cacertfile, undefined) ->
"";
validate_option(cacertfile, Value) when is_list(Value), Value =/= "" ->
Value;
+validate_option(dh, Value) when Value == undefined;
+ is_binary(Value) ->
+ Value;
validate_option(dhfile, undefined = Value) ->
Value;
validate_option(dhfile, Value) when is_list(Value), Value =/= "" ->
@@ -701,14 +734,16 @@ validate_inet_option(active, Value)
validate_inet_option(_, _) ->
ok.
-ca_cert_default(verify_none, _) ->
+%% The option cacerts overrides cacertsfile
+ca_cert_default(_,_, [_|_]) ->
+ undefined;
+ca_cert_default(verify_none, _, _) ->
undefined;
-%% Client may leave verification up to the user
-ca_cert_default(verify_peer, client) ->
+ca_cert_default(verify_peer, {Fun,_}, _) when is_function(Fun) ->
undefined;
-%% Server that wants to verify_peer must have
+%% Server that wants to verify_peer and has no verify_fun must have
%% some trusted certs.
-ca_cert_default(verify_peer, server) ->
+ca_cert_default(verify_peer, undefined, _) ->
"".
emulated_options() ->
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 917e75157b..206024315e 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -31,10 +31,10 @@
-include("ssl_debug.hrl").
-include_lib("public_key/include/public_key.hrl").
--export([trusted_cert_and_path/3,
+-export([trusted_cert_and_path/2,
certificate_chain/2,
file_to_certificats/1,
- validate_extensions/6,
+ validate_extension/3,
is_valid_extkey_usage/2,
is_valid_key_usage/2,
select_extension/2,
@@ -47,48 +47,46 @@
%%====================================================================
%%--------------------------------------------------------------------
--spec trusted_cert_and_path([der_cert()], certdb_ref(), boolean()) ->
- {der_cert(), [der_cert()], list()}.
+-spec trusted_cert_and_path([der_cert()], certdb_ref()) ->
+ {der_cert() | unknown_ca, [der_cert()]}.
%%
%% 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),
+trusted_cert_and_path(CertChain, CertDbRef) ->
+ Path = [Cert | _] = lists:reverse(CertChain),
OtpCert = public_key:pkix_decode_cert(Cert, otp),
- IssuerAnPath =
+ IssuerID =
case public_key:pkix_is_self_signed(OtpCert) of
true ->
{ok, IssuerId} = public_key:pkix_issuer_id(OtpCert, self),
- {IssuerId, RestPath};
- false ->
+ IssuerId;
+ false ->
case public_key:pkix_issuer_id(OtpCert, other) of
{ok, IssuerId} ->
- {IssuerId, [Cert | RestPath]};
+ IssuerId;
{error, issuer_not_found} ->
case find_issuer(OtpCert, no_candidate) of
{ok, IssuerId} ->
- {IssuerId, [Cert | RestPath]};
+ IssuerId;
Other ->
- {Other, RestPath}
+ Other
end
end
end,
- case IssuerAnPath of
- {{error, issuer_not_found}, _ } ->
- %% The root CA was not sent and can not be found, we fail if verify = true
- not_valid(?ALERT_REC(?FATAL, ?UNKNOWN_CA), Verify, {Cert, RestPath});
- {{SerialNr, Issuer}, Path} ->
- case ssl_manager:lookup_trusted_cert(CertDbRef,
- SerialNr, Issuer) of
+ case IssuerID of
+ {error, issuer_not_found} ->
+ %% The root CA was not sent and can not be found.
+ {unknown_ca, Path};
+ {SerialNr, Issuer} ->
+ case ssl_manager:lookup_trusted_cert(CertDbRef, SerialNr, Issuer) of
{ok, {BinCert,_}} ->
- {BinCert, Path, []};
+ {BinCert, Path};
_ ->
- %% Fail if verify = true
- not_valid(?ALERT_REC(?FATAL, ?UNKNOWN_CA),
- Verify, {Cert, RestPath})
+ %% Root CA could not be verified
+ {unknown_ca, Path}
end
end.
@@ -112,32 +110,26 @@ file_to_certificats(File) ->
{ok, List} = ssl_manager:cache_pem_file(File),
[Bin || {'Certificate', Bin, not_encrypted} <- List].
%%--------------------------------------------------------------------
--spec validate_extensions([#'Extension'{}], term(), [#'Extension'{}],
- boolean(), list(), client | server) -> {[#'Extension'{}], term(), list()}.
+-spec validate_extension(term(), #'Extension'{}, term()) -> {valid, term()} |
+ {fail, tuple()} |
+ {unknown, term()}.
%%
%% Description: Validates ssl/tls specific extensions
%%--------------------------------------------------------------------
-validate_extensions([], ValidationState, UnknownExtensions, _, AccErr, _) ->
- {UnknownExtensions, ValidationState, AccErr};
-
-validate_extensions([#'Extension'{extnID = ?'id-ce-extKeyUsage',
- extnValue = KeyUse,
- critical = true} | Rest],
- ValidationState, UnknownExtensions, Verify, AccErr0, Role) ->
+validate_extension(_,{extension, #'Extension'{extnID = ?'id-ce-extKeyUsage',
+ extnValue = KeyUse}}, Role) ->
case is_valid_extkey_usage(KeyUse, Role) of
true ->
- validate_extensions(Rest, ValidationState, UnknownExtensions,
- Verify, AccErr0, Role);
+ {valid, Role};
false ->
- AccErr =
- not_valid_extension({bad_cert, invalid_ext_key_usage}, Verify, AccErr0),
- validate_extensions(Rest, ValidationState, UnknownExtensions, Verify, AccErr, Role)
+ {fail, {bad_cert, invalid_ext_key_usage}}
end;
-
-validate_extensions([Extension | Rest], ValidationState, UnknownExtensions,
- Verify, AccErr, Role) ->
- validate_extensions(Rest, ValidationState, [Extension | UnknownExtensions],
- Verify, AccErr, Role).
+validate_extension(_, {bad_cert, _} = Reason, _) ->
+ {fail, Reason};
+validate_extension(_, {extension, _}, Role) ->
+ {unknown, Role};
+validate_extension(_, valid, Role) ->
+ {valid, Role}.
%%--------------------------------------------------------------------
-spec is_valid_key_usage(list(), term()) -> boolean().
@@ -244,19 +236,9 @@ find_issuer(OtpCert, PrevCandidateKey) ->
end
end.
-not_valid(Alert, true, _) ->
- throw(Alert);
-not_valid(_, false, {ErlCert, Path}) ->
- {ErlCert, Path, [{bad_cert, unknown_ca}]}.
-
is_valid_extkey_usage(KeyUse, client) ->
%% Client wants to verify server
is_valid_key_usage(KeyUse,?'id-kp-serverAuth');
is_valid_extkey_usage(KeyUse, server) ->
%% Server wants to verify client
is_valid_key_usage(KeyUse, ?'id-kp-clientAuth').
-
-not_valid_extension(Error, true, _) ->
- throw(Error);
-not_valid_extension(Error, false, AccErrors) ->
- [Error | AccErrors].
diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl
index 00d3079cb3..86477f369d 100644
--- a/lib/ssl/src/ssl_certificate_db.erl
+++ b/lib/ssl/src/ssl_certificate_db.erl
@@ -74,12 +74,16 @@ lookup_cached_certs(File) ->
ets:lookup(certificate_db_name(), {file, File}).
%%--------------------------------------------------------------------
--spec add_trusted_certs(pid(), string(), certdb_ref()) -> {ok, certdb_ref()}.
+-spec add_trusted_certs(pid(), string() | {der, list()}, 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
%% together with the cert serialnumber and issuer.
%%--------------------------------------------------------------------
+add_trusted_certs(_Pid, {der, DerList}, [CerDb, _,_]) ->
+ NewRef = make_ref(),
+ add_certs_from_der(DerList, NewRef, CerDb),
+ {ok, NewRef};
add_trusted_certs(Pid, File, [CertsDb, FileToRefDb, PidToFileDb]) ->
Ref = case lookup(File, FileToRefDb) of
undefined ->
@@ -93,7 +97,6 @@ add_trusted_certs(Pid, File, [CertsDb, FileToRefDb, PidToFileDb]) ->
end,
insert(Pid, File, PidToFileDb),
{ok, Ref}.
-
%%--------------------------------------------------------------------
-spec cache_pem_file(pid(), string(), certdb_ref()) -> term().
%%
@@ -202,16 +205,20 @@ lookup(Key, Db) ->
remove_certs(Ref, CertsDb) ->
ets:match_delete(CertsDb, {{Ref, '_', '_'}, '_'}).
+add_certs_from_der(DerList, Ref, CertsDb) ->
+ Add = fun(Cert) -> add_certs(Cert, Ref, CertsDb) end,
+ [Add(Cert) || Cert <- DerList].
+
add_certs_from_file(File, Ref, CertsDb) ->
- Add = fun(Cert) ->
- ErlCert = public_key:pkix_decode_cert(Cert, otp),
- TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate,
- SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber,
- Issuer = public_key:pkix_normalize_name(
- TBSCertificate#'OTPTBSCertificate'.issuer),
- insert({Ref, SerialNumber, Issuer}, {Cert,ErlCert}, CertsDb)
- end,
+ Add = fun(Cert) -> add_certs(Cert, Ref, CertsDb) end,
{ok, PemBin} = file:read_file(File),
PemEntries = public_key:pem_decode(PemBin),
[Add(Cert) || {'Certificate', Cert, not_encrypted} <- PemEntries].
+add_certs(Cert, Ref, CertsDb) ->
+ ErlCert = public_key:pkix_decode_cert(Cert, otp),
+ TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate,
+ SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber,
+ Issuer = public_key:pkix_normalize_name(
+ TBSCertificate#'OTPTBSCertificate'.issuer),
+ insert({Ref, SerialNumber, Issuer}, {Cert,ErlCert}, CertsDb).
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index dd8f77a0ca..c94199c336 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -500,8 +500,7 @@ certify(#certificate{} = Cert,
ssl_options = Opts} = State) ->
case ssl_handshake:certify(Cert, CertDbRef, Opts#ssl_options.depth,
Opts#ssl_options.verify,
- Opts#ssl_options.verify_fun,
- Opts#ssl_options.validate_extensions_fun, Role) of
+ Opts#ssl_options.verify_fun, Role) of
{PeerCert, PublicKeyInfo} ->
handle_peer_cert(PeerCert, PublicKeyInfo,
State#state{client_certificate_requested = false});
@@ -1035,23 +1034,32 @@ ssl_init(SslOpts, Role) ->
PrivateKey =
init_private_key(SslOpts#ssl_options.key, SslOpts#ssl_options.keyfile,
SslOpts#ssl_options.password, Role),
- DHParams = init_diffie_hellman(SslOpts#ssl_options.dhfile, Role),
+ DHParams = init_diffie_hellman(SslOpts#ssl_options.dh, SslOpts#ssl_options.dhfile, Role),
{ok, CertDbRef, CacheRef, OwnCert, PrivateKey, DHParams}.
-init_certificates(#ssl_options{cacertfile = CACertFile,
- certfile = CertFile}, Role) ->
+
+init_certificates(#ssl_options{cacerts = CaCerts,
+ cacertfile = CACertFile,
+ certfile = CertFile,
+ cert = Cert}, Role) ->
{ok, CertDbRef, CacheRef} =
try
- {ok, _, _} = ssl_manager:connection_init(CACertFile, Role)
+ Certs = case CaCerts of
+ undefined ->
+ CACertFile;
+ _ ->
+ {der, CaCerts}
+ end,
+ {ok, _, _} = ssl_manager:connection_init(Certs, Role)
catch
Error:Reason ->
handle_file_error(?LINE, Error, Reason, CACertFile, ecacertfile,
erlang:get_stacktrace())
end,
- init_certificates(CertDbRef, CacheRef, CertFile, Role).
+ init_certificates(Cert, CertDbRef, CacheRef, CertFile, Role).
-init_certificates(CertDbRef, CacheRef, CertFile, client) ->
+init_certificates(undefined, CertDbRef, CacheRef, CertFile, client) ->
try
[OwnCert] = ssl_certificate:file_to_certificats(CertFile),
{ok, CertDbRef, CacheRef, OwnCert}
@@ -1059,7 +1067,7 @@ init_certificates(CertDbRef, CacheRef, CertFile, client) ->
{ok, CertDbRef, CacheRef, undefined}
end;
-init_certificates(CertDbRef, CacheRef, CertFile, server) ->
+init_certificates(undefined, CertDbRef, CacheRef, CertFile, server) ->
try
[OwnCert] = ssl_certificate:file_to_certificats(CertFile),
{ok, CertDbRef, CacheRef, OwnCert}
@@ -1067,7 +1075,9 @@ init_certificates(CertDbRef, CacheRef, CertFile, server) ->
Error:Reason ->
handle_file_error(?LINE, Error, Reason, CertFile, ecertfile,
erlang:get_stacktrace())
- end.
+ end;
+init_certificates(Cert, CertDbRef, CacheRef, _, _) ->
+ {ok, CertDbRef, CacheRef, Cert}.
init_private_key(undefined, "", _Password, client) ->
undefined;
@@ -1084,8 +1094,10 @@ init_private_key(undefined, KeyFile, Password, _) ->
erlang:get_stacktrace())
end;
-init_private_key(PrivateKey, _, _,_) ->
- PrivateKey.
+init_private_key({rsa, PrivateKey}, _, _,_) ->
+ public_key:der_decode('RSAPrivateKey', PrivateKey);
+init_private_key({dsa, PrivateKey},_,_,_) ->
+ public_key:der_decode('DSAPrivateKey', PrivateKey).
handle_file_error(Line, Error, {badmatch, Reason}, File, Throw, Stack) ->
file_error(Line, Error, Reason, File, Throw, Stack);
@@ -1099,11 +1111,13 @@ file_error(Line, Error, Reason, File, Throw, Stack) ->
error_logger:error_report(Report),
throw(Throw).
-init_diffie_hellman(_, client) ->
+init_diffie_hellman(Params, _,_) when is_binary(Params)->
+ public_key:der_decode('DHParameter', Params);
+init_diffie_hellman(_,_, client) ->
undefined;
-init_diffie_hellman(undefined, _) ->
+init_diffie_hellman(_,undefined, _) ->
?DEFAULT_DIFFIE_HELLMAN_PARAMS;
-init_diffie_hellman(DHParamFile, server) ->
+init_diffie_hellman(_, DHParamFile, server) ->
try
{ok, List} = ssl_manager:cache_pem_file(DHParamFile),
case [Entry || Entry = {'DHParameter', _ , _} <- List] of
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index ee725997a4..99bc47f04b 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -32,15 +32,13 @@
-include_lib("public_key/include/public_key.hrl").
-export([master_secret/4, client_hello/5, server_hello/4, hello/4,
- hello_request/0, certify/7, certificate/3,
- client_certificate_verify/6,
- certificate_verify/6, certificate_request/2,
- key_exchange/2, server_key_exchange_hash/2, finished/4,
- verify_connection/5,
- get_tls_handshake/2, decode_client_key/3,
- server_hello_done/0, sig_alg/1,
- encode_handshake/3, init_hashes/0,
- update_hashes/2, decrypt_premaster_secret/2]).
+ hello_request/0, certify/6, certificate/3,
+ client_certificate_verify/6, certificate_verify/6,
+ certificate_request/2, key_exchange/2, server_key_exchange_hash/2,
+ finished/4, verify_connection/5, get_tls_handshake/2,
+ decode_client_key/3, server_hello_done/0, sig_alg/1,
+ 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{} |
@@ -177,62 +175,55 @@ hello(#client_hello{client_version = ClientVersion, random = Random,
%%--------------------------------------------------------------------
-spec certify(#certificate{}, term(), integer() | nolimit,
- verify_peer | verify_none, fun(), fun(),
+ verify_peer | verify_none, {fun(), term},
client | server) -> {der_cert(), public_key_info()} | #alert{}.
%%
%% Description: Handles a certificate handshake message
%%--------------------------------------------------------------------
-certify(#certificate{asn1_certificates = ASN1Certs}, CertDbRef,
- MaxPathLen, Verify, VerifyFun, ValidateFun, Role) ->
+certify(#certificate{asn1_certificates = ASN1Certs}, CertDbRef,
+ MaxPathLen, _Verify, VerifyFunAndState, Role) ->
[PeerCert | _] = ASN1Certs,
- VerifyBool = verify_bool(Verify),
- ValidateExtensionFun =
- case ValidateFun of
+ ValidationFunAndState =
+ case VerifyFunAndState of
undefined ->
- fun(Extensions, ValidationState, Verify0, AccError) ->
- ssl_certificate:validate_extensions(Extensions, ValidationState,
- [], Verify0, AccError, Role)
- end;
- Fun ->
- fun(Extensions, ValidationState, Verify0, AccError) ->
- {NewExtensions, NewValidationState, NewAccError}
- = ssl_certificate:validate_extensions(Extensions, ValidationState,
- [], Verify0, AccError, Role),
- Fun(NewExtensions, NewValidationState, Verify0, NewAccError)
- end
+ {fun(OtpCert, ExtensionOrError, SslState) ->
+ ssl_certificate:validate_extension(OtpCert,
+ ExtensionOrError, SslState)
+ end, Role};
+ {Fun, UserState0} ->
+ {fun(OtpCert, ExtensionOrError, {SslState, UserState}) ->
+ case ssl_certificate:validate_extension(OtpCert,
+ ExtensionOrError,
+ SslState) of
+ {valid, _} ->
+ apply_user_fun(Fun, OtpCert,
+ ExtensionOrError, UserState,
+ SslState);
+ {fail, Reason} ->
+ apply_user_fun(Fun, OtpCert, Reason, UserState,
+ SslState);
+ {unknown, _} ->
+ apply_user_fun(Fun, OtpCert,
+ ExtensionOrError, UserState, SslState)
+ end
+ end, {Role, UserState0}}
end,
- try
- %% Allow missing root_cert and check that with VerifyFun
- ssl_certificate:trusted_cert_and_path(ASN1Certs, CertDbRef, false) of
- {TrustedErlCert, CertPath, VerifyErrors} ->
- Result = public_key:pkix_path_validation(TrustedErlCert,
- CertPath,
- [{max_path_length,
- MaxPathLen},
- {verify, VerifyBool},
- {validate_extensions_fun,
- ValidateExtensionFun},
- {acc_errors,
- VerifyErrors}]),
- case Result of
- {error, Reason} ->
- path_validation_alert(Reason, Verify);
- {ok, {PublicKeyInfo,_, []}} ->
- {PeerCert, PublicKeyInfo};
- {ok, {PublicKeyInfo,_, AccErrors = [Error | _]}} ->
- case VerifyFun(AccErrors) of
- true ->
- {PeerCert, PublicKeyInfo};
- false ->
- path_validation_alert(Error, Verify)
- end
- end
- catch
- throw:Alert ->
- Alert
+
+ {TrustedErlCert, CertPath} =
+ ssl_certificate:trusted_cert_and_path(ASN1Certs, CertDbRef),
+
+ case public_key:pkix_path_validation(TrustedErlCert,
+ CertPath,
+ [{max_path_length,
+ MaxPathLen},
+ {verify_fun, ValidationFunAndState}]) of
+ {ok, {PublicKeyInfo,_}} ->
+ {PeerCert, PublicKeyInfo};
+ {error, Reason} ->
+ path_validation_alert(Reason)
end.
-
+
%%--------------------------------------------------------------------
-spec certificate(der_cert(), term(), client | server) -> #certificate{} | #alert{}.
%%
@@ -474,7 +465,7 @@ get_tls_handshake(Data, Buffer) ->
get_tls_handshake_aux(list_to_binary([Buffer, Data]), []).
%%--------------------------------------------------------------------
--spec dec_client_key(binary(), key_algo(), tls_version()) ->
+-spec decode_client_key(binary(), key_algo(), tls_version()) ->
#encrypted_premaster_secret{} | #client_diffie_hellman_public{}.
%%
%% Description: Decode client_key data and return appropriate type
@@ -493,24 +484,21 @@ get_tls_handshake_aux(<<?BYTE(Type), ?UINT24(Length),
get_tls_handshake_aux(Data, Acc) ->
{lists:reverse(Acc), Data}.
-verify_bool(verify_peer) ->
- true;
-verify_bool(verify_none) ->
- false.
-
-path_validation_alert({bad_cert, cert_expired}, _) ->
+path_validation_alert({bad_cert, cert_expired}) ->
?ALERT_REC(?FATAL, ?CERTIFICATE_EXPIRED);
-path_validation_alert({bad_cert, invalid_issuer}, _) ->
+path_validation_alert({bad_cert, invalid_issuer}) ->
?ALERT_REC(?FATAL, ?BAD_CERTIFICATE);
-path_validation_alert({bad_cert, invalid_signature} , _) ->
+path_validation_alert({bad_cert, invalid_signature}) ->
?ALERT_REC(?FATAL, ?BAD_CERTIFICATE);
-path_validation_alert({bad_cert, name_not_permitted}, _) ->
+path_validation_alert({bad_cert, name_not_permitted}) ->
?ALERT_REC(?FATAL, ?BAD_CERTIFICATE);
-path_validation_alert({bad_cert, unknown_critical_extension}, _) ->
+path_validation_alert({bad_cert, unknown_critical_extension}) ->
?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE);
-path_validation_alert({bad_cert, cert_revoked}, _) ->
+path_validation_alert({bad_cert, cert_revoked}) ->
?ALERT_REC(?FATAL, ?CERTIFICATE_REVOKED);
-path_validation_alert(_, _) ->
+path_validation_alert({bad_cert, unknown_ca}) ->
+ ?ALERT_REC(?FATAL, ?UNKNOWN_CA);
+path_validation_alert(_) ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE).
select_session(Hello, Port, Session, Version,
@@ -1129,7 +1117,17 @@ sig_alg(_) ->
key_exchange_alg(rsa) ->
?KEY_EXCHANGE_RSA;
key_exchange_alg(Alg) when Alg == dhe_rsa; Alg == dhe_dss;
- Alg == dh_dss; Alg == dh_rsa; Alg == dh_anon ->
+ Alg == dh_dss; Alg == dh_rsa ->
?KEY_EXCHANGE_DIFFIE_HELLMAN;
key_exchange_alg(_) ->
?NULL.
+
+apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) ->
+ case Fun(OtpCert, ExtensionOrError, UserState0) of
+ {valid, UserState} ->
+ {valid, {SslState, UserState}};
+ {fail, _} = Fail ->
+ Fail;
+ {unknown, UserState} ->
+ {unknown, {SslState, UserState}}
+ end.
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index 337403531e..ddb05e70f6 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -63,10 +63,13 @@
validate_extensions_fun,
depth, % integer()
certfile, % file()
+ cert, % der_encoded()
keyfile, % file()
- key, %
+ key, % der_encoded()
password, %
+ cacerts, % [der_encoded()]
cacertfile, % file()
+ dh, % der_encoded()
dhfile, % file()
ciphers, %
%% Local policy for the server if it want's to reuse the session
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index 459dcefb79..0116466677 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -69,12 +69,12 @@ start_link(Opts) ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [Opts], []).
%%--------------------------------------------------------------------
--spec connection_init(string(), client | server) -> {ok, reference(), cache_ref()}.
+-spec connection_init(string()| {der, list()}, client | server) -> {ok, reference(), cache_ref()}.
%%
%% Description: Do necessary initializations for a new connection.
%%--------------------------------------------------------------------
-connection_init(TrustedcertsFile, Role) ->
- call({connection_init, TrustedcertsFile, Role}).
+connection_init(Trustedcerts, Role) ->
+ call({connection_init, Trustedcerts, Role}).
%%--------------------------------------------------------------------
-spec cache_pem_file(string()) -> {ok, term()}.
%%
@@ -185,13 +185,13 @@ handle_call({{connection_init, "", _Role}, Pid}, _From,
Result = {ok, make_ref(), Cache},
{reply, Result, State};
-handle_call({{connection_init, TrustedcertsFile, _Role}, Pid}, _From,
+handle_call({{connection_init, Trustedcerts, _Role}, Pid}, _From,
#state{certificate_db = Db,
session_cache = Cache} = State) ->
erlang:monitor(process, Pid),
Result =
try
- {ok, Ref} = ssl_certificate_db:add_trusted_certs(Pid, TrustedcertsFile, Db),
+ {ok, Ref} = ssl_certificate_db:add_trusted_certs(Pid, Trustedcerts, Db),
{ok, Ref, Cache}
catch
_:Reason ->
diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl
index 6db13e5b7a..25e7445180 100644
--- a/lib/ssl/src/ssl_session.erl
+++ b/lib/ssl/src/ssl_session.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2010. All Rights Reserved.
%%
%% 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
@@ -113,7 +113,7 @@ select_session(Sessions, #ssl_options{ciphers = Ciphers,
List ->
hd(List)
end.
-
+
%% If we can not generate a not allready in use session ID in
%% ?GEN_UNIQUE_ID_MAX_TRIES we make the new session uncacheable The
%% value of ?GEN_UNIQUE_ID_MAX_TRIES is stolen from open SSL which
diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl
index c9db0d3851..f8aef55754 100644
--- a/lib/ssl/test/erl_make_certs.erl
+++ b/lib/ssl/test/erl_make_certs.erl
@@ -66,9 +66,9 @@ make_cert(Opts) ->
%% @end
%%--------------------------------------------------------------------
write_pem(Dir, FileName, {Cert, Key = {_,_,not_encrypted}}) when is_binary(Cert) ->
- ok = ssl_test_lib:der_to_pem(filename:join(Dir, FileName ++ ".pem"),
+ ok = 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]).
+ ok = der_to_pem(filename:join(Dir, FileName ++ "_key.pem"), [Key]).
%%--------------------------------------------------------------------
%% @doc Creates a rsa key (OBS: for testing only)
@@ -144,34 +144,39 @@ encode_key(Key = #'DSAPrivateKey'{}) ->
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
- {Issuer, IssuerKey} = issuer(Opts, SubjectKey),
+
+ IssuerProp = proplists:get_value(issuer, Opts, true),
+ {Issuer, IssuerKey} = issuer(IssuerProp, Opts, SubjectKey),
{Algo, Parameters} = sign_algorithm(IssuerKey, Opts),
SignAlgo = #'SignatureAlgorithm'{algorithm = Algo,
parameters = Parameters},
-
+ Subject = case IssuerProp of
+ true -> %% Is a Root Ca
+ Issuer;
+ _ ->
+ subject(proplists:get_value(subject, Opts),false)
+ end,
+
{#'OTPTBSCertificate'{serialNumber = trunc(random:uniform()*100000000)*10000 + 1,
signature = SignAlgo,
issuer = Issuer,
validity = validity(Opts),
- subject = subject(proplists:get_value(subject, Opts),false),
+ subject = Subject,
subjectPublicKeyInfo = publickey(SubjectKey),
version = Version,
extensions = extensions(Opts)
}, IssuerKey}.
-issuer(Opts, SubjectKey) ->
- IssuerProp = proplists:get_value(issuer, Opts, true),
- case IssuerProp of
- true -> %% Self signed
- {subject(proplists:get_value(subject, Opts), true), SubjectKey};
- {Issuer, IssuerKey} when is_binary(Issuer) ->
- {issuer_der(Issuer), decode_key(IssuerKey)};
- {File, IssuerKey} when is_list(File) ->
- {ok, [{cert, Cert, _}|_]} = public_key:pem_to_der(File),
- {issuer_der(Cert), decode_key(IssuerKey)}
- end.
+issuer(true, Opts, SubjectKey) ->
+ %% Self signed
+ {subject(proplists:get_value(subject, Opts), true), SubjectKey};
+issuer({Issuer, IssuerKey}, _Opts, _SubjectKey) when is_binary(Issuer) ->
+ {issuer_der(Issuer), decode_key(IssuerKey)};
+issuer({File, IssuerKey}, _Opts, _SubjectKey) when is_list(File) ->
+ {ok, [{cert, Cert, _}|_]} = public_key:pem_to_der(File),
+ {issuer_der(Cert), decode_key(IssuerKey)}.
issuer_der(Issuer) ->
Decoded = public_key:pkix_decode_cert(Issuer, otp),
@@ -179,8 +184,8 @@ issuer_der(Issuer) ->
#'OTPTBSCertificate'{subject=Subject} = Tbs,
Subject.
-subject(undefined, IsCA) ->
- User = if IsCA -> "CA"; true -> os:getenv("USER") end,
+subject(undefined, IsRootCA) ->
+ User = if IsRootCA -> "RootCA"; true -> os:getenv("USER") end,
Opts = [{email, User ++ "@erlang.org"},
{name, User},
{city, "Stockholm"},
@@ -267,7 +272,7 @@ publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
#'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}.
validity(Opts) ->
- DefFrom0 = date(),
+ DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1),
DefTo0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())+7),
{DefFrom, DefTo} = proplists:get_value(validity, Opts, {DefFrom0, DefTo0}),
Format = fun({Y,M,D}) -> lists:flatten(io_lib:format("~w~2..0w~2..0w000000Z",[Y,M,D])) end,
@@ -406,3 +411,11 @@ extended_gcd(A, B) ->
{X, Y} = extended_gcd(B, N),
{Y, X-Y*(A div B)}
end.
+
+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_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index c6807c7b32..3cb9337775 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -232,9 +232,11 @@ all(suite) ->
server_renegotiate, client_renegotiate_reused_session,
server_renegotiate_reused_session, client_no_wrap_sequence_number,
server_no_wrap_sequence_number, extended_key_usage,
- validate_extensions_fun, no_authority_key_identifier,
+ no_authority_key_identifier,
invalid_signature_client, invalid_signature_server, cert_expired,
- client_with_cert_cipher_suites_handshake
+ client_with_cert_cipher_suites_handshake, unknown_server_ca_fail,
+ der_input, unknown_server_ca_accept_verify_none, unknown_server_ca_accept_verify_peer,
+ unknown_server_ca_accept_backwardscompatibilty
].
%% Test cases starts here.
@@ -1259,7 +1261,6 @@ eoptions(Config) when is_list(Config) ->
{verify_fun, function},
{fail_if_no_peer_cert, 0},
{verify_client_once, 1},
- {validate_extensions_fun, function},
{depth, four},
{certfile, 'cert.pem'},
{keyfile,'key.pem' },
@@ -2270,14 +2271,7 @@ client_verify_none_active_once(Config) when is_list(Config) ->
{mfa, {?MODULE, send_recv_result_active_once, []}},
{options, [{active, once} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
- %% TODO: send message to test process to make sure
- %% verifyfun has beeen run as it has the same behavior as
- %% the default fun
- VerifyFun = fun([{bad_cert, unknown_ca}]) ->
- true;
- (_) ->
- false
- end,
+
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
@@ -2285,8 +2279,7 @@ client_verify_none_active_once(Config) when is_list(Config) ->
send_recv_result_active_once,
[]}},
{options, [{active, once},
- {verify, verify_none},
- {verify_fun, VerifyFun}
+ {verify, verify_none}
| ClientOpts]}]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -2577,48 +2570,14 @@ extended_key_usage(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-validate_extensions_fun(doc) ->
- ["Test that it is possible to specify a validate_extensions_fun"];
-
-validate_extensions_fun(suite) ->
- [];
-
-validate_extensions_fun(Config) when is_list(Config) ->
- ClientOpts = ?config(client_verification_opts, Config),
- ServerOpts = ?config(server_verification_opts, Config),
-
- Fun = fun(Extensions, State, _, AccError) ->
- {Extensions, State, AccError}
- end,
-
- {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, [{validate_extensions_fun, Fun},
- {verify, verify_peer} | 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,[{validate_extensions_fun, Fun} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
no_authority_key_identifier(doc) ->
- ["Test cert that does not have authorityKeyIdentifier extension"];
+ ["Test cert that does not have authorityKeyIdentifier extension"
+ " but are present in trusted certs db."];
no_authority_key_identifier(suite) ->
[];
no_authority_key_identifier(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
+ ClientOpts = ?config(client_verification_opts, Config),
ServerOpts = ?config(server_opts, Config),
PrivDir = ?config(priv_dir, Config),
@@ -2676,7 +2635,7 @@ invalid_signature_server(suite) ->
[];
invalid_signature_server(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
+ ClientOpts = ?config(client_verification_opts, Config),
ServerOpts = ?config(server_verification_opts, Config),
PrivDir = ?config(priv_dir, Config),
@@ -2747,7 +2706,7 @@ invalid_signature_client(Config) when is_list(Config) ->
tcp_delivery_workaround(Server, {error, "bad certificate"},
Client, {error,"bad certificate"}).
-tcp_delivery_workaround(Server, ServMsg, Client, ClientMsg) ->
+tcp_delivery_workaround(Server, ServerMsg, Client, ClientMsg) ->
receive
{Server, ServerMsg} ->
receive
@@ -2793,7 +2752,7 @@ cert_expired(suite) ->
[];
cert_expired(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
+ ClientOpts = ?config(client_verification_opts, Config),
ServerOpts = ?config(server_verification_opts, Config),
PrivDir = ?config(priv_dir, Config),
@@ -2882,6 +2841,204 @@ client_with_cert_cipher_suites_handshake(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+unknown_server_ca_fail(doc) ->
+ ["Test that the client fails if the ca is unknown in verify_peer mode"];
+unknown_server_ca_fail(suite) ->
+ [];
+unknown_server_ca_fail(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ FunAndState = {fun(_,{bad_cert, _} = Reason, _) ->
+ {fail, Reason};
+ (_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, UserState) ->
+ {valid, UserState}
+ end, []},
+
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options,
+ [{verify, verify_peer},
+ {verify_fun, FunAndState}
+ | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, {error,"unknown ca"},
+ Client, {error, "unknown ca"}),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+unknown_server_ca_accept_verify_none(doc) ->
+ ["Test that the client succeds if the ca is unknown in verify_none mode"];
+unknown_server_ca_accept_verify_none(suite) ->
+ [];
+unknown_server_ca_accept_verify_none(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_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, 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,
+ [{verify, verify_none}| ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+unknown_server_ca_accept_verify_peer(doc) ->
+ ["Test that the client succeds if the ca is unknown in verify_peer mode"
+ " with a verify_fun that accepts the unknown ca error"];
+unknown_server_ca_accept_verify_peer(suite) ->
+ [];
+unknown_server_ca_accept_verify_peer(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_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, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ FunAndState = {fun(_,{bad_cert, unknown_ca}, UserState) ->
+ {valid, UserState};
+ (_,{bad_cert, _} = Reason, _) ->
+ {fail, Reason};
+ (_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, UserState) ->
+ {valid, UserState}
+ end, []},
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ send_recv_result_active, []}},
+ {options,
+ [{verify, verify_peer},
+ {verify_fun, FunAndState}| ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+unknown_server_ca_accept_backwardscompatibilty(doc) ->
+ ["Test that the client succeds if the ca is unknown in verify_none mode"];
+unknown_server_ca_accept_backwardscompatibilty(suite) ->
+ [];
+unknown_server_ca_accept_backwardscompatibilty(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_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, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ AcceptBadCa = fun({bad_cert,unknown_ca}, Acc) -> Acc;
+ (Other, Acc) -> [Other | Acc]
+ end,
+ VerifyFun =
+ fun(ErrorList) ->
+ case lists:foldl(AcceptBadCa, [], ErrorList) of
+ [] -> true;
+ [_|_] -> false
+ end
+ end,
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ send_recv_result_active, []}},
+ {options,
+ [{verify, verify_peer},
+ {verify_fun, VerifyFun}| ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+der_input(doc) ->
+ ["Test to input certs and key as der"];
+
+der_input(suite) ->
+ [];
+
+der_input(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ DHParamFile = filename:join(DataDir, "dHParam.pem"),
+
+ SeverVerifyOpts = ?config(server_verification_opts, Config),
+ {ServerCert, ServerKey, ServerCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} |
+ SeverVerifyOpts]),
+ ClientVerifyOpts = ?config(client_verification_opts, Config),
+ {ClientCert, ClientKey, ClientCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} |
+ ClientVerifyOpts]),
+ ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true},
+ {dh, DHParams},
+ {cert, ServerCert}, {key, ServerKey}, {cacerts, ServerCaCerts}],
+ ClientOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true},
+ {dh, DHParams},
+ {cert, ClientCert}, {key, ClientKey}, {cacerts, ClientCaCerts}],
+ {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, []}},
+ {options, [{active, false} | 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, []}},
+ {options, [{active, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+der_input_opts(Opts) ->
+ Certfile = proplists:get_value(certfile, Opts),
+ CaCertsfile = proplists:get_value(cacertfile, Opts),
+ Keyfile = proplists:get_value(keyfile, Opts),
+ Dhfile = proplists:get_value(dhfile, Opts),
+ [{_, Cert, _}] = ssl_test_lib:pem_to_der(Certfile),
+ [{_, Key, _}] = ssl_test_lib:pem_to_der(Keyfile),
+ [{_, DHParams, _}] = ssl_test_lib:pem_to_der(Dhfile),
+ CaCerts =
+ lists:map(fun(Entry) ->
+ {_, CaCert, _} = Entry,
+ CaCert
+ end, ssl_test_lib:pem_to_der(CaCertsfile)),
+ {Cert, {rsa, Key}, CaCerts, DHParams}.
%%--------------------------------------------------------------------
%%% Internal functions
@@ -2942,7 +3099,7 @@ session_cache_process_mnesia(suite) ->
session_cache_process_mnesia(Config) when is_list(Config) ->
session_cache_process(mnesia,Config).
-session_cache_process(Type,Config) when is_list(Config) ->
+session_cache_process(_Type,Config) when is_list(Config) ->
reuse_session(Config).
init([Type]) ->
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index 1e7cde1c25..88d2d99ef8 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -149,6 +149,7 @@ all(suite) ->
packet_http_decode,
packet_http_decode_list,
packet_http_bin_decode_multi,
+ packet_http_error_passive,
packet_line_decode,
packet_line_decode_list,
packet_asn1_decode,
@@ -1737,6 +1738,71 @@ client_http_bin_decode(Socket, HttpRequest, Count) when Count > 0 ->
client_http_bin_decode(Socket, HttpRequest, Count - 1);
client_http_bin_decode(_, _, _) ->
ok.
+
+%%--------------------------------------------------------------------
+packet_http_error_passive(doc) ->
+ ["Test setting the packet option {packet, http}, {active, false}"
+ " with a incorrect http header." ];
+packet_http_error_passive(suite) ->
+ [];
+packet_http_error_passive(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Request = "GET / HTTP/1.1\r\n"
+ "host: www.example.com\r\n"
+ "user-agent HttpTester\r\n"
+ "\r\n",
+ Response = "HTTP/1.1 200 OK\r\n"
+ "\r\n"
+ "Hello!",
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, server_http_decode_error,
+ [Response]}},
+ {options, [{active, false}, binary,
+ {packet, http} |
+ 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_http_decode_list,
+ [Request]}},
+ {options, [{active, true}, list,
+ {packet, http} |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+server_http_decode_error(Socket, HttpResponse) ->
+ assert_packet_opt(Socket, http),
+
+ {ok, {http_request, 'GET', _, {1,1}}} = ssl:recv(Socket, 0),
+
+ assert_packet_opt(Socket, http),
+
+ {ok, {http_header, _, 'Host', _, "www.example.com"}} = ssl:recv(Socket, 0),
+ assert_packet_opt(Socket, http),
+
+ {ok, {http_error, _}} = ssl:recv(Socket, 0),
+
+ assert_packet_opt(Socket, http),
+
+ {ok, http_eoh} = ssl:recv(Socket, 0),
+
+ assert_packet_opt(Socket, http),
+ ok = ssl:send(Socket, HttpResponse),
+ ok.
+
+
%%--------------------------------------------------------------------
packet_line_decode(doc) ->
["Test setting the packet option {packet, line}, {mode, binary}"];
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index c35178460f..ce164f7e4c 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -332,7 +332,7 @@ make_dsa_cert(Config) ->
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
{server_dsa_verify_opts, [{ssl_imp, new},{reuseaddr, true},
- {cacertfile, ServerCaCertFile},
+ {cacertfile, ClientCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile},
{verify, verify_peer}]},
{client_dsa_opts, [{ssl_imp, new},{reuseaddr, true},
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index 6c40a4529c..709a089892 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1,20 +1 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2010. All Rights Reserved.
-#
-# 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.
-#
-# %CopyrightEnd%
-#
-
SSL_VSN = 4.0.1