58
57
transport_cb, % atom() - callback module
59
58
data_tag, % atom() - ex tcp.
60
59
close_tag, % atom() - ex tcp_closed
60
error_tag, % atom() - ex tcp_error
61
61
host, % string() | ipadress()
64
64
ssl_options, % #ssl_options{}
65
65
socket_options, % #socket_options{}
66
66
connection_states, % #connection_states{} from ssl_record.hrl
67
tls_packets = [], % Not yet handled decode ssl/tls packets.
67
68
tls_record_buffer, % binary() buffer of incomplete records
68
69
tls_handshake_buffer, % binary() buffer of incomplete handshakes
69
70
%% {{md5_hash, sha_hash}, {prev_md5, prev_sha}} (binary())
70
71
tls_handshake_hashes, % see above
71
72
tls_cipher_texts, % list() received but not deciphered yet
73
session, % #session{} from ssl_handshake.erl
73
session, % #session{} from ssl_handshake.hrl
75
75
session_cache_cb, %
76
negotiated_version, % #protocol_version{}
76
negotiated_version, % tls_version()
77
77
supported_protocol_versions, % [atom()]
78
78
client_certificate_requested = false,
79
79
key_algorithm, % atom as defined by cipher_suite
80
80
public_key_info, % PKIX: {Algorithm, PublicKey, PublicKeyParams}
81
private_key, % PKIX: 'RSAPrivateKey'
82
diffie_hellman_params, %
81
private_key, % PKIX: #'RSAPrivateKey'{}
82
diffie_hellman_params, % PKIX: #'DHParameter'{} relevant for server side
83
diffie_hellman_keys, % {PublicKey, PrivateKey}
83
84
premaster_secret, %
84
85
cert_db_ref, % ets_table()
85
86
from, % term(), where to reply
86
87
bytes_to_read, % integer(), # bytes to read in passive mode
87
88
user_data_buffer, % binary()
88
%% tls_buffer, % Keeps a lookahead one packet if available
89
log_alert, % boolean()
90
renegotiation, % {boolean(), From | internal | peer}
91
recv_during_renegotiation, %boolean()
96
-define(DEFAULT_DIFFIE_HELLMAN_PARAMS,
97
#'DHParameter'{prime = ?DEFAULT_DIFFIE_HELLMAN_PRIME,
98
base = ?DEFAULT_DIFFIE_HELLMAN_GENERATOR}).
100
-type state_name() :: hello | abbreviated | certify | cipher | connection.
101
-type gen_fsm_state_return() :: {next_state, state_name(), #state{}} |
102
{next_state, state_name(), #state{}, timeout()} |
103
{stop, term(), #state{}}.
92
105
%%====================================================================
93
106
%% Internal application API
94
107
%%====================================================================
96
109
%%--------------------------------------------------------------------
110
-spec send(pid(), iolist()) -> ok | {error, reason()}.
112
%% Description: Sends data over the ssl connection
100
113
%%--------------------------------------------------------------------
101
114
send(Pid, Data) ->
102
sync_send_event(Pid, {application_data, erlang:iolist_to_binary(Data)}, infinity).
103
send(Pid, Data, Timeout) ->
104
sync_send_event(Pid, {application_data, erlang:iolist_to_binary(Data)}, Timeout).
115
sync_send_all_state_event(Pid, {application_data,
116
erlang:iolist_to_binary(Data)}, infinity).
105
118
%%--------------------------------------------------------------------
119
-spec recv(pid(), integer(), timeout()) ->
120
{ok, binary() | list()} | {error, reason()}.
122
%% Description: Receives data when active = false
109
123
%%--------------------------------------------------------------------
110
recv(Pid, Length, Timeout) -> % TODO: Prio with renegotiate?
124
recv(Pid, Length, Timeout) ->
111
125
sync_send_all_state_event(Pid, {recv, Length}, Timeout).
112
126
%%--------------------------------------------------------------------
127
-spec connect(host(), port_num(), port(), {#ssl_options{}, #socket_options{}},
128
pid(), tuple(), timeout()) ->
129
{ok, #sslsocket{}} | {error, reason()}.
131
%% Description: Connect to a ssl server.
116
132
%%--------------------------------------------------------------------
117
133
connect(Host, Port, Socket, Options, User, CbInfo, Timeout) ->
118
start_fsm(client, Host, Port, Socket, Options, User, CbInfo,
120
%%--------------------------------------------------------------------
124
%%--------------------------------------------------------------------
125
accept(Port, Socket, Opts, User, CbInfo, Timeout) ->
126
start_fsm(server, "localhost", Port, Socket, Opts, User,
128
%%--------------------------------------------------------------------
134
try start_fsm(client, Host, Port, Socket, Options, User, CbInfo,
138
{error, ssl_not_started}
140
%%--------------------------------------------------------------------
141
-spec ssl_accept(port_num(), port(), {#ssl_options{}, #socket_options{}},
142
pid(), tuple(), timeout()) ->
143
{ok, #sslsocket{}} | {error, reason()}.
145
%% Description: Performs accept on a ssl listen socket. e.i. performs
147
%%--------------------------------------------------------------------
148
ssl_accept(Port, Socket, Opts, User, CbInfo, Timeout) ->
149
try start_fsm(server, "localhost", Port, Socket, Opts, User,
153
{error, ssl_not_started}
156
%%--------------------------------------------------------------------
157
-spec handshake(#sslsocket{}, timeout()) -> ok | {error, reason()}.
159
%% Description: Starts ssl handshake.
160
%%--------------------------------------------------------------------
161
handshake(#sslsocket{pid = Pid}, Timeout) ->
162
case sync_send_all_state_event(Pid, start, Timeout) of
168
%--------------------------------------------------------------------
169
-spec socket_control(port(), pid(), atom()) ->
170
{ok, #sslsocket{}} | {error, reason()}.
172
%% Description: Set the ssl process to own the accept socket
173
%%--------------------------------------------------------------------
174
socket_control(Socket, Pid, CbModule) ->
175
case CbModule:controlling_process(Socket, Pid) of
177
{ok, sslsocket(Pid)};
182
%%--------------------------------------------------------------------
183
-spec close(pid()) -> ok | {error, reason()}.
185
%% Description: Close a ssl connection
132
186
%%--------------------------------------------------------------------
133
187
close(ConnectionPid) ->
134
188
case sync_send_all_state_event(ConnectionPid, close) of
224
285
gen_fsm:start_link(?MODULE, [Role, Host, Port, Socket, Options,
225
286
User, CbInfo], []).
228
288
%%====================================================================
229
289
%% gen_fsm callbacks
230
290
%%====================================================================
231
291
%%--------------------------------------------------------------------
232
%% Function: init(Args) -> {ok, StateName, State} |
233
%% {ok, StateName, State, Timeout} |
235
%% {stop, StopReason}
292
-spec init(list()) -> {ok, state_name(), #state{}, timeout()} | {stop, term()}.
293
%% Possible return values not used now.
294
%% | {ok, state_name(), #state{}} |
236
296
%% Description:Whenever a gen_fsm is started using gen_fsm:start/[3,4] or
237
297
%% gen_fsm:start_link/3,4, this function is called by the new process to
239
299
%%--------------------------------------------------------------------
240
init([Role, Host, Port, Socket, {SSLOpts, _} = Options,
300
init([Role, Host, Port, Socket, {SSLOpts0, _} = Options,
241
301
User, CbInfo]) ->
242
302
State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
243
303
Hashes0 = ssl_handshake:init_hashes(),
245
try ssl_init(SSLOpts, Role) of
246
{ok, Ref, CacheRef, OwnCert, Key} ->
305
try ssl_init(SSLOpts0, Role) of
306
{ok, Ref, CacheRef, OwnCert, Key, DHParams} ->
307
Session = State0#state.session,
247
308
State = State0#state{tls_handshake_hashes = Hashes0,
309
session = Session#session{own_certificate = OwnCert},
249
310
cert_db_ref = Ref,
250
311
session_cache = CacheRef,
313
diffie_hellman_params = DHParams},
314
{ok, hello, State, get_timeout(State)}
258
%%--------------------------------------------------------------------
260
%% state_name(Event, State) -> {next_state, NextStateName, NextState}|
261
%% {next_state, NextStateName,
262
%% NextState, Timeout} |
263
%% {stop, Reason, NewState}
264
%% Description:There should be one instance of this function for each possible
265
%% state name. Whenever a gen_fsm receives an event sent using
266
%% gen_fsm:send_event/2, the instance of this function with the same name as
267
%% the current state name StateName is called to handle the event. It is also
268
%% called if a timeout occurs.
269
%%--------------------------------------------------------------------
270
hello(socket_control, #state{host = Host, port = Port, role = client,
271
ssl_options = SslOpts,
272
transport_cb = Transport, socket = Socket,
273
connection_states = ConnectionStates}
275
Hello = ssl_handshake:client_hello(Host, Port, ConnectionStates, SslOpts),
320
%%--------------------------------------------------------------------
321
%% -spec state_name(event(), #state{}) -> gen_fsm_state_return()
323
%% Description:There should be one instance of this function for each
324
%% possible state name. Whenever a gen_fsm receives an event sent
325
%% using gen_fsm:send_event/2, the instance of this function with the
326
%% same name as the current state name StateName is called to handle
327
%% the event. It is also called if a timeout occurs.
329
%%--------------------------------------------------------------------
330
-spec hello(start | #hello_request{} | #client_hello{} | #server_hello{} | term(),
331
#state{}) -> gen_fsm_state_return().
332
%%--------------------------------------------------------------------
333
hello(start, #state{host = Host, port = Port, role = client,
334
ssl_options = SslOpts,
335
session = #session{own_certificate = Cert} = Session0,
336
transport_cb = Transport, socket = Socket,
337
connection_states = ConnectionStates,
338
renegotiation = {Renegotiation, _}} = State0) ->
339
Hello = ssl_handshake:client_hello(Host, Port,
341
SslOpts, Renegotiation, Cert),
276
343
Version = Hello#client_hello.client_version,
277
344
Hashes0 = ssl_handshake:init_hashes(),
278
345
{BinMsg, CS2, Hashes1} =
279
346
encode_handshake(Hello, Version, ConnectionStates, Hashes0),
280
347
Transport:send(Socket, BinMsg),
281
State = State0#state{connection_states = CS2,
348
State1 = State0#state{connection_states = CS2,
282
349
negotiated_version = Version, %% Requested version
284
#session{session_id = Hello#client_hello.session_id,
285
is_resumable = false},
286
tls_handshake_hashes = Hashes1},
287
{next_state, hello, next_record(State)};
289
hello(socket_control, #state{role = server} = State) ->
290
{next_state, hello, next_record(State)};
292
hello(hello, #state{role = client} = State) ->
293
{next_state, hello, State};
351
Session0#session{session_id = Hello#client_hello.session_id,
352
is_resumable = false},
353
tls_handshake_hashes = Hashes1},
354
{Record, State} = next_record(State1),
355
next_state(hello, Record, State);
357
hello(start, #state{role = server} = State0) ->
358
{Record, State} = next_record(State0),
359
next_state(hello, Record, State);
361
hello(#hello_request{}, #state{role = client} = State0) ->
362
{Record, State} = next_record(State0),
363
next_state(hello, Record, State);
295
365
hello(#server_hello{cipher_suite = CipherSuite,
296
366
compression_method = Compression} = Hello,
297
#state{session = Session0 = #session{session_id = OldId},
367
#state{session = #session{session_id = OldId},
298
368
connection_states = ConnectionStates0,
300
370
negotiated_version = ReqVersion,
301
host = Host, port = Port,
302
session_cache = Cache,
303
session_cache_cb = CacheCb} = State0) ->
304
{Version, NewId, ConnectionStates1} =
305
ssl_handshake:hello(Hello, ConnectionStates0),
307
{KeyAlgorithm, _, _, _} =
308
ssl_cipher:suite_definition(CipherSuite),
310
PremasterSecret = make_premaster_secret(ReqVersion),
312
State = State0#state{key_algorithm = KeyAlgorithm,
313
negotiated_version = Version,
314
connection_states = ConnectionStates1,
315
premaster_secret = PremasterSecret},
317
case ssl_session:is_new(OldId, NewId) of
319
Session = Session0#session{session_id = NewId,
320
cipher_suite = CipherSuite,
321
compression_method = Compression},
322
{next_state, certify,
323
next_record(State#state{session = Session})};
325
Session = CacheCb:lookup(Cache, {{Host, Port}, NewId}),
326
case ssl_handshake:master_secret(Version, Session,
327
ConnectionStates1, client) of
328
{_, ConnectionStates2} ->
329
{next_state, abbreviated,
330
next_record(State#state{
331
connection_states = ConnectionStates2,
332
session = Session})};
334
handle_own_alert(Alert, Version, hello, State),
335
{stop, normal, State}
371
renegotiation = {Renegotiation, _},
372
ssl_options = SslOptions} = State0) ->
373
case ssl_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
374
{Version, NewId, ConnectionStates} ->
375
{KeyAlgorithm, _, _} =
376
ssl_cipher:suite_definition(CipherSuite),
378
PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm),
380
State = State0#state{key_algorithm = KeyAlgorithm,
381
negotiated_version = Version,
382
connection_states = ConnectionStates,
383
premaster_secret = PremasterSecret},
385
case ssl_session:is_new(OldId, NewId) of
387
handle_new_session(NewId, CipherSuite, Compression, State);
389
handle_resumed_session(NewId, State#state{connection_states = ConnectionStates})
392
handle_own_alert(Alert, ReqVersion, hello, State0),
393
{stop, normal, State0}
339
396
hello(Hello = #client_hello{client_version = ClientVersion},
340
397
State = #state{connection_states = ConnectionStates0,
341
port = Port, session = Session0,
342
session_cache = Cache,
398
port = Port, session = #session{own_certificate = Cert} = Session0,
399
renegotiation = {Renegotiation, _},
400
session_cache = Cache,
343
401
session_cache_cb = CacheCb,
344
402
ssl_options = SslOpts}) ->
346
case ssl_handshake:hello(Hello, {Port, SslOpts,
347
Session0, Cache, CacheCb,
348
ConnectionStates0}) of
403
case ssl_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
404
ConnectionStates0, Cert}, Renegotiation) of
349
405
{Version, {Type, Session}, ConnectionStates} ->
350
406
do_server_hello(Type, State#state{connection_states =
351
407
ConnectionStates,
480
571
{stop, normal, State0}
483
certify(#client_key_exchange{},
484
State = #state{role = server,
485
client_certificate_requested = true,
486
ssl_options = #ssl_options{fail_if_no_peer_cert = true},
487
negotiated_version = Version}) ->
574
certify(#client_key_exchange{} = Msg,
575
#state{role = server,
576
client_certificate_requested = true,
577
ssl_options = #ssl_options{fail_if_no_peer_cert = true}} = State) ->
488
578
%% We expect a certificate here
489
Alert = ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE),
490
handle_own_alert(Alert, Version, certify_server_waiting_certificate, State),
491
{stop, normal, State};
494
certify(#client_key_exchange{exchange_keys
495
= #encrypted_premaster_secret{premaster_secret
497
#state{negotiated_version = Version,
498
connection_states = ConnectionStates0,
500
private_key = Key} = State0) ->
501
try ssl_handshake:decrypt_premaster_secret(EncPMS, Key) of
503
case ssl_handshake:master_secret(Version, PremasterSecret,
504
ConnectionStates0, server) of
505
{MasterSecret, ConnectionStates} ->
506
Session = Session0#session{master_secret = MasterSecret},
507
State = State0#state{connection_states = ConnectionStates,
509
{next_state, cipher, next_record(State)};
511
handle_own_alert(Alert, Version,
512
certify_client_key_exchange, State0),
513
{stop, normal, State0}
579
handle_unexpected_message(Msg, certify_client_key_exchange, State);
581
certify(#client_key_exchange{exchange_keys = Keys},
582
State = #state{key_algorithm = KeyAlg, negotiated_version = Version}) ->
584
certify_client_key_exchange(ssl_handshake:decode_client_key(Keys, KeyAlg, Version), State)
516
586
#alert{} = Alert ->
517
handle_own_alert(Alert, Version, certify_client_key_exchange,
587
handle_own_alert(Alert, Version, certify_client_key_exchange, State),
588
{stop, normal, State}
591
certify(timeout, State) ->
592
{ next_state, certify, State, hibernate };
594
certify(Msg, State) ->
595
handle_unexpected_message(Msg, certify, State).
597
certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS},
598
#state{negotiated_version = Version,
599
connection_states = ConnectionStates0,
601
private_key = Key} = State0) ->
602
PremasterSecret = ssl_handshake:decrypt_premaster_secret(EncPMS, Key),
603
case ssl_handshake:master_secret(Version, PremasterSecret,
604
ConnectionStates0, server) of
605
{MasterSecret, ConnectionStates} ->
606
Session = Session0#session{master_secret = MasterSecret},
607
State1 = State0#state{connection_states = ConnectionStates,
609
{Record, State} = next_record(State1),
610
next_state(cipher, Record, State);
612
handle_own_alert(Alert, Version,
613
certify_client_key_exchange, State0),
614
{stop, normal, State0}
617
certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPublicDhKey},
618
#state{negotiated_version = Version,
619
diffie_hellman_params = #'DHParameter'{prime = P,
621
diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) ->
622
case dh_master_secret(crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of
624
{Record, State} = next_record(State1),
625
next_state(cipher, Record, State);
627
handle_own_alert(Alert, Version,
628
certify_client_key_exchange, State0),
519
629
{stop, normal, State0}
522
cipher(socket_control, #state{role = server} = State) ->
523
{next_state, cipher, State};
524
cipher(hello, State) ->
525
{next_state, cipher, State};
632
%%--------------------------------------------------------------------
633
-spec cipher(#hello_request{} | #certificate_verify{} | #finished{} | term(),
634
#state{}) -> gen_fsm_state_return().
635
%%--------------------------------------------------------------------
636
cipher(#hello_request{}, State0) ->
637
{Record, State} = next_record(State0),
638
next_state(hello, Record, State);
527
640
cipher(#certificate_verify{signature = Signature},
528
641
#state{role = server,
529
642
public_key_info = PublicKeyInfo,
530
643
negotiated_version = Version,
531
644
session = #session{master_secret = MasterSecret},
532
key_algorithm = Algorithm,
533
645
tls_handshake_hashes = Hashes
535
647
case ssl_handshake:certificate_verify(Signature, PublicKeyInfo,
536
Version, MasterSecret,
537
Algorithm, Hashes) of
648
Version, MasterSecret, Hashes) of
539
{next_state, cipher, next_record(State)};
650
{Record, State} = next_record(State0),
651
next_state(cipher, Record, State);
540
652
#alert{} = Alert ->
541
handle_own_alert(Alert, Version, cipher, State),
542
{stop, normal, State}
653
handle_own_alert(Alert, Version, cipher, State0),
654
{stop, normal, State0}
545
cipher(#finished{} = Finished,
546
State = #state{from = From,
547
negotiated_version = Version,
551
session = #session{master_secret = MasterSecret}
553
tls_handshake_hashes = Hashes}) ->
657
cipher(#finished{verify_data = Data} = Finished,
658
#state{negotiated_version = Version,
662
session = #session{master_secret = MasterSecret}
664
tls_handshake_hashes = Hashes0} = State) ->
555
665
case ssl_handshake:verify_connection(Version, Finished,
556
666
opposite_role(Role),
557
MasterSecret, Hashes) of
667
MasterSecret, Hashes0) of
559
gen_fsm:reply(From, connected),
560
669
Session = register_session(Role, Host, Port, Session0),
563
{next_state, connection,
564
next_record_if_active(State#state{session = Session})};
566
{NewConnectionStates, NewHashes} =
567
finalize_server_handshake(State#state{
570
State#state{connection_states = NewConnectionStates,
572
tls_handshake_hashes = NewHashes},
573
{next_state, connection, next_record_if_active(NewState)}
670
cipher_role(Role, Data, Session, State);
575
671
#alert{} = Alert ->
576
672
handle_own_alert(Alert, Version, cipher, State),
577
673
{stop, normal, State}
580
connection(socket_control, #state{role = server} = State) ->
581
{next_state, connection, State};
582
connection(hello, State = #state{host = Host, port = Port,
584
ssl_options = SslOpts,
585
negotiated_version = Version,
586
transport_cb = Transport,
587
connection_states = ConnectionStates0,
588
tls_handshake_hashes = Hashes0}) ->
590
Hello = ssl_handshake:client_hello(Host, Port,
591
ConnectionStates0, SslOpts),
676
cipher(timeout, State) ->
677
{ next_state, cipher, State, hibernate };
679
cipher(Msg, State) ->
680
handle_unexpected_message(Msg, cipher, State).
682
%%--------------------------------------------------------------------
683
-spec connection(#hello_request{} | #client_hello{} | term(),
684
#state{}) -> gen_fsm_state_return().
685
%%--------------------------------------------------------------------
686
connection(#hello_request{}, #state{host = Host, port = Port,
688
session = #session{own_certificate = Cert},
689
ssl_options = SslOpts,
690
negotiated_version = Version,
691
transport_cb = Transport,
692
connection_states = ConnectionStates0,
693
renegotiation = {Renegotiation, _},
694
tls_handshake_hashes = Hashes0} = State0) ->
695
Hello = ssl_handshake:client_hello(Host, Port, ConnectionStates0,
696
SslOpts, Renegotiation, Cert),
592
698
{BinMsg, ConnectionStates1, Hashes1} =
593
699
encode_handshake(Hello, Version, ConnectionStates0, Hashes0),
594
700
Transport:send(Socket, BinMsg),
595
{next_state, hello, State#state{connection_states = ConnectionStates1,
596
tls_handshake_hashes = Hashes1}}.
598
%%--------------------------------------------------------------------
600
%% state_name(Event, From, State) -> {next_state, NextStateName, NextState} |
601
%% {next_state, NextStateName,
602
%% NextState, Timeout} |
603
%% {reply, Reply, NextStateName, NextState}|
604
%% {reply, Reply, NextStateName,
605
%% NextState, Timeout} |
606
%% {stop, Reason, NewState}|
607
%% {stop, Reason, Reply, NewState}
608
%% Description: There should be one instance of this function for each
609
%% possible state name. Whenever a gen_fsm receives an event sent using
610
%% gen_fsm:sync_send_event/2,3, the instance of this function with the same
611
%% name as the current state name StateName is called to handle the event.
612
%%--------------------------------------------------------------------
613
connection({application_data, Data}, _From,
614
State = #state{socket = Socket,
615
negotiated_version = Version,
616
transport_cb = Transport,
617
connection_states = ConnectionStates0}) ->
701
{Record, State} = next_record(State0#state{connection_states =
703
tls_handshake_hashes = Hashes1}),
704
next_state(hello, Record, State);
705
connection(#client_hello{} = Hello, #state{role = server} = State) ->
708
connection(timeout, State) ->
709
{next_state, connection, State, hibernate};
711
connection(Msg, State) ->
712
handle_unexpected_message(Msg, connection, State).
713
%%--------------------------------------------------------------------
714
-spec handle_event(term(), state_name(), #state{}) -> term().
715
%% As it is not currently used gen_fsm_state_return() makes
718
%% Description: Whenever a gen_fsm receives an event sent using
719
%% gen_fsm:send_all_state_event/2, this function is called to handle
720
%% the event. Not currently used!
721
%%--------------------------------------------------------------------
722
handle_event(_Event, StateName, State) ->
723
{next_state, StateName, State, get_timeout(State)}.
725
%%--------------------------------------------------------------------
726
-spec handle_sync_event(term(), from(), state_name(), #state{}) ->
727
gen_fsm_state_return() |
728
{reply, reply(), state_name(), #state{}} |
729
{reply, reply(), state_name(), #state{}, timeout()} |
730
{stop, reason(), reply(), #state{}}.
732
%% Description: Whenever a gen_fsm receives an event sent using
733
%% gen_fsm:sync_send_all_state_event/2,3, this function is called to handle
735
%%--------------------------------------------------------------------
736
handle_sync_event({application_data, Data0}, From, connection,
737
#state{socket = Socket,
738
negotiated_version = Version,
739
transport_cb = Transport,
740
connection_states = ConnectionStates0,
741
send_queue = SendQueue,
742
socket_options = SockOpts,
743
ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}}
618
745
%% We should look into having a worker process to do this to
619
746
%% parallize send and receive decoding and not block the receiver
620
747
%% if sending is overloading the socket.
621
{Msgs, ConnectionStates1} = encode_data(Data, Version, ConnectionStates0),
622
Result = Transport:send(Socket, Msgs),
624
connection, State#state{connection_states = ConnectionStates1}}.
626
%%--------------------------------------------------------------------
628
%% handle_event(Event, StateName, State) -> {next_state, NextStateName,
630
%% {next_state, NextStateName,
631
%% NextState, Timeout} |
632
%% {stop, Reason, NewState}
633
%% Description: Whenever a gen_fsm receives an event sent using
634
%% gen_fsm:send_all_state_event/2, this function is called to handle
636
%%--------------------------------------------------------------------
637
handle_event(#ssl_tls{type = ?HANDSHAKE, fragment = Data},
639
State = #state{key_algorithm = KeyAlg,
640
tls_handshake_buffer = Buf0,
641
negotiated_version = Version}) ->
643
fun({Packet, Raw}, {next_state, SName, AS=#state{tls_handshake_hashes=Hs0}}) ->
644
Hs1 = ssl_handshake:update_hashes(Hs0, Raw),
645
?MODULE:SName(Packet, AS#state{tls_handshake_hashes=Hs1});
646
(_, StopState) -> StopState
649
{Packets, Buf} = ssl_handshake:get_tls_handshake(Data,Buf0, KeyAlg,Version),
650
Start = {next_state, StateName, State#state{tls_handshake_buffer = Buf}},
651
lists:foldl(Handle, Start, Packets)
652
catch throw:#alert{} = Alert ->
653
handle_own_alert(Alert, Version, StateName, State),
654
{stop, normal, State}
657
handle_event(#ssl_tls{type = ?APPLICATION_DATA, fragment = Data},
658
StateName, State0) ->
659
case application_data(Data, State0) of
663
{next_state, StateName, State}
666
handle_event(#ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = <<1>>} =
669
State = #state{connection_states = ConnectionStates0}) ->
670
?DBG_TERM(_ChangeCipher),
672
ssl_record:activate_pending_connection_state(ConnectionStates0, read),
673
{next_state, StateName,
674
next_record(State#state{connection_states = ConnectionStates1})};
676
handle_event(#ssl_tls{type = ?ALERT, fragment = Data}, StateName, State) ->
677
Alerts = decode_alerts(Data),
679
[alert_event(A) || A <- Alerts],
680
{next_state, StateName, State};
682
handle_event(#alert{level = ?FATAL} = Alert, connection,
683
#state{from = From, user_application = {_Mon, Pid}, log_alert = Log,
684
host = Host, port = Port, session = Session,
685
role = Role, socket_options = Opts} = State) ->
686
invalidate_session(Role, Host, Port, Session),
687
log_alert(Log, connection, Alert),
688
alert_user(Opts#socket_options.active, Pid, From, Alert, Role),
689
{stop, normal, State};
690
handle_event(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert,
691
connection, #state{from = From,
693
user_application = {_Mon, Pid},
694
socket_options = Opts} = State) ->
695
alert_user(Opts#socket_options.active, Pid, From, Alert, Role),
696
{stop, normal, State};
698
handle_event(#alert{level = ?FATAL} = Alert, StateName,
699
#state{from = From, host = Host, port = Port, session = Session,
700
log_alert = Log, role = Role} = State) ->
701
invalidate_session(Role, Host, Port, Session),
702
log_alert(Log, StateName, Alert),
703
alert_user(From, Alert, Role),
704
{stop, normal, State};
705
handle_event(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert,
706
_, #state{from = From, role = Role} = State) ->
707
alert_user(From, Alert, Role),
708
{stop, normal, State};
709
handle_event(#alert{level = ?WARNING} = Alert, StateName,
710
#state{log_alert = Log} = State) ->
711
log_alert(Log, StateName, Alert),
712
%%TODO: Could be user_canceled or no_negotiation should the latter be
713
%% treated as fatal?!
714
{next_state, StateName, next_record(State)}.
716
%%--------------------------------------------------------------------
718
%% handle_sync_event(Event, From, StateName,
719
%% State) -> {next_state, NextStateName, NextState} |
720
%% {next_state, NextStateName, NextState,
722
%% {reply, Reply, NextStateName, NextState}|
723
%% {reply, Reply, NextStateName, NextState,
725
%% {stop, Reason, NewState} |
726
%% {stop, Reason, Reply, NewState}
727
%% Description: Whenever a gen_fsm receives an event sent using
728
%% gen_fsm:sync_send_all_state_event/2,3, this function is called to handle
730
%%--------------------------------------------------------------------
731
handle_sync_event(started, From, StateName, State) ->
732
{next_state, StateName, State#state{from = From}};
734
handle_sync_event(close, From, _StateName, State) ->
735
{stop, normal, ok, State#state{from = From}};
737
handle_sync_event({shutdown, How}, From, StateName,
738
#state{transport_cb = CbModule,
749
Data = encode_packet(Data0, SockOpts),
750
case encode_data(Data, Version, ConnectionStates0, RenegotiateAt) of
751
{Msgs, [], ConnectionStates} ->
752
Result = Transport:send(Socket, Msgs),
754
connection, State#state{connection_states = ConnectionStates},
756
{Msgs, RestData, ConnectionStates} ->
759
Transport:send(Socket, Msgs);
763
renegotiate(State#state{connection_states = ConnectionStates,
764
send_queue = queue:in_r({From, RestData}, SendQueue),
765
renegotiation = {true, internal}})
768
{reply, Error, connection, State, get_timeout(State)}
770
handle_sync_event({application_data, Data}, From, StateName,
771
#state{send_queue = Queue} = State) ->
772
%% In renegotiation priorities handshake, send data when handshake is finished
773
{next_state, StateName,
774
State#state{send_queue = queue:in({From, Data}, Queue)},
777
handle_sync_event(start, From, hello, State) ->
778
hello(start, State#state{from = From});
780
%% The two clauses below could happen if a server upgrades a socket in
781
%% active mode. Note that in this case we are lucky that
782
%% controlling_process has been evalueated before receiving handshake
783
%% messages from client. The server should put the socket in passive
784
%% mode before telling the client that it is willing to upgrade
785
%% and before calling ssl:ssl_accept/2. These clauses are
786
%% here to make sure it is the users problem and not owers if
787
%% they upgrade a active socket.
788
handle_sync_event(start, _, connection, State) ->
789
{reply, connected, connection, State, get_timeout(State)};
790
handle_sync_event(start, From, StateName, State) ->
791
{next_state, StateName, State#state{from = From}, get_timeout(State)};
793
handle_sync_event(close, _, StateName, State) ->
794
%% Run terminate before returning
795
%% so that the reuseaddr inet-option will work
797
(catch terminate(user_close, StateName, State)),
798
{stop, normal, ok, State#state{terminated = true}};
800
handle_sync_event({shutdown, How0}, _, StateName,
801
#state{transport_cb = Transport,
802
negotiated_version = Version,
803
connection_states = ConnectionStates,
739
804
socket = Socket} = State) ->
740
case CbModule:shutdown(Socket, How) of
806
How when How == write; How == both ->
807
Alert = ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
809
encode_alert(Alert, Version, ConnectionStates),
810
Transport:send(Socket, BinMsg);
815
case Transport:shutdown(Socket, How0) of
742
{reply, ok, StateName, State};
817
{reply, ok, StateName, State, get_timeout(State)};
744
{stop, normal, Error, State#state{from = From}}
819
{stop, normal, Error, State}
747
%% TODO: men vad g�r next_record om det �r t.ex. renegotiate? kanske
748
%% inte bra... t�l att t�nkas p�!
749
handle_sync_event({recv, N}, From, StateName,
750
State0 = #state{user_data_buffer = Buffer}) ->
751
State1 = State0#state{bytes_to_read = N, from = From},
754
State = next_record(State1),
755
{next_state, StateName, State};
757
case application_data(<<>>, State1) of
758
Stop = {stop, _, _} ->
761
{next_state, StateName, State}
822
handle_sync_event({recv, N}, From, connection = StateName, State0) ->
823
passive_receive(State0#state{bytes_to_read = N, from = From}, StateName);
825
%% Doing renegotiate wait with handling request until renegotiate is
826
%% finished. Will be handled by next_state_connection/2.
827
handle_sync_event({recv, N}, From, StateName, State) ->
828
{next_state, StateName,
829
State#state{bytes_to_read = N, from = From,
830
recv_during_renegotiation = true},
765
833
handle_sync_event({new_user, User}, _From, StateName,
766
834
State =#state{user_application = {OldMon, _}}) ->
767
835
NewMon = erlang:monitor(process, User),
768
836
erlang:demonitor(OldMon, [flush]),
769
{reply, ok, StateName, State#state{user_application = {NewMon,User}}};
837
{reply, ok, StateName, State#state{user_application = {NewMon,User}},
771
840
handle_sync_event({get_opts, OptTags}, _From, StateName,
772
841
#state{socket = Socket,
773
842
socket_options = SockOpts} = State) ->
774
843
OptsReply = get_socket_opts(Socket, OptTags, SockOpts, []),
775
{reply, OptsReply, StateName, State};
844
{reply, OptsReply, StateName, State, get_timeout(State)};
777
846
handle_sync_event(sockname, _From, StateName,
778
847
#state{socket = Socket} = State) ->
779
848
SockNameReply = inet:sockname(Socket),
780
{reply, SockNameReply, StateName, State};
849
{reply, SockNameReply, StateName, State, get_timeout(State)};
782
851
handle_sync_event(peername, _From, StateName,
783
852
#state{socket = Socket} = State) ->
784
853
PeerNameReply = inet:peername(Socket),
785
{reply, PeerNameReply, StateName, State};
854
{reply, PeerNameReply, StateName, State, get_timeout(State)};
787
856
handle_sync_event({set_opts, Opts0}, _From, StateName,
788
857
#state{socket_options = Opts1,
941
1022
%%--------------------------------------------------------------------
942
1023
%%% Internal functions
943
1024
%%--------------------------------------------------------------------
944
start_fsm(Role, Host, Port, Socket, Opts, User, {CbModule, _,_} = CbInfo,
1025
start_fsm(Role, Host, Port, Socket, Opts, User, {CbModule, _,_, _} = CbInfo,
946
case ssl_connection_sup:start_child([Role, Host, Port, Socket,
947
Opts, User, CbInfo]) of
949
CbModule:controlling_process(Socket, Pid),
950
send_event(Pid, socket_control),
951
case sync_send_all_state_event(Pid, started, Timeout) of
953
{ok, sslsocket(Pid)};
1028
{ok, Pid} = ssl_connection_sup:start_child([Role, Host, Port, Socket,
1029
Opts, User, CbInfo]),
1030
{ok, SslSocket} = socket_control(Socket, Pid, CbModule),
1031
ok = handshake(SslSocket, Timeout),
1034
error:{badmatch, {error, _} = Error} ->
961
1038
ssl_init(SslOpts, Role) ->
962
1039
{ok, CertDbRef, CacheRef, OwnCert} = init_certificates(SslOpts, Role),
964
1041
init_private_key(SslOpts#ssl_options.key, SslOpts#ssl_options.keyfile,
965
1042
SslOpts#ssl_options.password, Role),
966
?DBG_TERM(PrivateKey),
967
{ok, CertDbRef, CacheRef, OwnCert, PrivateKey}.
969
init_certificates(#ssl_options{cacertfile = CACertFile,
970
certfile = CertFile}, Role) ->
972
case ssl_manager:connection_init(CACertFile, Role) of
973
{ok, CertDbRef, CacheRef} ->
974
init_certificates(CertDbRef, CacheRef, CertFile, Role);
976
Report = io_lib:format("SSL: Error ~p ~n",[_Error]),
977
error_logger:error_report(Report),
981
init_certificates(CertDbRef, CacheRef, CertFile, client) ->
1043
DHParams = init_diffie_hellman(SslOpts#ssl_options.dh, SslOpts#ssl_options.dhfile, Role),
1044
{ok, CertDbRef, CacheRef, OwnCert, PrivateKey, DHParams}.
1047
init_certificates(#ssl_options{cacerts = CaCerts,
1048
cacertfile = CACertFile,
1049
certfile = CertFile,
1050
cert = Cert}, Role) ->
1051
{ok, CertDbRef, CacheRef} =
1053
Certs = case CaCerts of
1059
{ok, _, _} = ssl_manager:connection_init(Certs, Role)
1062
handle_file_error(?LINE, Error, Reason, CACertFile, ecacertfile,
1063
erlang:get_stacktrace())
1065
init_certificates(Cert, CertDbRef, CacheRef, CertFile, Role).
1067
init_certificates(undefined, CertDbRef, CacheRef, "", _) ->
1068
{ok, CertDbRef, CacheRef, undefined};
1070
init_certificates(undefined, CertDbRef, CacheRef, CertFile, client) ->
983
1072
[OwnCert] = ssl_certificate:file_to_certificats(CertFile),
984
1073
{ok, CertDbRef, CacheRef, OwnCert}
1074
catch _Error:_Reason ->
986
1075
{ok, CertDbRef, CacheRef, undefined}
989
init_certificates(CertDbRef, CacheRef, CertFile, server) ->
1078
init_certificates(undefined, CertDbRef, CacheRef, CertFile, server) ->
991
1080
[OwnCert] = ssl_certificate:file_to_certificats(CertFile),
992
1081
{ok, CertDbRef, CacheRef, OwnCert}
994
Report = io_lib:format("SSL: ~p: ~p:~p ~p~n",
995
[?LINE, _E,_R, erlang:get_stacktrace()]),
996
error_logger:error_report(Report),
1084
handle_file_error(?LINE, Error, Reason, CertFile, ecertfile,
1085
erlang:get_stacktrace())
1087
init_certificates(Cert, CertDbRef, CacheRef, _, _) ->
1088
{ok, CertDbRef, CacheRef, Cert}.
1000
init_private_key(undefined, "", _Password, client) ->
1090
init_private_key(undefined, "", _Password, _Client) ->
1002
1092
init_private_key(undefined, KeyFile, Password, _) ->
1004
{ok, List} = ssl_manager:cache_pem_file(KeyFile),
1005
[Der] = [Der || Der = {PKey, _ , _} <- List,
1006
PKey =:= rsa_private_key orelse PKey =:= dsa_private_key],
1007
{ok, Decoded} = public_key:decode_private_key(Der,Password),
1010
Report = io_lib:format("SSL: ~p: ~p:~p ~p~n",
1011
[?LINE, _E,_R, erlang:get_stacktrace()]),
1012
error_logger:error_report(Report),
1094
{ok, List} = ssl_manager:cache_pem_file(KeyFile),
1095
[PemEntry] = [PemEntry || PemEntry = {PKey, _ , _} <- List,
1096
PKey =:= 'RSAPrivateKey' orelse
1097
PKey =:= 'DSAPrivateKey'],
1098
public_key:pem_entry_decode(PemEntry, Password)
1101
handle_file_error(?LINE, Error, Reason, KeyFile, ekeyfile,
1102
erlang:get_stacktrace())
1015
init_private_key(PrivateKey, _, _,_) ->
1018
send_event(FsmPid, Event) ->
1019
gen_fsm:send_event(FsmPid, Event).
1021
sync_send_event(FsmPid, Event, Timeout) ->
1022
try gen_fsm:sync_send_event(FsmPid, Event, Timeout) of
1105
init_private_key({rsa, PrivateKey}, _, _,_) ->
1106
public_key:der_decode('RSAPrivateKey', PrivateKey);
1107
init_private_key({dsa, PrivateKey},_,_,_) ->
1108
public_key:der_decode('DSAPrivateKey', PrivateKey).
1110
-spec(handle_file_error(_,_,_,_,_,_) -> no_return()).
1111
handle_file_error(Line, Error, {badmatch, Reason}, File, Throw, Stack) ->
1112
file_error(Line, Error, Reason, File, Throw, Stack);
1113
handle_file_error(Line, Error, Reason, File, Throw, Stack) ->
1114
file_error(Line, Error, Reason, File, Throw, Stack).
1116
-spec(file_error(_,_,_,_,_,_) -> no_return()).
1117
file_error(Line, Error, Reason, File, Throw, Stack) ->
1118
Report = io_lib:format("SSL: ~p: ~p:~p ~s~n ~p~n",
1119
[Line, Error, Reason, File, Stack]),
1120
error_logger:error_report(Report),
1123
init_diffie_hellman(Params, _,_) when is_binary(Params)->
1124
public_key:der_decode('DHParameter', Params);
1125
init_diffie_hellman(_,_, client) ->
1127
init_diffie_hellman(_,undefined, _) ->
1128
?DEFAULT_DIFFIE_HELLMAN_PARAMS;
1129
init_diffie_hellman(_, DHParamFile, server) ->
1131
{ok, List} = ssl_manager:cache_pem_file(DHParamFile),
1132
case [Entry || Entry = {'DHParameter', _ , _} <- List] of
1134
public_key:pem_entry_decode(Entry);
1136
?DEFAULT_DIFFIE_HELLMAN_PARAMS
1028
exit:{timeout, _} ->
1140
handle_file_error(?LINE, Error, Reason,
1141
DHParamFile, edhfile, erlang:get_stacktrace())
1036
send_all_state_event(FsmPid, Event) ->
1037
gen_fsm:send_all_state_event(FsmPid, Event).
1039
1144
sync_send_all_state_event(FsmPid, Event) ->
1040
sync_send_all_state_event(FsmPid, Event, ?DEFAULT_TIMEOUT
1145
sync_send_all_state_event(FsmPid, Event, infinity).
1043
1147
sync_send_all_state_event(FsmPid, Event, Timeout) ->
1044
1148
try gen_fsm:sync_send_all_state_event(FsmPid, Event, Timeout)
1076
1189
connection_states = ConnectionStates0,
1077
1190
transport_cb = Transport,
1078
1191
negotiated_version = Version,
1080
1192
socket = Socket,
1081
key_algorithm = KeyAlg,
1082
1193
private_key = PrivateKey,
1083
session = #session{master_secret = MasterSecret},
1194
session = #session{master_secret = MasterSecret,
1195
own_certificate = OwnCert},
1084
1196
tls_handshake_hashes = Hashes0} = State) ->
1085
1198
case ssl_handshake:client_certificate_verify(OwnCert, MasterSecret,
1087
PrivateKey, Hashes0) of
1088
ignore -> %% No key or cert or fixed_diffie_hellman
1091
SigAlg = ssl_handshake:sig_alg(KeyAlg),
1199
Version, PrivateKey, Hashes0) of
1200
#certificate_verify{} = Verified ->
1092
1201
{BinVerified, ConnectionStates1, Hashes1} =
1093
encode_handshake(Verified, SigAlg, Version,
1202
encode_handshake(Verified, Version,
1094
1203
ConnectionStates0, Hashes0),
1095
1204
Transport:send(Socket, BinVerified),
1096
1205
State#state{connection_states = ConnectionStates1,
1097
tls_handshake_hashes = Hashes1}
1206
tls_handshake_hashes = Hashes1};
1210
handle_own_alert(Alert, Version, certify, State)
1099
1213
verify_client_cert(#state{client_certificate_requested = false} = State) ->
1102
1216
do_server_hello(Type, #state{negotiated_version = Version,
1104
connection_states = ConnectionStates0}
1217
session = #session{session_id = SessId} = Session,
1218
connection_states = ConnectionStates0,
1219
renegotiation = {Renegotiation, _}}
1105
1220
= State0) when is_atom(Type) ->
1107
ssl_handshake:server_hello(Session#session.session_id, Version,
1109
State = server_hello(ServerHello, State0),
1223
ssl_handshake:server_hello(SessId, Version,
1224
ConnectionStates0, Renegotiation),
1225
State1 = server_hello(ServerHello, State0),
1113
do_server_hello(ServerHello, State);
1229
new_server_hello(ServerHello, State1);
1231
ConnectionStates1 = State1#state.connection_states,
1115
1232
case ssl_handshake:master_secret(Version, Session,
1116
ConnectionStates0, server) of
1117
{_, ConnectionStates1} ->
1118
{ConnectionStates, Hashes} =
1119
finished(State#state{connection_states =
1120
ConnectionStates1}),
1121
{next_state, abbreviated,
1122
next_record(State#state{connection_states =
1124
tls_handshake_hashes = Hashes})};
1233
ConnectionStates1, server) of
1234
{_, ConnectionStates2} ->
1235
State2 = State1#state{connection_states=ConnectionStates2,
1237
{ConnectionStates, Hashes} =
1238
finalize_handshake(State2, abbreviated),
1239
State3 = State2#state{connection_states =
1241
tls_handshake_hashes = Hashes},
1242
{Record, State} = next_record(State3),
1243
next_state(abbreviated, Record, State);
1125
1244
#alert{} = Alert ->
1126
handle_own_alert(Alert, Version, hello, State),
1127
{stop, normal, State}
1245
handle_own_alert(Alert, Version, hello, State1),
1246
{stop, normal, State1}
1131
do_server_hello(#server_hello{cipher_suite = CipherSuite,
1250
new_server_hello(#server_hello{cipher_suite = CipherSuite,
1132
1251
compression_method = Compression,
1133
1252
session_id = SessionId},
1134
1253
#state{session = Session0,
1135
1254
negotiated_version = Version} = State0) ->
1136
1255
try server_certify_and_key_exchange(State0) of
1137
1256
#state{} = State1 ->
1138
State = server_hello_done(State1),
1257
State2 = server_hello_done(State1),
1140
1259
Session0#session{session_id = SessionId,
1141
1260
cipher_suite = CipherSuite,
1142
1261
compression_method = Compression},
1143
{next_state, certify, State#state{session = Session}}
1262
{Record, State} = next_record(State2#state{session = Session}),
1263
next_state(certify, Record, State)
1145
1265
#alert{} = Alert ->
1146
1266
handle_own_alert(Alert, Version, hello, State0),
1147
1267
{stop, normal, State0}
1270
handle_new_session(NewId, CipherSuite, Compression, #state{session = Session0} = State0) ->
1271
Session = Session0#session{session_id = NewId,
1272
cipher_suite = CipherSuite,
1273
compression_method = Compression},
1274
{Record, State} = next_record(State0#state{session = Session}),
1275
next_state(certify, Record, State).
1277
handle_resumed_session(SessId, #state{connection_states = ConnectionStates0,
1278
negotiated_version = Version,
1279
host = Host, port = Port,
1280
session_cache = Cache,
1281
session_cache_cb = CacheCb} = State0) ->
1282
Session = CacheCb:lookup(Cache, {{Host, Port}, SessId}),
1283
case ssl_handshake:master_secret(Version, Session,
1284
ConnectionStates0, client) of
1285
{_, ConnectionStates1} ->
1287
next_record(State0#state{
1288
connection_states = ConnectionStates1,
1289
session = Session}),
1290
next_state(abbreviated, Record, State);
1292
handle_own_alert(Alert, Version, hello, State0),
1293
{stop, normal, State0}
1150
1297
client_certify_and_key_exchange(#state{negotiated_version = Version} =
1152
1299
try do_client_certify_and_key_exchange(State0) of
1153
1300
State1 = #state{} ->
1154
{ConnectionStates, Hashes} = finalize_client_handshake(State1),
1155
State = State1#state{connection_states = ConnectionStates,
1301
{ConnectionStates, Hashes} = finalize_handshake(State1, certify),
1302
State2 = State1#state{connection_states = ConnectionStates,
1156
1303
%% Reinitialize
1157
1304
client_certificate_requested = false,
1158
1305
tls_handshake_hashes = Hashes},
1159
{next_state, cipher, next_record(State)}
1306
{Record, State} = next_record(State2),
1307
next_state(cipher, Record, State)
1162
1309
#alert{} = Alert ->
1163
handle_own_alert(Alert, Version, certify_foo, State0),
1310
handle_own_alert(Alert, Version, client_certify_and_key_exchange, State0),
1164
1311
{stop, normal, State0}
1345
finalize_client_handshake(#state{connection_states = ConnectionStates0}
1348
cipher_protocol(State#state{connection_states =
1349
ConnectionStates0}),
1351
ssl_record:activate_pending_connection_state(ConnectionStates1,
1465
finalize_handshake(State, StateName) ->
1466
ConnectionStates0 = cipher_protocol(State),
1468
ssl_record:activate_pending_connection_state(ConnectionStates0,
1353
finished(State#state{connection_states = ConnectionStates2}).
1470
finished(State#state{connection_states = ConnectionStates}, StateName).
1356
finalize_server_handshake(State) ->
1357
ConnectionStates0 = cipher_protocol(State),
1359
ssl_record:activate_pending_connection_state(ConnectionStates0, write),
1360
finished(State#state{connection_states = ConnectionStates}).
1362
cipher_protocol(#state{connection_states = ConnectionStates,
1472
cipher_protocol(#state{connection_states = ConnectionStates0,
1363
1473
socket = Socket,
1364
1474
negotiated_version = Version,
1365
1475
transport_cb = Transport}) ->
1366
{BinChangeCipher, NewConnectionStates} =
1367
encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates),
1476
{BinChangeCipher, ConnectionStates} =
1477
encode_change_cipher(#change_cipher_spec{},
1478
Version, ConnectionStates0),
1368
1479
Transport:send(Socket, BinChangeCipher),
1369
NewConnectionStates.
1371
1482
finished(#state{role = Role, socket = Socket, negotiated_version = Version,
1372
1483
transport_cb = Transport,
1373
1484
session = Session,
1374
connection_states = ConnectionStates,
1375
tls_handshake_hashes = Hashes}) ->
1485
connection_states = ConnectionStates0,
1486
tls_handshake_hashes = Hashes0}, StateName) ->
1376
1487
MasterSecret = Session#session.master_secret,
1377
Finished = ssl_handshake:finished(Version, Role, MasterSecret, Hashes),
1378
{BinFinished, NewConnectionStates, NewHashes} =
1379
encode_handshake(Finished, Version, ConnectionStates, Hashes),
1488
Finished = ssl_handshake:finished(Version, Role, MasterSecret, Hashes0),
1489
ConnectionStates1 = save_verify_data(Role, Finished, ConnectionStates0, StateName),
1490
{BinFinished, ConnectionStates, Hashes} =
1491
encode_handshake(Finished, Version, ConnectionStates1, Hashes0),
1380
1492
Transport:send(Socket, BinFinished),
1381
{NewConnectionStates, NewHashes}.
1383
handle_server_key(_KeyExchangeMsg, State) ->
1385
handle_clinet_key(_KeyExchangeMsg, State) ->
1493
{ConnectionStates, Hashes}.
1495
save_verify_data(client, #finished{verify_data = Data}, ConnectionStates, certify) ->
1496
ssl_record:set_client_verify_data(current_write, Data, ConnectionStates);
1497
save_verify_data(server, #finished{verify_data = Data}, ConnectionStates, cipher) ->
1498
ssl_record:set_server_verify_data(current_both, Data, ConnectionStates);
1499
save_verify_data(client, #finished{verify_data = Data}, ConnectionStates, abbreviated) ->
1500
ssl_record:set_client_verify_data(current_both, Data, ConnectionStates);
1501
save_verify_data(server, #finished{verify_data = Data}, ConnectionStates, abbreviated) ->
1502
ssl_record:set_server_verify_data(current_write, Data, ConnectionStates).
1504
handle_server_key(#server_key_exchange{params =
1505
#server_dh_params{dh_p = P,
1507
dh_y = ServerPublicDhKey},
1508
signed_params = <<>>},
1509
#state{key_algorithm = dh_anon} = State) ->
1510
dh_master_secret(P, G, ServerPublicDhKey, undefined, State);
1513
#server_key_exchange{params =
1514
#server_dh_params{dh_p = P,
1516
dh_y = ServerPublicDhKey},
1517
signed_params = Signed},
1518
#state{public_key_info = PubKeyInfo,
1519
key_algorithm = KeyAlgo,
1520
connection_states = ConnectionStates} = State) ->
1524
YLen = size(ServerPublicDhKey),
1527
ssl_record:pending_connection_state(ConnectionStates, read),
1528
SecParams = ConnectionState#connection_state.security_parameters,
1529
#security_parameters{client_random = ClientRandom,
1530
server_random = ServerRandom} = SecParams,
1531
Hash = ssl_handshake:server_key_exchange_hash(KeyAlgo,
1532
<<ClientRandom/binary,
1533
ServerRandom/binary,
1534
?UINT16(PLen), P/binary,
1535
?UINT16(GLen), G/binary,
1537
ServerPublicDhKey/binary>>),
1539
case verify_dh_params(Signed, Hash, PubKeyInfo) of
1541
dh_master_secret(P, G, ServerPublicDhKey, undefined, State);
1543
?ALERT_REC(?FATAL, ?DECRYPT_ERROR)
1546
verify_dh_params(Signed, Hashes, {?rsaEncryption, PubKey, _PubKeyParams}) ->
1547
case public_key:decrypt_public(Signed, PubKey,
1548
[{rsa_pad, rsa_pkcs1_padding}]) of
1554
verify_dh_params(Signed, Hash, {?'id-dsa', PublicKey, PublicKeyParams}) ->
1555
public_key:verify(Hash, none, Signed, {PublicKey, PublicKeyParams}).
1557
dh_master_secret(Prime, Base, PublicDhKey, undefined, State) ->
1558
PMpint = mpint_binary(Prime),
1559
GMpint = mpint_binary(Base),
1560
Keys = {_, PrivateDhKey} =
1561
crypto:dh_generate_key([PMpint,GMpint]),
1562
dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys});
1564
dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey,
1565
#state{session = Session,
1566
negotiated_version = Version, role = Role,
1567
connection_states = ConnectionStates0} = State) ->
1569
crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey,
1571
case ssl_handshake:master_secret(Version, PremasterSecret,
1572
ConnectionStates0, Role) of
1573
{MasterSecret, ConnectionStates} ->
1576
Session#session{master_secret = MasterSecret},
1577
connection_states = ConnectionStates};
1582
cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} = State) ->
1583
ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0),
1584
next_state_connection(cipher, ack_connection(State#state{session = Session,
1585
connection_states = ConnectionStates}));
1587
cipher_role(server, Data, Session, #state{connection_states = ConnectionStates0} = State) ->
1588
ConnectionStates1 = ssl_record:set_client_verify_data(current_read, Data, ConnectionStates0),
1589
{ConnectionStates, Hashes} =
1590
finalize_handshake(State#state{connection_states = ConnectionStates1,
1591
session = Session}, cipher),
1592
next_state_connection(cipher, ack_connection(State#state{connection_states =
1595
tls_handshake_hashes =
1388
1597
encode_alert(#alert{} = Alert, Version, ConnectionStates) ->
1390
1598
ssl_record:encode_alert_record(Alert, Version, ConnectionStates).
1392
1600
encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) ->
1393
?DBG_TERM(#change_cipher_spec{}),
1394
1601
ssl_record:encode_change_cipher_spec(Version, ConnectionStates).
1396
encode_handshake(HandshakeRec, Version, ConnectionStates, Hashes) ->
1397
encode_handshake(HandshakeRec, undefined, Version,
1398
ConnectionStates, Hashes).
1400
encode_handshake(HandshakeRec, SigAlg, Version, ConnectionStates0, Hashes0) ->
1401
?DBG_TERM(HandshakeRec),
1402
Frag = ssl_handshake:encode_handshake(HandshakeRec, Version, SigAlg),
1603
encode_handshake(HandshakeRec, Version, ConnectionStates0, Hashes0) ->
1604
Frag = ssl_handshake:encode_handshake(HandshakeRec, Version),
1403
1605
Hashes1 = ssl_handshake:update_hashes(Hashes0, Frag),
1404
1606
{E, ConnectionStates1} =
1405
1607
ssl_record:encode_handshake(Frag, Version, ConnectionStates0),
1406
1608
{E, ConnectionStates1, Hashes1}.
1408
encode_data(Data, Version, ConnectionStates) ->
1409
ssl_record:encode_data(Data, Version, ConnectionStates).
1610
encode_packet(Data, #socket_options{packet=Packet}) ->
1612
1 -> encode_size_packet(Data, 8, (1 bsl 8) - 1);
1613
2 -> encode_size_packet(Data, 16, (1 bsl 16) - 1);
1614
4 -> encode_size_packet(Data, 32, (1 bsl 32) - 1);
1618
encode_size_packet(Bin, Size, Max) ->
1619
Len = byte_size(Bin),
1621
true -> throw({error, {badarg, {packet_to_large, Len, Max}}});
1622
false -> <<Len:Size, Bin/binary>>
1625
encode_data(Data, Version, ConnectionStates, RenegotiateAt) ->
1626
ssl_record:encode_data(Data, Version, ConnectionStates, RenegotiateAt).
1411
1628
decode_alerts(Bin) ->
1412
1629
decode_alerts(Bin, []).
1463
1696
{ok, Data, Rest};
1465
1698
%% Passive Mode not enough data
1468
1701
get_data(#socket_options{packet=Type, packet_size=Size}, _, Buffer) ->
1469
1702
PacketOpts = [{packet_size, Size}],
1470
case erlang:decode_packet(Type, Buffer, PacketOpts) of
1703
case decode_packet(Type, Buffer, PacketOpts) of
1477
deliver_app_data(SO = #socket_options{active=once}, Data, Pid, From) ->
1478
send_or_reply(once, Pid, From, format_reply(SO, Data)),
1479
SO#socket_options{active=false};
1480
deliver_app_data(SO= #socket_options{active=Active}, Data, Pid, From) ->
1481
send_or_reply(Active, Pid, From, format_reply(SO, Data)),
1484
format_reply(#socket_options{active=false, mode=Mode, header=Header}, Data) ->
1485
{ok, format_reply(Mode, Header, Data)};
1486
format_reply(#socket_options{active=_, mode=Mode, header=Header}, Data) ->
1487
{ssl, sslsocket(), format_reply(Mode, Header, Data)}.
1489
deliver_packet_error(SO= #socket_options{active=Active}, Data, Pid, From) ->
1710
decode_packet({http, headers}, Buffer, PacketOpts) ->
1711
decode_packet(httph, Buffer, PacketOpts);
1712
decode_packet({http_bin, headers}, Buffer, PacketOpts) ->
1713
decode_packet(httph_bin, Buffer, PacketOpts);
1714
decode_packet(Type, Buffer, PacketOpts) ->
1715
erlang:decode_packet(Type, Buffer, PacketOpts).
1717
%% Just like with gen_tcp sockets, an ssl socket that has been configured with
1718
%% {packet, http} (or {packet, http_bin}) will automatically switch to expect
1719
%% HTTP headers after it sees a HTTP Request or HTTP Response line. We
1720
%% represent the current state as follows:
1721
%% #socket_options.packet =:= http: Expect a HTTP Request/Response line
1722
%% #socket_options.packet =:= {http, headers}: Expect HTTP Headers
1723
%% Note that if the user has explicitly configured the socket to expect
1724
%% HTTP headers using the {packet, httph} option, we don't do any automatic
1725
%% switching of states.
1726
deliver_app_data(SOpts = #socket_options{active=Active, packet=Type},
1728
send_or_reply(Active, Pid, From, format_reply(SOpts, Data)),
1730
{P, _, _, _} when ((P =:= http_request) or (P =:= http_response)),
1731
((Type =:= http) or (Type =:= http_bin)) ->
1732
SOpts#socket_options{packet={Type, headers}};
1733
http_eoh when tuple_size(Type) =:= 2 ->
1734
% End of headers - expect another Request/Response line
1735
{Type1, headers} = Type,
1736
SOpts#socket_options{packet=Type1};
1742
SO#socket_options{active=false};
1747
format_reply(#socket_options{active = false, mode = Mode, packet = Packet,
1748
header = Header}, Data) ->
1749
{ok, format_reply(Mode, Packet, Header, Data)};
1750
format_reply(#socket_options{active = _, mode = Mode, packet = Packet,
1751
header = Header}, Data) ->
1752
{ssl, sslsocket(), format_reply(Mode, Packet, Header, Data)}.
1754
deliver_packet_error(SO= #socket_options{active = Active}, Data, Pid, From) ->
1490
1755
send_or_reply(Active, Pid, From, format_packet_error(SO, Data)).
1492
format_packet_error(#socket_options{active=false, mode=Mode}, Data) ->
1493
{error, {invalid_packet, format_reply(Mode, raw, Data)}};
1494
format_packet_error(#socket_options{active=_, mode=Mode}, Data) ->
1495
{ssl_error, sslsocket(), {invalid_packet, format_reply(Mode, raw, Data)}}.
1497
format_reply(list, _, Data) -> binary_to_list(Data);
1498
format_reply(binary, 0, Data) -> Data;
1499
format_reply(binary, raw, Data) -> Data;
1500
format_reply(binary, N, Data) -> % Header mode
1501
<<Header:N/binary, Rest/binary>> = Data,
1502
[binary_to_list(Header), Rest].
1505
send_or_reply(false, _Pid, undefined, _Data) ->
1506
Report = io_lib:format("SSL(debug): Unexpected Data ~p ~n",[_Data]),
1507
error_logger:error_report(Report),
1508
erlang:error({badarg, _Pid, undefined, _Data}),
1510
send_or_reply(false, _Pid, From, Data) ->
1757
format_packet_error(#socket_options{active = false, mode = Mode}, Data) ->
1758
{error, {invalid_packet, format_reply(Mode, raw, 0, Data)}};
1759
format_packet_error(#socket_options{active = _, mode = Mode}, Data) ->
1760
{ssl_error, sslsocket(), {invalid_packet, format_reply(Mode, raw, 0, Data)}}.
1762
format_reply(binary, _, N, Data) when N > 0 -> % Header mode
1764
format_reply(binary, _, _, Data) ->
1766
format_reply(list, Packet, _, Data)
1767
when Packet == http; Packet == {http, headers}; Packet == http_bin; Packet == {http_bin, headers} ->
1769
format_reply(list, _,_, Data) ->
1770
binary_to_list(Data).
1776
header(0, Binary) ->
1778
header(N, Binary) ->
1779
<<?BYTE(ByteN), NewBinary/binary>> = Binary,
1780
[ByteN | header(N-1, NewBinary)].
1782
send_or_reply(false, _Pid, From, Data) when From =/= undefined ->
1511
1783
gen_fsm:reply(From, Data);
1512
1784
send_or_reply(_, Pid, _From, Data) ->
1513
1785
send_user(Pid, Data).
1520
1792
send_user(Pid, Msg) ->
1523
%% %% This is the code for {packet,ssl} removed because it was slower
1524
%% %% than handling it in erlang.
1525
%% next_record(#state{socket = Socket,
1526
%% tls_buffer = [Msg|Rest],
1527
%% connection_states = ConnectionStates0} = State) ->
1531
%% inet:setopts(Socket, [{active,once}]),
1537
%% {Plain, ConnectionStates} =
1538
%% ssl_record:decode_cipher_text(Msg, ConnectionStates0),
1539
%% gen_fsm:send_all_state_event(self(), Plain),
1540
%% State#state{tls_buffer=Buffer, connection_states = ConnectionStates};
1541
%% {ssl_close, Msg} ->
1543
%% State#state{tls_buffer=Buffer}
1545
%% next_record(#state{socket = Socket, tls_buffer = undefined} = State) ->
1546
%% inet:setopts(Socket, [{active,once}]),
1547
%% State#state{tls_buffer=continue};
1548
%% next_record(State) ->
1549
%% State#state{tls_buffer=continue}.
1551
next_record(#state{tls_cipher_texts = [], socket = Socket} = State) ->
1795
handle_tls_handshake(Handle, StateName, #state{tls_packets = [Packet]} = State) ->
1796
FsmReturn = {next_state, StateName, State#state{tls_packets = []}},
1797
Handle(Packet, FsmReturn);
1799
handle_tls_handshake(Handle, StateName, #state{tls_packets = [Packet | Packets]} = State0) ->
1800
FsmReturn = {next_state, StateName, State0#state{tls_packets = Packets}},
1801
case Handle(Packet, FsmReturn) of
1802
{next_state, NextStateName, State, _Timeout} ->
1803
handle_tls_handshake(Handle, NextStateName, State);
1804
{stop, _,_} = Stop ->
1808
next_state(_, #alert{} = Alert, #state{negotiated_version = Version} = State) ->
1809
handle_own_alert(Alert, Version, decipher_error, State),
1810
{stop, normal, State};
1812
next_state(Next, no_record, State) ->
1813
{next_state, Next, State, get_timeout(State)};
1815
next_state(Next, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, State) ->
1816
Alerts = decode_alerts(EncAlerts),
1817
handle_alerts(Alerts, {next_state, Next, State, get_timeout(State)});
1819
next_state(StateName, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
1820
State0 = #state{tls_handshake_buffer = Buf0, negotiated_version = Version}) ->
1822
fun({#hello_request{} = Packet, _}, {next_state, connection = SName, State}) ->
1823
%% This message should not be included in handshake
1824
%% message hashes. Starts new handshake (renegotiation)
1825
Hs0 = ssl_handshake:init_hashes(),
1826
?MODULE:SName(Packet, State#state{tls_handshake_hashes=Hs0,
1827
renegotiation = {true, peer}});
1828
({#hello_request{} = Packet, _}, {next_state, SName, State}) ->
1829
%% This message should not be included in handshake
1830
%% message hashes. Already in negotiation so it will be ignored!
1831
?MODULE:SName(Packet, State);
1832
({#client_hello{} = Packet, Raw}, {next_state, connection = SName, State}) ->
1833
Hs0 = ssl_handshake:init_hashes(),
1834
Hs1 = ssl_handshake:update_hashes(Hs0, Raw),
1835
?MODULE:SName(Packet, State#state{tls_handshake_hashes=Hs1,
1836
renegotiation = {true, peer}});
1837
({Packet, Raw}, {next_state, SName, State = #state{tls_handshake_hashes=Hs0}}) ->
1838
Hs1 = ssl_handshake:update_hashes(Hs0, Raw),
1839
?MODULE:SName(Packet, State#state{tls_handshake_hashes=Hs1});
1840
(_, StopState) -> StopState
1843
{Packets, Buf} = ssl_handshake:get_tls_handshake(Data,Buf0),
1844
State = State0#state{tls_packets = Packets, tls_handshake_buffer = Buf},
1845
handle_tls_handshake(Handle, StateName, State)
1846
catch throw:#alert{} = Alert ->
1847
handle_own_alert(Alert, Version, StateName, State0),
1848
{stop, normal, State0}
1851
next_state(StateName, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, State0) ->
1852
case application_data(Data, State0) of
1853
Stop = {stop,_,_} ->
1856
next_state(StateName, Record, State)
1858
next_state(StateName, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = <<1>>} =
1860
#state{connection_states = ConnectionStates0} = State0) ->
1862
ssl_record:activate_pending_connection_state(ConnectionStates0, read),
1863
{Record, State} = next_record(State0#state{connection_states = ConnectionStates1}),
1864
next_state(StateName, Record, State);
1865
next_state(StateName, #ssl_tls{type = _Unknown}, State0) ->
1866
%% Ignore unknown type
1867
{Record, State} = next_record(State0),
1868
next_state(StateName, Record, State).
1870
next_tls_record(Data, #state{tls_record_buffer = Buf0,
1871
tls_cipher_texts = CT0} = State0) ->
1872
case ssl_record:get_tls_records(Data, Buf0) of
1874
CT1 = CT0 ++ Records,
1875
next_record(State0#state{tls_record_buffer = Buf1,
1876
tls_cipher_texts = CT1});
1881
next_record(#state{tls_packets = [], tls_cipher_texts = [], socket = Socket} = State) ->
1552
1882
inet:setopts(Socket, [{active,once}]),
1554
next_record(#state{tls_cipher_texts = [CT | Rest],
1884
next_record(#state{tls_packets = [], tls_cipher_texts = [CT | Rest],
1555
1885
connection_states = ConnStates0} = State) ->
1556
{Plain, ConnStates} = ssl_record:decode_cipher_text(CT, ConnStates0),
1557
gen_fsm:send_all_state_event(self(), Plain),
1558
State#state{tls_cipher_texts = Rest, connection_states = ConnStates}.
1886
case ssl_record:decode_cipher_text(CT, ConnStates0) of
1887
{Plain, ConnStates} ->
1888
{Plain, State#state{tls_cipher_texts = Rest, connection_states = ConnStates}};
1892
next_record(State) ->
1560
1895
next_record_if_active(State =
1561
1896
#state{socket_options =
1562
1897
#socket_options{active = false}}) ->
1564
1900
next_record_if_active(State) ->
1565
1901
next_record(State).
1903
next_state_connection(StateName, #state{send_queue = Queue0,
1904
negotiated_version = Version,
1906
transport_cb = Transport,
1907
connection_states = ConnectionStates0,
1908
ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}
1910
%% Send queued up data
1911
case queue:out(Queue0) of
1912
{{value, {From, Data}}, Queue} ->
1913
case encode_data(Data, Version, ConnectionStates0, RenegotiateAt) of
1914
{Msgs, [], ConnectionStates} ->
1915
Result = Transport:send(Socket, Msgs),
1916
gen_fsm:reply(From, Result),
1917
next_state_connection(StateName,
1918
State#state{connection_states = ConnectionStates,
1919
send_queue = Queue});
1920
%% This is unlikely to happen. User configuration of the
1921
%% undocumented test option renegotiation_at can make it more likely.
1922
{Msgs, RestData, ConnectionStates} ->
1925
Transport:send(Socket, Msgs);
1929
renegotiate(State#state{connection_states = ConnectionStates,
1930
send_queue = queue:in_r({From, RestData}, Queue),
1931
renegotiation = {true, internal}})
1934
next_state_is_connection(State)
1937
%% In next_state_is_connection/1: clear tls_handshake_hashes,
1938
%% premaster_secret and public_key_info (only needed during handshake)
1939
%% to reduce memory foot print of a connection.
1940
next_state_is_connection(State =
1941
#state{recv_during_renegotiation = true, socket_options =
1942
#socket_options{active = false}}) ->
1943
passive_receive(State#state{recv_during_renegotiation = false,
1944
premaster_secret = undefined,
1945
public_key_info = undefined,
1946
tls_handshake_hashes = {<<>>, <<>>}}, connection);
1948
next_state_is_connection(State0) ->
1949
{Record, State} = next_record_if_active(State0),
1950
next_state(connection, Record, State#state{premaster_secret = undefined,
1951
public_key_info = undefined,
1952
tls_handshake_hashes = {<<>>, <<>>}}).
1567
1954
register_session(_, _, _, #session{is_resumable = true} = Session) ->
1568
1955
Session; %% Already registered
1569
1956
register_session(client, Host, Port, Session0) ->
1680
2127
{ssl_error, sslsocket(), ReasonCode})
1683
log_alert(true, StateName, Alert) ->
2130
log_alert(true, Info, Alert) ->
1684
2131
Txt = ssl_alert:alert_txt(Alert),
1685
error_logger:format("SSL: ~p: ~s\n", [StateName, Txt]);
2132
error_logger:format("SSL: ~p: ~s\n", [Info, Txt]);
1686
2133
log_alert(false, _, _) ->
1689
handle_own_alert(Alert, Version, StateName,
2136
handle_own_alert(Alert, Version, Info,
1690
2137
#state{transport_cb = Transport,
1691
2138
socket = Socket,
1694
2141
connection_states = ConnectionStates,
1695
2142
log_alert = Log}) ->
2143
try %% Try to tell the other side
1697
2145
encode_alert(Alert, Version, ConnectionStates),
1698
Transport:send(Socket, BinMsg),
1699
log_alert(Log, StateName, Alert),
1700
alert_user(User, Alert, Role).
1702
make_premaster_secret({MajVer, MinVer}) ->
2146
linux_workaround_transport_delivery_problems(Alert, Socket),
2147
Transport:send(Socket, BinMsg)
2148
catch _:_ -> %% Can crash if we are in a uninitialized state
2151
try %% Try to tell the local user
2152
log_alert(Log, Info, Alert),
2153
alert_user(User, Alert, Role)
2158
handle_unexpected_message(Msg, Info, #state{negotiated_version = Version} = State) ->
2159
Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE),
2160
handle_own_alert(Alert, Version, {Info, Msg}, State),
2161
{stop, normal, State}.
2163
make_premaster_secret({MajVer, MinVer}, rsa) ->
1703
2164
Rand = crypto:rand_bytes(?NUM_OF_PREMASTERSECRET_BYTES-2),
1704
<<?BYTE(MajVer), ?BYTE(MinVer), Rand/binary>>.
2165
<<?BYTE(MajVer), ?BYTE(MinVer), Rand/binary>>;
2166
make_premaster_secret(_, _) ->
2169
mpint_binary(Binary) ->
2170
Size = byte_size(Binary),
2171
<<?UINT32(Size), Binary/binary>>.
2174
ack_connection(#state{renegotiation = {true, Initiater}} = State)
2175
when Initiater == internal;
2176
Initiater == peer ->
2177
State#state{renegotiation = undefined};
2178
ack_connection(#state{renegotiation = {true, From}} = State) ->
2179
gen_fsm:reply(From, ok),
2180
State#state{renegotiation = undefined};
2181
ack_connection(#state{renegotiation = {false, first},
2182
from = From} = State) when From =/= undefined ->
2183
gen_fsm:reply(From, connected),
2184
State#state{renegotiation = undefined};
2185
ack_connection(State) ->
2188
renegotiate(#state{role = client} = State) ->
2189
%% Handle same way as if server requested
2190
%% the renegotiation
2191
Hs0 = ssl_handshake:init_hashes(),
2192
connection(#hello_request{}, State#state{tls_handshake_hashes = Hs0});
2193
renegotiate(#state{role = server,
2195
transport_cb = Transport,
2196
negotiated_version = Version,
2197
connection_states = ConnectionStates0} = State0) ->
2198
HelloRequest = ssl_handshake:hello_request(),
2199
Frag = ssl_handshake:encode_handshake(HelloRequest, Version),
2200
Hs0 = ssl_handshake:init_hashes(),
2201
{BinMsg, ConnectionStates} =
2202
ssl_record:encode_handshake(Frag, Version, ConnectionStates0),
2203
Transport:send(Socket, BinMsg),
2204
{Record, State} = next_record(State0#state{connection_states =
2206
tls_handshake_hashes = Hs0}),
2207
next_state(hello, Record, State).
2209
notify_senders(SendQueue) ->
2210
lists:foreach(fun({From, _}) ->
2211
gen_fsm:reply(From, {error, closed})
2212
end, queue:to_list(SendQueue)).
2214
notify_renegotiater({true, From}) when not is_atom(From) ->
2215
gen_fsm:reply(From, {error, closed});
2216
notify_renegotiater(_) ->
2219
terminate_alert(Reason, Version, ConnectionStates) when Reason == normal; Reason == shutdown;
2220
Reason == user_close ->
2221
{BinAlert, _} = encode_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
2222
Version, ConnectionStates),
2224
terminate_alert(_, Version, ConnectionStates) ->
2225
{BinAlert, _} = encode_alert(?ALERT_REC(?FATAL, ?INTERNAL_ERROR),
2226
Version, ConnectionStates),
2229
workaround_transport_delivery_problems(_,_, user_close) ->
2231
workaround_transport_delivery_problems(Socket, Transport, _) ->
2232
%% Standard trick to try to make sure all
2233
%% data sent to to tcp port is really sent
2234
%% before tcp port is closed so that the peer will
2235
%% get a correct error message.
2236
inet:setopts(Socket, [{active, false}]),
2237
Transport:shutdown(Socket, write),
2238
Transport:recv(Socket, 0).
2240
linux_workaround_transport_delivery_problems(#alert{level = ?FATAL}, Socket) ->
2243
inet:setopts(Socket, [{nodelay, true}]);
2247
linux_workaround_transport_delivery_problems(_, _) ->
2250
get_timeout(#state{ssl_options=#ssl_options{hibernate_after=undefined}}) ->
2252
get_timeout(#state{ssl_options=#ssl_options{hibernate_after=HibernateAfter}}) ->