From 4f4bf872831b12cac8913e8a62e35725d0173b0d Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 6 Oct 2017 17:15:52 +0200 Subject: public_key, ssl: Handles keys so that APIs are preserved correctly --- lib/public_key/src/pubkey_cert.erl | 13 ++++++++++--- lib/ssl/test/x509_test.erl | 15 ++++++--------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl index 13833830a7..76fd0f8133 100644 --- a/lib/public_key/src/pubkey_cert.erl +++ b/lib/public_key/src/pubkey_cert.erl @@ -1144,7 +1144,7 @@ issuer(Contact, Role, Name) -> subject(Contact, Role ++ Name). subject(Contact, Name) -> - Opts = [{email, Contact ++ "@erlang.org"}, + Opts = [{email, Contact ++ "@example.org"}, {name, Name}, {city, "Stockholm"}, {country, "SE"}, @@ -1223,12 +1223,12 @@ cert_chain(Role, IssuerCert, IssuerKey, [PeerOpts], _, Acc) -> Key = gen_key(proplists:get_value(key, PeerOpts, default_key_gen())), Cert = cert(Role, public_key:pkix_decode_cert(IssuerCert, otp), IssuerKey, Key, "admin", " Peer cert", PeerOpts, peer), - [{Cert, Key}, {IssuerCert, IssuerKey} | Acc]; + [{Cert, encode_key(Key)}, {IssuerCert, encode_key(IssuerKey)} | Acc]; cert_chain(Role, IssuerCert, IssuerKey, [CAOpts | Rest], N, Acc) -> Key = gen_key(proplists:get_value(key, CAOpts, default_key_gen())), Cert = cert(Role, public_key:pkix_decode_cert(IssuerCert, otp), IssuerKey, Key, "webadmin", " Intermidiate CA " ++ integer_to_list(N), CAOpts, ca), - cert_chain(Role, Cert, Key, Rest, N+1, [{IssuerCert, IssuerKey} | Acc]). + cert_chain(Role, Cert, Key, Rest, N+1, [{IssuerCert, encode_key(IssuerKey)} | Acc]). cert(Role, #'OTPCertificate'{tbsCertificate = #'OTPTBSCertificate'{subject = Issuer}}, PrivKey, Key, Contact, Name, Opts, Type) -> @@ -1311,3 +1311,10 @@ add_default_extensions(Defaults0, Exts) -> end, Defaults0), Exts ++ Defaults. +encode_key(#'RSAPrivateKey'{} = Key) -> + {'RSAPrivateKey', public_key:der_encode('RSAPrivateKey', Key)}; +encode_key(#'ECPrivateKey'{} = Key) -> + {'ECPrivateKey', public_key:der_encode('ECPrivateKey', Key)}; +encode_key(#'DSAPrivateKey'{} = Key) -> + {'DSAPrivateKey', public_key:der_encode('DSAPrivateKey', Key)}. + diff --git a/lib/ssl/test/x509_test.erl b/lib/ssl/test/x509_test.erl index 031fad1216..fea01efdaf 100644 --- a/lib/ssl/test/x509_test.erl +++ b/lib/ssl/test/x509_test.erl @@ -64,15 +64,12 @@ do_gen_pem_config_files(Config, CertFile, KeyFile, CAFile) -> cert_entry(Cert) -> {'Certificate', Cert, not_encrypted}. -key_entry(Key = #'RSAPrivateKey'{}) -> - Der = public_key:der_encode('RSAPrivateKey', Key), - {'RSAPrivateKey', Der, not_encrypted}; -key_entry(Key = #'DSAPrivateKey'{}) -> - Der = public_key:der_encode('DSAPrivateKey', Key), - {'DSAPrivateKey', Der, not_encrypted}; -key_entry(Key = #'ECPrivateKey'{}) -> - Der = public_key:der_encode('ECPrivateKey', Key), - {'ECPrivateKey', Der, not_encrypted}. +key_entry({'RSAPrivateKey', DERKey}) -> + {'RSAPrivateKey', DERKey, not_encrypted}; +key_entry({'DSAPrivateKey', DERKey}) -> + {'DSAPrivateKey', DERKey, not_encrypted}; +key_entry({'ECPrivateKey', DERKey}) -> + {'ECPrivateKey', DERKey, not_encrypted}. ca_entries(CAs) -> [{'Certificate', CACert, not_encrypted} || CACert <- CAs]. -- cgit v1.2.3 From 0bb96516ce308b6fb837696338b492d3c9a9f429 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 6 Oct 2017 17:24:16 +0200 Subject: ssl: Extend hostname check to fallback to checking IP-address If no SNI is available and the hostname is an IP-address also check for IP-address match. This check is not as good as a DNS hostname check and certificates using IP-address are not recommended. --- lib/ssl/doc/src/ssl.xml | 52 ++++++++++++++------- lib/ssl/src/ssl.erl | 2 +- lib/ssl/src/ssl_certificate.erl | 38 ++++++++++++--- lib/ssl/src/ssl_connection.erl | 3 +- lib/ssl/src/ssl_handshake.erl | 18 ++++++-- lib/ssl/test/ssl_sni_SUITE.erl | 100 +++++++++++++++++++++++++++++++++++++++- 6 files changed, 182 insertions(+), 31 deletions(-) diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index ca2dcbb761..e80fd59a7f 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -589,22 +589,19 @@ fun(srp, Username :: string(), UserState :: term()) -> {server_name_indication, HostName :: hostname()}

Specify the hostname to be used in TLS Server Name Indication extension. - Is usefull when upgrading a TCP socket to a TLS socket or if the hostname can not be - derived from the Host argument to ssl:connect/3. - Will also cause the client to preform host name verification of the peer certificate - public_key:pkix_verify_hostname(PeerCert, [{dns_id, HostName}]) -

during the x509-path validation. If the check fails the error {bad_cert, hostname_check_failiure} will be - propagated to the path validation fun verify_fun -
- - {server_name_indication, disable} - -

When starting a TLS connection without upgrade, the Server Name - Indication extension is sent if possible that is can be derived from the Host argument - to ssl:connect/3. - This option can be used to disable that behavior.

-

Note that this also disables the default host name verification check of the peer certificate.

+ If not specified it will default to the Host argument of connect/[3,4] + unless it is of type inet:ipaddress().

+

+ The HostName will also be used in the hostname verification of the peer certificate using + public_key:pkix_verify_hostname/2. +

+ {server_name_indication, disable} + +

Prevents the Server Name Indication extension from being sent and + disables the hostname verification check + public_key:pkix_verify_hostname/2

+
{fallback, boolean()}

Send special cipher suite TLS_FALLBACK_SCSV to avoid undesired TLS version downgrade. @@ -881,6 +878,12 @@ fun(srp, Username :: string(), UserState :: term()) ->

Upgrades a gen_tcp, or equivalent, connected socket to an SSL socket, that is, performs the client-side ssl handshake.

+ +

If the option verify is set to verify_peer + the option server_name_indication shall also be specified, + if it is not no Server Name Indication extension will be sent, + and public_key:pkix_verify_hostname/2 + will be called with the IP-address of the connection as ReferenceID, which is proably not what you want.

@@ -897,7 +900,24 @@ fun(srp, Username :: string(), UserState :: term()) -> SslSocket = sslsocket() Reason = term() -

Opens an SSL connection to Host, Port.

+

Opens an SSL connection to Host, Port.

+ +

When the option verify is set to verify_peer the check + public_key:pkix_verify_hostname/2 + will be performed in addition to the usual x509-path validation checks. If the check fails the error {bad_cert, hostname_check_failed} will + be propagated to the path validation fun verify_fun, where it is possible to do customized + checks by using the full possibilitis of the public_key:pkix_verify_hostname/2 API. + + When the option server_name_indication is provided, its value (the DNS name) will be used as ReferenceID + to public_key:pkix_verify_hostname/2. + When no server_name_indication option is given, the Host argument will be used as + Server Name Indication extension. The Host argument will also be used for the + public_key:pkix_verify_hostname/2 check and if the Host + argument is an inet:ip_address() the ReferenceID used for the check will be {ip, Host} otherwise + dns_id will be assumed with a fallback to ip if that fails.

+

According to good practices certificates should not use IP-addresses as "server names". It would + be very surprising if this happen outside a closed network.

+
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 4e592c02ec..054e3b7ae3 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -1003,7 +1003,7 @@ validate_option(server_name_indication = Opt, Value) when is_list(Value) -> validate_option(server_name_indication, undefined = Value) -> Value; validate_option(server_name_indication, disable) -> - undefined; + disable; validate_option(sni_hosts, []) -> []; diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index 0dd5e5c5cf..a3333d35e9 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -138,13 +138,8 @@ validate(_, {bad_cert, _} = Reason, _) -> {fail, Reason}; validate(_, valid, UserState) -> {valid, UserState}; -validate(Cert, valid_peer, UserState = {client, _,_, Hostname, _, _}) when Hostname =/= undefined -> - case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}]) of - true -> - {valid, UserState}; - false -> - {fail, {bad_cert, hostname_check_failed}} - end; +validate(Cert, valid_peer, UserState = {client, _,_, Hostname, _, _}) when Hostname =/= disable -> + verify_hostname(Hostname, Cert, UserState); validate(_, valid_peer, UserState) -> {valid, UserState}. @@ -337,3 +332,32 @@ new_trusteded_chain(DerCert, [_ | Rest]) -> new_trusteded_chain(DerCert, Rest); new_trusteded_chain(_, []) -> unknown_ca. + +verify_hostname({fallback, Hostname}, Cert, UserState) when is_list(Hostname) -> + case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}]) of + true -> + {valid, UserState}; + false -> + case public_key:pkix_verify_hostname(Cert, [{ip, Hostname}]) of + true -> + {valid, UserState}; + false -> + {fail, {bad_cert, hostname_check_failed}} + end + end; + +verify_hostname({fallback, Hostname}, Cert, UserState) -> + case public_key:pkix_verify_hostname(Cert, [{ip, Hostname}]) of + true -> + {valid, UserState}; + false -> + {fail, {bad_cert, hostname_check_failed}} + end; + +verify_hostname(Hostname, Cert, UserState) -> + case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}]) of + true -> + {valid, UserState}; + false -> + {fail, {bad_cert, hostname_check_failed}} + end. diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 2dbe08e0a7..2fed7d864f 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -496,12 +496,13 @@ certify(internal, #certificate{}, certify(internal, #certificate{} = Cert, #state{negotiated_version = Version, role = Role, + host = Host, cert_db = CertDbHandle, cert_db_ref = CertDbRef, crl_db = CRLDbInfo, ssl_options = Opts} = State, Connection) -> case ssl_handshake:certify(Cert, CertDbHandle, CertDbRef, - Opts, CRLDbInfo, Role) of + Opts, CRLDbInfo, Role, Host) of {PeerCert, PublicKeyInfo} -> handle_peer_cert(Role, PeerCert, PublicKeyInfo, State#state{client_certificate_requested = false}, Connection); diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index b1661624b5..0ee9ee3322 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -50,7 +50,7 @@ finished/5, next_protocol/1]). %% Handle handshake messages --export([certify/6, client_certificate_verify/6, certificate_verify/6, verify_signature/5, +-export([certify/7, client_certificate_verify/6, certificate_verify/6, verify_signature/5, master_secret/4, server_key_exchange_hash/2, verify_connection/6, init_handshake_history/0, update_handshake_history/3, verify_server_key/5 ]). @@ -389,21 +389,21 @@ verify_signature(_, Hash, {HashAlgo, _SignAlg}, Signature, %%-------------------------------------------------------------------- -spec certify(#certificate{}, db_handle(), certdb_ref(), #ssl_options{}, term(), - client | server) -> {der_cert(), public_key_info()} | #alert{}. + client | server, inet:hostname() | inet:ip_address()) -> {der_cert(), public_key_info()} | #alert{}. %% %% Description: Handles a certificate handshake message %%-------------------------------------------------------------------- certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef, - Opts, CRLDbHandle, Role) -> + Opts, CRLDbHandle, Role, Host) -> + ServerName = server_name(Opts#ssl_options.server_name_indication, Host, Role), [PeerCert | _] = ASN1Certs, try {TrustedCert, CertPath} = ssl_certificate:trusted_cert_and_path(ASN1Certs, CertDbHandle, CertDbRef, Opts#ssl_options.partial_chain), ValidationFunAndState = validation_fun_and_state(Opts#ssl_options.verify_fun, Role, - CertDbHandle, CertDbRef, - Opts#ssl_options.server_name_indication, + CertDbHandle, CertDbRef, ServerName, Opts#ssl_options.crl_check, CRLDbHandle, CertPath), case public_key:pkix_path_validation(TrustedCert, CertPath, @@ -1528,6 +1528,8 @@ select_shared_curve([Curve | Rest], Curves) -> sni(undefined) -> undefined; +sni(disable) -> + undefined; sni(Hostname) -> #sni{hostname = Hostname}. @@ -2353,3 +2355,9 @@ available_signature_algs(#hash_sign_algos{hash_sign_algos = ClientHashSigns}, Su available_signature_algs(_, _, _, _) -> undefined. +server_name(_, _, server) -> + undefined; %% Not interesting to check your own name. +server_name(undefined, Host, client) -> + {fallback, Host}; %% Fallback to Host argument to connect +server_name(SNI, _, client) -> + SNI. %% If Server Name Indication is available diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl index 03676cb828..e080de95f6 100644 --- a/lib/ssl/test/ssl_sni_SUITE.erl +++ b/lib/ssl/test/ssl_sni_SUITE.erl @@ -25,6 +25,8 @@ -include_lib("common_test/include/ct.hrl"). -include_lib("public_key/include/public_key.hrl"). +-include_lib("kernel/include/inet.hrl"). + %%-------------------------------------------------------------------- %% Common Test interface functions ----------------------------------- @@ -55,7 +57,10 @@ sni_tests() -> sni_no_match, no_sni_header_fun, sni_match_fun, - sni_no_match_fun]. + sni_no_match_fun, + dns_name, + ip_fallback, + no_ip_fallback]. init_per_suite(Config0) -> catch crypto:stop(), @@ -112,6 +117,65 @@ sni_no_match(Config) -> sni_no_match_fun(Config) -> run_sni_fun_handshake(Config, "c.server", undefined, "server Peer cert"). +dns_name(Config) -> + Hostname = "OTP.test.server", + #{server_config := ServerConf, + client_config := ClientConf} = public_key:pkix_test_data(#{server_chain => + #{root => [], + intermediates => [[]], + peer => [{extensions, [#'Extension'{extnID = + ?'id-ce-subjectAltName', + extnValue = [{dNSName, Hostname}], + critical = false}]}]}, + client_chain => + #{root => [], + intermediates => [[]], + peer => []}}), + unsuccessfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], undefined, Config), + successfull_connect(ServerConf, [{verify, verify_peer}, {server_name_indication, Hostname} | ClientConf], undefined, Config), + unsuccessfull_connect(ServerConf, [{verify, verify_peer}, {server_name_indication, "foo"} | ClientConf], undefined, Config), + successfull_connect(ServerConf, [{verify, verify_peer}, {server_name_indication, disable} | ClientConf], undefined, Config). + +ip_fallback(Config) -> + Hostname = net_adm:localhost(), + {ok, #hostent{h_addr_list = [IP |_]}} = inet:gethostbyname(net_adm:localhost()), + IPStr = tuple_to_list(IP), + #{server_config := ServerConf, + client_config := ClientConf} = public_key:pkix_test_data(#{server_chain => + #{root => [], + intermediates => [[]], + peer => [{extensions, [#'Extension'{extnID = + ?'id-ce-subjectAltName', + extnValue = [{dNSName, Hostname}, + {iPAddress, IPStr}], + critical = false}]} + ]}, + client_chain => + #{root => [], + intermediates => [[]], + peer => []}}), + successfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], Hostname, Config), + successfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], IP, Config). + +no_ip_fallback(Config) -> + Hostname = net_adm:localhost(), + {ok, #hostent{h_addr_list = [IP |_]}} = inet:gethostbyname(net_adm:localhost()), + #{server_config := ServerConf, + client_config := ClientConf} = public_key:pkix_test_data(#{server_chain => + #{root => [], + intermediates => [[]], + peer => [{extensions, [#'Extension'{extnID = + ?'id-ce-subjectAltName', + extnValue = [{dNSName, Hostname}], + critical = false}]} + ]}, + client_chain => + #{root => [], + intermediates => [[]], + peer => []}}), + successfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], Hostname, Config), + unsuccessfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], IP, Config). + %%-------------------------------------------------------------------- %% Internal Functions ------------------------------------------------ @@ -217,3 +281,37 @@ run_handshake(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) -> ssl_test_lib:check_result(Server, ExpectedSNIHostname, Client, ExpectedCN), ssl_test_lib:close(Server), ssl_test_lib:close(Client). + +successfull_connect(ServerOptions, ClientOptions, Hostname0, Config) -> + {ClientNode, ServerNode, Hostname1} = ssl_test_lib:run_where(Config), + Hostname = host_name(Hostname0, Hostname1), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, {mfa, {ssl_test_lib, send_recv_result_active, []}}, + {options, ServerOptions}]), + 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, send_recv_result_active, []}}, + {options, ClientOptions}]), + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +unsuccessfull_connect(ServerOptions, ClientOptions, Hostname0, Config) -> + {ClientNode, ServerNode, Hostname1} = ssl_test_lib:run_where(Config), + Hostname = host_name(Hostname0, Hostname1), + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, ServerOptions}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, ClientOptions}]), + + ssl_test_lib:check_result(Server, {error, {tls_alert, "handshake failure"}}, + Client, {error, {tls_alert, "handshake failure"}}). +host_name(undefined, Hostname) -> + Hostname; +host_name(Hostname, _) -> + Hostname. -- cgit v1.2.3 From 6703f2b42b306a3d5d8d819652e77a6124bbcc58 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Fri, 6 Oct 2017 17:26:43 +0200 Subject: ssl: Sessions must be registered with SNI if exists --- lib/ssl/src/ssl_connection.erl | 8 +++++- lib/ssl/test/ssl_sni_SUITE.erl | 62 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 2fed7d864f..1775acb2b0 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -702,6 +702,7 @@ cipher(internal, #finished{verify_data = Data} = Finished, expecting_finished = true, session = #session{master_secret = MasterSecret} = Session0, + ssl_options = SslOpts, connection_states = ConnectionStates0, tls_handshake_history = Handshake0} = State, Connection) -> case ssl_handshake:verify_connection(ssl:tls_version(Version), Finished, @@ -709,7 +710,7 @@ cipher(internal, #finished{verify_data = Data} = Finished, get_current_prf(ConnectionStates0, read), MasterSecret, Handshake0) of verified -> - Session = register_session(Role, Host, Port, Session0), + Session = register_session(Role, host_id(Role, Host, SslOpts), Port, Session0), cipher_role(Role, Data, Session, State#state{expecting_finished = false}, Connection); #alert{} = Alert -> @@ -2098,6 +2099,11 @@ register_session(server, _, Port, #session{is_resumable = new} = Session0) -> register_session(_, _, _, Session) -> Session. %% Already registered +host_id(client, _Host, #ssl_options{server_name_indication = Hostname}) when is_list(Hostname) -> + Hostname; +host_id(_, Host, _) -> + Host. + handle_new_session(NewId, CipherSuite, Compression, #state{session = Session0, protocol_cb = Connection} = State0) -> diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl index e080de95f6..13cb567110 100644 --- a/lib/ssl/test/ssl_sni_SUITE.erl +++ b/lib/ssl/test/ssl_sni_SUITE.erl @@ -60,7 +60,8 @@ sni_tests() -> sni_no_match_fun, dns_name, ip_fallback, - no_ip_fallback]. + no_ip_fallback, + dns_name_reuse]. init_per_suite(Config0) -> catch crypto:stop(), @@ -87,6 +88,13 @@ end_per_suite(_) -> ssl:stop(), application:stop(crypto). +init_per_testcase(TestCase, Config) when TestCase == ip_fallback; + TestCase == no_ip_fallback; + TestCase == dns_name_reuse -> + ssl_test_lib:ct_log_supported_protocol_versions(Config), + ct:log("Ciphers: ~p~n ", [ ssl:cipher_suites()]), + ct:timetrap({seconds, 20}), + Config; init_per_testcase(_TestCase, Config) -> ssl_test_lib:ct_log_supported_protocol_versions(Config), ct:log("Ciphers: ~p~n ", [ ssl:cipher_suites()]), @@ -176,7 +184,57 @@ no_ip_fallback(Config) -> successfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], Hostname, Config), unsuccessfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], IP, Config). - +dns_name_reuse(Config) -> + SNIHostname = "OTP.test.server", + #{server_config := ServerConf, + client_config := ClientConf} = public_key:pkix_test_data(#{server_chain => + #{root => [], + intermediates => [[]], + peer => [{extensions, [#'Extension'{extnID = + ?'id-ce-subjectAltName', + extnValue = [{dNSName, SNIHostname}], + critical = false}]}]}, + client_chain => + #{root => [], + intermediates => [[]], + peer => []}}), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + unsuccessfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], undefined, Config), + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, session_info_result, []}}, + {options, ServerConf}]), + 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, [{verify, verify_peer}, + {server_name_indication, SNIHostname} | ClientConf]}]), + SessionInfo = + receive + {Server, Info} -> + Info + end, + + Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, + + %% Make sure session is registered + ct:sleep(1000), + + Client1 = + ssl_test_lib:start_client_error([{node, ClientNode}, + {port, Port}, {host, Hostname}, + {mfa, {ssl_test_lib, session_info_result, []}}, + {from, self()}, {options, [{verify, verify_peer} | ClientConf]}]), + + ssl_test_lib:check_result(Server, {error, {tls_alert, "handshake failure"}}, + Client1, {error, {tls_alert, "handshake failure"}}), + ssl_test_lib:close(Client0). %%-------------------------------------------------------------------- %% Internal Functions ------------------------------------------------ %%-------------------------------------------------------------------- -- cgit v1.2.3 From 2c7256fdced5f48a6cd7e560542bc6d951ea3e0d Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 10 Oct 2017 18:54:52 +0200 Subject: public_key: Fix dialyzer spec --- lib/public_key/src/public_key.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index c3f2d791a3..31cb1fff3c 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -850,10 +850,10 @@ pkix_crls_validate(OtpCert, DPAndCRLs0, Options) -> %-------------------------------------------------------------------- -spec pkix_verify_hostname(Cert :: #'OTPCertificate'{} | binary(), - ReferenceIDs :: [{uri_id | dns_id | oid(), string()}]) -> boolean(). + ReferenceIDs :: [{uri_id | dns_id | ip | srv_id | oid(), string()}]) -> boolean(). -spec pkix_verify_hostname(Cert :: #'OTPCertificate'{} | binary(), - ReferenceIDs :: [{uri_id | dns_id | oid(), string()}], + ReferenceIDs :: [{uri_id | dns_id | ip | srv_id | oid(), string()}], Options :: proplists:proplist()) -> boolean(). %% Description: Validates a hostname to RFC 6125 -- cgit v1.2.3 From 7d05f57c2182626aaaee4a7c164d4bb6a7b9e38c Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Mon, 16 Oct 2017 11:17:53 +0200 Subject: ssl: Fix test cases to work on all test platforms Use hradcoded rsa keys as this will work on all legacy platforms. In test case dns_name_reuse only do the relevant client check in the final test. --- lib/ssl/test/ssl_sni_SUITE.erl | 73 ++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl index 13cb567110..7e78c41444 100644 --- a/lib/ssl/test/ssl_sni_SUITE.erl +++ b/lib/ssl/test/ssl_sni_SUITE.erl @@ -129,75 +129,80 @@ dns_name(Config) -> Hostname = "OTP.test.server", #{server_config := ServerConf, client_config := ClientConf} = public_key:pkix_test_data(#{server_chain => - #{root => [], - intermediates => [[]], + #{root => [{key, ssl_test_lib:hardcode_rsa_key(1)}], + intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(2)}]], peer => [{extensions, [#'Extension'{extnID = ?'id-ce-subjectAltName', extnValue = [{dNSName, Hostname}], - critical = false}]}]}, + critical = false}]}, + {key, ssl_test_lib:hardcode_rsa_key(3)}]}, client_chain => - #{root => [], - intermediates => [[]], - peer => []}}), + #{root => [{key, ssl_test_lib:hardcode_rsa_key(4)}], + intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(5)}]], + peer => [{key, ssl_test_lib:hardcode_rsa_key(6)}]}}), unsuccessfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], undefined, Config), successfull_connect(ServerConf, [{verify, verify_peer}, {server_name_indication, Hostname} | ClientConf], undefined, Config), unsuccessfull_connect(ServerConf, [{verify, verify_peer}, {server_name_indication, "foo"} | ClientConf], undefined, Config), successfull_connect(ServerConf, [{verify, verify_peer}, {server_name_indication, disable} | ClientConf], undefined, Config). - + ip_fallback(Config) -> Hostname = net_adm:localhost(), {ok, #hostent{h_addr_list = [IP |_]}} = inet:gethostbyname(net_adm:localhost()), IPStr = tuple_to_list(IP), #{server_config := ServerConf, client_config := ClientConf} = public_key:pkix_test_data(#{server_chain => - #{root => [], - intermediates => [[]], + #{root => [{key, ssl_test_lib:hardcode_rsa_key(1)}], + intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(2)}]], peer => [{extensions, [#'Extension'{extnID = ?'id-ce-subjectAltName', extnValue = [{dNSName, Hostname}, {iPAddress, IPStr}], - critical = false}]} - ]}, + critical = false}]}, + {key, ssl_test_lib:hardcode_rsa_key(3)}]}, client_chain => - #{root => [], - intermediates => [[]], - peer => []}}), + #{root => [{key, ssl_test_lib:hardcode_rsa_key(4)}], + intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(5)}]], + peer => [{key, ssl_test_lib:hardcode_rsa_key(6)}]}}), successfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], Hostname, Config), successfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], IP, Config). - + no_ip_fallback(Config) -> Hostname = net_adm:localhost(), {ok, #hostent{h_addr_list = [IP |_]}} = inet:gethostbyname(net_adm:localhost()), #{server_config := ServerConf, client_config := ClientConf} = public_key:pkix_test_data(#{server_chain => - #{root => [], - intermediates => [[]], + #{root => [{key, ssl_test_lib:hardcode_rsa_key(1)}], + intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(2)}]], peer => [{extensions, [#'Extension'{extnID = ?'id-ce-subjectAltName', extnValue = [{dNSName, Hostname}], - critical = false}]} + critical = false}]}, + {key, ssl_test_lib:hardcode_rsa_key(3)} ]}, client_chain => - #{root => [], - intermediates => [[]], - peer => []}}), + #{root => [{key, ssl_test_lib:hardcode_rsa_key(4)}], + intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(5)}]], + peer => [{key, ssl_test_lib:hardcode_rsa_key(6)}]}}), successfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], Hostname, Config), unsuccessfull_connect(ServerConf, [{verify, verify_peer} | ClientConf], IP, Config). - + dns_name_reuse(Config) -> SNIHostname = "OTP.test.server", #{server_config := ServerConf, client_config := ClientConf} = public_key:pkix_test_data(#{server_chain => - #{root => [], - intermediates => [[]], + #{root => [{key, ssl_test_lib:hardcode_rsa_key(1)}], + intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(2)}]], peer => [{extensions, [#'Extension'{extnID = ?'id-ce-subjectAltName', extnValue = [{dNSName, SNIHostname}], - critical = false}]}]}, + critical = false} + ]}, + {key, ssl_test_lib:hardcode_rsa_key(3)} + ]}, client_chain => - #{root => [], - intermediates => [[]], - peer => []}}), + #{root => [{key, ssl_test_lib:hardcode_rsa_key(4)}], + intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(5)}]], + peer => [{key, ssl_test_lib:hardcode_rsa_key(6)}]}}), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -215,11 +220,10 @@ dns_name_reuse(Config) -> {mfa, {ssl_test_lib, no_result, []}}, {from, self()}, {options, [{verify, verify_peer}, {server_name_indication, SNIHostname} | ClientConf]}]), - SessionInfo = - receive - {Server, Info} -> - Info - end, + receive + {Server, _} -> + ok + end, Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}}, @@ -232,8 +236,7 @@ dns_name_reuse(Config) -> {mfa, {ssl_test_lib, session_info_result, []}}, {from, self()}, {options, [{verify, verify_peer} | ClientConf]}]), - ssl_test_lib:check_result(Server, {error, {tls_alert, "handshake failure"}}, - Client1, {error, {tls_alert, "handshake failure"}}), + ssl_test_lib:check_result(Client1, {error, {tls_alert, "handshake failure"}}), ssl_test_lib:close(Client0). %%-------------------------------------------------------------------- %% Internal Functions ------------------------------------------------ -- cgit v1.2.3