File 4641-public_key-ssl-add-password-fun-for-decoding-keyfile.patch of Package erlang

From c6e437b5e914deb06983cc7bd224d1b1e2d8f9ea Mon Sep 17 00:00:00 2001
From: Jakub Witczak <kuba@erlang.org>
Date: Fri, 14 Jan 2022 17:20:35 +0100
Subject: [PATCH] public_key,ssl: add password fun for decoding keyfiles

Implementing password fun option for ssl connect API

This change allows password option to accept as a value
either a string or a fun. Added specific tests and
documentation.

The motivation for this change is to better protect a
private key. If the private key is protected by password the
password may be retreived using user supplied function therefore
enabling storing password in a secure vault or something similar.
---
 lib/public_key/doc/src/public_key.xml    |   1 +
 lib/public_key/src/public_key.erl        |  10 +-
 lib/public_key/test/public_key_SUITE.erl |  57 ++--
 lib/ssl/doc/src/ssl.xml                  |   4 +-
 lib/ssl/src/ssl.erl                      |  11 +-
 lib/ssl/src/ssl_config.erl               |   2 +-
 lib/ssl/test/ssl_api_SUITE.erl           |   3 +-
 lib/ssl/test/ssl_test_lib.erl            |  36 ++-
 lib/ssl/test/tls_api_SUITE.erl           | 372 +++++++++++++++--------
 9 files changed, 331 insertions(+), 165 deletions(-)

diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index 4c674333b2..884425cf15 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -418,6 +418,7 @@
     entries. Notice that if the PEM entry is of type
     'SubjectPublickeyInfo', it is further decoded to an
     <c>rsa_public_key()</c> or <c>dsa_public_key()</c>.</p>
+    <p>Password can be either an octet string or function which returns same type.</p>
   </desc> 
   </func>
 
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 0b5061f695..b3b830b3c8 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -241,8 +241,11 @@ pem_entry_decode({Asn1Type, Der, not_encrypted}) when is_atom(Asn1Type),
 						      is_binary(Der) ->
     der_decode(Asn1Type, Der).
 
--spec pem_entry_decode(PemEntry, Password) -> term() when PemEntry :: pem_entry(),
-                                                          Password :: string() .
+-spec pem_entry_decode(PemEntry, Password) -> term() when
+      PemEntry :: pem_entry(),
+      Password :: string() | fun(() -> string()).
+pem_entry_decode(PemEntry, PasswordFun) when is_function(PasswordFun) ->
+     pem_entry_decode(PemEntry, PasswordFun());
 pem_entry_decode({Asn1Type, Der, not_encrypted}, _) when is_atom(Asn1Type),
 							 is_binary(Der) ->
     der_decode(Asn1Type, Der);
@@ -264,8 +267,7 @@ pem_entry_decode({Asn1Type, CryptDer, {Cipher, Salt}} = PemEntry,
 				is_binary(Salt) andalso
 				((erlang:byte_size(Salt) == 8) or (erlang:byte_size(Salt) == 16)) andalso
 				is_list(Password) ->
-    do_pem_entry_decode(PemEntry, Password).	
-
+    do_pem_entry_decode(PemEntry, Password).
 
 %%--------------------------------------------------------------------
 %%
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index b176cbef6a..3984110f5d 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -62,8 +62,10 @@
          init_ec_pem_encode_generated/1,
          ec_pem_encode_generated/0,
          ec_pem_encode_generated/1,
-         encrypted_pem/0,
-         encrypted_pem/1,
+         encrypted_pem_pwdstring/0,
+         encrypted_pem_pwdstring/1,
+         encrypted_pem_pwdfun/0,
+         encrypted_pem_pwdfun/1,
          dh_pem/0,
          dh_pem/1,
          pkcs10_pem/0,
@@ -121,7 +123,8 @@
         ]).
 
 -define(TIMEOUT, 120000). % 2 min
-
+-define(PASSWORD1, "1234abcd").
+-define(PASSWORD2, "4567efgh").
 
 %%--------------------------------------------------------------------
 %% Common Test interface functions -----------------------------------
@@ -158,13 +161,13 @@ all() ->
     ].
 
 groups() -> 
