open Tls open OUnit2 open Testlib let readerwriter_version v _ = let buf = Writer.assemble_protocol_version v in match Reader.parse_version buf with | Ok ver -> assert_equal v ver ; (* lets get crazy and do it one more time *) let buf' = Writer.assemble_protocol_version v in (match Reader.parse_version buf' with | Ok ver' -> assert_equal v ver' | Error _ -> assert_failure "read and write version broken") | Error _ -> assert_failure "read and write version broken" let version_tests = [ "ReadWrite version TLS-1.0" >:: readerwriter_version `TLS_1_0 ; "ReadWrite version TLS-1.1" >:: readerwriter_version `TLS_1_1 ; "ReadWrite version TLS-1.2" >:: readerwriter_version `TLS_1_2 ] let readerwriter_header (v, ct, cs) _ = let buf = Writer.assemble_hdr v (ct, cs) in match Reader.parse_record buf with | Ok (`Record ((hdr, payload), f)) -> let open Core in assert_equal 0 (String.length f) ; assert_equal (v :> tls_any_version) hdr.version ; assert_equal ct hdr.content_type ; assert_cs_eq cs payload ; let buf' = Writer.assemble_hdr v (hdr.content_type, payload) in (match Reader.parse_record buf' with | Ok (`Record ((hdr, payload), f)) -> assert_equal 0 (String.length f) ; assert_equal (v :> tls_any_version) hdr.version ; assert_equal ct hdr.content_type ; assert_cs_eq cs payload ; | _ -> assert_failure "inner header broken") | _ -> assert_failure "header broken" let header_tests = let a = list_to_cstruct [ 0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15 ] in [ "ReadWrite header" >:: readerwriter_header (`TLS_1_0, Packet.HANDSHAKE, a) ; "ReadWrite header" >:: readerwriter_header (`TLS_1_1, Packet.HANDSHAKE, a) ; "ReadWrite header" >:: readerwriter_header (`TLS_1_2, Packet.HANDSHAKE, a) ; "ReadWrite header" >:: readerwriter_header (`TLS_1_0, Packet.APPLICATION_DATA, a) ; "ReadWrite header" >:: readerwriter_header (`TLS_1_1, Packet.APPLICATION_DATA, a) ; "ReadWrite header" >:: readerwriter_header (`TLS_1_2, Packet.APPLICATION_DATA, a) ; "ReadWrite header" >:: readerwriter_header (`TLS_1_0, Packet.CHANGE_CIPHER_SPEC, a) ; "ReadWrite header" >:: readerwriter_header (`TLS_1_1, Packet.CHANGE_CIPHER_SPEC, a) ; "ReadWrite header" >:: readerwriter_header (`TLS_1_2, Packet.CHANGE_CIPHER_SPEC, a) ; "ReadWrite header" >:: readerwriter_header (`TLS_1_0, Packet.ALERT, a) ; "ReadWrite header" >:: readerwriter_header (`TLS_1_1, Packet.ALERT, a) ; "ReadWrite header" >:: readerwriter_header (`TLS_1_2, Packet.ALERT, a) ; ] let readerwriter_alert (lvl, typ) _ = let buf, expl = match lvl with | None -> (Writer.assemble_alert typ, Packet.FATAL) | Some l -> (Writer.assemble_alert ~level:l typ, l) in (match Reader.parse_alert buf with | Ok (l', t') -> assert_equal expl l' ; assert_equal typ t' ; (* lets get crazy and do it one more time *) let buf' = Writer.assemble_alert ~level:l' t' in (match Reader.parse_alert buf' with | Ok (l'', t'') -> assert_equal expl l'' ; assert_equal typ t'' | Error _ -> assert_failure "inner read and write alert broken") | Error _ -> assert_failure "read and write alert broken") let rw_alert_tests = Packet.([ ( None, CLOSE_NOTIFY ) ; ( None, UNEXPECTED_MESSAGE ) ; ( None, BAD_RECORD_MAC ) ; ( None, RECORD_OVERFLOW ) ; ( None, HANDSHAKE_FAILURE ) ; ( None, BAD_CERTIFICATE ) ; ( None, CERTIFICATE_EXPIRED ) ; ( None, DECODE_ERROR ) ; ( None, PROTOCOL_VERSION ) ; ( None, UNSUPPORTED_EXTENSION ) ; ( None, UNRECOGNIZED_NAME ) ; ( None, NO_APPLICATION_PROTOCOL ) ; ( Some FATAL, CLOSE_NOTIFY ) ; ( Some FATAL, UNEXPECTED_MESSAGE ) ; ( Some FATAL, BAD_RECORD_MAC ) ; ( Some FATAL, RECORD_OVERFLOW ) ; ( Some FATAL, HANDSHAKE_FAILURE ) ; ( Some FATAL, BAD_CERTIFICATE ) ; ( Some FATAL, CERTIFICATE_EXPIRED ) ; ( Some FATAL, DECODE_ERROR ) ; ( Some FATAL, PROTOCOL_VERSION ) ; ( Some FATAL, UNSUPPORTED_EXTENSION ) ; ( Some FATAL, UNRECOGNIZED_NAME ) ; ( Some FATAL, NO_APPLICATION_PROTOCOL ) ; ( Some WARNING, CLOSE_NOTIFY ) ; (* ( Some WARNING, UNEXPECTED_MESSAGE ) ; ( Some WARNING, BAD_RECORD_MAC ) ; ( Some WARNING, DECRYPTION_FAILED ) ; ( Some WARNING, RECORD_OVERFLOW ) ; ( Some WARNING, DECOMPRESSION_FAILURE ) ; ( Some WARNING, HANDSHAKE_FAILURE ) ; *) ( Some FATAL, BAD_CERTIFICATE ) ; ( Some FATAL, CERTIFICATE_EXPIRED ) ; (* ( Some WARNING, UNKNOWN_CA ) ; ( Some WARNING, ACCESS_DENIED ) ; ( Some WARNING, DECODE_ERROR ) ; ( Some WARNING, DECRYPT_ERROR ) ; *) (* ( Some WARNING, PROTOCOL_VERSION ) ; ( Some WARNING, INSUFFICIENT_SECURITY ) ; ( Some WARNING, INTERNAL_ERROR ) ; *) ( Some WARNING, USER_CANCELED ) ; ( Some WARNING, NO_RENEGOTIATION ) ; (* ( Some WARNING, UNSUPPORTED_EXTENSION ) ; *) ( Some FATAL, UNRECOGNIZED_NAME ) ; ]) let rw_alert_tests = List.mapi (fun i f -> "RW alert " ^ string_of_int i >:: readerwriter_alert f) rw_alert_tests let assert_dh_eq a b = Core.(assert_cs_eq a.dh_p b.dh_p) ; Core.(assert_cs_eq a.dh_g b.dh_g) ; Core.(assert_cs_eq a.dh_Ys b.dh_Ys) let readerwriter_dh_params params _ = let buf = Writer.assemble_dh_parameters params in match Reader.parse_dh_parameters buf with | Ok (p, raw, rst) -> assert_equal (String.length rst) 0 ; assert_dh_eq p params ; assert_equal buf raw ; (* lets get crazy and do it one more time *) let buf' = Writer.assemble_dh_parameters p in (match Reader.parse_dh_parameters buf' with | Ok (p', raw', rst') -> assert_equal (String.length rst') 0 ; assert_dh_eq p' params ; assert_equal buf raw' ; | Error _ -> assert_failure "inner read and write dh params broken") | Error _ -> assert_failure "read and write dh params broken" let rw_dh_params = let a = list_to_cstruct [ 0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15 ] in let emp = list_to_cstruct [] in Core.([ { dh_p = emp ; dh_g = emp ; dh_Ys = emp } ; { dh_p = a ; dh_g = emp ; dh_Ys = emp } ; { dh_p = emp ; dh_g = a ; dh_Ys = emp } ; { dh_p = emp ; dh_g = emp ; dh_Ys = a } ; { dh_p = a ^ a ; dh_g = a ^ a ; dh_Ys = a ^ a } ; ]) let rw_dh_tests = List.mapi (fun i f -> "RW dh_param " ^ string_of_int i >:: readerwriter_dh_params f) rw_dh_params let readerwriter_digitally_signed params _ = let buf = Writer.assemble_digitally_signed params in match Reader.parse_digitally_signed buf with | Ok params' -> assert_cs_eq params params' ; (* lets get crazy and do it one more time *) let buf' = Writer.assemble_digitally_signed params' in (match Reader.parse_digitally_signed buf' with | Ok params'' -> assert_cs_eq params params'' | Error _ -> assert_failure "inner read and write digitally signed broken") | Error _ -> assert_failure "read and write digitally signed broken" let rw_ds_params = let a = list_to_cstruct [ 0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15 ] in let emp = list_to_cstruct [] in [ a ; a ^ a ; emp ; emp ^ a ] let rw_ds_tests = List.mapi (fun i f -> "RW digitally signed " ^ string_of_int i >:: readerwriter_digitally_signed f) rw_ds_params let readerwriter_digitally_signed_1_2 (sigalg, params) _ = let buf = Writer.assemble_digitally_signed_1_2 sigalg params in match Reader.parse_digitally_signed_1_2 buf with | Ok (sigalg', params') -> assert_equal sigalg sigalg' ; assert_cs_eq params params' ; (* lets get crazy and do it one more time *) let buf' = Writer.assemble_digitally_signed_1_2 sigalg' params' in (match Reader.parse_digitally_signed_1_2 buf' with | Ok (sigalg'', params'') -> assert_equal sigalg sigalg'' ; assert_cs_eq params params'' | Error _ -> assert_failure "inner read and write digitally signed 1.2 broken") | Error _ -> assert_failure "read and write digitally signed 1.2 broken" let rec cartesian_product f a b = match b with | [] -> [] | e::rt -> (List.map (fun x -> f x e) a) @ (cartesian_product f a rt) let rw_ds_1_2_params = let a = list_to_cstruct [ 0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15 ] in let emp = list_to_cstruct [] in let cs = [ a ; a ^ a ; emp ; emp ^ a ] in let sig_algs = [ `RSA_PKCS1_MD5 ; `RSA_PKCS1_SHA1 ; `RSA_PKCS1_SHA224 ; `RSA_PKCS1_SHA256 ; `RSA_PKCS1_SHA384 ; `RSA_PKCS1_SHA512 ; `RSA_PSS_RSAENC_SHA256 ; `RSA_PSS_RSAENC_SHA384 ; `RSA_PSS_RSAENC_SHA512 ] in cartesian_product (fun sigalg c -> (sigalg, c)) sig_algs cs let rw_ds_1_2_tests = List.mapi (fun i f -> "RW digitally signed 1.2 " ^ string_of_int i >:: readerwriter_digitally_signed_1_2 f) rw_ds_1_2_params let rw_handshake_no_data hs _ = let buf = Writer.assemble_handshake hs in match Reader.parse_handshake buf with | Ok hs' -> assert_equal hs hs' ; (* lets get crazy and do it one more time *) let buf' = Writer.assemble_handshake hs' in (match Reader.parse_handshake buf' with | Ok hs'' -> assert_equal hs hs'' | Error _ -> assert_failure "handshake no data inner failed") | Error _ -> assert_failure "handshake no data failed" let rw_handshakes_no_data_vals = [ Core.HelloRequest ; Core.ServerHelloDone ] let rw_handshake_no_data_tests = List.mapi (fun i f -> "handshake no data " ^ string_of_int i >:: rw_handshake_no_data f) rw_handshakes_no_data_vals let rw_handshake_cstruct_data hs _ = let buf = Writer.assemble_handshake hs in match Reader.parse_handshake buf with | Ok hs' -> Readertests.cmp_handshake_cstruct hs hs' ; (* lets get crazy and do it one more time *) let buf' = Writer.assemble_handshake hs' in (match Reader.parse_handshake buf' with | Ok hs'' -> Readertests.cmp_handshake_cstruct hs hs'' | Error _ -> assert_failure "handshake cstruct data inner failed") | Error _ -> assert_failure "handshake cstruct data failed" let rw_handshake_cstruct_data_vals = let data_cs = list_to_cstruct [ 0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11 ] in let emp = list_to_cstruct [ ] in Core.([ ServerKeyExchange emp ; ServerKeyExchange data_cs ; Finished emp ; Finished data_cs ; ClientKeyExchange emp ; ClientKeyExchange data_cs ; Certificate (Writer.assemble_certificates []) ; Certificate (Writer.assemble_certificates [data_cs]) ; Certificate (Writer.assemble_certificates [data_cs; data_cs]) ; Certificate (Writer.assemble_certificates [data_cs ; emp]) ; Certificate (Writer.assemble_certificates [emp ; data_cs]) ; Certificate (Writer.assemble_certificates [emp ; data_cs ; emp]) ; Certificate (Writer.assemble_certificates [emp ; data_cs ; emp ; data_cs]) ]) let rw_handshake_cstruct_data_tests = List.mapi (fun i f -> "handshake cstruct data " ^ string_of_int i >:: rw_handshake_cstruct_data f) rw_handshake_cstruct_data_vals let rw_handshake_client_hello hs _ = let buf = Writer.assemble_handshake hs in match Reader.parse_handshake buf with | Ok hs' -> Core.(match hs, hs' with | ClientHello ch, ClientHello ch' -> Readertests.cmp_client_hellos ch ch' ; | _ -> assert_failure "handshake client hello broken") ; (* lets get crazy and do it one more time *) let buf' = Writer.assemble_handshake hs' in (match Reader.parse_handshake buf' with | Ok hs'' -> Core.(match hs, hs'' with | ClientHello ch, ClientHello ch'' -> Readertests.cmp_client_hellos ch ch'' ; | _ -> assert_failure "handshake client hello broken") | Error _ -> assert_failure "handshake client hello inner failed") | Error _ -> assert_failure "handshake client hello failed" let rw_handshake_client_hello_vals = let rnd = [ 0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15 ] in let client_random = list_to_cstruct (rnd @ rnd) in Core.(let ch : client_hello = { client_version = `TLS_1_2 ; client_random ; sessionid = None ; ciphersuites = [] ; extensions = []} in [ ClientHello ch ; ClientHello { ch with client_version = `TLS_1_0 } ; ClientHello { ch with client_version = `TLS_1_1 } ; ClientHello { ch with ciphersuites = [ Packet.TLS_RSA_WITH_3DES_EDE_CBC_SHA ] } ; ClientHello { ch with ciphersuites = Packet.([ TLS_RSA_WITH_3DES_EDE_CBC_SHA ; TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA ; TLS_RSA_WITH_AES_256_CBC_SHA ]) } ; ClientHello { ch with sessionid = (Some (list_to_cstruct rnd)) } ; ClientHello { ch with sessionid = (Some client_random) } ; ClientHello { ch with ciphersuites = Packet.([ TLS_RSA_WITH_3DES_EDE_CBC_SHA ; TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA ; TLS_RSA_WITH_AES_256_CBC_SHA ]) ; sessionid = (Some client_random) } ; ClientHello { ch with extensions = [ make_hostname_ext "foobar" ] } ; ClientHello { ch with extensions = [ make_hostname_ext "foobarblubb" ] } ; ClientHello { ch with extensions = [ make_hostname_ext "foobarblubb" ; `SupportedGroups Packet.([SECP521R1; SECP384R1]) ] } ; ClientHello { ch with extensions = [ `ALPN ["h2"; "http/1.1"] ] } ; ClientHello { ch with extensions = [ make_hostname_ext "foobarblubb" ; `SupportedGroups Packet.([SECP521R1; SECP384R1]) ; `SignatureAlgorithms [`RSA_PKCS1_MD5] ; `ALPN ["h2"; "http/1.1"] ] } ; ClientHello { ch with ciphersuites = Packet.([ TLS_RSA_WITH_3DES_EDE_CBC_SHA ; TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA ; TLS_RSA_WITH_AES_256_CBC_SHA ]) ; sessionid = (Some client_random) ; extensions = [ make_hostname_ext "foobarblubb" ] } ; ClientHello { ch with ciphersuites = Packet.([ TLS_RSA_WITH_3DES_EDE_CBC_SHA ; TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA ; TLS_RSA_WITH_AES_256_CBC_SHA ]) ; sessionid = (Some client_random) ; extensions = [ make_hostname_ext "foobarblubb" ; `SupportedGroups Packet.([SECP521R1; SECP384R1]) ; `SignatureAlgorithms [`RSA_PKCS1_SHA1; `RSA_PKCS1_SHA512] ; `ALPN ["h2"; "http/1.1"] ] } ; ClientHello { ch with ciphersuites = Packet.([ TLS_RSA_WITH_3DES_EDE_CBC_SHA ; TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA ; TLS_RSA_WITH_AES_256_CBC_SHA ]) ; sessionid = (Some client_random) ; extensions = [ make_hostname_ext "foobarblubb" ; `SupportedGroups Packet.([SECP521R1; SECP384R1]) ; `SignatureAlgorithms [`RSA_PKCS1_MD5; `RSA_PKCS1_SHA256] ; `SecureRenegotiation client_random ; `ALPN ["h2"; "http/1.1"] ] } ; ]) let rw_handshake_client_hello_tests = List.mapi (fun i f -> "handshake client hello " ^ string_of_int i >:: rw_handshake_client_hello f) rw_handshake_client_hello_vals let rw_handshake_server_hello hs _ = let buf = Writer.assemble_handshake hs in (match Reader.parse_handshake buf with | Ok hs' -> Core.(match hs, hs' with | ServerHello sh, ServerHello sh' -> Readertests.cmp_server_hellos sh sh' ; | _ -> assert_failure "handshake server hello broken") ; (* lets get crazy and do it one more time *) let buf' = Writer.assemble_handshake hs' in (match Reader.parse_handshake buf' with | Ok hs'' -> Core.(match hs, hs'' with | ServerHello sh, ServerHello sh'' -> Readertests.cmp_server_hellos sh sh'' ; | _ -> assert_failure "handshake server hello broken") | Error _ -> assert_failure "handshake server hello inner failed") | Error _ -> assert_failure "handshake server hello failed") let rw_handshake_server_hello_vals = let rnd = [ 0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15 ] in let server_random = list_to_cstruct (rnd @ rnd) in Core.(let sh : server_hello = { server_version = `TLS_1_2 ; server_random ; sessionid = None ; ciphersuite = `RSA_WITH_AES_256_CCM ; extensions = []} in [ ServerHello sh ; ServerHello { sh with server_version = `TLS_1_0 } ; ServerHello { sh with server_version = `TLS_1_1 } ; ServerHello { sh with sessionid = (Some server_random) } ; ServerHello { sh with sessionid = (Some server_random) ; extensions = [`Hostname] } ; ServerHello { sh with sessionid = (Some server_random) ; extensions = [`Hostname ; `SecureRenegotiation server_random] } ; ServerHello { sh with sessionid = (Some server_random) ; extensions = [`Hostname ; `SecureRenegotiation server_random ; `ALPN "h2"] } ; ]) let rw_handshake_server_hello_tests = List.mapi (fun i f -> "handshake server hello " ^ string_of_int i >:: rw_handshake_server_hello f) rw_handshake_server_hello_vals let readerwriter_tests = version_tests @ header_tests @ rw_alert_tests @ rw_dh_tests @ rw_ds_tests @ rw_ds_1_2_tests @ rw_handshake_no_data_tests @ rw_handshake_cstruct_data_tests @ rw_handshake_client_hello_tests @ rw_handshake_server_hello_tests