aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl32
-rw-r--r--lib/hipe/cerl/erl_types.erl34
-rw-r--r--lib/hipe/doc/src/notes.xml18
-rw-r--r--lib/hipe/vsn.mk2
-rw-r--r--lib/ssh/src/ssh_acceptor.erl6
-rwxr-xr-xlib/ssh/src/ssh_file.erl14
-rw-r--r--lib/ssh/src/ssh_transport.erl4
-rw-r--r--lib/ssl/doc/src/notes.xml48
-rw-r--r--lib/ssl/src/ssl.appup.src4
-rw-r--r--lib/ssl/src/ssl_certificate_db.erl58
-rw-r--r--lib/ssl/src/ssl_connection.erl42
-rw-r--r--lib/ssl/src/ssl_handshake.erl26
-rw-r--r--lib/ssl/src/ssl_handshake.hrl1
-rw-r--r--lib/ssl/src/ssl_manager.erl89
-rw-r--r--lib/ssl/src/ssl_session.erl30
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl480
-rw-r--r--lib/ssl/test/ssl_test_lib.erl120
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl4
-rw-r--r--lib/ssl/vsn.mk2
-rw-r--r--lib/stdlib/doc/src/notes.xml18
-rw-r--r--lib/stdlib/src/filename.erl14
-rw-r--r--lib/stdlib/src/io.erl20
-rw-r--r--lib/stdlib/src/re.erl42
-rw-r--r--lib/stdlib/vsn.mk2
24 files changed, 794 insertions, 316 deletions
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index ed5bf03804..f00821e450 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -48,6 +48,7 @@
t_boolean/0,
t_byte/0,
t_char/0,
+ t_charlist/0,
t_cons/0,
t_cons/2,
t_cons_hd/1,
@@ -124,7 +125,8 @@
t_tuple/1,
t_tuple_args/1,
t_tuple_size/1,
- t_tuple_subtypes/1
+ t_tuple_subtypes/1,
+ t_unicode_string/0
]).
-ifdef(DO_ERL_BIF_TYPES_TEST).
@@ -3799,7 +3801,7 @@ arg_types(erlang, now, 0) ->
arg_types(erlang, open_port, 2) ->
[t_sup(t_atom(), t_sup([t_tuple([t_atom('spawn'), t_string()]),
t_tuple([t_atom('spawn_driver'), t_string()]),
- t_tuple([t_atom('spawn_executable'), t_string()]),
+ t_tuple([t_atom('spawn_executable'), t_sup(t_unicode_string(),t_binary())]),
t_tuple([t_atom('fd'), t_integer(), t_integer()])])),
t_list(t_sup(t_sup([t_atom('stream'),
t_atom('exit_status'),
@@ -3815,8 +3817,8 @@ arg_types(erlang, open_port, 2) ->
t_tuple([t_atom('line'), t_integer()]),
t_tuple([t_atom('cd'), t_string()]),
t_tuple([t_atom('env'), t_list(t_tuple(2))]), % XXX: More
- t_tuple([t_atom('args'), t_list(t_string())]),
- t_tuple([t_atom('arg0'), t_string()])])))];
+ t_tuple([t_atom('args'), t_list(t_sup(t_unicode_string(),t_binary()))]),
+ t_tuple([t_atom('arg0'),t_sup(t_unicode_string(),t_binary())])])))];
arg_types(erlang, phash, 2) ->
[t_any(), t_pos_integer()];
arg_types(erlang, phash2, 1) ->
@@ -4517,11 +4519,11 @@ arg_types(os, timestamp, 0) ->
arg_types(re, compile, 1) ->
[t_iodata()];
arg_types(re, compile, 2) ->
- [t_iodata(), t_list(t_re_compile_option())];
+ [t_sup(t_iodata(), t_charlist()), t_list(t_re_compile_option())];
arg_types(re, run, 2) ->
- [t_iodata(), t_re_RE()];
+ [t_sup(t_iodata(), t_charlist()), t_re_RE()];
arg_types(re, run, 3) ->
- [t_iodata(), t_re_RE(), t_list(t_re_run_option())];
+ [t_sup(t_iodata(), t_charlist()), t_re_RE(), t_list(t_re_run_option())];
%%------- string --------------------------------------------------------------
arg_types(string, chars, 2) ->
[t_char(), t_non_neg_integer()];
@@ -4978,8 +4980,7 @@ t_ets_info_items() ->
%% =====================================================================
t_prim_file_name() ->
- t_sup([t_string(),
- t_binary()]).
+ t_sup(t_unicode_string(), t_binary()).
%% =====================================================================
%% These are used for the built-in functions of 'gen_tcp'
@@ -5136,13 +5137,14 @@ t_re_MP() -> %% it's supposed to be an opaque data type
t_tuple([t_atom('re_pattern'), t_integer(), t_integer(), t_binary()]).
t_re_RE() ->
- t_sup(t_re_MP(), t_iodata()).
+ t_sup([t_re_MP(), t_iodata(), t_charlist()]).
t_re_compile_option() ->
- t_sup([t_atoms(['anchored', 'caseless', 'dollar_endonly', 'dotall',
- 'extended', 'firstline', 'multiline', 'no_auto_capture',
- 'dupnames', 'ungreedy']),
- t_tuple([t_atom('newline'), t_re_NLSpec()])]).
+ t_sup([t_atoms(['unicode', 'anchored', 'caseless', 'dollar_endonly',
+ 'dotall', 'extended', 'firstline', 'multiline',
+ 'no_auto_capture', 'dupnames', 'ungreedy']),
+ t_tuple([t_atom('newline'), t_re_NLSpec()]),
+ t_atoms(['bsr_anycrlf', 'bsr_unicode'])]).
t_re_run_option() ->
t_sup([t_atoms(['anchored', 'global', 'notbol', 'noteol', 'notempty']),
@@ -5159,7 +5161,7 @@ t_re_Type() ->
t_atoms(['index', 'list', 'binary']).
t_re_NLSpec() ->
- t_atoms(['cr', 'crlf', 'lf', 'anycrlf']).
+ t_atoms(['cr', 'crlf', 'lf', 'anycrlf', 'any']).
t_re_ValueSpec() ->
t_sup(t_atoms(['all', 'all_but_first', 'first', 'none']), t_re_ValueList()).
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 1ed85af172..080d6936b2 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -62,6 +62,7 @@
t_boolean/0,
t_byte/0,
t_char/0,
+ t_charlist/0,
t_collect_vars/1,
t_cons/0,
t_cons/2,
@@ -195,6 +196,7 @@
t_tuple_size/1,
t_tuple_sizes/1,
t_tuple_subtypes/1,
+ t_unicode_string/0,
t_unify/2,
t_unify/3,
t_unit/0,
@@ -1455,6 +1457,26 @@ t_is_tuple(_) -> false.
%% Non-primitive types, including some handy syntactic sugar types
%%
+-spec t_unicode_string() -> erl_type().
+
+t_unicode_string() ->
+ t_list(t_unicode_char()).
+
+-spec t_charlist() -> erl_type().
+
+t_charlist() ->
+ t_charlist(1).
+
+-spec t_charlist(non_neg_integer()) -> erl_type().
+
+t_charlist(N) when N > 0 ->
+ t_maybe_improper_list(t_sup([t_unicode_char(),
+ t_unicode_binary(),
+ t_charlist(N-1)]),
+ t_sup(t_unicode_binary(), t_nil()));
+t_charlist(0) ->
+ t_maybe_improper_list(t_any(), t_sup(t_unicode_binary(), t_nil())).
+
-spec t_constant() -> erl_type().
t_constant() ->
@@ -1549,6 +1571,16 @@ t_parameterized_module() ->
t_timeout() ->
t_sup(t_non_neg_integer(), t_atom('infinity')).
+-spec t_unicode_binary() -> erl_type().
+
+t_unicode_binary() ->
+ t_binary(). % with characters encoded in UTF-8 coding standard
+
+-spec t_unicode_char() -> erl_type().
+
+t_unicode_char() ->
+ t_integer(). % representing a valid unicode codepoint
+
%%-----------------------------------------------------------------------------
%% Some built-in opaque types
%%
@@ -2825,7 +2857,7 @@ t_subtract(?list(Contents1, Termination1, Size1) = T,
true ->
case {Size1, Size2} of
{?nonempty_qual, ?unknown_qual} -> ?none;
- {?unknown_qual, ?nonempty_qual} -> Termination1;
+ {?unknown_qual, ?nonempty_qual} -> ?nil;
{S, S} -> ?none
end;
false ->
diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml
index c188db483d..8c9dbc0c18 100644
--- a/lib/hipe/doc/src/notes.xml
+++ b/lib/hipe/doc/src/notes.xml
@@ -30,6 +30,24 @@
</header>
<p>This document describes the changes made to HiPE.</p>
+<section><title>Hipe 3.7.8.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Several type specifications for standard libraries were
+ wrong in the R14B01 release. This is now corrected. The
+ corrections concern types in re,io,filename and the
+ module erlang itself.</p>
+ <p>
+ Own Id: OTP-9008</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Hipe 3.7.8</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk
index fa9dc91ff0..513b1f4943 100644
--- a/lib/hipe/vsn.mk
+++ b/lib/hipe/vsn.mk
@@ -1 +1 @@
-HIPE_VSN = 3.7.8
+HIPE_VSN = 3.7.8.1
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 9060626ab3..59fbd24cf5 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. 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
@@ -55,6 +55,10 @@ acceptor_init(Parent, Port, Address, SockOpts, Opts, AcceptTimeout) ->
do_socket_listen(Callback, Port, Opts) ->
case Callback:listen(Port, Opts) of
+ {error, nxdomain} ->
+ Callback:listen(Port, lists:delete(inet6, Opts));
+ {error, enetunreach} ->
+ Callback:listen(Port, lists:delete(inet6, Opts));
{error, eafnosupport} ->
Callback:listen(Port, lists:delete(inet6, Opts));
Other ->
diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl
index cd0d01c546..ff23f714cd 100755
--- a/lib/ssh/src/ssh_file.erl
+++ b/lib/ssh/src/ssh_file.erl
@@ -27,6 +27,8 @@
-include("PKCS-1.hrl").
-include("DSS.hrl").
+-include_lib("kernel/include/file.hrl").
+
-export([public_host_dsa_key/2,private_host_dsa_key/2,
public_host_rsa_key/2,private_host_rsa_key/2,
public_host_key/2,private_host_key/2,
@@ -43,6 +45,9 @@
-define(DBG_PATHS, true).
+-define(PERM_700, 8#700).
+-define(PERM_644, 8#644).
+
%% API
public_host_dsa_key(Type, Opts) ->
File = file_name(Type, "ssh_host_dsa_key.pub", Opts),
@@ -113,8 +118,10 @@ do_lookup_host_key(Host, Alg, Opts) ->
add_host_key(Host, Key, Opts) ->
Host1 = add_ip(replace_localhost(Host)),
- case file:open(file_name(user, "known_hosts", Opts),[write,append]) of
+ KnownHosts = file_name(user, "known_hosts", Opts),
+ case file:open(KnownHosts, [write,append]) of
{ok, Fd} ->
+ ok = file:change_mode(KnownHosts, ?PERM_644),
Res = add_key_fd(Fd, Host1, Key),
file:close(Fd),
Res;
@@ -537,4 +544,7 @@ file_name(Type, Name, Opts) ->
default_user_dir()->
{ok,[[Home|_]]} = init:get_argument(home),
- filename:join(Home, ".ssh").
+ UserDir = filename:join(Home, ".ssh"),
+ ok = filelib:ensure_dir(filename:join(UserDir, "dummy")),
+ ok = file:change_mode(UserDir, ?PERM_700),
+ UserDir.
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index e79ccdda0c..de3e29e2f1 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2011. 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
@@ -169,6 +169,8 @@ do_connect(Callback, Address, Port, SocketOpts, Timeout) ->
Callback:connect(Address, Port, lists:delete(inet6, Opts), Timeout);
{error, eafnosupport} ->
Callback:connect(Address, Port, lists:delete(inet6, Opts), Timeout);
+ {error, enetunreach} ->
+ Callback:connect(Address, Port, lists:delete(inet6, Opts), Timeout);
Other ->
Other
end.
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 313f1e59c9..8f81ccb567 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -31,7 +31,53 @@
<p>This document describes the changes made to the SSL application.
</p>
- <section><title>SSL 4.1.1</title>
+ <section><title>SSL 4.1.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed error in cache-handling fix from ssl-4.1.2</p>
+ <p>
+ Own Id: OTP-9018 Aux Id: seq11739 </p>
+ </item>
+ <item>
+ <p>
+ Verification of a critical extended_key_usage-extension
+ corrected</p>
+ <p>
+ Own Id: OTP-9029 Aux Id: seq11541 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 4.1.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The ssl application caches certificate files, it will now
+ invalidate cache entries if the diskfile is changed.</p>
+ <p>
+ Own Id: OTP-8965 Aux Id: seq11739 </p>
+ </item>
+ <item>
+ <p>
+ Now runs the terminate function before returning from the
+ call made by ssl:close/1, as before the caller of
+ ssl:close/1 could get problems with the reuseaddr option.</p>
+ <p>
+ Own Id: OTP-8992</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 4.1.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src
index 51c5289bd2..e6a8c557fc 100644
--- a/lib/ssl/src/ssl.appup.src
+++ b/lib/ssl/src/ssl.appup.src
@@ -1,10 +1,14 @@
%% -*- erlang -*-
{"%VSN%",
[
+ {"4.1.2", [{restart_application, ssl}]},
+ {"4.1.1", [{restart_application, ssl}]},
{"4.1", [{restart_application, ssl}]},
{"4.0.1", [{restart_application, ssl}]}
],
[
+ {"4.1.2", [{restart_application, ssl}]},
+ {"4.1.1", [{restart_application, ssl}]},
{"4.1", [{restart_application, ssl}]},
{"4.0.1", [{restart_application, ssl}]}
]}.
diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl
index 2a5a7f3394..3eceefa304 100644
--- a/lib/ssl/src/ssl_certificate_db.erl
+++ b/lib/ssl/src/ssl_certificate_db.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2011. 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
@@ -27,7 +27,9 @@
-export([create/0, remove/1, add_trusted_certs/3,
remove_trusted_certs/2, lookup_trusted_cert/3, issuer_candidate/1,
- lookup_cached_certs/1, cache_pem_file/3]).
+ lookup_cached_certs/1, cache_pem_file/4, uncache_pem_file/2, lookup/2]).
+
+-type time() :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}.
%%====================================================================
%% Internal application API
@@ -98,17 +100,35 @@ add_trusted_certs(Pid, File, [CertsDb, FileToRefDb, PidToFileDb]) ->
insert(Pid, File, PidToFileDb),
{ok, Ref}.
%%--------------------------------------------------------------------
--spec cache_pem_file(pid(), string(), certdb_ref()) -> term().
+-spec cache_pem_file(pid(), string(), time(), certdb_ref()) -> term().
%%
%% Description: Cache file as binary in DB
%%--------------------------------------------------------------------
-cache_pem_file(Pid, File, [CertsDb, _FileToRefDb, PidToFileDb]) ->
+cache_pem_file(Pid, File, Time, [CertsDb, _FileToRefDb, PidToFileDb]) ->
{ok, PemBin} = file:read_file(File),
Content = public_key:pem_decode(PemBin),
- insert({file, File}, Content, CertsDb),
+ insert({file, File}, {Time, Content}, CertsDb),
insert(Pid, File, PidToFileDb),
{ok, Content}.
+%--------------------------------------------------------------------
+-spec uncache_pem_file(string(), certdb_ref()) -> no_return().
+%%
+%% Description: If a cached file is no longer valid (changed on disk)
+%% we must terminate the connections using the old file content, and
+%% when those processes are finish the cache will be cleaned. It is
+%% a rare but possible case a new ssl client/server is started with
+%% a filename with the same name as previously started client/server
+%% but with different content.
+%% --------------------------------------------------------------------
+uncache_pem_file(File, [_CertsDb, _FileToRefDb, PidToFileDb]) ->
+ Pids = select(PidToFileDb, [{{'$1', File},[],['$$']}]),
+ lists:foreach(fun([Pid]) ->
+ exit(Pid, shutdown)
+ end, Pids).
+
+
+
%%--------------------------------------------------------------------
-spec remove_trusted_certs(pid(), certdb_ref()) -> term().
@@ -174,6 +194,22 @@ issuer_candidate(PrevCandidateKey) ->
end.
%%--------------------------------------------------------------------
+-spec lookup(term(), term()) -> term() | undefined.
+%%
+%% Description: Looks up an element in a certificat <Db>.
+%%--------------------------------------------------------------------
+lookup(Key, Db) ->
+ case ets:lookup(Db, Key) of
+ [] ->
+ undefined;
+ Contents ->
+ Pick = fun({_, Data}) -> Data;
+ ({_,_,Data}) -> Data
+ end,
+ [Pick(Data) || Data <- Contents]
+ end.
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
certificate_db_name() ->
@@ -191,16 +227,8 @@ ref_count(Key, Db,N) ->
delete(Key, Db) ->
_ = ets:delete(Db, Key).
-lookup(Key, Db) ->
- case ets:lookup(Db, Key) of
- [] ->
- undefined;
- Contents ->
- Pick = fun({_, Data}) -> Data;
- ({_,_,Data}) -> Data
- end,
- [Pick(Data) || Data <- Contents]
- end.
+select(Db, MatchSpec)->
+ ets:select(Db, MatchSpec).
remove_certs(Ref, CertsDb) ->
ets:match_delete(CertsDb, {{Ref, '_', '_'}, '_'}).
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 6c9ac65b64..675e5e44bd 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -70,7 +70,7 @@
%% {{md5_hash, sha_hash}, {prev_md5, prev_sha}} (binary())
tls_handshake_hashes, % see above
tls_cipher_texts, % list() received but not deciphered yet
- own_cert, % binary()
+ own_cert, % binary() | undefined
session, % #session{} from ssl_handshake.hrl
session_cache, %
session_cache_cb, %
@@ -90,7 +90,8 @@
log_alert, % boolean()
renegotiation, % {boolean(), From | internal | peer}
recv_during_renegotiation, %boolean()
- send_queue % queue()
+ send_queue, % queue()
+ terminated = false %
}).
-define(DEFAULT_DIFFIE_HELLMAN_PARAMS,
@@ -304,8 +305,10 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options,
try ssl_init(SSLOpts0, Role) of
{ok, Ref, CacheRef, OwnCert, Key, DHParams} ->
+ Session = State0#state.session,
State = State0#state{tls_handshake_hashes = Hashes0,
own_cert = OwnCert,
+ session = Session#session{own_certificate = OwnCert},
cert_db_ref = Ref,
session_cache = CacheRef,
private_key = Key,
@@ -331,6 +334,7 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options,
%%--------------------------------------------------------------------
hello(start, #state{host = Host, port = Port, role = client,
ssl_options = SslOpts,
+ own_cert = Cert,
transport_cb = Transport, socket = Socket,
connection_states = ConnectionStates,
renegotiation = {Renegotiation, _}}
@@ -338,7 +342,7 @@ hello(start, #state{host = Host, port = Port, role = client,
Hello = ssl_handshake:client_hello(Host, Port,
ConnectionStates,
- SslOpts, Renegotiation),
+ SslOpts, Renegotiation, Cert),
Version = Hello#client_hello.client_version,
Hashes0 = ssl_handshake:init_hashes(),
@@ -678,6 +682,7 @@ cipher(Msg, State) ->
%%--------------------------------------------------------------------
connection(#hello_request{}, #state{host = Host, port = Port,
socket = Socket,
+ own_cert = Cert,
ssl_options = SslOpts,
negotiated_version = Version,
transport_cb = Transport,
@@ -686,7 +691,7 @@ connection(#hello_request{}, #state{host = Host, port = Port,
tls_handshake_hashes = Hashes0} = State0) ->
Hello = ssl_handshake:client_hello(Host, Port, ConnectionStates0,
- SslOpts, Renegotiation),
+ SslOpts, Renegotiation, Cert),
{BinMsg, ConnectionStates1, Hashes1} =
encode_handshake(Hello, Version, ConnectionStates0, Hashes0),
@@ -777,8 +782,12 @@ handle_sync_event(start, _, connection, State) ->
handle_sync_event(start, From, StateName, State) ->
{next_state, StateName, State#state{from = From}};
-handle_sync_event(close, _, _StateName, State) ->
- {stop, normal, ok, State};
+handle_sync_event(close, _, StateName, State) ->
+ %% Run terminate before returning
+ %% so that the reuseaddr inet-option will work
+ %% as intended.
+ (catch terminate(user_close, StateName, State)),
+ {stop, normal, ok, State#state{terminated = true}};
handle_sync_event({shutdown, How0}, _, StateName,
#state{transport_cb = Transport,
@@ -966,6 +975,11 @@ handle_info(Msg, StateName, State) ->
%% necessary cleaning up. When it returns, the gen_fsm terminates with
%% Reason. The return value is ignored.
%%--------------------------------------------------------------------
+terminate(_, _, #state{terminated = true}) ->
+ %% Happens when user closes the connection using ssl:close/1
+ %% we want to guarantee that Transport:close has been called
+ %% when ssl:close/1 returns.
+ ok;
terminate(Reason, connection, #state{negotiated_version = Version,
connection_states = ConnectionStates,
transport_cb = Transport,
@@ -975,14 +989,14 @@ terminate(Reason, connection, #state{negotiated_version = Version,
notify_renegotiater(Renegotiate),
BinAlert = terminate_alert(Reason, Version, ConnectionStates),
Transport:send(Socket, BinAlert),
- workaround_transport_delivery_problems(Socket, Transport),
+ workaround_transport_delivery_problems(Socket, Transport, Reason),
Transport:close(Socket);
-terminate(_Reason, _StateName, #state{transport_cb = Transport,
+terminate(Reason, _StateName, #state{transport_cb = Transport,
socket = Socket, send_queue = SendQueue,
renegotiation = Renegotiate}) ->
notify_senders(SendQueue),
notify_renegotiater(Renegotiate),
- workaround_transport_delivery_problems(Socket, Transport),
+ workaround_transport_delivery_problems(Socket, Transport, Reason),
Transport:close(Socket).
%%--------------------------------------------------------------------
@@ -2185,7 +2199,8 @@ notify_renegotiater({true, From}) when not is_atom(From) ->
notify_renegotiater(_) ->
ok.
-terminate_alert(Reason, Version, ConnectionStates) when Reason == normal; Reason == shutdown ->
+terminate_alert(Reason, Version, ConnectionStates) when Reason == normal; Reason == shutdown;
+ Reason == user_close ->
{BinAlert, _} = encode_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
Version, ConnectionStates),
BinAlert;
@@ -2194,10 +2209,13 @@ terminate_alert(_, Version, ConnectionStates) ->
Version, ConnectionStates),
BinAlert.
-workaround_transport_delivery_problems(Socket, Transport) ->
+workaround_transport_delivery_problems(_,_, user_close) ->
+ ok;
+workaround_transport_delivery_problems(Socket, Transport, _) ->
%% Standard trick to try to make sure all
%% data sent to to tcp port is really sent
- %% before tcp port is closed.
+ %% before tcp port is closed so that the peer will
+ %% get a correct error message.
inet:setopts(Socket, [{active, false}]),
Transport:shutdown(Socket, write),
Transport:recv(Socket, 0).
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index c7a1c4965d..1f4c44d115 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2011. 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
@@ -30,7 +30,7 @@
-include("ssl_internal.hrl").
-include_lib("public_key/include/public_key.hrl").
--export([master_secret/4, client_hello/5, server_hello/4, hello/4,
+-export([master_secret/4, client_hello/6, server_hello/4, hello/4,
hello_request/0, certify/6, certificate/3,
client_certificate_verify/5, certificate_verify/5,
certificate_request/2, key_exchange/2, server_key_exchange_hash/2,
@@ -49,13 +49,13 @@
%%====================================================================
%%--------------------------------------------------------------------
-spec client_hello(host(), port_num(), #connection_states{},
- #ssl_options{}, boolean()) -> #client_hello{}.
+ #ssl_options{}, boolean(), der_cert()) -> #client_hello{}.
%%
%% Description: Creates a client hello message.
%%--------------------------------------------------------------------
client_hello(Host, Port, ConnectionStates, #ssl_options{versions = Versions,
ciphers = UserSuites}
- = SslOpts, Renegotiation) ->
+ = SslOpts, Renegotiation, OwnCert) ->
Fun = fun(Version) ->
ssl_record:protocol_version(Version)
@@ -65,7 +65,7 @@ client_hello(Host, Port, ConnectionStates, #ssl_options{versions = Versions,
SecParams = Pending#connection_state.security_parameters,
Ciphers = available_suites(UserSuites, Version),
- Id = ssl_manager:client_session_id(Host, Port, SslOpts),
+ Id = ssl_manager:client_session_id(Host, Port, SslOpts, OwnCert),
#client_hello{session_id = Id,
client_version = Version,
@@ -194,14 +194,12 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbRef,
{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);
+ SslState) of
+ {valid, NewSslState} ->
+ {valid, {NewSslState, UserState}};
+ {fail, Reason} ->
+ apply_user_fun(Fun, OtpCert, Reason, UserState,
+ SslState);
{unknown, _} ->
apply_user_fun(Fun, OtpCert,
ExtensionOrError, UserState, SslState)
@@ -571,7 +569,7 @@ select_session(Hello, Port, Session, Version,
#ssl_options{ciphers = UserSuites} = SslOpts, Cache, CacheCb, Cert) ->
SuggestedSessionId = Hello#client_hello.session_id,
SessionId = ssl_manager:server_session_id(Port, SuggestedSessionId,
- SslOpts),
+ SslOpts, Cert),
Suites = available_suites(Cert, UserSuites, Version),
case ssl_session:is_new(SuggestedSessionId, SessionId) of
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 68a7802ef2..8ae4d2332e 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -36,6 +36,7 @@
-record(session, {
session_id,
peer_certificate,
+ own_certificate,
compression_method,
cipher_suite,
master_secret,
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index 3b02d96562..f845b1ecc0 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -29,8 +29,8 @@
%% Internal application API
-export([start_link/1,
connection_init/2, cache_pem_file/1,
- lookup_trusted_cert/3, issuer_candidate/1, client_session_id/3,
- server_session_id/3,
+ lookup_trusted_cert/3, issuer_candidate/1, client_session_id/4,
+ server_session_id/4,
register_session/2, register_session/3, invalidate_session/2,
invalidate_session/3]).
@@ -43,6 +43,7 @@
-include("ssl_handshake.hrl").
-include("ssl_internal.hrl").
+-include_lib("kernel/include/file.hrl").
-record(state, {
session_cache,
@@ -76,16 +77,17 @@ start_link(Opts) ->
connection_init(Trustedcerts, Role) ->
call({connection_init, Trustedcerts, Role}).
%%--------------------------------------------------------------------
--spec cache_pem_file(string()) -> {ok, term()}.
+-spec cache_pem_file(string()) -> {ok, term()} | {error, reason()}.
%%
-%% Description: Cach a pem file and
+%% Description: Cach a pem file and return its content.
%%--------------------------------------------------------------------
-cache_pem_file(File) ->
- case ssl_certificate_db:lookup_cached_certs(File) of
- [{_,Content}] ->
- {ok, Content};
- [] ->
- call({cache_pem, File})
+cache_pem_file(File) ->
+ try file:read_file_info(File) of
+ {ok, #file_info{mtime = LastWrite}} ->
+ cache_pem_file(File, LastWrite)
+ catch
+ _:Reason ->
+ {error, Reason}
end.
%%--------------------------------------------------------------------
-spec lookup_trusted_cert(reference(), serialnumber(), issuer()) ->
@@ -106,20 +108,21 @@ lookup_trusted_cert(Ref, SerialNumber, Issuer) ->
issuer_candidate(PrevCandidateKey) ->
ssl_certificate_db:issuer_candidate(PrevCandidateKey).
%%--------------------------------------------------------------------
--spec client_session_id(host(), port_num(), #ssl_options{}) -> session_id().
+-spec client_session_id(host(), port_num(), #ssl_options{},
+ der_cert() | undefined) -> session_id().
%%
%% Description: Select a session id for the client.
%%--------------------------------------------------------------------
-client_session_id(Host, Port, SslOpts) ->
- call({client_session_id, Host, Port, SslOpts}).
+client_session_id(Host, Port, SslOpts, OwnCert) ->
+ call({client_session_id, Host, Port, SslOpts, OwnCert}).
%%--------------------------------------------------------------------
--spec server_session_id(host(), port_num(), #ssl_options{}) -> session_id().
+-spec server_session_id(host(), port_num(), #ssl_options{}, der_cert()) -> session_id().
%%
%% Description: Select a session id for the server.
%%--------------------------------------------------------------------
-server_session_id(Port, SuggestedSessionId, SslOpts) ->
- call({server_session_id, Port, SuggestedSessionId, SslOpts}).
+server_session_id(Port, SuggestedSessionId, SslOpts, OwnCert) ->
+ call({server_session_id, Port, SuggestedSessionId, SslOpts, OwnCert}).
%%--------------------------------------------------------------------
-spec register_session(port_num(), #session{}) -> ok.
@@ -201,28 +204,35 @@ handle_call({{connection_init, Trustedcerts, _Role}, Pid}, _From,
end,
{reply, Result, State};
-handle_call({{client_session_id, Host, Port, SslOpts}, _}, _,
+handle_call({{client_session_id, Host, Port, SslOpts, OwnCert}, _}, _,
#state{session_cache = Cache,
session_cache_cb = CacheCb} = State) ->
- Id = ssl_session:id({Host, Port, SslOpts}, Cache, CacheCb),
+ Id = ssl_session:id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
{reply, Id, State};
-handle_call({{server_session_id, Port, SuggestedSessionId, SslOpts}, _},
+handle_call({{server_session_id, Port, SuggestedSessionId, SslOpts, OwnCert}, _},
_, #state{session_cache_cb = CacheCb,
session_cache = Cache,
session_lifetime = LifeTime} = State) ->
Id = ssl_session:id(Port, SuggestedSessionId, SslOpts,
- Cache, CacheCb, LifeTime),
+ Cache, CacheCb, LifeTime, OwnCert),
{reply, Id, State};
-handle_call({{cache_pem, File},Pid}, _, State = #state{certificate_db = Db}) ->
- try ssl_certificate_db:cache_pem_file(Pid,File,Db) of
+handle_call({{cache_pem, File, LastWrite}, Pid}, _,
+ #state{certificate_db = Db} = State) ->
+ try ssl_certificate_db:cache_pem_file(Pid, File, LastWrite, Db) of
Result ->
{reply, Result, State}
catch
_:Reason ->
{reply, {error, Reason}, State}
- end.
+ end;
+handle_call({{recache_pem, File, LastWrite}, Pid}, From,
+ #state{certificate_db = Db} = State) ->
+ ssl_certificate_db:uncache_pem_file(File, Db),
+ cast({recache_pem, File, LastWrite, Pid, From}),
+ {noreply, State}.
+
%%--------------------------------------------------------------------
-spec handle_cast(msg(), #state{}) -> {noreply, #state{}}.
%% Possible return values not used now.
@@ -259,7 +269,21 @@ handle_cast({invalidate_session, Port, #session{session_id = ID}},
#state{session_cache = Cache,
session_cache_cb = CacheCb} = State) ->
CacheCb:delete(Cache, {Port, ID}),
- {noreply, State}.
+ {noreply, State};
+
+handle_cast({recache_pem, File, LastWrite, Pid, From},
+ #state{certificate_db = [_, FileToRefDb, _]} = State0) ->
+ case ssl_certificate_db:lookup(File, FileToRefDb) of
+ undefined ->
+ {reply, Msg, State} = handle_call({{cache_pem, File, LastWrite}, Pid}, From, State0),
+ gen_server:reply(From, Msg),
+ {noreply, State};
+ _ -> %% Send message to self letting cleanup messages be handled
+ %% first so that no reference to the old version of file
+ %% exists when we cache the new one.
+ cast({recache_pem, File, LastWrite, Pid, From}),
+ {noreply, State0}
+ end.
%%--------------------------------------------------------------------
-spec handle_info(msg(), #state{}) -> {noreply, #state{}}.
@@ -286,12 +310,14 @@ handle_info({'EXIT', _, _}, State) ->
handle_info({'DOWN', _Ref, _Type, _Pid, ecacertfile}, State) ->
{noreply, State};
+handle_info({'DOWN', _Ref, _Type, Pid, shutdown}, State) ->
+ handle_info({remove_trusted_certs, Pid}, State);
handle_info({'DOWN', _Ref, _Type, Pid, _Reason}, State) ->
erlang:send_after(?CERTIFICATE_CACHE_CLEANUP, self(),
{remove_trusted_certs, Pid}),
{noreply, State};
handle_info({remove_trusted_certs, Pid},
- State = #state{certificate_db = Db}) ->
+ #state{certificate_db = Db} = State) ->
ssl_certificate_db:remove_trusted_certs(Pid, Db),
{noreply, State};
@@ -362,3 +388,16 @@ session_validation({{{Host, Port}, _}, Session}, LifeTime) ->
session_validation({{Port, _}, Session}, LifeTime) ->
validate_session(Port, Session, LifeTime),
LifeTime.
+
+cache_pem_file(File, LastWrite) ->
+ case ssl_certificate_db:lookup_cached_certs(File) of
+ [{_, {Mtime, Content}}] ->
+ case LastWrite of
+ Mtime ->
+ {ok, Content};
+ _ ->
+ call({recache_pem, File, LastWrite})
+ end;
+ [] ->
+ call({cache_pem, File, LastWrite})
+ end.
diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl
index 25e7445180..dc4b7a711c 100644
--- a/lib/ssl/src/ssl_session.erl
+++ b/lib/ssl/src/ssl_session.erl
@@ -28,7 +28,7 @@
-include("ssl_internal.hrl").
%% Internal application API
--export([is_new/2, id/3, id/6, valid_session/2]).
+-export([is_new/2, id/4, id/7, valid_session/2]).
-define(GEN_UNIQUE_ID_MAX_TRIES, 10).
@@ -48,13 +48,14 @@ is_new(_ClientSuggestion, _ServerDecision) ->
true.
%%--------------------------------------------------------------------
--spec id({host(), port_num(), #ssl_options{}}, cache_ref(), atom()) -> binary().
+-spec id({host(), port_num(), #ssl_options{}}, cache_ref(), atom(),
+ undefined | binary()) -> binary().
%%
%% Description: Should be called by the client side to get an id
%% for the client hello message.
%%--------------------------------------------------------------------
-id(ClientInfo, Cache, CacheCb) ->
- case select_session(ClientInfo, Cache, CacheCb) of
+id(ClientInfo, Cache, CacheCb, OwnCert) ->
+ case select_session(ClientInfo, Cache, CacheCb, OwnCert) of
no_session ->
<<>>;
SessionId ->
@@ -63,19 +64,19 @@ id(ClientInfo, Cache, CacheCb) ->
%%--------------------------------------------------------------------
-spec id(port_num(), binary(), #ssl_options{}, cache_ref(),
- atom(), seconds()) -> binary().
+ atom(), seconds(), binary()) -> binary().
%%
%% Description: Should be called by the server side to get an id
%% for the server hello message.
%%--------------------------------------------------------------------
-id(Port, <<>>, _, Cache, CacheCb, _) ->
+id(Port, <<>>, _, Cache, CacheCb, _, _) ->
new_id(Port, ?GEN_UNIQUE_ID_MAX_TRIES, Cache, CacheCb);
id(Port, SuggestedSessionId, #ssl_options{reuse_sessions = ReuseEnabled,
reuse_session = ReuseFun},
- Cache, CacheCb, SecondLifeTime) ->
+ Cache, CacheCb, SecondLifeTime, OwnCert) ->
case is_resumable(SuggestedSessionId, Port, ReuseEnabled,
- ReuseFun, Cache, CacheCb, SecondLifeTime) of
+ ReuseFun, Cache, CacheCb, SecondLifeTime, OwnCert) of
true ->
SuggestedSessionId;
false ->
@@ -93,19 +94,20 @@ valid_session(#session{time_stamp = TimeStamp}, LifeTime) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-select_session({HostIP, Port, SslOpts}, Cache, CacheCb) ->
+select_session({HostIP, Port, SslOpts}, Cache, CacheCb, OwnCert) ->
Sessions = CacheCb:select_session(Cache, {HostIP, Port}),
- select_session(Sessions, SslOpts).
+ select_session(Sessions, SslOpts, OwnCert).
-select_session([], _) ->
+select_session([], _, _) ->
no_session;
select_session(Sessions, #ssl_options{ciphers = Ciphers,
- reuse_sessions = ReuseSession}) ->
+ reuse_sessions = ReuseSession}, OwnCert) ->
IsResumable =
fun(Session) ->
ReuseSession andalso (Session#session.is_resumable) andalso
lists:member(Session#session.cipher_suite, Ciphers)
+ andalso (OwnCert == Session#session.own_certificate)
end,
case [Id || [Id, Session] <- Sessions, IsResumable(Session)] of
[] ->
@@ -140,14 +142,16 @@ new_id(Port, Tries, Cache, CacheCb) ->
end.
is_resumable(SuggestedSessionId, Port, ReuseEnabled, ReuseFun, Cache,
- CacheCb, SecondLifeTime) ->
+ CacheCb, SecondLifeTime, OwnCert) ->
case CacheCb:lookup(Cache, {Port, SuggestedSessionId}) of
#session{cipher_suite = CipherSuite,
+ own_certificate = SessionOwnCert,
compression_method = Compression,
is_resumable = Is_resumable,
peer_certificate = PeerCert} = Session ->
ReuseEnabled
andalso Is_resumable
+ andalso (OwnCert == SessionOwnCert)
andalso valid_session(Session, SecondLifeTime)
andalso ReuseFun(SuggestedSessionId, PeerCert,
Compression, CipherSuite);
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 8f9554f3ce..d3e846f60b 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2011. 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
@@ -27,6 +27,7 @@
-include("test_server.hrl").
-include("test_server_line.hrl").
-include_lib("public_key/include/public_key.hrl").
+
-include("ssl_alert.hrl").
-define('24H_in_sec', 86400).
@@ -125,6 +126,9 @@ init_per_testcase(empty_protocol_versions, Config) ->
ssl:start(),
Config;
+init_per_testcase(different_ca_peer_sign, Config0) ->
+ ssl_test_lib:make_mix_cert(Config0);
+
init_per_testcase(_TestCase, Config0) ->
Config = lists:keydelete(watchdog, 1, Config0),
Dog = test_server:timetrap(?TIMEOUT),
@@ -200,12 +204,16 @@ all(suite) ->
server_does_not_want_to_reuse_session, client_renegotiate,
server_renegotiate, client_renegotiate_reused_session,
server_renegotiate_reused_session, client_no_wrap_sequence_number,
- server_no_wrap_sequence_number, extended_key_usage,
+ server_no_wrap_sequence_number,
+ extended_key_usage_verify_peer, extended_key_usage_verify_none,
no_authority_key_identifier,
invalid_signature_client, invalid_signature_server, cert_expired,
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
+ unknown_server_ca_accept_backwardscompatibilty,
+ %different_ca_peer_sign,
+ no_reuses_session_server_restart_new_cert,
+ no_reuses_session_server_restart_new_cert_file, reuseaddr
].
%% Test cases starts here.
@@ -321,7 +329,6 @@ basic_test(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-
%%--------------------------------------------------------------------
controlling_process(doc) ->
@@ -521,9 +528,7 @@ client_closes_socket(Config) when is_list(Config) ->
_Client = spawn_link(Connect),
- ssl_test_lib:check_result(Server, {error,closed}),
-
- ssl_test_lib:close(Server).
+ ssl_test_lib:check_result(Server, {error,closed}).
%%--------------------------------------------------------------------
@@ -738,7 +743,6 @@ socket_options(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
{ok, Listen} = ssl:listen(0, ServerOpts),
{ok,[{mode,list}]} = ssl:getopts(Listen, [mode]),
@@ -841,6 +845,7 @@ send_recv(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
send_close(doc) ->
[""];
@@ -867,8 +872,7 @@ send_close(Config) when is_list(Config) ->
ok = ssl:send(SslS, "Hello world"),
{ok,<<"Hello world">>} = ssl:recv(SslS, 11),
gen_tcp:close(TcpS),
- {error, _} = ssl:send(SslS, "Hello world"),
- ssl_test_lib:close(Server).
+ {error, _} = ssl:send(SslS, "Hello world").
%%--------------------------------------------------------------------
close_transport_accept(doc) ->
@@ -1043,8 +1047,7 @@ tcp_connect(Config) when is_list(Config) ->
{Server, {error, Error}} ->
test_server:format("Error ~p", [Error])
end
- end,
- ssl_test_lib:close(Server).
+ end.
dummy(_Socket) ->
@@ -1149,13 +1152,13 @@ ecertfile(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-ecacertfile(doc) ->
+ecacertfile(doc) ->
["Test what happens with an invalid cacert file"];
-ecacertfile(suite) ->
+ecacertfile(suite) ->
[];
-ecacertfile(Config) when is_list(Config) ->
+ecacertfile(Config) when is_list(Config) ->
ClientOpts = [{reuseaddr, true}|?config(client_opts, Config)],
ServerBadOpts = [{reuseaddr, true}|?config(server_bad_ca, Config)],
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -1532,7 +1535,7 @@ erlang_cipher_suite(Suite) ->
Suite.
cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
- process_flag(trap_exit, true),
+ %% process_flag(trap_exit, true),
test_server:format("Testing CipherSuite ~p~n", [CipherSuite]),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -1556,16 +1559,8 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
Result = ssl_test_lib:wait_for_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
- receive
- {'EXIT', Server, normal} ->
- ok
- end,
ssl_test_lib:close(Client),
- receive
- {'EXIT', Client, normal} ->
- ok
- end,
- process_flag(trap_exit, false),
+
case Result of
ok ->
[];
@@ -1607,7 +1602,6 @@ reuse_session(suite) ->
[];
reuse_session(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -1615,13 +1609,13 @@ reuse_session(Config) when is_list(Config) ->
Server =
ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, session_info_result, []}},
- {options, ServerOpts}]),
+ {mfa, {?MODULE, session_info_result, []}},
+ {options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
Client0 =
ssl_test_lib:start_client([{node, ClientNode},
{port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
+ {mfa, {ssl_test_lib, no_result, []}},
{from, self()}, {options, ClientOpts}]),
SessionInfo =
receive
@@ -1629,16 +1623,16 @@ reuse_session(Config) when is_list(Config) ->
Info
end,
- Server ! listen,
+ Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
%% Make sure session is registered
test_server:sleep(?SLEEP),
Client1 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {?MODULE, session_info_result, []}},
- {from, self()}, {options, ClientOpts}]),
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {?MODULE, session_info_result, []}},
+ {from, self()}, {options, ClientOpts}]),
receive
{Client1, SessionInfo} ->
ok;
@@ -1648,10 +1642,10 @@ reuse_session(Config) when is_list(Config) ->
test_server:fail(session_not_reused)
end,
- Server ! listen,
+ Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
Client2 =
- ssl_test_lib:start_client([{node, ClientNode},
+ ssl_test_lib:start_client([{node, ClientNode},
{port, Port}, {host, Hostname},
{mfa, {?MODULE, session_info_result, []}},
{from, self()}, {options, [{reuse_sessions, false}
@@ -1665,10 +1659,6 @@ reuse_session(Config) when is_list(Config) ->
end,
ssl_test_lib:close(Server),
- ssl_test_lib:close(Client0),
- ssl_test_lib:close(Client1),
- ssl_test_lib:close(Client2),
-
Server1 =
ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
@@ -1680,7 +1670,7 @@ reuse_session(Config) when is_list(Config) ->
Client3 =
ssl_test_lib:start_client([{node, ClientNode},
{port, Port1}, {host, Hostname},
- {mfa, {?MODULE, session_info_result, []}},
+ {mfa, {ssl_test_lib, no_result, []}},
{from, self()}, {options, ClientOpts}]),
SessionInfo1 =
@@ -1689,7 +1679,7 @@ reuse_session(Config) when is_list(Config) ->
Info1
end,
- Server1 ! listen,
+ Server1 ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
%% Make sure session is registered
test_server:sleep(?SLEEP),
@@ -1705,14 +1695,16 @@ reuse_session(Config) when is_list(Config) ->
test_server:fail(
session_reused_when_session_reuse_disabled_by_server);
{Client4, _Other} ->
+ test_server:format("OTHER: ~p ~n", [_Other]),
ok
end,
-
+
ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client0),
+ ssl_test_lib:close(Client1),
+ ssl_test_lib:close(Client2),
ssl_test_lib:close(Client3),
- ssl_test_lib:close(Client4),
- process_flag(trap_exit, false).
-
+ ssl_test_lib:close(Client4).
session_info_result(Socket) ->
ssl:session_info(Socket).
@@ -1725,7 +1717,6 @@ reuse_session_expired(suite) ->
[];
reuse_session_expired(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -1746,8 +1737,8 @@ reuse_session_expired(Config) when is_list(Config) ->
{Server, Info} ->
Info
end,
-
- Server ! listen,
+
+ Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
%% Make sure session is registered
test_server:sleep(?SLEEP),
@@ -1767,7 +1758,7 @@ reuse_session_expired(Config) when is_list(Config) ->
end,
Server ! listen,
-
+
%% Make sure session is unregistered due to expiration
test_server:sleep((?EXPIRE+1) * 1000),
@@ -1782,12 +1773,12 @@ reuse_session_expired(Config) when is_list(Config) ->
{Client2, _} ->
ok
end,
-
+ process_flag(trap_exit, false),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client0),
ssl_test_lib:close(Client1),
- ssl_test_lib:close(Client2),
- process_flag(trap_exit, false).
+ ssl_test_lib:close(Client2).
+
%%--------------------------------------------------------------------
server_does_not_want_to_reuse_session(doc) ->
["Test reuse of sessions (short handshake)"];
@@ -1820,10 +1811,11 @@ server_does_not_want_to_reuse_session(Config) when is_list(Config) ->
Info
end,
- Server ! listen,
+ Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
%% Make sure session is registered
test_server:sleep(?SLEEP),
+ ssl_test_lib:close(Client0),
Client1 =
ssl_test_lib:start_client([{node, ClientNode},
@@ -1836,11 +1828,9 @@ server_does_not_want_to_reuse_session(Config) when is_list(Config) ->
{Client1, _Other} ->
ok
end,
-
+
ssl_test_lib:close(Server),
- ssl_test_lib:close(Client0),
- ssl_test_lib:close(Client1),
- process_flag(trap_exit, false).
+ ssl_test_lib:close(Client1).
%%--------------------------------------------------------------------
@@ -2007,6 +1997,7 @@ server_verify_none_active_once(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+
%%--------------------------------------------------------------------
server_verify_client_once_passive(doc) ->
@@ -2034,7 +2025,7 @@ server_verify_client_once_passive(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok, Client0, ok),
ssl_test_lib:close(Client0),
- Server ! listen,
+ Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
@@ -2072,7 +2063,7 @@ server_verify_client_once_active(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok, Client0, ok),
ssl_test_lib:close(Client0),
- Server ! listen,
+ Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
@@ -2083,7 +2074,6 @@ server_verify_client_once_active(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client1).
-
%%--------------------------------------------------------------------
server_verify_client_once_active_once(doc) ->
@@ -2111,18 +2101,17 @@ server_verify_client_once_active_once(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok, Client0, ok),
ssl_test_lib:close(Client0),
- Server ! listen,
-
+ Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, result_ok, []}},
- {options, [{active, once} | ClientOpts]}]),
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, result_ok, []}},
+ {options, [{active, once} | ClientOpts]}]),
ssl_test_lib:check_result(Client1, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client1).
-
+
%%--------------------------------------------------------------------
server_verify_no_cacerts(doc) ->
@@ -2130,9 +2119,8 @@ server_verify_no_cacerts(doc) ->
server_verify_no_cacerts(suite) ->
[];
-
server_verify_no_cacerts(Config) when is_list(Config) ->
- ServerOpts = ServerOpts = ?config(server_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
@@ -2293,8 +2281,6 @@ client_verify_none_active_once(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-
-
%%--------------------------------------------------------------------
client_renegotiate(doc) ->
["Test ssl:renegotiate/1 on client."];
@@ -2303,7 +2289,6 @@ client_renegotiate(suite) ->
[];
client_renegotiate(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
ClientOpts = ?config(client_opts, Config),
@@ -2326,11 +2311,9 @@ client_renegotiate(Config) when is_list(Config) ->
{options, [{reuse_sessions, false} | ClientOpts]}]),
ssl_test_lib:check_result(Client, ok, Server, ok),
-
ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false),
- ok.
+ ssl_test_lib:close(Client).
+
%%--------------------------------------------------------------------
server_renegotiate(doc) ->
["Test ssl:renegotiate/1 on server."];
@@ -2339,7 +2322,6 @@ server_renegotiate(suite) ->
[];
server_renegotiate(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
ClientOpts = ?config(client_opts, Config),
@@ -2362,8 +2344,7 @@ server_renegotiate(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
- ok.
+ ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
client_renegotiate_reused_session(doc) ->
@@ -2373,7 +2354,6 @@ client_renegotiate_reused_session(suite) ->
[];
client_renegotiate_reused_session(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
ClientOpts = ?config(client_opts, Config),
@@ -2396,11 +2376,8 @@ client_renegotiate_reused_session(Config) when is_list(Config) ->
{options, [{reuse_sessions, true} | ClientOpts]}]),
ssl_test_lib:check_result(Client, ok, Server, ok),
-
ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false),
- ok.
+ ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
server_renegotiate_reused_session(doc) ->
["Test ssl:renegotiate/1 on server when the ssl session will be reused."];
@@ -2409,7 +2386,6 @@ server_renegotiate_reused_session(suite) ->
[];
server_renegotiate_reused_session(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
ClientOpts = ?config(client_opts, Config),
@@ -2432,9 +2408,7 @@ server_renegotiate_reused_session(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
- ok.
-
+ ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
client_no_wrap_sequence_number(doc) ->
["Test that erlang client will renegotiate session when",
@@ -2446,7 +2420,6 @@ client_no_wrap_sequence_number(suite) ->
[];
client_no_wrap_sequence_number(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
ClientOpts = ?config(client_opts, Config),
@@ -2471,11 +2444,8 @@ client_no_wrap_sequence_number(Config) when is_list(Config) ->
{renegotiate_at, N} | ClientOpts]}]),
ssl_test_lib:check_result(Client, ok),
-
ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false),
- ok.
+ ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
server_no_wrap_sequence_number(doc) ->
["Test that erlang server will renegotiate session when",
@@ -2487,7 +2457,6 @@ server_no_wrap_sequence_number(suite) ->
[];
server_no_wrap_sequence_number(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
ClientOpts = ?config(client_opts, Config),
@@ -2511,17 +2480,15 @@ server_no_wrap_sequence_number(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok),
ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
- ok.
-
+ ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-extended_key_usage(doc) ->
- ["Test cert that has a critical extended_key_usage extension"];
+extended_key_usage_verify_peer(doc) ->
+ ["Test cert that has a critical extended_key_usage extension in verify_peer mode"];
-extended_key_usage(suite) ->
+extended_key_usage_verify_peer(suite) ->
[];
-extended_key_usage(Config) when is_list(Config) ->
+extended_key_usage_verify_peer(Config) when is_list(Config) ->
ClientOpts = ?config(client_verification_opts, Config),
ServerOpts = ?config(server_verification_opts, Config),
PrivDir = ?config(priv_dir, Config),
@@ -2537,13 +2504,13 @@ extended_key_usage(Config) when is_list(Config) ->
ServerExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']},
ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate,
ServerExtensions = ServerOTPTbsCert#'OTPTBSCertificate'.extensions,
- NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions =
- [ServerExtKeyUsageExt |
+ NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions =
+ [ServerExtKeyUsageExt |
ServerExtensions]},
- NewServerDerCert = public_key:pkix_sign(NewServerOTPTbsCert, Key),
+ NewServerDerCert = public_key:pkix_sign(NewServerOTPTbsCert, Key),
ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
-
+
ClientCertFile = proplists:get_value(certfile, ClientOpts),
NewClientCertFile = filename:join(PrivDir, "client/new_cert.pem"),
[{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
@@ -2551,28 +2518,90 @@ extended_key_usage(Config) when is_list(Config) ->
ClientExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-clientAuth']},
ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
ClientExtensions = ClientOTPTbsCert#'OTPTBSCertificate'.extensions,
- NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions =
+ NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions =
[ClientExtKeyUsageExt |
ClientExtensions]},
- NewClientDerCert = public_key:pkix_sign(NewClientOTPTbsCert, Key),
+ NewClientDerCert = public_key:pkix_sign(NewClientOTPTbsCert, Key),
ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]),
NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)],
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
{mfa, {?MODULE, send_recv_result_active, []}},
{options, [{verify, verify_peer} | NewServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
- {from, self()},
+ {from, self()},
{mfa, {?MODULE, send_recv_result_active, []}},
{options, [{verify, verify_peer} | NewClientOpts]}]),
-
+
ssl_test_lib:check_result(Server, ok, Client, ok),
-
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+extended_key_usage_verify_none(doc) ->
+ ["Test cert that has a critical extended_key_usage extension in verify_none mode"];
+
+extended_key_usage_verify_none(suite) ->
+ [];
+
+extended_key_usage_verify_none(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_verification_opts, Config),
+ ServerOpts = ?config(server_verification_opts, Config),
+ PrivDir = ?config(priv_dir, Config),
+
+ KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = public_key:pem_entry_decode(KeyEntry),
+
+ ServerCertFile = proplists:get_value(certfile, ServerOpts),
+ NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"),
+ [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
+ ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp),
+ ServerExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']},
+ ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate,
+ ServerExtensions = ServerOTPTbsCert#'OTPTBSCertificate'.extensions,
+ NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions =
+ [ServerExtKeyUsageExt |
+ ServerExtensions]},
+ NewServerDerCert = public_key:pkix_sign(NewServerOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
+ NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
+
+ ClientCertFile = proplists:get_value(certfile, ClientOpts),
+ NewClientCertFile = filename:join(PrivDir, "client/new_cert.pem"),
+ [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
+ ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp),
+ ClientExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-clientAuth']},
+ ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
+ ClientExtensions = ClientOTPTbsCert#'OTPTBSCertificate'.extensions,
+ NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions =
+ [ClientExtKeyUsageExt |
+ ClientExtensions]},
+ NewClientDerCert = public_key:pkix_sign(NewClientOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]),
+ NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)],
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, send_recv_result_active, []}},
+ {options, [{verify, verify_none} | NewServerOpts]}]),
+ 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} | NewClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
@@ -2885,9 +2914,7 @@ unknown_server_ca_fail(Config) when is_list(Config) ->
| ClientOpts]}]),
ssl_test_lib:check_result(Server, {error,"unknown ca"},
- Client, {error, "unknown ca"}),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ Client, {error, "unknown ca"}).
%%--------------------------------------------------------------------
unknown_server_ca_accept_verify_none(doc) ->
@@ -3052,12 +3079,205 @@ der_input_opts(Opts) ->
{Cert, {rsa, Key}, CaCerts, DHParams}.
%%--------------------------------------------------------------------
+%% different_ca_peer_sign(doc) ->
+%% ["Check that a CA can have a different signature algorithm than the peer cert."];
+
+%% different_ca_peer_sign(suite) ->
+%% [];
+
+%% different_ca_peer_sign(Config) when is_list(Config) ->
+%% ClientOpts = ?config(client_mix_opts, Config),
+%% ServerOpts = ?config(server_mix_verify_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_once, []}},
+%% {options, [{active, once},
+%% {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_once,
+%% []}},
+%% {options, [{active, once},
+%% {verify, verify_peer}
+%% | ClientOpts]}]),
+
+%% ssl_test_lib:check_result(Server, ok, Client, ok),
+%% ssl_test_lib:close(Server),
+%% ssl_test_lib:close(Client).
+
+
+%%--------------------------------------------------------------------
+no_reuses_session_server_restart_new_cert(doc) ->
+ ["Check that a session is not reused if the server is restarted with a new cert."];
+
+no_reuses_session_server_restart_new_cert(suite) ->
+ [];
+
+no_reuses_session_server_restart_new_cert(Config) when is_list(Config) ->
+
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ DsaServerOpts = ?config(server_dsa_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, session_info_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client0 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {from, self()}, {options, ClientOpts}]),
+ SessionInfo =
+ receive
+ {Server, Info} ->
+ Info
+ end,
+
+ %% Make sure session is registered
+ test_server:sleep(?SLEEP),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client0),
+
+ Server1 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, DsaServerOpts}]),
+
+ Client1 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {?MODULE, session_info_result, []}},
+ {from, self()}, {options, ClientOpts}]),
+ receive
+ {Client1, SessionInfo} ->
+ test_server:fail(session_reused_when_server_has_new_cert);
+ {Client1, _Other} ->
+ ok
+ end,
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client1).
+
+%%--------------------------------------------------------------------
+no_reuses_session_server_restart_new_cert_file(doc) ->
+ ["Check that a session is not reused if a server is restarted with a new "
+ "cert contained in a file with the same name as the old cert."];
+
+no_reuses_session_server_restart_new_cert_file(suite) ->
+ [];
+
+no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_verification_opts, Config),
+ DsaServerOpts = ?config(server_dsa_opts, Config),
+ PrivDir = ?config(priv_dir, Config),
+
+ NewServerOpts = new_config(PrivDir, ServerOpts),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, session_info_result, []}},
+ {options, NewServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client0 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {from, self()}, {options, ClientOpts}]),
+ SessionInfo =
+ receive
+ {Server, Info} ->
+ Info
+ end,
+
+ %% Make sure session is registered and we get
+ %% new file time stamp when calling new_config!
+ test_server:sleep(?SLEEP* 2),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client0),
+
+ NewServerOpts = new_config(PrivDir, DsaServerOpts),
+
+ Server1 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, NewServerOpts}]),
+ Client1 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {?MODULE, session_info_result, []}},
+ {from, self()}, {options, ClientOpts}]),
+ receive
+ {Client1, SessionInfo} ->
+ test_server:fail(session_reused_when_server_has_new_cert);
+ {Client1, _Other} ->
+ ok
+ end,
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client1).
+
+%%--------------------------------------------------------------------
+reuseaddr(doc) ->
+ [""];
+
+reuseaddr(suite) ->
+ [];
+
+reuseaddr(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, {ssl_test_lib, no_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, {ssl_test_lib, no_result, []}},
+ {options, [{active, false} | ClientOpts]}]),
+ test_server:sleep(?SLEEP),
+ ssl_test_lib:close(Server),
+
+ Server1 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
+ {from, self()},
+ {mfa, {?MODULE, send_recv_result, []}},
+ {options, [{active, false} | ServerOpts]}]),
+ Client1 =
+ 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(Server1, ok, Client1, ok),
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client1).
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
erlang_ssl_receive(Socket, Data) ->
receive
{ssl, Socket, Data} ->
- io:format("Received ~p~n",[Data]),
+ test_server:format("Received ~p~n",[Data]),
ok;
Other ->
test_server:fail({unexpected_message, Other})
@@ -3087,7 +3307,6 @@ send_recv_result_active_once(Socket) ->
result_ok(_Socket) ->
ok.
-
renegotiate(Socket, Data) ->
test_server:format("Renegotiating ~n", []),
Result = ssl:renegotiate(Socket),
@@ -3104,3 +3323,24 @@ renegotiate_reuse_session(Socket, Data) ->
%% Make sure session is registerd
test_server:sleep(?SLEEP),
renegotiate(Socket, Data).
+
+
+new_config(PrivDir, ServerOpts0) ->
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts0),
+ CertFile = proplists:get_value(certfile, ServerOpts0),
+ KeyFile = proplists:get_value(keyfile, ServerOpts0),
+ NewCaCertFile = filename:join(PrivDir, "new_ca.pem"),
+ NewCertFile = filename:join(PrivDir, "new_cert.pem"),
+ NewKeyFile = filename:join(PrivDir, "new_key.pem"),
+ file:copy(CaCertFile, NewCaCertFile),
+ file:copy(CertFile, NewCertFile),
+ file:copy(KeyFile, NewKeyFile),
+ ServerOpts1 = proplists:delete(cacertfile, ServerOpts0),
+ ServerOpts2 = proplists:delete(certfile, ServerOpts1),
+ ServerOpts = proplists:delete(keyfile, ServerOpts2),
+
+ {ok, PEM} = file:read_file(NewCaCertFile),
+ test_server:format("CA file content: ~p~n", [public_key:pem_decode(PEM)]),
+
+ [{cacertfile, NewCaCertFile}, {certfile, NewCertFile},
+ {keyfile, NewKeyFile} | ServerOpts].
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index e1e8214ed6..f6ccbe85e3 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -81,14 +81,20 @@ run_server(ListenSocket, Opts) ->
no_result_msg ->
ok;
Msg ->
- test_server:format("Msg: ~p ~n", [Msg]),
+ test_server:format("Server Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg}
end,
- receive
+ receive
listen ->
run_server(ListenSocket, Opts);
+ {listen, MFA} ->
+ run_server(ListenSocket, [MFA | proplists:delete(mfa, Opts)]);
close ->
- ok = rpc:call(Node, ssl, close, [AcceptSocket])
+ test_server:format("Server closing ~p ~n", [self()]),
+ Result = rpc:call(Node, ssl, close, [AcceptSocket], 500),
+ test_server:format("Result ~p ~n", [Result]);
+ {ssl_closed, _} ->
+ ok
end.
%%% To enable to test with s_client -reconnect
@@ -151,19 +157,30 @@ run_client(Opts) ->
no_result_msg ->
ok;
Msg ->
+ test_server:format("Client Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg}
end,
- receive
+ receive
close ->
- ok = rpc:call(Node, ssl, close, [Socket])
+ test_server:format("Client closing~n", []),
+ rpc:call(Node, ssl, close, [Socket]);
+ {ssl_closed, Socket} ->
+ ok
end;
{error, Reason} ->
- test_server:format("Client: connection failed: ~p ~n", [Reason]),
+ test_server:format("Client: connection failed: ~p ~n", [Reason]),
Pid ! {self(), {error, Reason}}
end.
close(Pid) ->
- Pid ! close.
+ test_server:format("Close ~p ~n", [Pid]),
+ Monitor = erlang:monitor(process, Pid),
+ Pid ! close,
+ receive
+ {'DOWN', Monitor, process, Pid, Reason} ->
+ erlang:demonitor(Monitor),
+ test_server:format("Pid: ~p down due to:~p ~n", [Pid, Reason])
+ end.
check_result(Server, ServerMsg, Client, ClientMsg) ->
receive
@@ -208,47 +225,27 @@ check_result(Pid, Msg) ->
test_server:fail(Reason)
end.
-check_result_ignore_renegotiation_reject(Pid, Msg) ->
- receive
- {Pid, fail_session_fatal_alert_during_renegotiation} ->
- test_server:comment("Server rejected old renegotiation"),
- ok;
- {ssl_error, _, esslconnect} ->
- test_server:comment("Server rejected old renegotiation"),
- ok;
- {Pid, Msg} ->
- ok;
- {Port, {data,Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
- check_result(Pid,Msg);
- Unexpected ->
- Reason = {{expected, {Pid, Msg}},
- {got, Unexpected}},
- test_server:fail(Reason)
- end.
-
-
wait_for_result(Server, ServerMsg, Client, ClientMsg) ->
receive
{Server, ServerMsg} ->
receive
{Client, ClientMsg} ->
- ok;
- Unexpected ->
- Unexpected
+ ok
+ %% Unexpected ->
+ %% Unexpected
end;
{Client, ClientMsg} ->
receive
{Server, ServerMsg} ->
- ok;
- Unexpected ->
- Unexpected
+ ok
+ %% Unexpected ->
+ %% Unexpected
end;
{Port, {data,Debug}} when is_port(Port) ->
io:format("openssl ~s~n",[Debug]),
- wait_for_result(Server, ServerMsg, Client, ClientMsg);
- Unexpected ->
- Unexpected
+ wait_for_result(Server, ServerMsg, Client, ClientMsg)
+ %% Unexpected ->
+ %% Unexpected
end.
@@ -258,9 +255,9 @@ wait_for_result(Pid, Msg) ->
ok;
{Port, {data,Debug}} when is_port(Port) ->
io:format("openssl ~s~n",[Debug]),
- wait_for_result(Pid,Msg);
- Unexpected ->
- Unexpected
+ wait_for_result(Pid,Msg)
+ %% Unexpected ->
+ %% Unexpected
end.
cert_options(Config) ->
@@ -327,8 +324,8 @@ cert_options(Config) ->
make_dsa_cert(Config) ->
- {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_dsa_cert_files("server", Config),
- {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_dsa_cert_files("client", Config),
+ {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, dsa, dsa, ""),
+ {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, dsa, dsa, ""),
[{server_dsa_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
@@ -342,22 +339,41 @@ make_dsa_cert(Config) ->
| Config].
-
-make_dsa_cert_files(RoleStr, Config) ->
- CaInfo = {CaCert, _} = erl_make_certs:make_cert([{key, dsa}]),
- {Cert, CertKey} = erl_make_certs:make_cert([{key, dsa}, {issuer, CaInfo}]),
+make_mix_cert(Config) ->
+ {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, dsa,
+ rsa, "mix"),
+ {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, dsa,
+ rsa, "mix"),
+ [{server_mix_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ServerCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
+ {server_mix_verify_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {verify, verify_peer}]},
+ {client_mix_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
+ | Config].
+
+make_cert_files(RoleStr, Config, Alg1, Alg2, Prefix) ->
+ Alg1Str = atom_to_list(Alg1),
+ Alg2Str = atom_to_list(Alg2),
+ CaInfo = {CaCert, _} = erl_make_certs:make_cert([{key, Alg1}]),
+ {Cert, CertKey} = erl_make_certs:make_cert([{key, Alg2}, {issuer, CaInfo}]),
CaCertFile = filename:join([?config(priv_dir, Config),
- RoleStr, "dsa_cacerts.pem"]),
+ RoleStr, Prefix ++ Alg1Str ++ "_cacerts.pem"]),
CertFile = filename:join([?config(priv_dir, Config),
- RoleStr, "dsa_cert.pem"]),
+ RoleStr, Prefix ++ Alg2Str ++ "_cert.pem"]),
KeyFile = filename:join([?config(priv_dir, Config),
- RoleStr, "dsa_key.pem"]),
+ RoleStr, Prefix ++ Alg2Str ++ "_key.pem"]),
der_to_pem(CaCertFile, [{'Certificate', CaCert, not_encrypted}]),
der_to_pem(CertFile, [{'Certificate', Cert, not_encrypted}]),
der_to_pem(KeyFile, [CertKey]),
{CaCertFile, CertFile, KeyFile}.
+
start_upgrade_server(Args) ->
Result = spawn_link(?MODULE, run_upgrade_server, [Args]),
receive
@@ -395,10 +411,12 @@ run_upgrade_server(Opts) ->
end,
{Module, Function, Args} = proplists:get_value(mfa, Opts),
Msg = rpc:call(Node, Module, Function, [SslAcceptSocket | Args]),
+ test_server:format("Upgrade Server Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg},
receive
close ->
- ok = rpc:call(Node, ssl, close, [SslAcceptSocket])
+ test_server:format("Upgrade Server closing~n", []),
+ rpc:call(Node, ssl, close, [SslAcceptSocket])
end
catch error:{badmatch, Error} ->
Pid ! {self(), Error}
@@ -428,10 +446,12 @@ run_upgrade_client(Opts) ->
test_server:format("apply(~p, ~p, ~p)~n",
[Module, Function, [SslSocket | Args]]),
Msg = rpc:call(Node, Module, Function, [SslSocket | Args]),
+ test_server:format("Upgrade Client Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg},
receive
close ->
- ok = rpc:call(Node, ssl, close, [SslSocket])
+ test_server:format("Upgrade Client closing~n", []),
+ rpc:call(Node, ssl, close, [SslSocket])
end.
start_upgrade_server_error(Args) ->
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index afedeaf099..46ad0c17b6 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -1164,10 +1164,6 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
close_port(OpenSslPort),
%% Clean close down!
ssl_test_lib:close(Client),
- receive
- {'EXIT', Client, normal} ->
- ok
- end,
Return = case Result of
ok ->
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index ee692adb3b..a4be7bb889 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1,2 +1,2 @@
-SSL_VSN = 4.1.1
+SSL_VSN = 4.1.3
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index 940044d0a8..a8fe41f000 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -30,6 +30,24 @@
</header>
<p>This document describes the changes made to the STDLIB application.</p>
+<section><title>STDLIB 1.17.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Several type specifications for standard libraries were
+ wrong in the R14B01 release. This is now corrected. The
+ corrections concern types in re,io,filename and the
+ module erlang itself.</p>
+ <p>
+ Own Id: OTP-9008</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 1.17.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/stdlib/src/filename.erl b/lib/stdlib/src/filename.erl
index e38b8957f2..24abf1e977 100644
--- a/lib/stdlib/src/filename.erl
+++ b/lib/stdlib/src/filename.erl
@@ -165,8 +165,6 @@ basename1([$/|[]], Tail, DirSep2) ->
basename1([], Tail, DirSep2);
basename1([$/|Rest], _Tail, DirSep2) ->
basename1(Rest, [], DirSep2);
-basename1([[_|_]=List|Rest], Tail, DirSep2) ->
- basename1(List++Rest, Tail, DirSep2);
basename1([DirSep2|Rest], Tail, DirSep2) when is_integer(DirSep2) ->
basename1([$/|Rest], Tail, DirSep2);
basename1([Char|Rest], Tail, DirSep2) when is_integer(Char) ->
@@ -280,8 +278,6 @@ dirname(Name0) ->
Name = flatten(Name0),
dirname(Name, [], [], separators()).
-dirname([[_|_]=List|Rest], Dir, File, Seps) ->
- dirname(List++Rest, Dir, File, Seps);
dirname([$/|Rest], Dir, File, Seps) ->
dirname(Rest, File++Dir, [$/], Seps);
dirname([DirSep|Rest], Dir, File, {DirSep,_}=Seps) when is_integer(DirSep) ->
@@ -346,8 +342,6 @@ extension(Name) when is_binary(Name) ->
[]
end,
case binary:matches(Name,[<<".">>]) of
- nomatch -> % Bug in binary workaround :(
- <<>>;
[] ->
<<>>;
List ->
@@ -479,6 +473,12 @@ maybe_remove_dirsep(Name, _) ->
%% by a previous call to join/{1,2}.
-spec append(file:filename(), file:name()) -> file:filename().
+append(Dir, Name) when is_binary(Dir), is_binary(Name) ->
+ <<Dir/binary,$/:8,Name/binary>>;
+append(Dir, Name) when is_binary(Dir) ->
+ append(Dir,filename_string_to_binary(Name));
+append(Dir, Name) when is_binary(Name) ->
+ append(filename_string_to_binary(Dir),Name);
append(Dir, Name) ->
Dir ++ [$/|Name].
@@ -685,8 +685,6 @@ split([$/|Rest], Comp, Components, OsType) ->
split(Rest, [], [lists:reverse(Comp)|Components], OsType);
split([Char|Rest], Comp, Components, OsType) when is_integer(Char) ->
split(Rest, [Char|Comp], Components, OsType);
-split([List|Rest], Comp, Components, OsType) when is_list(List) ->
- split(List++Rest, Comp, Components, OsType);
split([], [], Components, _OsType) ->
lists:reverse(Components);
split([], Comp, Components, OsType) ->
diff --git a/lib/stdlib/src/io.erl b/lib/stdlib/src/io.erl
index 1d0f9374bc..78412ab2bc 100644
--- a/lib/stdlib/src/io.erl
+++ b/lib/stdlib/src/io.erl
@@ -39,6 +39,8 @@
-type device() :: atom() | pid().
-type prompt() :: atom() | string().
+-type error_description() :: term(). % Whatever the io-server sends.
+-type request_error() :: {'error',error_description()}.
%% XXX: Some uses of line() in this file may need to read erl_scan:location()
-type line() :: pos_integer().
@@ -299,32 +301,32 @@ format(Io, Format, Args) ->
%% Scanning Erlang code.
--spec scan_erl_exprs(prompt()) -> erl_scan:tokens_result().
+-spec scan_erl_exprs(prompt()) -> erl_scan:tokens_result() | request_error().
scan_erl_exprs(Prompt) ->
scan_erl_exprs(default_input(), Prompt, 1).
--spec scan_erl_exprs(device(), prompt()) -> erl_scan:tokens_result().
+-spec scan_erl_exprs(device(), prompt()) -> erl_scan:tokens_result() | request_error().
scan_erl_exprs(Io, Prompt) ->
scan_erl_exprs(Io, Prompt, 1).
--spec scan_erl_exprs(device(), prompt(), line()) -> erl_scan:tokens_result().
+-spec scan_erl_exprs(device(), prompt(), line()) -> erl_scan:tokens_result() | request_error().
scan_erl_exprs(Io, Prompt, Pos0) ->
request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[Pos0]}).
--spec scan_erl_form(prompt()) -> erl_scan:tokens_result().
+-spec scan_erl_form(prompt()) -> erl_scan:tokens_result() | request_error().
scan_erl_form(Prompt) ->
scan_erl_form(default_input(), Prompt, 1).
--spec scan_erl_form(device(), prompt()) -> erl_scan:tokens_result().
+-spec scan_erl_form(device(), prompt()) -> erl_scan:tokens_result() | request_error().
scan_erl_form(Io, Prompt) ->
scan_erl_form(Io, Prompt, 1).
--spec scan_erl_form(device(), prompt(), line()) -> erl_scan:tokens_result().
+-spec scan_erl_form(device(), prompt(), line()) -> erl_scan:tokens_result() | request_error().
scan_erl_form(Io, Prompt, Pos0) ->
request(Io, {get_until,unicode,Prompt,erl_scan,tokens,[Pos0]}).
@@ -335,7 +337,8 @@ scan_erl_form(Io, Prompt, Pos0) ->
-type parse_ret() :: {'ok', erl_parse_expr_list(), line()}
| {'eof', line()}
- | {'error', erl_scan:error_info(), line()}.
+ | {'error', erl_scan:error_info(), line()}
+ | request_error().
-spec parse_erl_exprs(prompt()) -> parse_ret().
@@ -364,7 +367,8 @@ parse_erl_exprs(Io, Prompt, Pos0) ->
-type parse_form_ret() :: {'ok', erl_parse_absform(), line()}
| {'eof', line()}
- | {'error', erl_scan:error_info(), line()}.
+ | {'error', erl_scan:error_info(), line()}
+ | request_error().
-spec parse_erl_form(prompt()) -> parse_form_ret().
diff --git a/lib/stdlib/src/re.erl b/lib/stdlib/src/re.erl
index 296a6b3d23..9642de17b4 100644
--- a/lib/stdlib/src/re.erl
+++ b/lib/stdlib/src/re.erl
@@ -208,29 +208,25 @@ replace(Subject,RE,Replacement,Options) ->
process_repl_params(Options,iodata,false),
FlatSubject = to_binary(Subject, Unicode),
FlatReplacement = to_binary(Replacement, Unicode),
- case do_replace(FlatSubject,Subject,RE,FlatReplacement,NewOpt) of
- {error,_Err} ->
- throw(badre);
- IoList ->
- case Convert of
- iodata ->
- IoList;
- binary ->
- case Unicode of
- false ->
- iolist_to_binary(IoList);
- true ->
- unicode:characters_to_binary(IoList,unicode)
- end;
- list ->
- case Unicode of
- false ->
- binary_to_list(iolist_to_binary(IoList));
- true ->
- unicode:characters_to_list(IoList,unicode)
- end
- end
- end
+ IoList = do_replace(FlatSubject,Subject,RE,FlatReplacement,NewOpt),
+ case Convert of
+ iodata ->
+ IoList;
+ binary ->
+ case Unicode of
+ false ->
+ iolist_to_binary(IoList);
+ true ->
+ unicode:characters_to_binary(IoList,unicode)
+ end;
+ list ->
+ case Unicode of
+ false ->
+ binary_to_list(iolist_to_binary(IoList));
+ true ->
+ unicode:characters_to_list(IoList,unicode)
+ end
+ end
catch
throw:badopt ->
erlang:error(badarg,[Subject,RE,Replacement,Options]);
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index db7954af04..6c209e97b9 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 1.17.2
+STDLIB_VSN = 1.17.2.1