-    [{pem_decode_encode, [], [dsa_pem, rsa_pem, rsa_pss_pss_pem, ec_pem, encrypted_pem,
+    [{pem_decode_encode, [], [dsa_pem, rsa_pem, rsa_pss_pss_pem, ec_pem,
+			      encrypted_pem_pwdstring, encrypted_pem_pwdfun,
 			      dh_pem, cert_pem, pkcs7_pem, pkcs10_pem, ec_pem2,
 			      rsa_priv_pkcs8, dsa_priv_pkcs8, ec_priv_pkcs8,
-                              eddsa_priv_pkcs8, eddsa_priv_rfc5958,
-                              ec_pem_encode_generated,
-                              gen_ec_param_prime_field, gen_ec_param_char_2_field
-                             ]},
+			      eddsa_priv_pkcs8, eddsa_priv_rfc5958,
+			      ec_pem_encode_generated, gen_ec_param_prime_field,
+			      gen_ec_param_char_2_field]},
      {sign_verify, [], [rsa_sign_verify, rsa_pss_sign_verify, dsa_sign_verify]}
     ].
 %%-------------------------------------------------------------------
@@ -451,37 +454,45 @@ ec_pem_encode_generated(_Config) ->
 
 %%--------------------------------------------------------------------
 
-encrypted_pem() ->
-    [{doc, "Encrypted PEM-file decode/encode"}].
-encrypted_pem(Config) when is_list(Config) ->
+encrypted_pem_pwdstring() ->
+    [{doc, "Encrypted PEM-file decode/encode with password string used"}].
+encrypted_pem_pwdstring(Config) when is_list(Config) ->
+    encrypted_pem(Config, ?PASSWORD1, ?PASSWORD2).
+
+encrypted_pem_pwdfun() ->
+    [{doc, "Encrypted PEM-file decode/encode with password fun used"}].
+encrypted_pem_pwdfun(Config) when is_list(Config) ->
+    encrypted_pem(Config, fun() -> ?PASSWORD1 end, fun() -> ?PASSWORD2 end).
+
+encrypted_pem(Config, Password1, Password2) ->
     Datadir = proplists:get_value(data_dir, Config),
 
     [{'RSAPrivateKey', DerRSAKey, not_encrypted}] =
-	erl_make_certs:pem_to_der(filename:join(Datadir, "client_key.pem")),
+        erl_make_certs:pem_to_der(filename:join(Datadir, "client_key.pem")),
 
     RSAKey = public_key:der_decode('RSAPrivateKey', DerRSAKey),
 
     Salt0 = crypto:strong_rand_bytes(8),
     Entry0 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey,
-					 {{"DES-EDE3-CBC", Salt0}, "1234abcd"}),
-    RSAKey = public_key:pem_entry_decode(Entry0,"1234abcd"),
+                                         {{"DES-EDE3-CBC", Salt0}, ?PASSWORD1}),
+    RSAKey = public_key:pem_entry_decode(Entry0, Password1),
     Des3KeyFile = filename:join(Datadir, "des3_client_key.pem"),
     erl_make_certs:der_to_pem(Des3KeyFile, [Entry0]),
     [{'RSAPrivateKey', _, {"DES-EDE3-CBC", Salt0}}] =
-	erl_make_certs:pem_to_der(Des3KeyFile),
+        erl_make_certs:pem_to_der(Des3KeyFile),
 
     Salt1 = crypto:strong_rand_bytes(8),
     Entry1 = public_key:pem_entry_encode('RSAPrivateKey', RSAKey,
-					   {{"DES-CBC", Salt1}, "4567efgh"}),
+                                           {{"DES-CBC", Salt1}, ?PASSWORD2}),
     DesKeyFile = filename:join(Datadir, "des_client_key.pem"),
     erl_make_certs:der_to_pem(DesKeyFile, [Entry1]),
-    [{'RSAPrivateKey', _, {"DES-CBC", Salt1}} =Entry2] =
-	erl_make_certs:pem_to_der(DesKeyFile),
+    [{'RSAPrivateKey', _, {"DES-CBC", Salt1}} = Entry2] =
+        erl_make_certs:pem_to_der(DesKeyFile),
     {ok, Pem} = file:read_file(DesKeyFile),
     check_encapsulated_header(Pem),
-    true = check_entry_type(public_key:pem_entry_decode(Entry2, "4567efgh"),
-			     'RSAPrivateKey').
-    
+    true = check_entry_type(public_key:pem_entry_decode(Entry2, Password2),
+                             'RSAPrivateKey').
+
 %%--------------------------------------------------------------------
 
 dh_pem() ->
@@ -783,7 +794,7 @@ pkix_path_validation(Config) when is_list(Config) ->
     % RsaPssKey = {public_key:generate_key({rsa, 1024, 65537}), pss_params(sha256)},
     RsaPssKey = {hardcode_rsa_key(1), pss_params(sha256)},
 
