228
209
%%--------------------------------------------------------------------
229
%% Function: increment_sequence_number(States, Type) -> #connection_states{}
230
%% States = #connection_states{}
231
%% Type = read | write
233
%% Description: Creates a new instance of the connection_states record
234
%% where the sequence number of the current state of <Type> has been
236
%%--------------------------------------------------------------------
237
increment_sequence_number(States = #connection_states{current_read = Current},
239
SeqNr = Current#connection_state.sequence_number + 1,
240
States#connection_states{current_read = Current#connection_state{
241
sequence_number = SeqNr
244
increment_sequence_number(States = #connection_states{current_write = Current},
246
SeqNr = Current#connection_state.sequence_number + 1,
247
States#connection_states{current_write = Current#connection_state{
248
sequence_number = SeqNr
251
%%--------------------------------------------------------------------
252
%% Function: update_cipher_state(CipherState, States, Type) ->
253
%% #connection_states{}
254
%% CipherState = #cipher_state{}
255
%% States = #connection_states{}
256
%% Type = read | write
258
%% update the cipher state in the specified current connection state
259
%%--------------------------------------------------------------------
260
update_cipher_state(CipherState,
261
States = #connection_states{current_read = Current},
263
States#connection_states{current_read = Current#connection_state{
264
cipher_state = CipherState
267
update_cipher_state(CipherState,
268
States = #connection_states{current_write = Current},
270
States#connection_states{current_write = Current#connection_state{
271
cipher_state = CipherState
275
%%--------------------------------------------------------------------
276
%% Function: set_pending_cipher_state(States, CSCW, CSSW, Role) ->
210
%% Function: set_pending_cipher_state(States, ClientState,
211
%% ServerState, Role) ->
277
212
%% #connection_states{}
278
%% CSCW = CSSW = #cipher_state{}
279
%% States = #connection_states{}
281
%% set the cipher state in the specified pending connection state
282
%%--------------------------------------------------------------------
283
set_pending_cipher_state(States, CSCW, CSSW, server) ->
284
set_pending_cipher_state(States, CSSW, CSCW, client);
285
set_pending_cipher_state(#connection_states{pending_read = PRCS,
286
pending_write = PWCS} = States,
287
CSCW, CSSW, client) ->
288
States#connection_states{
289
pending_read = PRCS#connection_state{cipher_state = CSCW},
290
pending_write = PWCS#connection_state{cipher_state = CSSW}}.
292
%%--------------------------------------------------------------------
293
%% Function: update_compression_state(CompressionState, States, Type) ->
294
%% #connection_states{}
295
%% CompressionState = #compression_state{}
296
%% States = #connection_states{}
297
%% Type = read | write
299
%% Description: Creates a new instance of the connection_states record
300
%% where the compression state of the current state of <Type> has been
302
%%--------------------------------------------------------------------
303
update_compression_state(CompressionState,
304
States = #connection_states{current_read = Current},
306
States#connection_states{current_read = Current#connection_state{
311
update_compression_state(CompressionState,
312
States = #connection_states{current_write = Current},
314
States#connection_states{current_write = Current#connection_state{
213
%% ClientState = ServerState = #cipher_state{}
214
%% States = #connection_states{}
216
%% Description: Set the cipher state in the specified pending connection state.
217
%%--------------------------------------------------------------------
218
set_pending_cipher_state(#connection_states{pending_read = Read,
219
pending_write = Write} = States,
220
ClientState, ServerState, server) ->
221
States#connection_states{
222
pending_read = Read#connection_state{cipher_state = ClientState},
223
pending_write = Write#connection_state{cipher_state = ServerState}};
225
set_pending_cipher_state(#connection_states{pending_read = Read,
226
pending_write = Write} = States,
227
ClientState, ServerState, client) ->
228
States#connection_states{
229
pending_read = Read#connection_state{cipher_state = ServerState},
230
pending_write = Write#connection_state{cipher_state = ClientState}}.
319
232
%%--------------------------------------------------------------------
320
233
%% Function: get_tls_record(Data, Buffer) -> Result
325
238
%% and returns it as a list of #tls_compressed, also returns leftover
327
240
%%--------------------------------------------------------------------
241
get_tls_records(Data, <<>>) ->
242
get_tls_records_aux(Data, []);
328
243
get_tls_records(Data, Buffer) ->
329
244
get_tls_records_aux(list_to_binary([Buffer, Data]), []).
246
get_tls_records_aux(<<?BYTE(?APPLICATION_DATA),?BYTE(MajVer),?BYTE(MinVer),
247
?UINT16(Length), Data:Length/binary, Rest/binary>>,
249
get_tls_records_aux(Rest, [#ssl_tls{type = ?APPLICATION_DATA,
250
version = {MajVer, MinVer},
251
fragment = Data} | Acc]);
252
get_tls_records_aux(<<?BYTE(?HANDSHAKE),?BYTE(MajVer),?BYTE(MinVer),
254
Data:Length/binary, Rest/binary>>, Acc) ->
255
get_tls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
256
version = {MajVer, MinVer},
257
fragment=Data} | Acc]);
258
get_tls_records_aux(<<?BYTE(?ALERT),?BYTE(MajVer),?BYTE(MinVer),
259
?UINT16(Length), Data:Length/binary,
260
Rest/binary>>, Acc) ->
261
get_tls_records_aux(Rest, [#ssl_tls{type = ?ALERT,
262
version = {MajVer, MinVer},
263
fragment = Data} | Acc]);
264
get_tls_records_aux(<<?BYTE(?CHANGE_CIPHER_SPEC),?BYTE(MajVer),?BYTE(MinVer),
265
?UINT16(Length), Data:Length/binary, Rest/binary>>,
267
get_tls_records_aux(Rest, [#ssl_tls{type = ?CHANGE_CIPHER_SPEC,
268
version = {MajVer, MinVer},
269
fragment = Data} | Acc]);
331
270
%% Matches a ssl v2 client hello message.
332
271
%% The server must be able to receive such messages, from clients that
333
272
%% are willing to use ssl v3 or higher, but have ssl v2 compatibility.
334
get_tls_records_aux(<<?BYTE(Byte0), ?BYTE(Byte1),
335
?BYTE(?CLIENT_HELLO), ?BYTE(MajVer), ?BYTE(MinVer),
336
?UINT16(CSLength), ?UINT16(0),
338
_CipherSuites:CSLength/binary,
339
_ChallangeData:CDLength/binary, Data/binary>> = Msg,
340
Acc) when (Byte0 bsr 7) == 1 ->
341
Length = Byte0 band 2#01111111 + Byte1 - 1,
342
<<?BYTE(_), ?BYTE(_), ?BYTE(_), Fragment:Length/binary, Data/binary>> = Msg,
343
C = #tls_cipher_text{type = ?HANDSHAKE,
344
version = #protocol_version{major = MajVer,
347
fragment = <<?BYTE(?CLIENT_HELLO), ?UINT24(Length),
349
get_tls_records_aux(Data, [C | Acc]);
273
get_tls_records_aux(<<1:1, Length0:15, Data0:Length0/binary, Rest/binary>>,
276
<<?BYTE(?CLIENT_HELLO), ?BYTE(MajVer), ?BYTE(MinVer), _/binary>> ->
278
<<?BYTE(_), Data1:Length/binary>> = Data0,
279
Data = <<?BYTE(?CLIENT_HELLO), ?UINT24(Length), Data1/binary>>,
280
get_tls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
281
version = {MajVer, MinVer},
282
fragment = Data} | Acc]);
284
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)
351
get_tls_records_aux(<<?BYTE(CT), ?BYTE(MajVer), ?BYTE(MinVer),
352
?UINT16(Length), Data:Length/binary, Rest/binary>>,
353
Acc) when CT == ?CHANGE_CIPHER_SPEC;
356
CT == ?APPLICATION_DATA ->
357
C = #tls_cipher_text{type = CT,
358
version = #protocol_version{major = MajVer,
362
get_tls_records_aux(Rest, [C | Acc]);
363
get_tls_records_aux(<<?BYTE(_CT), ?BYTE(_MajVer), ?BYTE(_MinVer),
288
get_tls_records_aux(<<0:1, _CT:7, ?BYTE(_MajVer), ?BYTE(_MinVer),
364
289
?UINT16(Length), _/binary>>,
365
290
_Acc) when Length > ?MAX_CIPHER_TEXT_LENGTH->
366
error; % TODO appropriate error code
291
?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
293
get_tls_records_aux(<<1:1, Length0:15, _/binary>>,_Acc)
294
when Length0 > ?MAX_CIPHER_TEXT_LENGTH->
295
?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
367
297
get_tls_records_aux(Data, Acc) ->
368
298
{lists:reverse(Acc), Data}.
415
343
%% Description: Highest protocol version present in a list
416
344
%%--------------------------------------------------------------------
345
highest_protocol_version([]) ->
346
highest_protocol_version();
417
347
highest_protocol_version(Versions) ->
418
348
[Ver | Vers] = Versions,
419
349
highest_protocol_version(Ver, Vers).
421
351
highest_protocol_version(Version, []) ->
423
highest_protocol_version(Version = #protocol_version{major = N,
425
[#protocol_version{major = N,
428
highest_protocol_version(Version, Rest);
429
highest_protocol_version(#protocol_version{major = M,
432
#protocol_version{major = M,
433
minor = _} | Rest]) ->
434
highest_protocol_version(Version, Rest);
435
highest_protocol_version(Version = #protocol_version{major = M},
436
[#protocol_version{major = N} | Rest])
353
highest_protocol_version(Version = {N, M}, [{N, O} | Rest]) when M > O ->
354
highest_protocol_version(Version, Rest);
355
highest_protocol_version({M, _}, [Version = {M, _} | Rest]) ->
356
highest_protocol_version(Version, Rest);
357
highest_protocol_version(Version = {M,_}, [{N,_} | Rest]) when M > N ->
438
358
highest_protocol_version(Version, Rest);
439
359
highest_protocol_version(_, [Version | Rest]) ->
440
360
highest_protocol_version(Version, Rest).
503
403
%%--------------------------------------------------------------------
504
%% Function: uncompress(Method, #tls_compressed{}, CompressionState)
505
%% -> {#tls_plain_text, NewCompState}
507
%% expand compressed data using given compression
508
%%--------------------------------------------------------------------
509
uncompress(?NULL, #tls_compressed{type = Type,
512
fragment = Fragment}, CS) ->
513
{#tls_plain_text{type = Type,
516
fragment = Fragment}, CS}.
519
%%--------------------------------------------------------------------
520
%% Function: compress(Method, #tls_plain_text{}, CompressionState)
521
%% -> {#tls_compressed, NewCompState}
523
%% compress data using given compression
524
%%--------------------------------------------------------------------
525
compress(?NULL, #tls_plain_text{type = Type,
528
fragment = Fragment}, CS) ->
529
{#tls_compressed{type = Type,
532
fragment = Fragment}, CS}.
534
%%--------------------------------------------------------------------
535
%% Function: cipher(Method, #tls_compressed{}, ConnectionState)
536
%% {#tls_cipher_text, NewConnectionState}
539
%%--------------------------------------------------------------------
540
cipher(#tls_compressed{type = Type, version = Version,
541
length = Length, fragment = Fragment}, CS0) ->
542
{Hash, CS1} = hash_and_bump_seqno(CS0, Type, Version, Length, Fragment),
543
SP = CS1#connection_state.security_parameters,
544
CipherS0 = CS1#connection_state.cipher_state,
545
BCA = SP#security_parameters.bulk_cipher_algorithm,
547
{Ciphered, CipherS1} = ssl_cipher:cipher(BCA, CipherS0, Hash, Fragment),
549
CS2 = CS1#connection_state{cipher_state=CipherS1},
550
{#tls_cipher_text{type = Type,
552
length = erlang:iolist_size(Ciphered),
553
cipher = BCA, %% TODO, kolla om det är BCA det ska vara...
554
fragment = Ciphered}, CS2}.
556
%%--------------------------------------------------------------------
557
%% Function: decipher(Method, #tls_cipher_text{}, ConnectionState)
558
%% -> {#tls_compressed, NewConnectionState}
561
%%--------------------------------------------------------------------
562
decipher(#tls_cipher_text{type = Type,
566
fragment = Fragment}, CS)
567
when Type == ?CHANGE_CIPHER_SPEC ->
568
%% These are never encrypted
569
{#tls_compressed{type = Type,
572
fragment = erlang:iolist_to_binary(Fragment)}, CS};
573
decipher(#tls_cipher_text{type = Type,
577
fragment = Fragment}, CS0) ->
578
SP = CS0#connection_state.security_parameters,
579
BCA = SP#security_parameters.bulk_cipher_algorithm, % eller Cipher?
580
HashSz = SP#security_parameters.hash_size,
581
CipherS0 = CS0#connection_state.cipher_state,
582
{T, Mac, CipherS1} = ssl_cipher:decipher(BCA, HashSz, CipherS0, Fragment),
583
CS1 = CS0#connection_state{cipher_state = CipherS1},
585
{Hash, CS2} = hash_and_bump_seqno(CS1, Type, Version, TLength, Fragment),
586
ok = check_hash(Hash, Mac),
587
{#tls_compressed{type = Type,
593
ok. %% TODO kolla också
404
%% Function: decode_cipher_text(CipherText, ConnectionStates0) ->
405
%% {Plain, ConnectionStates}
407
%% Description: Decode cipher text
408
%%--------------------------------------------------------------------
409
decode_cipher_text(CipherText, ConnnectionStates0) ->
410
ReadState0 = ConnnectionStates0#connection_states.current_read,
411
#connection_state{compression_state = CompressionS0,
412
security_parameters = SecParams} = ReadState0,
413
CompressAlg = SecParams#security_parameters.compression_algorithm,
414
{Compressed, ReadState1} = decipher(CipherText, ReadState0),
415
{Plain, CompressionS1} = uncompress(CompressAlg,
416
Compressed, CompressionS0),
417
ConnnectionStates = ConnnectionStates0#connection_states{
418
current_read = ReadState1#connection_state{
419
compression_state = CompressionS1}},
420
{Plain, ConnnectionStates}.
595
422
%%--------------------------------------------------------------------
596
423
%%% Internal functions
597
424
%%--------------------------------------------------------------------
425
highest_protocol_version() ->
426
highest_protocol_version(supported_protocol_versions()).
599
428
initial_connection_state(ConnectionEnd) ->
600
429
#connection_state{security_parameters =
639
473
lists:reverse(Acc, [Bin])
476
encode_data(Frag, Version, ConnectionStates)
477
when erlang:byte_size(Frag) < (?MAX_PLAIN_TEXT_LENGTH - 2048) ->
478
encode_plain_text(?APPLICATION_DATA,Version,Frag,ConnectionStates);
642
479
encode_data(Frag, Version, ConnectionStates) ->
643
Bin = erlang:iolist_to_binary(Frag),
644
Data = split_bin(Bin, ?MAX_PLAIN_TEXT_LENGTH-2048),
480
Data = split_bin(Frag, ?MAX_PLAIN_TEXT_LENGTH - 2048),
646
482
lists:foldl(fun(B, {CS0, Acc}) ->
647
T = #tls_plain_text{type = ?APPLICATION_DATA,
651
{ET, CS1} = encode_plain_text(T, CS0),
484
encode_plain_text(?APPLICATION_DATA,
652
486
{CS1, [ET | Acc]}
653
487
end, {ConnectionStates, []}, Data),
654
488
{lists:reverse(Acc), CS1}.
656
490
encode_handshake(Frag, Version, ConnectionStates) ->
657
PT = #tls_plain_text{type = ?HANDSHAKE,
659
length = erlang:iolist_size(Frag),
661
encode_plain_text(PT, ConnectionStates).
491
encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates).
663
493
encode_alert_record(#alert{level = Level, description = Description},
664
494
Version, ConnectionStates) ->
665
PT = #tls_plain_text{type = ?ALERT,
668
fragment = <<?BYTE(Level), ?BYTE(Description)>>},
669
encode_plain_text(PT, ConnectionStates).
495
encode_plain_text(?ALERT, Version, <<?BYTE(Level), ?BYTE(Description)>>,
671
498
encode_change_cipher_spec(Version, ConnectionStates) ->
672
PT = #tls_plain_text{type = ?CHANGE_CIPHER_SPEC,
676
encode_plain_text(PT, ConnectionStates).
499
encode_plain_text(?CHANGE_CIPHER_SPEC, Version, <<1:8>>, ConnectionStates).
678
encode_plain_text(PT, ConnectionStates) ->
679
CS0 = ConnectionStates#connection_states.current_write,
680
CompS0 = CS0#connection_state.compression_state,
681
SecParams = (CS0#connection_state.security_parameters),
682
CompAlg = SecParams#security_parameters.compression_algorithm,
683
{Comp, CompS1} = compress(CompAlg, PT, CompS0),
501
encode_plain_text(Type, Version, Data, ConnectionStates) ->
502
#connection_states{current_write=#connection_state{
503
compression_state=CompS0,
505
#security_parameters{compression_algorithm=CompAlg}
506
}=CS0} = ConnectionStates,
507
{Comp, CompS1} = compress(CompAlg, Data, CompS0),
684
508
CS1 = CS0#connection_state{compression_state = CompS1},
685
{CipherText, CS2} = cipher(Comp, CS1),
686
CTBin = encode_tls_cipher_text(CipherText),
509
{CipherText, CS2} = cipher(Type, Version, Comp, CS1),
510
CTBin = encode_tls_cipher_text(Type, Version, CipherText),
687
511
{CTBin, ConnectionStates#connection_states{current_write = CS2}}.
689
encode_tls_cipher_text(#tls_cipher_text{type = Type,
692
fragment = Fragment}) ->
693
#protocol_version{major = MajVer, minor = MinVer} = Version,
694
[?byte(Type), ?byte(MajVer), ?byte(MinVer), ?uint16(Length), Fragment].
696
decode_cipher_text(CipherText, CSs0) ->
697
CR0 = CSs0#connection_states.current_read,
698
#connection_state{compression_state = CompressionS0,
699
security_parameters = SP} = CR0,
700
CA = SP#security_parameters.compression_algorithm,
701
{Compressed, CR1} = decipher(CipherText, CR0),
702
{Plain, CompressionS1} = uncompress(CA, Compressed, CompressionS0),
703
CSs1 = CSs0#connection_states{
704
current_read = CR1#connection_state{
705
compression_state = CompressionS1}},
513
encode_tls_cipher_text(Type,{MajVer,MinVer},Fragment) ->
514
Length = erlang:iolist_size(Fragment),
515
[<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Length)>>, Fragment].
517
cipher(Type, Version, Fragment, CS0) ->
518
Length = erlang:iolist_size(Fragment),
519
{Hash, CS1=#connection_state{cipher_state = CipherS0,
521
#security_parameters{bulk_cipher_algorithm =
524
hash_and_bump_seqno(CS0, Type, Version, Length, Fragment),
526
{Ciphered, CipherS1} = ssl_cipher:cipher(BCA, CipherS0, Hash, Fragment),
528
CS2 = CS1#connection_state{cipher_state=CipherS1},
531
decipher(TLS=#ssl_tls{type = ?CHANGE_CIPHER_SPEC}, CS) ->
532
%% These are never encrypted
534
decipher(TLS=#ssl_tls{type=Type, version=Version, fragment=Fragment}, CS0) ->
535
SP = CS0#connection_state.security_parameters,
536
BCA = SP#security_parameters.bulk_cipher_algorithm, % eller Cipher?
537
HashSz = SP#security_parameters.hash_size,
538
CipherS0 = CS0#connection_state.cipher_state,
539
{T, Mac, CipherS1} = ssl_cipher:decipher(BCA, HashSz, CipherS0, Fragment),
540
CS1 = CS0#connection_state{cipher_state = CipherS1},
542
{Hash, CS2} = hash_and_bump_seqno(CS1, Type, Version, TLength, Fragment),
543
ok = check_hash(Hash, Mac),
544
{TLS#ssl_tls{fragment = T}, CS2}.
546
uncompress(?NULL, Data = #ssl_tls{type = _Type,
548
fragment = _Fragment}, CS) ->
551
compress(?NULL, Data, CS) ->
708
554
hash_and_bump_seqno(#connection_state{sequence_number = SeqNo,
709
mac_secret = MacSecret,
710
security_parameters =
555
mac_secret = MacSecret,
556
security_parameters =
712
558
Type, Version, Length, Fragment) ->
713
Hash = ssl_cipher:mac_hash(SecPars#security_parameters.mac_algorithm,
714
Version, MacSecret, SeqNo, Type,
559
Hash = mac_hash(Version,
560
SecPars#security_parameters.mac_algorithm,
561
MacSecret, SeqNo, Type,
716
563
{Hash, CS0#connection_state{sequence_number = SeqNo+1}}.
566
ok. %% TODO check this
568
mac_hash(?NULL, {_,_}, _MacSecret, _SeqNo, _Type,
569
_Length, _Fragment) ->
571
mac_hash({3, 0}, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) ->
572
ssl_ssl3:mac_hash(MacAlg, MacSecret, SeqNo, Type, Length, Fragment);
573
mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment)
574
when N == 1; N == 2 ->
575
ssl_tls1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version,