diff options
Diffstat (limited to 'lib/ssl/src')
-rw-r--r-- | lib/ssl/src/ssl.appup.src | 2 | ||||
-rw-r--r-- | lib/ssl/src/ssl.erl | 18 | ||||
-rw-r--r-- | lib/ssl/src/ssl_app.erl | 4 | ||||
-rw-r--r-- | lib/ssl/src/ssl_certificate.erl | 10 | ||||
-rw-r--r-- | lib/ssl/src/ssl_certificate_db.erl | 27 | ||||
-rw-r--r-- | lib/ssl/src/ssl_cipher.erl | 12 | ||||
-rw-r--r-- | lib/ssl/src/ssl_cipher.hrl | 2 | ||||
-rw-r--r-- | lib/ssl/src/ssl_connection.erl | 116 | ||||
-rw-r--r-- | lib/ssl/src/ssl_handshake.erl | 54 | ||||
-rw-r--r-- | lib/ssl/src/ssl_internal.hrl | 4 | ||||
-rw-r--r-- | lib/ssl/src/ssl_manager.erl | 46 | ||||
-rw-r--r-- | lib/ssl/src/ssl_record.erl | 11 | ||||
-rw-r--r-- | lib/ssl/src/ssl_session.erl | 2 | ||||
-rw-r--r-- | lib/ssl/src/ssl_ssl3.erl | 7 | ||||
-rw-r--r-- | lib/ssl/src/ssl_sup.erl | 7 |
15 files changed, 183 insertions, 139 deletions
diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src index 65f23e2f74..88cd73be74 100644 --- a/lib/ssl/src/ssl.appup.src +++ b/lib/ssl/src/ssl.appup.src @@ -1,6 +1,7 @@ %% -*- erlang -*- {"%VSN%", [ + {"4.0", [{restart_application, ssl}]}, {"3.11.1", [{restart_application, ssl}]}, {"3.11", [{restart_application, ssl}]}, {"3.10", [{restart_application, ssl}]}, @@ -15,6 +16,7 @@ {"3.10.9", [{restart_application, ssl}]} ], [ + {"4.0", [{restart_application, ssl}]}, {"3.11.1", [{restart_application, ssl}]}, {"3.11", [{restart_application, ssl}]}, {"3.10", [{restart_application, ssl}]}, diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index df4cd7c84d..6e26f05c3d 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -77,8 +77,9 @@ stop() -> application:stop(ssl). %%-------------------------------------------------------------------- --spec connect(host() | port(), port_num(), list()) -> {ok, #sslsocket{}}. --spec connect(host() | port(), port_num(), list(), timeout()) -> {ok, #sslsocket{}}. +-spec connect(host() | port(), list()) -> {ok, #sslsocket{}}. +-spec connect(host() | port(), list() | port_num(), timeout() | list()) -> {ok, #sslsocket{}}. +-spec connect(host() | port(), port_num(), list(), timeout()) -> {ok, #sslsocket{}}. %% %% Description: Connect to a ssl server. %%-------------------------------------------------------------------- @@ -215,8 +216,8 @@ ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) -> {ok, #config{cb=CbInfo,ssl=SslOpts, emulated=EmOpts}} -> {ok, Port} = inet:port(Socket), ssl_connection:ssl_accept(Port, Socket, - {SslOpts, EmOpts}, - self(), CbInfo, Timeout) + {SslOpts, EmOpts}, + self(), CbInfo, Timeout) catch Error = {error, _Reason} -> Error end. @@ -326,7 +327,7 @@ decode_peercert(BinCert, Opts) -> {ok, BinCert} end. -select_part(otp, {ok, Cert}, Opts) -> +select_part(otp, Cert, Opts) -> case lists:member(subject, Opts) of true -> TBS = Cert#'OTPCertificate'.tbsCertificate, @@ -335,7 +336,7 @@ select_part(otp, {ok, Cert}, Opts) -> {ok, Cert} end; -select_part(plain, {ok, Cert}, Opts) -> +select_part(plain, Cert, Opts) -> case lists:member(subject, Opts) of true -> TBS = Cert#'Certificate'.tbsCertificate, @@ -446,8 +447,8 @@ session_info(#sslsocket{pid = Pid, fd = new_ssl}) -> ssl_connection:session_info(Pid). %%--------------------------------------------------------------- --spec versions() -> [{{ssl_app, string()}, {supported, [tls_version()]}, - {available, [tls_version()]}}]. +-spec versions() -> [{ssl_app, string()} | {supported, [tls_atom_version()]} | + {available, [tls_atom_version()]}]. %% %% Description: Returns a list of relevant versions. %%-------------------------------------------------------------------- @@ -457,6 +458,7 @@ versions() -> AvailableVsns = ?DEFAULT_SUPPORTED_VERSIONS, [{ssl_app, ?VSN}, {supported, SupportedVsns}, {available, AvailableVsns}]. + %%--------------------------------------------------------------- -spec renegotiate(#sslsocket{}) -> ok | {error, reason()}. %% diff --git a/lib/ssl/src/ssl_app.erl b/lib/ssl/src/ssl_app.erl index d9a354086d..8d50fd7bdb 100644 --- a/lib/ssl/src/ssl_app.erl +++ b/lib/ssl/src/ssl_app.erl @@ -29,14 +29,14 @@ %%-------------------------------------------------------------------- -spec start(normal | {takeover, node()} | {failover, node()}, list()) -> - {ok, pid()} | {ok, pid(), term()} | {error, term()}. + ignore | {ok, pid()} | {error, term()}. %%-------------------------------------------------------------------- start(_Type, _StartArgs) -> ssl_sup:start_link(). %-------------------------------------------------------------------- -spec stop(term())-> ok. -%%-------------------------------------------------------------------- +%%-------------------------------------------------------------------- stop(_State) -> ok. diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index 8a79f75725..917e75157b 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -56,7 +56,7 @@ %%-------------------------------------------------------------------- trusted_cert_and_path(CertChain, CertDbRef, Verify) -> [Cert | RestPath] = lists:reverse(CertChain), - {ok, OtpCert} = public_key:pkix_decode_cert(Cert, otp), + OtpCert = public_key:pkix_decode_cert(Cert, otp), IssuerAnPath = case public_key:pkix_is_self_signed(OtpCert) of true -> @@ -94,14 +94,14 @@ trusted_cert_and_path(CertChain, CertDbRef, Verify) -> %%-------------------------------------------------------------------- -spec certificate_chain(undefined | binary(), certdb_ref()) -> - {error, no_cert} | [der_cert()]. + {error, no_cert} | {ok, [der_cert()]}. %% %% Description: Return the certificate chain to send to peer. %%-------------------------------------------------------------------- certificate_chain(undefined, _CertsDbRef) -> {error, no_cert}; certificate_chain(OwnCert, CertsDbRef) -> - {ok, ErlCert} = public_key:pkix_decode_cert(OwnCert, otp), + ErlCert = public_key:pkix_decode_cert(OwnCert, otp), certificate_chain(ErlCert, OwnCert, CertsDbRef, [OwnCert]). %%-------------------------------------------------------------------- -spec file_to_certificats(string()) -> [der_cert()]. @@ -110,7 +110,7 @@ certificate_chain(OwnCert, CertsDbRef) -> %%-------------------------------------------------------------------- file_to_certificats(File) -> {ok, List} = ssl_manager:cache_pem_file(File), - [Bin || {cert, Bin, not_encrypted} <- List]. + [Bin || {'Certificate', Bin, not_encrypted} <- List]. %%-------------------------------------------------------------------- -spec validate_extensions([#'Extension'{}], term(), [#'Extension'{}], boolean(), list(), client | server) -> {[#'Extension'{}], term(), list()}. @@ -219,7 +219,7 @@ certificate_chain(CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned) -> case ssl_manager:lookup_trusted_cert(CertsDbRef, SerialNr, Issuer) of {ok, {IssuerCert, ErlCert}} -> - {ok, ErlCert} = public_key:pkix_decode_cert(IssuerCert, otp), + ErlCert = public_key:pkix_decode_cert(IssuerCert, otp), certificate_chain(ErlCert, IssuerCert, CertsDbRef, [IssuerCert | Chain]); _ -> diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl index e953821057..00d3079cb3 100644 --- a/lib/ssl/src/ssl_certificate_db.erl +++ b/lib/ssl/src/ssl_certificate_db.erl @@ -54,10 +54,9 @@ remove(Dbs) -> lists:foreach(fun(Db) -> true = ets:delete(Db) end, Dbs). %%-------------------------------------------------------------------- --spec lookup_trusted_cert(reference(), serialnumber(), issuer()) -> {der_cert(), #'OTPCertificate'{}}. +-spec lookup_trusted_cert(reference(), serialnumber(), issuer()) -> + undefined | {ok, {der_cert(), #'OTPCertificate'{}}}. -%% SerialNumber = integer() -%% Issuer = {rdnSequence, IssuerAttrs} %% %% Description: Retrives the trusted certificate identified by %% <SerialNumber, Issuer>. Ref is used as it is specified @@ -101,10 +100,11 @@ add_trusted_certs(Pid, File, [CertsDb, FileToRefDb, PidToFileDb]) -> %% Description: Cache file as binary in DB %%-------------------------------------------------------------------- cache_pem_file(Pid, File, [CertsDb, _FileToRefDb, PidToFileDb]) -> - Res = {ok, Content} = public_key:pem_to_der(File), + {ok, PemBin} = file:read_file(File), + Content = public_key:pem_decode(PemBin), insert({file, File}, Content, CertsDb), insert(Pid, File, PidToFileDb), - Res. + {ok, Content}. %%-------------------------------------------------------------------- -spec remove_trusted_certs(pid(), certdb_ref()) -> term(). @@ -138,13 +138,13 @@ remove_trusted_certs(Pid, [CertsDb, FileToRefDb, PidToFileDb]) -> end. %%-------------------------------------------------------------------- --spec issuer_candidate(no_candidate | cert_key()) -> - {cert_key(), der_cert()} | no_more_candidates. +-spec issuer_candidate(no_candidate | cert_key() | {file, term()}) -> + {cert_key(),{der_cert(), #'OTPCertificate'{}}} | no_more_candidates. %% %% Description: If a certificat does not define its issuer through %% the extension 'ce-authorityKeyIdentifier' we can %% try to find the issuer in the database over known -%% certificates. +%% certificates. %%-------------------------------------------------------------------- issuer_candidate(no_candidate) -> Db = certificate_db_name(), @@ -203,14 +203,15 @@ remove_certs(Ref, CertsDb) -> ets:match_delete(CertsDb, {{Ref, '_', '_'}, '_'}). add_certs_from_file(File, Ref, CertsDb) -> - Decode = fun(Cert) -> - {ok, ErlCert} = public_key:pkix_decode_cert(Cert, otp), + Add = fun(Cert) -> + ErlCert = public_key:pkix_decode_cert(Cert, otp), TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate, SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber, - Issuer = public_key:pkix_normalize_general_name( + Issuer = public_key:pkix_normalize_name( TBSCertificate#'OTPTBSCertificate'.issuer), insert({Ref, SerialNumber, Issuer}, {Cert,ErlCert}, CertsDb) end, - {ok,Der} = public_key:pem_to_der(File), - [Decode(Cert) || {cert, Cert, not_encrypted} <- Der]. + {ok, PemBin} = file:read_file(File), + PemEntries = public_key:pem_decode(PemBin), + [Add(Cert) || {'Certificate', Cert, not_encrypted} <- PemEntries]. diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl index a6e80047c2..8230149304 100644 --- a/lib/ssl/src/ssl_cipher.erl +++ b/lib/ssl/src/ssl_cipher.erl @@ -40,7 +40,7 @@ -compile(inline). %%-------------------------------------------------------------------- --spec security_parameters(erl_cipher_suite(), #security_parameters{}) -> +-spec security_parameters(cipher_suite(), #security_parameters{}) -> #security_parameters{}. %% %% Description: Returns a security parameters record where the @@ -119,7 +119,7 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0, %%-------------------------------------------------------------------- -spec decipher(cipher_enum(), integer(), #cipher_state{}, binary(), tls_version()) -> - {binary(), #cipher_state{}}. + {binary(), binary(), #cipher_state{}} | #alert{}. %% %% Description: Decrypts the data and the MAC using cipher described %% by cipher_enum() and updating the cipher state. @@ -370,7 +370,7 @@ openssl_suite_name(Cipher) -> filter(undefined, Ciphers) -> Ciphers; filter(DerCert, Ciphers) -> - {ok, OtpCert} = public_key:pkix_decode_cert(DerCert, otp), + OtpCert = public_key:pkix_decode_cert(DerCert, otp), SigAlg = OtpCert#'OTPCertificate'.signatureAlgorithm, case ssl_certificate:signature_type(SigAlg#'SignatureAlgorithm'.algorithm) of rsa -> @@ -506,6 +506,12 @@ generic_stream_cipher_from_bin(T, HashSz) -> is_correct_padding(_, {3, 0}) -> true; +%% For interoperability reasons we do not check the padding in TLS 1.0 as it +%% is not strictly required and breaks interopability with for instance +%% Google. +is_correct_padding(_, {3, 1}) -> + true; +%% Padding must be check in TLS 1.1 and after is_correct_padding(#generic_block_cipher{padding_length = Len, padding = Padding}, _) -> list_to_binary(lists:duplicate(Len, Len)) == Padding. diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl index 19de709d9c..8bd68cc190 100644 --- a/lib/ssl/src/ssl_cipher.hrl +++ b/lib/ssl/src/ssl_cipher.hrl @@ -28,7 +28,7 @@ -type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc' | aes_128_cbc | aes_256_cbc. --type hash() :: sha | md5. +-type hash() :: null | sha | md5. -type erl_cipher_suite() :: {key_algo(), cipher(), hash()}. -type cipher_suite() :: binary(). -type cipher_enum() :: integer(). diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index 5b4b129e30..76422155a5 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -125,8 +125,9 @@ send(Pid, Data) -> recv(Pid, Length, Timeout) -> sync_send_all_state_event(Pid, {recv, Length}, Timeout). %%-------------------------------------------------------------------- --spec connect(host(), port_num(), port(), list(), pid(), tuple(), timeout()) -> - {ok, #sslsocket{}} | {error, reason()}. +-spec connect(host(), port_num(), port(), {#ssl_options{}, #socket_options{}}, + pid(), tuple(), timeout()) -> + {ok, #sslsocket{}} | {error, reason()}. %% %% Description: Connect to a ssl server. %%-------------------------------------------------------------------- @@ -138,7 +139,8 @@ connect(Host, Port, Socket, Options, User, CbInfo, Timeout) -> {error, ssl_not_started} end. %%-------------------------------------------------------------------- --spec ssl_accept(port_num(), port(), list(), pid(), tuple(), timeout()) -> +-spec ssl_accept(port_num(), port(), {#ssl_options{}, #socket_options{}}, + pid(), tuple(), timeout()) -> {ok, #sslsocket{}} | {error, reason()}. %% %% Description: Performs accept on a ssl listen socket. e.i. performs @@ -253,7 +255,7 @@ session_info(ConnectionPid) -> sync_send_all_state_event(ConnectionPid, session_info). %%-------------------------------------------------------------------- --spec peer_certificate(pid()) -> {ok, binary()} | {error, reason()}. +-spec peer_certificate(pid()) -> {ok, binary()| undefined} | {error, reason()}. %% %% Description: Returns the peer cert %%-------------------------------------------------------------------- @@ -288,9 +290,10 @@ start_link(Role, Host, Port, Socket, Options, User, CbInfo) -> %% gen_fsm callbacks %%==================================================================== %%-------------------------------------------------------------------- --spec init(list()) -> {ok, state_name(), #state{}} - | {ok, state_name(), #state{}, timeout()} | - ignore | {stop, term()}. +-spec init(list()) -> {ok, state_name(), #state{}} | {stop, term()}. +%% Possible return values not used now. +%% | {ok, state_name(), #state{}, timeout()} | +%% ignore %% Description:Whenever a gen_fsm is started using gen_fsm:start/[3,4] or %% gen_fsm:start_link/3,4, this function is called by the new process to %% initialize. @@ -720,7 +723,9 @@ connection(#client_hello{} = Hello, #state{role = server} = State) -> connection(Msg, State) -> handle_unexpected_message(Msg, connection, State). %%-------------------------------------------------------------------- --spec handle_event(term(), state_name(), #state{}) -> gen_fsm_state_return(). +-spec handle_event(term(), state_name(), #state{}) -> term(). +%% As it is not currently used gen_fsm_state_return() makes +%% dialyzer unhappy! %% %% Description: Whenever a gen_fsm receives an event sent using %% gen_fsm:send_all_state_event/2, this function is called to handle @@ -1038,20 +1043,22 @@ ssl_init(SslOpts, Role) -> init_certificates(#ssl_options{cacertfile = CACertFile, certfile = CertFile}, Role) -> + {ok, CertDbRef, CacheRef} = + try + {ok, _, _} = ssl_manager:connection_init(CACertFile, Role) + catch + Error:Reason -> + handle_file_error(?LINE, Error, Reason, CACertFile, ecacertfile, + erlang:get_stacktrace()) + end, + init_certificates(CertDbRef, CacheRef, CertFile, Role). - case ssl_manager:connection_init(CACertFile, Role) of - {ok, CertDbRef, CacheRef} -> - init_certificates(CertDbRef, CacheRef, CertFile, Role); - {error, Reason} -> - handle_file_error(?LINE, error, Reason, CACertFile, ecacertfile, - erlang:get_stacktrace()) - end. init_certificates(CertDbRef, CacheRef, CertFile, client) -> try [OwnCert] = ssl_certificate:file_to_certificats(CertFile), {ok, CertDbRef, CacheRef, OwnCert} - catch _E:_R -> + catch _Error:_Reason -> {ok, CertDbRef, CacheRef, undefined} end; @@ -1068,15 +1075,15 @@ init_certificates(CertDbRef, CacheRef, CertFile, server) -> init_private_key(undefined, "", _Password, client) -> undefined; init_private_key(undefined, KeyFile, Password, _) -> - case ssl_manager:cache_pem_file(KeyFile) of - {ok, List} -> - [Der] = [Der || Der = {PKey, _ , _} <- List, - PKey =:= rsa_private_key orelse - PKey =:= dsa_private_key], - {ok, Decoded} = public_key:decode_private_key(Der,Password), - Decoded; - {error, Reason} -> - handle_file_error(?LINE, error, Reason, KeyFile, ekeyfile, + try + {ok, List} = ssl_manager:cache_pem_file(KeyFile), + [PemEntry] = [PemEntry || PemEntry = {PKey, _ , _} <- List, + PKey =:= 'RSAPrivateKey' orelse + PKey =:= 'DSAPrivateKey'], + public_key:pem_entry_decode(PemEntry, Password) + catch + Error:Reason -> + handle_file_error(?LINE, Error, Reason, KeyFile, ekeyfile, erlang:get_stacktrace()) end; @@ -1088,6 +1095,7 @@ handle_file_error(Line, Error, {badmatch, Reason}, File, Throw, Stack) -> handle_file_error(Line, Error, Reason, File, Throw, Stack) -> file_error(Line, Error, Reason, File, Throw, Stack). +-spec(file_error/6 :: (_,_,_,_,_,_) -> no_return()). file_error(Line, Error, Reason, File, Throw, Stack) -> Report = io_lib:format("SSL: ~p: ~p:~p ~s~n ~p~n", [Line, Error, Reason, File, Stack]), @@ -1099,17 +1107,18 @@ init_diffie_hellman(_, client) -> init_diffie_hellman(undefined, _) -> ?DEFAULT_DIFFIE_HELLMAN_PARAMS; init_diffie_hellman(DHParamFile, server) -> - case ssl_manager:cache_pem_file(DHParamFile) of - {ok, List} -> - case [Der || Der = {dh_params, _ , _} <- List] of - [Der] -> - {ok, Decoded} = public_key:decode_dhparams(Der), - Decoded; - [] -> - ?DEFAULT_DIFFIE_HELLMAN_PARAMS - end; - {error, Reason} -> - handle_file_error(?LINE, error, Reason, DHParamFile, edhfile, erlang:get_stacktrace()) + try + {ok, List} = ssl_manager:cache_pem_file(DHParamFile), + case [Entry || Entry = {'DHParameter', _ , _} <- List] of + [Entry] -> + public_key:pem_entry_decode(Entry); + [] -> + ?DEFAULT_DIFFIE_HELLMAN_PARAMS + end + catch + Error:Reason -> + handle_file_error(?LINE, Error, Reason, + DHParamFile, edhfile, erlang:get_stacktrace()) end. sync_send_all_state_event(FsmPid, Event) -> @@ -1178,7 +1187,7 @@ verify_client_cert(#state{client_certificate_requested = true, role = client, tls_handshake_hashes = Hashes1}; ignore -> State; - #alert{} = Alert -> + #alert{} = Alert -> handle_own_alert(Alert, Version, certify, State) end; @@ -1186,18 +1195,19 @@ verify_client_cert(#state{client_certificate_requested = false} = State) -> State. do_server_hello(Type, #state{negotiated_version = Version, - session = Session, + session = #session{session_id = SessId} = Session, connection_states = ConnectionStates0, renegotiation = {Renegotiation, _}} = State0) when is_atom(Type) -> + ServerHello = - ssl_handshake:server_hello(Session#session.session_id, Version, + ssl_handshake:server_hello(SessId, Version, ConnectionStates0, Renegotiation), State1 = server_hello(ServerHello, State0), case Type of new -> - do_server_hello(ServerHello, State1); + new_server_hello(ServerHello, State1); resumed -> ConnectionStates1 = State1#state.connection_states, case ssl_handshake:master_secret(Version, Session, @@ -1216,9 +1226,9 @@ do_server_hello(Type, #state{negotiated_version = Version, handle_own_alert(Alert, Version, hello, State1), {stop, normal, State1} end - end; + end. -do_server_hello(#server_hello{cipher_suite = CipherSuite, +new_server_hello(#server_hello{cipher_suite = CipherSuite, compression_method = Compression, session_id = SessionId}, #state{session = Session0, @@ -1343,7 +1353,7 @@ certify_server(#state{transport_cb = Transport, key_exchange(#state{role = server, key_algorithm = rsa} = State) -> State; key_exchange(#state{role = server, key_algorithm = Algo, - diffie_hellman_params = Params, + diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params, private_key = PrivateKey, connection_states = ConnectionStates0, negotiated_version = Version, @@ -1354,7 +1364,7 @@ key_exchange(#state{role = server, key_algorithm = Algo, when Algo == dhe_dss; Algo == dhe_rsa -> - Keys = public_key:gen_key(Params), + Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]), ConnectionState = ssl_record:pending_connection_state(ConnectionStates0, read), SecParams = ConnectionState#connection_state.security_parameters, @@ -1406,6 +1416,8 @@ key_exchange(#state{role = client, State#state{connection_states = ConnectionStates1, tls_handshake_hashes = Hashes1}. +-spec(rsa_key_exchange/2 :: (_,_) -> no_return()). + rsa_key_exchange(PremasterSecret, PublicKeyInfo = {Algorithm, _, _}) when Algorithm == ?rsaEncryption; Algorithm == ?md2WithRSAEncryption; @@ -1536,7 +1548,7 @@ verify_dh_params(Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) -> false end; verify_dh_params(Signed, Hash, {?'id-dsa', PublicKey, PublicKeyParams}) -> - public_key:verify_signature(Hash, none, Signed, PublicKey, PublicKeyParams). + public_key:verify(Hash, none, Signed, {PublicKey, PublicKeyParams}). cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} = State) -> @@ -1563,7 +1575,7 @@ encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) -> ssl_record:encode_change_cipher_spec(Version, ConnectionStates). encode_handshake(HandshakeRec, Version, ConnectionStates, Hashes) -> - encode_handshake(HandshakeRec, undefined, Version, + encode_handshake(HandshakeRec, null, Version, ConnectionStates, Hashes). encode_handshake(HandshakeRec, SigAlg, Version, ConnectionStates0, Hashes0) -> @@ -1726,11 +1738,13 @@ format_packet_error(#socket_options{active = _, mode = Mode}, Data) -> format_reply(binary, _, N, Data) when N > 0 -> % Header mode header(N, Data); -format_reply(binary, _, _, Data) -> Data; -format_reply(list, Packet, _, Data) when is_integer(Packet); Packet == raw -> - binary_to_list(Data); +format_reply(binary, _, _, Data) -> + Data; +format_reply(list, Packet, _, Data) + when Packet == http; Packet == {http, headers}; Packet == http_bin; Packet == {http_bin, headers} -> + Data; format_reply(list, _,_, Data) -> - Data. + binary_to_list(Data). header(0, <<>>) -> <<>>; @@ -2154,7 +2168,7 @@ renegotiate(#state{role = server, negotiated_version = Version, connection_states = ConnectionStates0} = State0) -> HelloRequest = ssl_handshake:hello_request(), - Frag = ssl_handshake:encode_handshake(HelloRequest, Version, undefined), + Frag = ssl_handshake:encode_handshake(HelloRequest, Version, null), Hs0 = ssl_handshake:init_hashes(), {BinMsg, ConnectionStates} = ssl_record:encode_handshake(Frag, Version, ConnectionStates0), diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index fcc30f6137..3d831eae02 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -42,8 +42,10 @@ encode_handshake/3, init_hashes/0, update_hashes/2, decrypt_premaster_secret/2]). --type tls_handshake() :: #client_hello{} | #server_hello{} | #server_hello_done{} | -#certificate{} | #client_key_exchange{} | #finished{} | #certificate_verify{}. +-type tls_handshake() :: #client_hello{} | #server_hello{} | + #server_hello_done{} | #certificate{} | #certificate_request{} | + #client_key_exchange{} | #finished{} | #certificate_verify{} | + #hello_request{}. %%==================================================================== %% Internal application API @@ -64,7 +66,7 @@ client_hello(Host, Port, ConnectionStates, #ssl_options{versions = Versions, Version = ssl_record:highest_protocol_version(lists:map(Fun, Versions)), Pending = ssl_record:pending_connection_state(ConnectionStates, read), SecParams = Pending#connection_state.security_parameters, - Ciphers = available_suites(Cert, UserSuites, Version), + Ciphers = available_suites(UserSuites, Version), Id = ssl_manager:client_session_id(Host, Port, SslOpts), @@ -110,7 +112,7 @@ hello_request() -> #connection_states{} | {port_num(), #session{}, cache_ref(), atom(), #connection_states{}, binary()}, boolean()) -> {tls_version(), session_id(), #connection_states{}}| - {tls_version(), {resumed | new, session_id()}, + {tls_version(), {resumed | new, #session{}}, #connection_states{}} | #alert{}. %% %% Description: Handles a recieved hello message @@ -232,7 +234,7 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbRef, end. %%-------------------------------------------------------------------- --spec certificate(der_cert(), term(), client | server) -> #certificate{}. +-spec certificate(der_cert(), term(), client | server) -> #certificate{} | #alert{}. %% %% Description: Creates a certificate message. %%-------------------------------------------------------------------- @@ -260,8 +262,8 @@ certificate(OwnCert, CertDbRef, server) -> %%-------------------------------------------------------------------- -spec client_certificate_verify(undefined | der_cert(), binary(), tls_version(), key_algo(), private_key(), - {binary(), binary()}) -> - #certificate_verify{} | ignore. + {{binary(), binary()},{binary(), binary()}}) -> + #certificate_verify{} | ignore | #alert{}. %% %% Description: Creates a certificate_verify message, called by the client. %%-------------------------------------------------------------------- @@ -283,9 +285,9 @@ client_certificate_verify(OwnCert, MasterSecret, Version, Algorithm, end. %%-------------------------------------------------------------------- --spec certificate_verify(binary(), public_key_info(), tls_version(), - binary(), key_algo(), - {binary(), binary()}) -> valid | #alert{}. +%% -spec certificate_verify(binary(), public_key_info(), tls_version(), +%% binary(), key_algo(), +%% {_, {binary(), binary()}}) -> valid | #alert{}. %% %% Description: Checks that the certificate_verify message is valid. %%-------------------------------------------------------------------- @@ -306,7 +308,7 @@ certificate_verify(Signature, {_, PublicKey, PublicKeyParams}, Version, MasterSecret, dhe_dss = Algorithm, {_, Hashes0}) -> Hashes = calc_certificate_verify(Version, MasterSecret, Algorithm, Hashes0), - case public_key:verify_signature(Hashes, none, Signature, PublicKey, PublicKeyParams) of + case public_key:verify(Hashes, none, Signature, {PublicKey, PublicKeyParams}) of true -> valid; false -> @@ -335,7 +337,7 @@ certificate_request(ConnectionStates, CertDbRef) -> -spec key_exchange(client | server, {premaster_secret, binary(), public_key_info()} | {dh, binary()} | - {dh, binary(), #'DHParameter'{}, key_algo(), + {dh, {binary(), binary()}, #'DHParameter'{}, key_algo(), binary(), binary(), private_key()}) -> #client_key_exchange{} | #server_key_exchange{}. %% @@ -412,7 +414,7 @@ master_secret(Version, PremasterSecret, ConnectionStates, Role) -> end. %%-------------------------------------------------------------------- --spec finished(tls_version(), client | server, binary(), {binary(), binary()}) -> +-spec finished(tls_version(), client | server, binary(), {{binary(), binary()},_}) -> #finished{}. %% %% Description: Creates a handshake finished message @@ -423,7 +425,7 @@ finished(Version, Role, MasterSecret, {Hashes, _}) -> % use the current hashes %%-------------------------------------------------------------------- -spec verify_connection(tls_version(), #finished{}, client | server, binary(), - {binary(), binary()}) -> verified | #alert{}. + {_, {binary(), binary()}}) -> verified | #alert{}. %% %% Description: Checks the ssl handshake finished message to verify %% the connection. @@ -448,7 +450,7 @@ server_hello_done() -> #server_hello_done{}. %%-------------------------------------------------------------------- --spec encode_handshake(tls_handshake(), tls_version(), key_algo()) -> binary(). +-spec encode_handshake(tls_handshake(), tls_version(), key_algo()) -> iolist(). %% %% Description: Encode a handshake packet to binary %%-------------------------------------------------------------------- @@ -459,8 +461,8 @@ encode_handshake(Package, Version, KeyAlg) -> [MsgType, ?uint24(Len), Bin]. %%-------------------------------------------------------------------- --spec get_tls_handshake(binary(), binary(), key_algo(), tls_version()) -> - {[tls_handshake()], [binary()], binary()}. +-spec get_tls_handshake(binary(), binary() | iolist(), key_algo(), tls_version()) -> + {[tls_handshake()], binary()}. %% %% Description: Given buffered and new data from ssl_record, collects %% and returns it as a list of handshake messages, also returns leftover @@ -524,13 +526,16 @@ select_session(Hello, Port, Session, Version, {resumed, CacheCb:lookup(Cache, {Port, SessionId})} end. -available_suites(Cert, UserSuites, Version) -> +available_suites(UserSuites, Version) -> case UserSuites of [] -> - ssl_cipher:filter(Cert, ssl_cipher:suites(Version)); + ssl_cipher:suites(Version); _ -> - ssl_cipher:filter(Cert, UserSuites) + UserSuites end. + +available_suites(ServerCert, UserSuites, Version) -> + ssl_cipher:filter(ServerCert, available_suites(UserSuites, Version)). cipher_suites(Suites, false) -> [?TLS_EMPTY_RENEGOTIATION_INFO_SCSV | Suites]; @@ -1042,9 +1047,10 @@ certificate_authorities(CertDbRef) -> Authorities = certificate_authorities_from_db(CertDbRef), Enc = fun(#'OTPCertificate'{tbsCertificate=TBSCert}) -> OTPSubj = TBSCert#'OTPTBSCertificate'.subject, - Subj = public_key:pkix_transform(OTPSubj, encode), - {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj), - DNEncodedBin = iolist_to_binary(DNEncoded), + DNEncodedBin = public_key:pkix_encode('Name', OTPSubj, otp), + %%Subj = public_key:pkix_transform(OTPSubj, encode), + %% {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj), + %% DNEncodedBin = iolist_to_binary(DNEncoded), DNEncodedLen = byte_size(DNEncodedBin), <<?UINT16(DNEncodedLen), DNEncodedBin/binary>> end, @@ -1068,7 +1074,7 @@ digitally_signed(Hash, #'RSAPrivateKey'{} = Key) -> public_key:encrypt_private(Hash, Key, [{rsa_pad, rsa_pkcs1_padding}]); digitally_signed(Hash, #'DSAPrivateKey'{} = Key) -> - public_key:sign(none, Hash, Key). + public_key:sign(Hash, none, Key). calc_master_secret({3,0}, PremasterSecret, ClientRandom, ServerRandom) -> ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom); diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index ddace02dea..337403531e 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -96,12 +96,12 @@ -type from() :: term(). -type host() :: string() | tuple(). -type port_num() :: integer(). --type session_id() :: binary(). +-type session_id() :: 0 | binary(). -type tls_version() :: {integer(), integer()}. -type tls_atom_version() :: sslv3 | tlsv1. -type cache_ref() :: term(). -type certdb_ref() :: term(). --type key_algo() :: rsa | dhe_rsa | dhe_dss. +-type key_algo() :: null | rsa | dhe_rsa | dhe_dss. -type enum_algo() :: integer(). -type public_key() :: #'RSAPublicKey'{} | integer(). -type public_key_params() :: #'Dss-Parms'{} | term(). diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index af30f78dbf..459dcefb79 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -29,7 +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/3, + server_session_id/3, register_session/2, register_session/3, invalidate_session/2, invalidate_session/3]). @@ -88,14 +89,17 @@ cache_pem_file(File) -> end. %%-------------------------------------------------------------------- -spec lookup_trusted_cert(reference(), serialnumber(), issuer()) -> - {der_cert(), #'OTPCertificate'{}}. + undefined | + {ok, {der_cert(), #'OTPCertificate'{}}}. %% -%% Description: Lookup the trusted cert with Key = {reference(), serialnumber(), issuer()}. -%%-------------------------------------------------------------------- +%% Description: Lookup the trusted cert with Key = {reference(), +%% serialnumber(), issuer()}. +%% -------------------------------------------------------------------- lookup_trusted_cert(Ref, SerialNumber, Issuer) -> ssl_certificate_db:lookup_trusted_cert(Ref, SerialNumber, Issuer). %%-------------------------------------------------------------------- --spec issuer_candidate(cert_key()) -> {cert_key(), der_cert()} | no_more_candidates. +-spec issuer_candidate(cert_key() | no_candidate) -> + {cert_key(), {der_cert(), #'OTPCertificate'{}}} | no_more_candidates. %% %% Description: Return next issuer candidate. %%-------------------------------------------------------------------- @@ -143,8 +147,9 @@ invalidate_session(Port, Session) -> %%==================================================================== %%-------------------------------------------------------------------- --spec init(list()) -> {ok, #state{}} | {ok, #state{}, timeout()} | - ignore | {stop, term()}. +-spec init(list()) -> {ok, #state{}}. +%% Possible return values not used now. +%% | {ok, #state{}, timeout()} | ignore | {stop, term()}. %% %% Description: Initiates the server %%-------------------------------------------------------------------- @@ -164,12 +169,13 @@ init([Opts]) -> session_validation_timer = Timer}}. %%-------------------------------------------------------------------- --spec handle_call(msg(), from(), #state{}) -> {reply, reply(), #state{}} | - {reply, reply(), #state{}, timeout()} | - {noreply, #state{}} | - {noreply, #state{}, timeout()} | - {stop, reason(), reply(), #state{}} | - {stop, reason(), #state{}}. +-spec handle_call(msg(), from(), #state{}) -> {reply, reply(), #state{}}. +%% Possible return values not used now. +%% {reply, reply(), #state{}, timeout()} | +%% {noreply, #state{}} | +%% {noreply, #state{}, timeout()} | +%% {stop, reason(), reply(), #state{}} | +%% {stop, reason(), #state{}}. %% %% Description: Handling call messages %%-------------------------------------------------------------------- @@ -216,9 +222,10 @@ handle_call({{cache_pem, File},Pid}, _, State = #state{certificate_db = Db}) -> {reply, {error, Reason}, State} end. %%-------------------------------------------------------------------- --spec handle_cast(msg(), #state{}) -> {noreply, #state{}} | - {noreply, #state{}, timeout()} | - {stop, reason(), #state{}}. +-spec handle_cast(msg(), #state{}) -> {noreply, #state{}}. +%% Possible return values not used now. +%% | {noreply, #state{}, timeout()} | +%% {stop, reason(), #state{}}. %% %% Description: Handling cast messages %%-------------------------------------------------------------------- @@ -253,9 +260,10 @@ handle_cast({invalidate_session, Port, #session{session_id = ID}}, {noreply, State}. %%-------------------------------------------------------------------- --spec handle_info(msg(), #state{}) -> {noreply, #state{}} | - {noreply, #state{}, timeout()} | - {stop, reason(), #state{}}. +-spec handle_info(msg(), #state{}) -> {noreply, #state{}}. +%% Possible return values not used now. +%% |{noreply, #state{}, timeout()} | +%% {stop, reason(), #state{}}. %% %% Description: Handling all non call/cast messages %%-------------------------------------------------------------------- diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index 90615c22a1..acd0d49c19 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -149,7 +149,7 @@ set_mac_secret(ReadMacSecret, WriteMacSecret, %%-------------------------------------------------------------------- --spec set_master_secret(binary(), #connection_state{}) -> #connection_states{}. +-spec set_master_secret(binary(), #connection_states{}) -> #connection_states{}. %% %% Description: Set master_secret in pending connection states %%-------------------------------------------------------------------- @@ -306,7 +306,7 @@ set_pending_cipher_state(#connection_states{pending_read = Read, pending_write = Write#connection_state{cipher_state = ClientState}}. %%-------------------------------------------------------------------- --spec get_tls_records(binary(), binary()) -> {[binary()], binary()}. +-spec get_tls_records(binary(), binary()) -> {[binary()], binary()} | #alert{}. %% %% Description: Given old buffer and new data from TCP, packs up a records %% and returns it as a list of tls_compressed binaries also returns leftover @@ -372,7 +372,8 @@ get_tls_records_aux(Data, Acc) -> {lists:reverse(Acc), Data}. %%-------------------------------------------------------------------- --spec protocol_version(tls_atom_version()) -> tls_version(). +-spec protocol_version(tls_atom_version() | tls_version()) -> + tls_version() | tls_atom_version(). %% %% Description: Creates a protocol version record from a version atom %% or vice versa. @@ -467,7 +468,7 @@ is_acceptable_version(_) -> false. %%-------------------------------------------------------------------- --spec compressions() -> binary(). +-spec compressions() -> [binary()]. %% %% Description: return a list of compressions supported (currently none) %%-------------------------------------------------------------------- @@ -476,7 +477,7 @@ compressions() -> %%-------------------------------------------------------------------- -spec decode_cipher_text(#ssl_tls{}, #connection_states{}) -> - {#ssl_tls{}, #connection_states{}}. + {#ssl_tls{}, #connection_states{}}| #alert{}. %% %% Description: Decode cipher text %%-------------------------------------------------------------------- diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl index e9755cb0e1..6db13e5b7a 100644 --- a/lib/ssl/src/ssl_session.erl +++ b/lib/ssl/src/ssl_session.erl @@ -35,7 +35,7 @@ -type seconds() :: integer(). %%-------------------------------------------------------------------- --spec is_new(binary(), binary()) -> boolean(). +-spec is_new(session_id(), session_id()) -> boolean(). %% %% Description: Checks if the session id decided by the server is a %% new or resumed sesion id. diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl index 375adf263a..1add203fb0 100644 --- a/lib/ssl/src/ssl_ssl3.erl +++ b/lib/ssl/src/ssl_ssl3.erl @@ -121,9 +121,10 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, Length, Fragment) -> ?DBG_HEX(Mac), Mac. --spec setup_keys(binary(), binary(), binary(), binary(), - integer(), integer(), binary()) -> {binary(), binary(), binary(), - binary(), binary(), binary()}. +-spec setup_keys(binary(), binary(), binary(), + integer(), integer(), term(), integer()) -> + {binary(), binary(), binary(), + binary(), binary(), binary()}. setup_keys(MasterSecret, ServerRandom, ClientRandom, HS, KML, _EKML, IVS) -> KeyBlock = generate_keyblock(MasterSecret, ServerRandom, ClientRandom, diff --git a/lib/ssl/src/ssl_sup.erl b/lib/ssl/src/ssl_sup.erl index b7cb5c3ab3..316ed8a4e9 100644 --- a/lib/ssl/src/ssl_sup.erl +++ b/lib/ssl/src/ssl_sup.erl @@ -32,14 +32,17 @@ %%%========================================================================= %%% API %%%========================================================================= + +-spec start_link() -> {ok, pid()} | ignore | {error, term()}. + start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []). %%%========================================================================= %%% Supervisor callback %%%========================================================================= -%% init([]) -> {ok, {SupFlags, [ChildSpec]}} -%% +-spec init([]) -> {ok, {SupFlags :: tuple(), [ChildSpec :: tuple()]}}. + init([]) -> %% OLD ssl - moved start to ssl.erl only if old %% ssl is acctualy run! |