-    CaKPSS = {TrustedPSSCert,_} = erl_make_certs:make_cert([{key, RsaPssKey},
+    _CaKPSS = {TrustedPSSCert,_} = erl_make_certs:make_cert([{key, RsaPssKey},
                  {subject, [
                     {name, "RSASSA-PSS Public Key"},
                     {?'id-at-name', {printableString, "public_key"}},
@@ -794,7 +805,7 @@ pkix_path_validation(Config) when is_list(Config) ->
                     {org_unit, "testing dep"}
                        ]}
                 ]),
-    ChainPSSCert = {CertPSS, _} = erl_make_certs:make_cert([{issuer, {TrustedPSSCert,RsaPssKey}}]),
+    _ChainPSSCert = {CertPSS, _} = erl_make_certs:make_cert([{issuer, {TrustedPSSCert,RsaPssKey}}]),
     {ok, _} = public_key:pkix_path_validation(TrustedPSSCert, [CertPSS], []).
 
 pkix_path_validation_root_expired() ->
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index f75005e1ac..486e21d51e 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -358,11 +358,11 @@
     <datatype>
       <name name="key_password"/>
       <desc>
-	<p>String containing the user's password. Only used if the 
+	<p>String containing the user's password or a function returning same type. Only used if the
 	private keyfile is password-protected.</p>
       </desc>
     </datatype>
-    
+
     <datatype>
       <name name="cipher_suites"/>
       <desc>
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index d1ca621e22..d70df3c473 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -347,7 +347,7 @@
                                        key_id := crypto:key_id(), 
                                        password => crypto:password()}. % exported
 -type key_pem()                   :: file:filename().
--type key_password()              :: string().
+-type key_password()              :: string() | fun(() -> string()).
 -type cipher_suites()             :: ciphers().    
 -type ciphers()                   :: [erl_cipher_suite()] |
                                      string(). % (according to old API) exported
@@ -1736,6 +1736,12 @@ handle_option(padding_check = Option, Value0,  #{versions := Versions} = Options
     assert_option_dependency(Option, versions, Versions, ['tlsv1']),
     Value = validate_option(Option, Value0),
     OptionsMap#{Option => Value};
+handle_option(password = Option, unbound, OptionsMap, #{rules := Rules}) ->
+    Value = validate_option(Option, default_value(Option, Rules)),
+    OptionsMap#{password => Value};
+handle_option(password = Option, Value0, OptionsMap, _Env) ->
+    Value = validate_option(Option, Value0),
+    OptionsMap#{password => Value};
 handle_option(psk_identity = Option, unbound, OptionsMap, #{rules := Rules}) ->
     Value = validate_option(Option, default_value(Option, Rules)),
     OptionsMap#{Option => Value};
@@ -2283,6 +2289,9 @@ validate_option(partial_chain, Value, _)
 validate_option(password, Value, _)
   when is_list(Value) ->
     Value;
+validate_option(password, Value, _)
+  when is_function(Value, 0) ->
+    Value;
 validate_option(protocol, Value = tls, _) ->
     Value;
 validate_option(protocol, Value = dtls, _) ->
diff --git a/lib/ssl/src/ssl_config.erl b/lib/ssl/src/ssl_config.erl
index 89198eaa2b..80a5b4f44c 100644
--- a/lib/ssl/src/ssl_config.erl
+++ b/lib/ssl/src/ssl_config.erl
@@ -43,7 +43,7 @@
 init(#{erl_dist := ErlDist,
        key := Key,
        keyfile := KeyFile,
-       password := Password,
+       password := Password, %% Can be fun() or string()
        dh := DH,
        dhfile := DHFile} = SslOpts, Role) ->
     
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index beabdcb8de..628e7119ba 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -157,6 +157,7 @@
        ]).
 
 -export([make_rsa_cert/1,
+         make_rsa_cert_with_protected_keyfile/2,
          make_dsa_cert/1,
          make_ecdsa_cert/1,
          make_ecdh_rsa_cert/1,
@@ -1764,7 +1765,7 @@ make_rsa_cert(Config) ->
 	    [{server_rsa_opts, [{reuseaddr, true} | ServerConf]},
 	     {server_rsa_verify_opts, [{reuseaddr, true}, {verify, verify_peer} | ServerConf]},
 	     {client_rsa_opts, ClientConf},
-             {client_rsa_verify_opts,  [{verify, verify_peer} |ClientConf]},
+             {client_rsa_verify_opts, [{verify, verify_peer} |ClientConf]},
              {server_rsa_der_opts, [{reuseaddr, true} | ServerDerConf]},
 	     {server_rsa_der_verify_opts, [{reuseaddr, true}, {verify, verify_peer} | ServerDerConf]},
 	     {client_rsa_der_opts, ClientDerConf},
@@ -1774,6 +1775,34 @@ make_rsa_cert(Config) ->
 	    Config
     end.
 
+make_rsa_cert_with_protected_keyfile(Config0, Password) ->
+    Config1 = make_rsa_cert(Config0),
+
+    ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config1),
+    [PemEntry] = pem_to_der(proplists:get_value(keyfile, ClientOpts)),
+    ASN1OctetStrTag = 4,
+    IV = <<4,8,154,8,95,192,188,232,4,8,154,8,95,192,188,232>>,
+    Length = <<16:8/unsigned-big-integer>>,
+    Params = {"AES-256-CBC",
+              {'PBES2-params',
+               {'PBES2-params_keyDerivationFunc',
+                ?'id-PBKDF2',
+                {'PBKDF2-params',
+                 {specified, <<125,96,67,95,2,233,224,174>>},
+                 2048,asn1_NOVALUE,
+                 {'PBKDF2-params_prf', ?'id-hmacWithSHA1','NULL'}}},
+               {'PBES2-params_encryptionScheme',
+                ?'id-aes256-CBC',
+                {asn1_OPENTYPE, <<ASN1OctetStrTag, Length/binary, IV/binary>>}}}},
+    ProtectedPemEntry = public_key:pem_entry_encode(
+                          'PrivateKeyInfo',public_key:pem_entry_decode(PemEntry),
+                          {Params, Password}),
+    ProtectedClientKeyFile = filename:join(proplists:get_value(priv_dir,Config1),
+                                           "tls_password_client.pem"),
+    der_to_pem(ProtectedClientKeyFile, [ProtectedPemEntry]),
+    ProtectedClientOpts = [{keyfile,ProtectedClientKeyFile} | proplists:delete(keyfile, ClientOpts)],
+    [{client_protected_rsa_opts, ProtectedClientOpts} | Config1].
+
 make_rsa_1024_cert(Config) ->
     CryptoSupport = crypto:supports(),
     case proplists:get_bool(rsa, proplists:get_value(public_keys, CryptoSupport)) of
@@ -1994,6 +2023,7 @@ run_server_error(Opts) ->
     Pid = proplists:get_value(from, Opts),
     Transport =  proplists:get_value(transport, Opts, ssl),
     ct:log("~p:~p~nssl:listen(~p, ~p)~n", [?MODULE,?LINE, Port, Options]),
+    Timeout = proplists:get_value(timeout, Opts, infinity),
     case Transport:listen(Port, Options) of
 	{ok, #sslsocket{} = ListenSocket} ->
 	    %% To make sure error_client will
@@ -2001,7 +2031,7 @@ run_server_error(Opts) ->
 	    Pid ! {listen, up},
 	    send_selected_port(Pid, Port, ListenSocket),
 	    ct:log("~p:~p~nssl:transport_accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
-	    case Transport:transport_accept(ListenSocket) of
+	    case Transport:transport_accept(ListenSocket, Timeout) of
 		{error, _} = Error ->
 		    Pid ! {self(), Error};
 		{ok, AcceptSocket} ->
diff --git a/lib/ssl/test/tls_api_SUITE.erl b/lib/ssl/test/tls_api_SUITE.erl
index e2e1629336..7acf0e19f7 100644
--- a/lib/ssl/test/tls_api_SUITE.erl
+++ b/lib/ssl/test/tls_api_SUITE.erl
@@ -22,6 +22,7 @@
 -module(tls_api_SUITE).
 
 -include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
 -include_lib("ssl/src/ssl_record.hrl").
 -include_lib("ssl/src/ssl_internal.hrl").
 -include_lib("ssl/src/ssl_api.hrl").
@@ -42,7 +43,7 @@
 -export([tls_upgrade/0,
          tls_upgrade/1,
          tls_upgrade_new_opts/0,
-         tls_upgrade_new_opts/1,         
+         tls_upgrade_new_opts/1,
          tls_upgrade_with_timeout/0,
          tls_upgrade_with_timeout/1,
          tls_upgrade_with_client_timeout/0,
@@ -59,6 +60,12 @@
          tls_client_closes_socket/1,
          tls_closed_in_active_once/0,
          tls_closed_in_active_once/1,
+         tls_password_incorrect/0,
+         tls_password_incorrect/1,
+         tls_password_correct/0,
+         tls_password_correct/1,
+         tls_password_badarg/0,
+         tls_password_badarg/1,
          tls_reset_in_active_once/0,
          tls_reset_in_active_once/1,
          tls_tcp_msg/0,
@@ -101,6 +108,9 @@
         ]).
 
 -define(SLEEP, 500).
+-define(CORRECT_PASSWORD, "hello test").
+-define(INCORRECT_PASSWORD, "hello").
+-define(BADARG_PASSWORD, hello).
 
 %%--------------------------------------------------------------------
 %% Common Test interface functions -----------------------------------
@@ -132,6 +142,9 @@ api_tests() ->
      tls_shutdown_write,
      tls_shutdown_both,
      tls_shutdown_error,
+     tls_password_correct,
+     tls_password_incorrect,
+     tls_password_badarg,
      tls_client_closes_socket,
      tls_closed_in_active_once,
      tls_reset_in_active_once,
@@ -155,7 +168,8 @@ init_per_suite(Config0) ->
     try crypto:start() of
 	ok ->
 	    ssl_test_lib:clean_start(),
-	    ssl_test_lib:make_rsa_cert(Config0)
+	    ssl_test_lib:make_rsa_cert_with_protected_keyfile(Config0,
+                                                              ?CORRECT_PASSWORD)
     catch _:_ ->
 	    {skip, "Crypto did not start"}
     end.
@@ -166,7 +180,7 @@ end_per_suite(_Config) ->
     application:stop(crypto).
 
 init_per_group(GroupName, Config) ->
-    ssl_test_lib:init_per_group(GroupName, Config). 
+    ssl_test_lib:init_per_group(GroupName, Config).
 
 end_per_group(GroupName, Config) ->
   ssl_test_lib:end_per_group(GroupName, Config).
@@ -178,7 +192,7 @@ init_per_testcase(Testcase, Config) when Testcase == tls_server_handshake_timeou
 init_per_testcase(_, Config) ->
     ct:timetrap({seconds, 5}),
     Config.
-end_per_testcase(_TestCase, Config) ->     
+end_per_testcase(_TestCase, Config) ->
     Config.
 
 %%--------------------------------------------------------------------
@@ -193,28 +207,28 @@ tls_upgrade(Config) when is_list(Config) ->
     {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
     TcpOpts = [binary, {reuseaddr, true}],
 
-    Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0}, 
-						{from, self()}, 
-						{mfa, {?MODULE, 
+    Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0},
+						{from, self()},
+						{mfa, {?MODULE,
 						       upgrade_result, []}},
-						{tcp_options, 
+						{tcp_options,
 						 [{active, false} | TcpOpts]},
 						{ssl_options, [{verify, verify_peer} | ServerOpts]}]),
     Port = ssl_test_lib:inet_port(Server),
-    Client = ssl_test_lib:start_upgrade_client([{node, ClientNode}, 
-						{port, Port}, 
+    Client = ssl_test_lib:start_upgrade_client([{node, ClientNode},
+						{port, Port},
 				   {host, Hostname},
-				   {from, self()}, 
+				   {from, self()},
 				   {mfa, {?MODULE, upgrade_result, []}},
 				   {tcp_options, [binary]},
 				   {ssl_options,  [{verify, verify_peer},
                                                    {server_name_indication, Hostname} | ClientOpts]}]),
-    
+
     ct:log("Testcase ~p, Client ~p  Server ~p ~n",
 		       [self(), Client, Server]),
-    
+
     ssl_test_lib:check_result(Server, ok, Client, ok),
-    
+
     ssl_test_lib:close(Server),
     ssl_test_lib:close(Client).
 
@@ -228,30 +242,30 @@ tls_upgrade_new_opts(Config) when is_list(Config) ->
     {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
     TcpOpts = [binary, {reuseaddr, true}],
 
-    Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0}, 
-						{from, self()}, 
-						{mfa, {?MODULE, 
+    Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0},
+						{from, self()},
+						{mfa, {?MODULE,
 						       upgrade_result_new_opts, []}},
-						{tcp_options, 
+						{tcp_options,
 						 [{active, false} | TcpOpts]},
 						{ssl_options, [{verify, verify_peer},
                                                                {mode, list} | ServerOpts]}]),
     Port = ssl_test_lib:inet_port(Server),
-    Client = ssl_test_lib:start_upgrade_client([{node, ClientNode}, 
-						{port, Port}, 
+    Client = ssl_test_lib:start_upgrade_client([{node, ClientNode},
+						{port, Port},
 				   {host, Hostname},
-				   {from, self()}, 
+				   {from, self()},
 				   {mfa, {?MODULE, upgrade_result_new_opts, []}},
 				   {tcp_options, [binary]},
 				   {ssl_options,  [{verify, verify_peer},
                                                    {mode, list},
                                                    {server_name_indication, Hostname} | ClientOpts]}]),
-    
+
     ct:log("Testcase ~p, Client ~p  Server ~p ~n",
 		       [self(), Client, Server]),
-    
+
     ssl_test_lib:check_result(Server, ok, Client, ok),
-    
+
     ssl_test_lib:close(Server),
     ssl_test_lib:close(Client).
 
@@ -265,29 +279,29 @@ tls_upgrade_with_timeout(Config) when is_list(Config) ->
     {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
     TcpOpts = [binary, {reuseaddr, true}],
 
-    Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0}, 
-						{from, self()}, 
+    Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0},
+						{from, self()},
 						{timeout, 5000},
-						{mfa, {?MODULE, 
+						{mfa, {?MODULE,
 						       upgrade_result, []}},
-						{tcp_options, 
+						{tcp_options,
 						 [{active, false} | TcpOpts]},
 						{ssl_options, [{verify, verify_peer} | ServerOpts]}]),
     Port = ssl_test_lib:inet_port(Server),
-    Client = ssl_test_lib:start_upgrade_client([{node, ClientNode}, 
-						{port, Port}, 
+    Client = ssl_test_lib:start_upgrade_client([{node, ClientNode},
+						{port, Port},
 						{host, Hostname},
-						{from, self()}, 
+						{from, self()},
 						{mfa, {?MODULE, upgrade_result, []}},
 						{tcp_options, TcpOpts},
 						{ssl_options, [{verify, verify_peer},
                                                                {server_name_indication, Hostname} | ClientOpts]}]),
-    
+
     ct:log("Testcase ~p, Client ~p  Server ~p ~n",
 		       [self(), Client, Server]),
-    
+
     ssl_test_lib:check_result(Server, ok, Client, ok),
-    
+
     ssl_test_lib:close(Server),
     ssl_test_lib:close(Client).
 
@@ -297,7 +311,7 @@ tls_downgrade() ->
 tls_downgrade(Config) when is_list(Config) ->
     ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
     ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
-    
+
     {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
 
     Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
@@ -310,7 +324,7 @@ tls_downgrade(Config) when is_list(Config) ->
 					{from, self()},
 					{mfa, {?MODULE, tls_downgrade_result, [self()]}},
 					{options, [{active, false}, {verify, verify_peer} | ClientOpts]}]),
-                                                   
+
     ssl_test_lib:check_result(Server, ready, Client, ready),
 
     Server ! go,
@@ -328,23 +342,23 @@ tls_shutdown(Config) when is_list(Config) ->
     ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
     ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
     {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, tls_shutdown_result, [server]}},
 			   {options, [{exit_on_close, false},
 				      {active, false} | ServerOpts]}]),
     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()}, 
-					{mfa, 
+					{from, self()},
+					{mfa,
 					 {?MODULE, tls_shutdown_result, [client]}},
-					{options, 
+					{options,
 					 [{exit_on_close, false},
 					  {active, false} | ClientOpts]}]),
-    
+
     ssl_test_lib:check_result(Server, ok, Client, ok),
-    
+
     ssl_test_lib:close(Server),
     ssl_test_lib:close(Client).
 
@@ -355,17 +369,17 @@ tls_shutdown_write(Config) when is_list(Config) ->
     ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
     ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
     {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, tls_shutdown_write_result, [server]}},
 			   {options, [{active, false} | ServerOpts]}]),
     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, tls_shutdown_write_result, [client]}},
 			   {options, [{active, false} | ClientOpts]}]),
-    
+
     ssl_test_lib:check_result(Server, ok, Client, {error, closed}).
 
 %%--------------------------------------------------------------------
@@ -375,17 +389,17 @@ tls_shutdown_both(Config) when is_list(Config) ->
     ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
     ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
     {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, tls_shutdown_both_result, [server]}},
 			   {options, [{active, false} | ServerOpts]}]),
     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, tls_shutdown_both_result, [client]}},
 			   {options, [{active, false} | ClientOpts]}]),
-    
+
     ssl_test_lib:check_result(Server, ok, Client, {error, closed}).
 
 %%--------------------------------------------------------------------
@@ -403,25 +417,25 @@ tls_shutdown_error(Config) when is_list(Config) ->
 tls_client_closes_socket() ->
     [{doc,"Test what happens when client closes socket before handshake is completed"}].
 
-tls_client_closes_socket(Config) when is_list(Config) -> 
+tls_client_closes_socket(Config) when is_list(Config) ->
     ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
     {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
     TcpOpts = [binary, {reuseaddr, true}],
-    
-    Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0}, 
-						      {from, self()}, 
+
+    Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0},
+						      {from, self()},
 						      {tcp_options, TcpOpts},
 						      {ssl_options, ServerOpts}]),
     Port = ssl_test_lib:inet_port(Server),
 
     Connect = fun() ->
-		      {ok, _Socket} = rpc:call(ClientNode, gen_tcp, connect, 
-					      [Hostname, Port, [binary]]),	      
-		      %% Make sure that ssl_accept is called before 
+		      {ok, _Socket} = rpc:call(ClientNode, gen_tcp, connect,
+					      [Hostname, Port, [binary]]),
+		      %% Make sure that ssl_accept is called before
 		      %% client process ends and closes socket.
 		      ct:sleep(?SLEEP)
 	      end,
-    
+
     _Client = spawn_link(Connect),
 
     ssl_test_lib:check_result(Server, {error,closed}).
@@ -460,7 +474,7 @@ tls_reset_in_active_once(Config) when is_list(Config) ->
 %%--------------------------------------------------------------------
 tls_closed_in_active_once() ->
     [{doc, "Test that active once can be used to deliver not only all data"
-      " but even the close message, see ERL-1409, in normal operation." 
+      " but even the close message, see ERL-1409, in normal operation."
       " This is also test, with slightly different circumstances in"
       " the old tls_closed_in_active_once test"
       " renamed tls_reset_in_active_once"}].
@@ -560,9 +574,9 @@ tls_tcp_msg(Config) when is_list(Config) ->
     ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
     gen_tcp:send(Socket, "<SOME GARBLED NON SSL MESSAGE>"),
 
-    receive 
+    receive
 	{tcp_closed, Socket} ->
-	    receive 
+	    receive
 		{Server, {error, Error}} ->
 		    ct:log("Error ~p", [Error])
 	    end
@@ -600,7 +614,7 @@ tls_tcp_msg_big(Config) when is_list(Config) ->
 		{Server, {error, Error}} ->
 		    ct:log("Error ~p", [Error]);
 		{'EXIT', Server, _} ->
-		    ok	 
+		    ok
 	    end
     end.
 
@@ -619,7 +633,7 @@ tls_dont_crash_on_handshake_garbage(Config) ->
                                         {mfa, ssl_test_lib, no_result},
                                         {options, [{versions, [Version]} | ServerOpts]}]),
     Port = ssl_test_lib:inet_port(Server),
- 
+
     {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {active, false}]),
 
     %% Send hello and garbage record
@@ -639,7 +653,7 @@ tls_dont_crash_on_handshake_garbage(Config) ->
         _  ->
             ssl_test_lib:check_server_alert(Server, handshake_failure)
     end.
-    
+
 %%--------------------------------------------------------------------
 tls_tcp_error_propagation_in_active_mode() ->
     [{doc,"Test that process receives {ssl_error, Socket, closed} when tcp error ocurres"}].
@@ -660,7 +674,7 @@ tls_tcp_error_propagation_in_active_mode(Config) when is_list(Config) ->
                                                                                {from, self()},
                                                                                {mfa, {?MODULE, receive_msg, []}},
                                                                                {options, ClientOpts}]),
-    
+
     {status, _, _, StatusInfo} = sys:get_status(Pid),
     [_, _,_, _, Prop] = StatusInfo,
     State = ssl_test_lib:state(Prop),
@@ -675,21 +689,21 @@ tls_tcp_error_propagation_in_active_mode(Config) when is_list(Config) ->
 peername() ->
     [{doc,"Test API function peername/1"}].
 
-peername(Config) when is_list(Config) -> 
+peername(Config) when is_list(Config) ->
     ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
     ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
     {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, {ssl, peername, []}},
 			   {options, ServerOpts}]),
     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, {ssl, peername, []}},
 					{options, [{port, 0} | ClientOpts]}]),
-    
+
     ClientPort = ssl_test_lib:inet_port(Client),
     ServerIp = ssl_test_lib:node_to_hostip(ServerNode, server),
     ClientIp = ssl_test_lib:node_to_hostip(ClientNode, client),
@@ -700,39 +714,39 @@ peername(Config) when is_list(Config) ->
 		       [self(), Client, Server]),
 
     ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-    
+
     ssl_test_lib:close(Server),
     ssl_test_lib:close(Client).
 
 %%--------------------------------------------------------------------
 sockname() ->
     [{doc,"Test API function sockname/1"}].
-sockname(Config) when is_list(Config) -> 
+sockname(Config) when is_list(Config) ->
     ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
     ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
     {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, {ssl, sockname, []}},
 			   {options, ServerOpts}]),
     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, {ssl, sockname, []}},
                                         {options, [{port, 0} | ClientOpts]}]),
-                                       
+
     ClientPort = ssl_test_lib:inet_port(Client),
     ServerIp = ssl_test_lib:node_to_hostip(ServerNode, server),
     ClientIp = ssl_test_lib:node_to_hostip(ClientNode, client),
     ServerMsg = {ok, {ServerIp, Port}},
     ClientMsg = {ok, {ClientIp, ClientPort}},
-			   
+
     ct:log("Testcase ~p, Client ~p  Server ~p ~n",
 			 [self(), Client, Server]),
-    
+
     ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-    
+
     ssl_test_lib:close(Server),
     ssl_test_lib:close(Client).
 %%--------------------------------------------------------------------
@@ -759,7 +773,7 @@ tls_server_handshake_timeout(Config) ->
 		{'EXIT', Server, _} ->
 		    %% Make sure supervisor had time to react on process exit
 		    %% Could we come up with a better solution to this?
-		    ct:sleep(500), 
+		    ct:sleep(500),
 		    [] = supervisor:which_children(tls_connection_sup)
 	    end
     end.
@@ -767,26 +781,26 @@ tls_server_handshake_timeout(Config) ->
 %%--------------------------------------------------------------------
 transport_close() ->
     [{doc, "Test what happens if socket is closed on TCP level after a while of normal operation"}].
-transport_close(Config) when is_list(Config) -> 
+transport_close(Config) when is_list(Config) ->
     ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
     ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
     {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, {ssl_test_lib, send_recv_result, []}},
 				   {options,  [{active, false} | ServerOpts]}]),
     Port = ssl_test_lib:inet_port(Server),
-    {ok, TcpS} = rpc:call(ClientNode, gen_tcp, connect, 
+    {ok, TcpS} = rpc:call(ClientNode, gen_tcp, connect,
 			  [Hostname,Port,[binary, {active, false}]]),
-    {ok, SslS} = rpc:call(ClientNode, ssl, connect, 
+    {ok, SslS} = rpc:call(ClientNode, ssl, connect,
 			  [TcpS,[{active, false}|ClientOpts]]),
-    
+
     ct:log("Testcase ~p, Client ~p  Server ~p ~n",
 		       [self(), self(), Server]),
-    ok = ssl:send(SslS, "Hello world"),      
-    {ok,<<"Hello world">>} = ssl:recv(SslS, 11),    
-    gen_tcp:close(TcpS),    
+    ok = ssl:send(SslS, "Hello world"),
+    {ok,<<"Hello world">>} = ssl:recv(SslS, 11),
+    gen_tcp:close(TcpS),
     {error, _} = ssl:send(SslS, "Hello world").
 
 %%--------------------------------------------------------------------
@@ -856,36 +870,36 @@ check_connection_processes(Sup, N, M) ->
 emulated_options() ->
     [{doc,"Test API function getopts/2 and setopts/2"}].
 
-emulated_options(Config) when is_list(Config) -> 
+emulated_options(Config) when is_list(Config) ->
     ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
     ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
     {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
     Values = [{mode, list}, {packet, 0}, {header, 0},
-		      {active, true}],    
-    %% Shall be the reverse order of Values! 
+		      {active, true}],
+    %% Shall be the reverse order of Values!
     Options = [active, header, packet, mode],
-    
+
     NewValues = [{mode, binary}, {active, once}],
-    %% Shall be the reverse order of NewValues! 
+    %% Shall be the reverse order of NewValues!
     NewOptions = [active, mode],
-    
-    Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, 
-					{from, self()}, 
-			   {mfa, {?MODULE, tls_socket_options_result, 
+
+    Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+					{from, self()},
+			   {mfa, {?MODULE, tls_socket_options_result,
 				  [Options, Values, NewOptions, NewValues]}},
 			   {options, ServerOpts}]),
     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()}, 
-			   {mfa, {?MODULE, tls_socket_options_result, 
+			   {from, self()},
+			   {mfa, {?MODULE, tls_socket_options_result,
 				  [Options, Values, NewOptions, NewValues]}},
 			   {options, ClientOpts}]),
-    
+
     ssl_test_lib:check_result(Server, ok, Client, ok),
 
     ssl_test_lib:close(Server),
-    
+
     {ok, Listen} = ssl:listen(0, ServerOpts),
     {ok,[{mode,list}]} = ssl:getopts(Listen, [mode]),
     ok = ssl:setopts(Listen, [{mode, binary}]),
@@ -896,40 +910,40 @@ accept_pool() ->
     [{doc,"Test having an accept pool."}].
 accept_pool(Config) when is_list(Config) ->
     ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
-    ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),  
+    ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
 
     {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-    Server0 = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, 
-					{from, self()}, 
+    Server0 = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+					{from, self()},
 					{accepters, 3},
 					{mfa, {ssl_test_lib, send_recv_result_active, []}},
 					{options, ServerOpts}]),
     Port = ssl_test_lib:inet_port(Server0),
     [Server1, Server2] = ssl_test_lib:accepters(2),
 
-    Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, 
+    Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
 					 {host, Hostname},
-					 {from, self()}, 
+					 {from, self()},
 					 {mfa, {ssl_test_lib, send_recv_result_active, []}},
 					 {options, ClientOpts}
 					]),
-    
-    Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, 
+
+    Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
 					 {host, Hostname},
-					 {from, self()}, 
+					 {from, self()},
 					 {mfa, {ssl_test_lib, send_recv_result_active, []}},
 					 {options, ClientOpts}
 					]),
-    
-    Client2 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, 
+
+    Client2 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
 					 {host, Hostname},
-					 {from, self()}, 
+					 {from, self()},
 					 {mfa, {ssl_test_lib, send_recv_result_active, []}},
 					 {options, ClientOpts}
 					]),
 
     ssl_test_lib:check_ok([Server0, Server1, Server2, Client0, Client1, Client2]),
-    
+
     ssl_test_lib:close(Server0),
     ssl_test_lib:close(Server1),
     ssl_test_lib:close(Server2),
@@ -959,7 +973,7 @@ reuseaddr(Config) when is_list(Config) ->
 				   {options, [{active, false} | ClientOpts]}]),
     ssl_test_lib:close(Server),
     ssl_test_lib:close(Client),
-    
+
     Server1 =
 	ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
 				   {from, self()},
@@ -976,6 +990,104 @@ reuseaddr(Config) when is_list(Config) ->
     ssl_test_lib:close(Server1),
     ssl_test_lib:close(Client1).
 
+%%--------------------------------------------------------------------
+tls_password_correct() ->
+    [{doc, "Test that connection is possible with a correct password"}].
+tls_password_correct(Config) when is_list(Config) ->
+    F = fun (P) ->
+                ProtectedClientOpts = ?config(client_protected_rsa_opts, Config),
+                ServerOpts = ssl_test_lib:ssl_options(server_rsa_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, tls_shutdown_result, [server]}},
+                                                    {options, [{exit_on_close, false},
+                                                               {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, tls_shutdown_result, [client]}},
+                                                    {options,
+                                                     [{exit_on_close, false},
+                                                      {verify, verify_none},
+                                                      {active, false},
+                                                      {password, P} | ProtectedClientOpts]}]),
+                ssl_test_lib:check_result(Server, ok, Client, ok),
+                ssl_test_lib:close(Server),
+                ssl_test_lib:close(Client)
+        end,
+    F(?CORRECT_PASSWORD),
+    F(fun() -> ?CORRECT_PASSWORD end).
+
+%%--------------------------------------------------------------------
+tls_password_incorrect() ->
+    [{doc, "Test that connection is not possible with wrong password"}].
+tls_password_incorrect(Config) when is_list(Config) ->
+    F = fun (P) ->
+                ProtectedClientOpts = ?config(client_protected_rsa_opts, Config),
+                ServerOpts = ssl_test_lib:ssl_options(server_rsa_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, [{active, false} | ServerOpts]}]),
+                Port = ssl_test_lib:inet_port(Server),
+                Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+                                                          {host, Hostname},
+                                                          {from, self()},
+                                                          {mfa, ssl_test_lib, no_result},
+                                                          {options,
+                                                           [{active, false},
+                                                            {verify, verify_none},
+                                                            {password, P} | ProtectedClientOpts]}]),
+                Results = ssl_test_lib:get_result([Server, Client]),
+                Pred = fun({Pid, {error, closed}}) ->
+                               Server == Pid;
+                          ({Pid, {error, {options, {keyfile, _, {error, _}}}}}) ->
+                               Client == Pid;
+                          (_) -> false
+                       end,
+                true = lists:all(Pred, Results)
+        end,
+    F(?INCORRECT_PASSWORD),
+    F(fun() -> ?INCORRECT_PASSWORD end).
+
+%%--------------------------------------------------------------------
+tls_password_badarg() ->
+    [{doc, "Test that connection is not possible with badarg password"}].
+tls_password_badarg(Config) when is_list(Config) ->
+    F = fun (P, ServerError, ClientError) ->
+                ProtectedClientOpts = ?config(client_protected_rsa_opts, Config),
+                ServerOpts = ssl_test_lib:ssl_options(server_rsa_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},
+                                                          {timeout, 100},
+                                                          {options, [{active, false} | ServerOpts]}]),
+                Port = ssl_test_lib:inet_port(Server),
+                Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+                                                          {host, Hostname},
+                                                          {from, self()},
+                                                          {mfa, ssl_test_lib, no_result},
+                                                          {options,
+                                                           [{active, false},
+                                                            {verify, verify_none},
+                                                            {password, P} | ProtectedClientOpts]}]),
+                ssl_test_lib:check_result(Server, ServerError, Client, ClientError)
+        end,
+    %% {options error comes from ssl app
+    F(?BADARG_PASSWORD, {error, timeout},
+      {error, {options, {password, ?BADARG_PASSWORD}}}),
+    %% {keyfile, badarg} error comes from crypto:macN, also handhsake is initiated
+    %% so different server error is observed
+    F(fun() -> ?BADARG_PASSWORD end, {error, closed},
+      {error, {keyfile,badarg}}).
+
 %%--------------------------------------------------------------------
 %% Internal functions ------------------------------------------------
 %%--------------------------------------------------------------------
@@ -991,7 +1103,7 @@ upgrade_result(Socket) ->
 upgrade_result_new_opts(Socket) ->
     ssl:setopts(Socket, [{active, true}]),
     ok = ssl:send(Socket, "Hello world"),
-    %% Make sure list option set in ssl:connect/handskae overrides 
+    %% Make sure list option set in ssl:connect/handshake overrides
     %% previous gen_tcp socket option that was set to binary.
     "Hello world" =  ssl_test_lib:active_recv(Socket, length("Hello world")),
     ok.
@@ -999,7 +1111,7 @@ upgrade_result_new_opts(Socket) ->
 tls_downgrade_result(Socket, Pid) ->
     ok = ssl_test_lib:send_recv_result(Socket),
     Pid ! {self(), ready},
-    receive 
+    receive
         go ->
             ok
     end,
@@ -1062,20 +1174,20 @@ receive_msg(_) ->
 	Msg ->
 	   Msg
     end.
- 
+
 tls_socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) ->
     %% Test get/set emulated opts
-    {ok, DefaultValues} = ssl:getopts(Socket, Options), 
+    {ok, DefaultValues} = ssl:getopts(Socket, Options),
     ssl:setopts(Socket, NewValues),
     {ok, NewValues} = ssl:getopts(Socket, NewOptions),
     %% Test get/set inet opts
-    {ok,[{nodelay,false}]} = ssl:getopts(Socket, [nodelay]),  
+    {ok,[{nodelay,false}]} = ssl:getopts(Socket, [nodelay]),
     ssl:setopts(Socket, [{nodelay, true}]),
     {ok,[{nodelay, true}]} = ssl:getopts(Socket, [nodelay]),
     {ok, All} = ssl:getopts(Socket, []),
     ct:log("All opts ~p~n", [All]),
     ok.
-	
+
 active_tcp_recv(Socket, N) ->
     active_tcp_recv(Socket, N, []).
 
-- 
2.31.1

openSUSE Build Service is sponsored by