This commit is contained in:
swrup 2025-11-11 02:07:51 +01:00
parent aa2ff7b2f0
commit 2f3113f55d
11742 changed files with 1223940 additions and 0 deletions

View file

@ -0,0 +1,69 @@
(library
(name ex_common)
(libraries lwt lwt.unix tls tls-lwt cmdliner fmt.cli logs.fmt fmt.tty logs.cli)
(modules ex_common))
(executable
(name starttls_server)
(modules starttls_server)
(libraries tls-lwt lwt.unix ex_common))
(executable
(name echo_server)
(modules echo_server)
(libraries tls-lwt lwt.unix ex_common))
(executable
(name echo_server_sni)
(modules echo_server_sni)
(libraries tls-lwt lwt.unix ex_common))
(executable
(name echo_server_alpn)
(modules echo_server_alpn)
(libraries tls-lwt lwt.unix ex_common))
(executable
(name echo_client)
(modules echo_client)
(libraries tls-lwt lwt.unix ex_common))
(executable
(name echo_client_alpn)
(modules echo_client_alpn)
(libraries tls-lwt lwt.unix ex_common))
(executable
(name test_server)
(modules test_server)
(libraries tls-lwt lwt.unix ex_common))
(executable
(name test_client)
(modules test_client)
(libraries tls-lwt lwt.unix ex_common))
(executable
(name tls_over_tls)
(modules tls_over_tls)
(libraries tls-lwt lwt lwt.unix ex_common))
(executable
(name http_client)
(modules http_client)
(libraries tls-lwt lwt.unix ex_common))
(executable
(name fuzz_server)
(modules fuzz_server)
(libraries tls-lwt lwt.unix ex_common))
(executable
(name resume_client)
(modules resume_client)
(libraries tls-lwt lwt.unix ex_common))
(executable
(name resume_echo_server)
(modules resume_echo_server)
(libraries randomconv tls-lwt lwt.unix ex_common))

View file

@ -0,0 +1,73 @@
open Ex_common
open Lwt
let cached_session : Tls.Core.epoch_data =
let hex = Ohex.decode in
{
Tls.Core.side = `Client ;
protocol_version = `TLS_1_3 ;
ciphersuite = `DHE_RSA_WITH_AES_128_GCM_SHA256 ;
peer_random = hex "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" ;
peer_certificate = None ;
peer_certificate_chain = [] ;
peer_name = None ;
trust_anchor = None ;
received_certificates = [] ;
own_random = hex "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" ;
own_certificate = [] ;
own_private_key = None ;
own_name = None ;
master_secret = hex "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" ;
exporter_master_secret = "" ;
session_id = "" ;
extended_ms = true ;
alpn_protocol = None ;
state = `Established ;
tls_unique = None ;
}
let echo_client ?ca hostname port =
let open Lwt_io in
auth ?ca () >>= fun authenticator ->
X509_lwt.private_of_pems
~cert:server_cert
~priv_key:server_key >>= fun certificate ->
Tls_lwt.connect_ext
(get_ok Tls.Config.(client ~authenticator ~cached_session ~certificates:(`Single certificate) ~ciphers:Ciphers.supported ()))
(hostname, port) >>= fun (ic, oc) ->
Lwt.join [
lines ic |> Lwt_stream.iter_s (printf "+ %s\n%!") ;
lines stdin |> Lwt_stream.iter_s (write_line oc)
]
let jump _ port host ca =
try
Lwt_main.run (echo_client ?ca host port)
with
| Tls_lwt.Tls_alert alert as exn ->
print_alert "remote end" alert ; raise exn
| Tls_lwt.Tls_failure alert as exn ->
print_fail "our end" alert ; raise exn
open Cmdliner
let port =
let doc = "Port to connect to" in
Arg.(value & opt int 443 & info [ "port" ] ~doc)
let host =
let doc = "Host to connect to" in
Arg.(value & opt string "" & info [ "host" ] ~doc)
let trust =
let doc = "Trust anchor" in
Arg.(value & opt (some string) None & info [ "trust" ] ~doc)
let cmd =
let term = Term.(const jump $ setup_log $ port $ host $ trust)
and info = Cmd.info "echo_client" ~version:"2.0.3"
in
Cmd.v info term
let () = exit (Cmd.eval cmd)

View file

@ -0,0 +1,22 @@
open Ex_common
open Lwt
let echo_client host port =
let open Lwt_io in
let port = int_of_string port in
let authenticator = null_auth in
Tls_lwt.Unix.connect
(get_ok Tls.Config.(client ~authenticator ~alpn_protocols:["http/1.1"; "h2"] ()))
(host, port) >>= fun t ->
match Tls_lwt.Unix.epoch t with
| Error () -> printl "Error"
| Ok epoch -> (
match epoch.Tls.Core.alpn_protocol with
| None -> printl "No protocol selected"
| Some protocol -> printl ("Selected protocol: " ^ protocol)
)
>>= fun () -> Tls_lwt.Unix.close t
let () =
Lwt_main.run (echo_client "127.0.0.1" "4433")

View file

@ -0,0 +1,75 @@
open Lwt
open Ex_common
let string_of_unix_err err f p =
Printf.sprintf "Unix_error (%s, %s, %s)"
(Unix.error_message err) f p
let serve_ssl port callback =
let tag = "server" in
X509_lwt.private_of_pems
~cert:server_cert
~priv_key:server_key >>= fun cert ->
let server_s () =
let open Lwt_unix in
let s = socket PF_INET SOCK_STREAM 0 in
setsockopt s SO_REUSEADDR true ;
bind s (ADDR_INET (Unix.inet_addr_any, port)) >|= fun () ->
listen s 10 ;
s in
let handle channels addr =
async @@ fun () ->
Lwt.catch (fun () -> callback channels addr >>= fun () -> yap ~tag "<- handler done")
(function
| Tls_lwt.Tls_alert a ->
yap ~tag @@ "handler: " ^ Tls.Packet.alert_type_to_string a
| Tls_lwt.Tls_failure a ->
yap ~tag @@ "handler: " ^ Tls.Engine.string_of_failure a
| Unix.Unix_error (e, f, p) ->
yap ~tag @@ "handler: " ^ (string_of_unix_err e f p)
| _exn -> yap ~tag "handler: exception")
in
yap ~tag ("-> start @ " ^ string_of_int port) >>= fun () ->
let rec loop s =
let authenticator = null_auth in
let config = get_ok (Tls.Config.server ~version:(`TLS_1_0, `TLS_1_3) ~ciphers:Tls.Config.Ciphers.supported ~reneg:true ~certificates:(`Single cert) ~authenticator ()) in
(Lwt.catch
(fun () -> Tls_lwt.accept_ext config s >|= fun r -> `R r)
(function
| Unix.Unix_error (e, f, p) -> return (`L (string_of_unix_err e f p))
| Tls_lwt.Tls_alert a -> return (`L (Tls.Packet.alert_type_to_string a))
| Tls_lwt.Tls_failure f -> return (`L (Tls.Engine.string_of_failure f))
| exn -> return (`L ("loop: exception: " ^ Printexc.to_string exn)))) >>= function
| `R (channels, addr) ->
yap ~tag "-> connect" >>= fun () -> ( handle channels addr ; loop s )
| `L (msg) ->
yap ~tag ("server socket: " ^ msg) >>= fun () -> loop s
in
server_s () >>= fun s ->
loop s
let echo_server _ port =
Lwt_main.run (
serve_ssl port @@ fun (ic, oc) _addr ->
lines ic |> Lwt_stream.iter_s (fun line ->
yap ~tag:"handler" ("+ " ^ line) >>= fun () ->
Lwt_io.write_line oc line))
open Cmdliner
let port =
let doc = "Port to connect to" in
Arg.(value & opt int 4433 & info [ "port" ] ~doc)
let cmd =
let term = Term.(ret (const echo_server $ setup_log $ port))
and info = Cmd.info "echo_server" ~version:"2.0.3"
in
Cmd.v info term
let () = exit (Cmd.eval cmd)

View file

@ -0,0 +1,68 @@
open Lwt
open Ex_common
let split_on_char sep s =
let r = ref [] in
let j = ref (String.length s) in
for i = String.length s - 1 downto 0 do
if s.[i] = sep then begin
r := String.sub s (i + 1) (!j - i - 1) :: !r;
j := i
end
done;
String.sub s 0 !j :: !r
let serve_ssl alpn_protocols port callback =
let tag = "server" in
X509_lwt.private_of_pems
~cert:server_cert
~priv_key:server_key >>= fun certificate ->
let server_s =
let open Lwt_unix in
let s = socket PF_INET SOCK_STREAM 0 in
bind s (ADDR_INET (Unix.inet_addr_any, port)) >|= fun () ->
listen s 10 ;
s in
let handle ep channels addr =
let alpn = match ep with
| Ok data -> (match data.Tls.Core.alpn_protocol with
| Some a -> a
| None -> "no alpn")
| Error () -> "no session"
in
async @@ fun () ->
Lwt.catch (fun () -> callback alpn channels addr >>= fun () -> yap ~tag "<- handler done")
(function
| Tls_lwt.Tls_alert a ->
yap ~tag @@ "handler: " ^ Tls.Packet.alert_type_to_string a
| exn -> yap ~tag "handler: exception" >>= fun () -> fail exn)
in
let ps = string_of_int port in
yap ~tag ("-> start @ " ^ ps ^ " (use `openssl s_client -connect host:" ^ ps ^ " -alpn <proto>`), available protocols: " ^ String.concat "," alpn_protocols) >>= fun () ->
let rec loop () =
let config = get_ok (Tls.Config.server ~certificates:(`Single certificate) ~alpn_protocols ()) in
server_s >>= fun s ->
Tls_lwt.Unix.accept config s >>= fun (t, addr) ->
yap ~tag "-> connect" >>= fun () ->
( handle (Tls_lwt.Unix.epoch t) (Tls_lwt.of_t t) addr ; loop () )
in
loop ()
let echo_server protocols port =
serve_ssl protocols port @@ fun alpn (ic, oc) _addr ->
lines ic |> Lwt_stream.iter_s (fun line ->
yap ~tag:("handler alpn: " ^ alpn) ("+ " ^ line) >>= fun () ->
Lwt_io.write_line oc line)
let () =
let protocols =
try split_on_char ',' Sys.argv.(1) with _ -> [ "h2" ; "http/1.1" ]
in
Lwt_main.run (echo_server protocols 4433)

View file

@ -0,0 +1,61 @@
open Lwt
open Ex_common
let serve_ssl port callback =
let tag = "server" in
X509_lwt.private_of_pems
~cert:(ca_cert_dir ^ "/bar.pem")
~priv_key:server_key >>= fun barcert ->
X509_lwt.private_of_pems
~cert:(ca_cert_dir ^ "/foo.pem")
~priv_key:server_key >>= fun foocert ->
let server_s =
let open Lwt_unix in
let s = socket PF_INET SOCK_STREAM 0 in
bind s (ADDR_INET (Unix.inet_addr_any, port)) >|= fun () ->
listen s 10 ;
s in
let handle ep channels addr =
let host = match ep with
| Ok data -> ( match data.Tls.Core.own_name with
| Some n -> Domain_name.to_string n
| None -> "no name" )
| Error () -> "no session"
in
async @@ fun () ->
Lwt.catch (fun () -> callback host channels addr >>= fun () -> yap ~tag "<- handler done")
(function
| Tls_lwt.Tls_alert a ->
yap ~tag @@ "handler: " ^ Tls.Packet.alert_type_to_string a
| exn -> yap ~tag "handler: exception" >>= fun () -> fail exn)
in
let ps = string_of_int port in
yap ~tag ("-> start @ " ^ ps ^ " (use `openssl s_client -connect host:" ^ ps ^ " -servername foo` (or -servername bar))") >>= fun () ->
let rec loop () =
let config = get_ok (Tls.Config.server ~certificates:(`Multiple [barcert ; foocert]) ()) in
server_s >>= fun s ->
Tls_lwt.Unix.accept config s >>= fun (t, addr) ->
yap ~tag "-> connect" >>= fun () ->
( handle (Tls_lwt.Unix.epoch t) (Tls_lwt.of_t t) addr ; loop () )
in
loop ()
let echo_server port =
serve_ssl port @@ fun host (ic, oc) _addr ->
lines ic |> Lwt_stream.iter_s (fun line ->
yap ~tag:("handler " ^ host) ("+ " ^ line) >>= fun () ->
Lwt_io.write_line oc line)
let () =
let port =
try int_of_string Sys.argv.(1) with _ -> 4433
in
Lwt_main.run (echo_server port)

View file

@ -0,0 +1,55 @@
open Lwt
let o f g x = f (g x)
let ca_cert_dir = "./certificates"
let server_cert = "./certificates/server.pem"
let server_key = "./certificates/server.key"
let server_ec_cert = "./certificates/server-ec.pem"
let server_ec_key = "./certificates/server-ec.key"
let yap ~tag msg = Lwt_io.printf "(%s %s)\n%!" tag msg
let lines ic =
Lwt_stream.from @@ fun () ->
Lwt_io.read_line_opt ic >>= function
| None -> Lwt_io.close ic >>= fun () -> return_none
| line -> return line
let print_alert where alert =
Printf.eprintf "(TLS ALERT (%s): %s)\n%!"
where (Tls.Packet.alert_type_to_string alert)
let print_fail where fail =
Printf.eprintf "(TLS FAIL (%s): %s)\n%!"
where (Tls.Engine.string_of_failure fail)
let null_auth ?ip:_ ~host:_ _ = Ok None
let auth ?ca ?fp () =
match ca with
| Some "NONE" when fp = None -> Lwt.return null_auth
| _ ->
let a = match ca, fp with
| None, Some fp -> `Hex_key_fingerprint (`SHA256, fp)
| None, _ -> `Ca_dir ca_cert_dir
| Some f, _ -> `Ca_file f
in
X509_lwt.authenticator a
let setup_log style_renderer level =
Fmt_tty.setup_std_outputs ?style_renderer ();
Logs.set_level level;
Logs.set_reporter (Logs_fmt.reporter ~dst:Format.std_formatter ())
open Cmdliner
let setup_log =
Term.(const setup_log
$ Fmt_cli.style_renderer ()
$ Logs_cli.level ())
let get_ok = function
| Ok cfg -> cfg
| Error `Msg msg -> invalid_arg msg

View file

@ -0,0 +1,101 @@
open Lwt
open Ex_common
let string_of_unix_err err f p =
Printf.sprintf "Unix_error (%s, %s, %s)"
(Unix.error_message err) f p
let add_to_cache, find_in_cache =
let c = ref [] in
(fun ticket session ->
let id = ticket.Tls.Core.identifier in
Logs.info (fun m -> m "adding id %a to cache" Ohex.pp id) ;
c := (id, (ticket, session)) :: !c),
(fun id -> match List.find_opt (fun (id', _) -> String.compare id id' = 0) !c with
| None -> None
| Some (_, ep) -> Some ep)
let ticket_cache = {
Tls.Config.lookup = find_in_cache ;
ticket_granted = add_to_cache ;
lifetime = 300l ;
timestamp = Ptime_clock.now
}
let serve_ssl port callback =
let tag = "server" in
X509_lwt.private_of_pems
~cert:server_cert
~priv_key:server_key >>= fun cert ->
let server_s () =
let open Lwt_unix in
let s = socket PF_INET SOCK_STREAM 0 in
setsockopt s SO_REUSEADDR true ;
bind s (ADDR_INET (Unix.inet_addr_any, port)) >|= fun () ->
listen s 10 ;
s in
let handle channels addr =
async @@ fun () ->
Lwt.catch (fun () -> callback channels addr >>= fun () -> yap ~tag "<- handler done")
(function
| Tls_lwt.Tls_alert a ->
yap ~tag @@ "handler: " ^ Tls.Packet.alert_type_to_string a
| Tls_lwt.Tls_failure a ->
yap ~tag @@ "handler: " ^ Tls.Engine.string_of_failure a
| Unix.Unix_error (e, f, p) ->
yap ~tag @@ "handler: " ^ (string_of_unix_err e f p)
| _exn -> yap ~tag "handler: exception")
in
yap ~tag ("-> start @ " ^ string_of_int port) >>= fun () ->
let rec loop s =
let config = get_ok (Tls.Config.server ~ticket_cache ~reneg:true ~certificates:(`Single cert) ~version:(`TLS_1_2, `TLS_1_3) ~zero_rtt:32768l ()) in
(Lwt.catch
(fun () -> Tls_lwt.Unix.accept config s >|= fun r -> `R r)
(function
| Unix.Unix_error (e, f, p) -> return (`L (string_of_unix_err e f p))
| Tls_lwt.Tls_alert a -> return (`L (Tls.Packet.alert_type_to_string a))
| Tls_lwt.Tls_failure f -> return (`L (Tls.Engine.string_of_failure f))
| exn -> let str = Printexc.to_string exn in return (`L ("loop: exception " ^ str)))) >>= function
| `R (t, addr) ->
let channels = Tls_lwt.of_t t in
yap ~tag "-> connect" >>= fun () -> ( handle channels addr ; loop s )
| `L (msg) ->
yap ~tag ("server socket: " ^ msg) >>= fun () -> loop s
in
server_s () >>= fun s ->
loop s
let echo_server port =
serve_ssl port @@ fun (ic, oc) _addr ->
yap ~tag:"handler" "accepted" >>= fun () ->
let out = "HTTP/1.1 404 Not Found\r\n\r\n" in
Lwt_io.write_from_string_exactly oc out 0 (String.length out) >>= fun () ->
(* Lwt_io.close oc *)
let rec loop () =
Lwt_io.read_line ic >>= fun line ->
yap ~tag:"handler" ("+ " ^ line) >>= fun () ->
loop ()
in
loop ()
let jump _ port =
Lwt_main.run (echo_server port)
open Cmdliner
let port =
let doc = "Port to connect to" in
Arg.(value & opt int 4433 & info [ "port" ] ~doc)
let cmd =
let term = Term.(ret (const jump $ setup_log $ port))
and info = Cmd.info "fuzz_server" ~version:"2.0.3"
in
Cmd.v info term
let () = exit (Cmd.eval cmd)

View file

@ -0,0 +1,29 @@
open Lwt
open Ex_common
let http_client ?ca ?fp hostname port =
let port = int_of_string port in
auth ?ca ?fp () >>= fun authenticator ->
Tls_lwt.connect_ext
(get_ok (Tls.Config.client ~authenticator ()))
(hostname, port) >>= fun (ic, oc) ->
let req = String.concat "\r\n" [
"GET / HTTP/1.1" ; "Host: " ^ hostname ; "Connection: close" ; "" ; ""
] in
Lwt_io.(write oc req >>= fun () -> read ic >>= print >>= fun () -> printf "++ done.\n%!")
let () =
try
match Sys.argv with
| [| _ ; host ; port ; "FP" ; fp |] -> Lwt_main.run (http_client host port ~fp)
| [| _ ; host ; port ; trust |] -> Lwt_main.run (http_client host port ~ca:trust)
| [| _ ; host ; port |] -> Lwt_main.run (http_client host port)
| [| _ ; host |] -> Lwt_main.run (http_client host "443")
| args -> Printf.eprintf "%s <host> <port>\n%!" args.(0)
with
| Tls_lwt.Tls_alert alert as exn ->
print_alert "remote end" alert ; raise exn
| Tls_lwt.Tls_failure fail as exn ->
print_fail "our end" fail ; raise exn

View file

@ -0,0 +1,39 @@
open Lwt
open Ex_common
let http_client ?ca ?fp hostname port =
let port = int_of_string port in
auth ?ca ?fp () >>= fun authenticator ->
let config = get_ok (Tls.Config.client ~authenticator ()) in
Tls_lwt.Unix.connect config (hostname, port) >>= fun t ->
Tls_lwt.Unix.write t "foo\n" >>= fun () ->
let cs = Bytes.create 4 in
Tls_lwt.Unix.read t cs >>= fun _len ->
let cached_session = match Tls_lwt.Unix.epoch t with
| Ok e -> e
| Error () -> invalid_arg "error retrieving epoch"
in
Tls_lwt.Unix.close t >>= fun () ->
Printf.printf "closed session\n" ;
let config = get_ok (Tls.Config.client ~authenticator ~cached_session ()) in
Tls_lwt.connect_ext config (hostname, port) >>= fun (ic, oc) ->
let req = String.concat "\r\n" [
"GET / HTTP/1.1" ; "Host: " ^ hostname ; "Connection: close" ; "" ; ""
] in
Lwt_io.(write oc req >>= fun () -> read ic >>= print >>= fun () -> printf "++ done.\n%!")
let () =
try
match Sys.argv with
| [| _ ; host ; port ; "FP" ; fp |] -> Lwt_main.run (http_client host port ~fp)
| [| _ ; host ; port ; trust |] -> Lwt_main.run (http_client host port ~ca:trust)
| [| _ ; host ; port |] -> Lwt_main.run (http_client host port)
| [| _ ; host |] -> Lwt_main.run (http_client host "443")
| args -> Printf.eprintf "%s <host> <port>\n%!" args.(0)
with
| Tls_lwt.Tls_alert alert as exn ->
print_alert "remote end" alert ; raise exn
| Tls_lwt.Tls_failure fail as exn ->
print_fail "our end" fail ; raise exn

View file

@ -0,0 +1,123 @@
open Lwt
open Ex_common
let string_of_unix_err err f p =
Printf.sprintf "Unix_error (%s, %s, %s)"
(Unix.error_message err) f p
module HT = Hashtbl.Make (Tls.Core.PreSharedKeyID)
let cache_psk, psk_cache =
let cache = HT.create 7 in
((fun psk ed -> HT.add cache psk.Tls.Core.identifier (psk, ed)),
HT.find_opt cache)
let ticket_cache = {
Tls.Config.lookup = psk_cache ;
ticket_granted = cache_psk ;
lifetime = 300l ;
timestamp = Ptime_clock.now
}
let serve_ssl port callback =
let tag = "server" in
X509_lwt.private_of_pems
~cert:server_cert
~priv_key:server_key >>= fun cert ->
let hex = Ohex.decode in
let epoch =
{
Tls.Core.side = `Client ;
state = `Established ;
protocol_version = `TLS_1_3 ;
ciphersuite = `DHE_RSA_WITH_AES_128_GCM_SHA256 ;
peer_random = hex "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" ;
peer_certificate_chain = [] ;
peer_certificate = None ;
peer_name = None ;
trust_anchor = None ;
received_certificates = [] ;
own_random = hex "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" ;
own_certificate = fst cert ;
own_private_key = Some (snd cert) ;
own_name = Some Domain_name.(host_exn (of_string_exn "tls13test.nqsb.io")) ;
master_secret = hex "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" ;
exporter_master_secret = "" ;
session_id = "" ;
extended_ms = true ;
alpn_protocol = None ;
tls_unique = None ;
}
and psk = {
Tls.Core.identifier = hex "0000" ;
obfuscation = Randomconv.int32 Mirage_crypto_rng.generate ;
secret = hex "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" ;
lifetime = 300l ;
early_data = 0l ;
issued_at = Ptime_clock.now ();
}
in
cache_psk psk epoch ;
let server_s () =
let open Lwt_unix in
let s = socket PF_INET SOCK_STREAM 0 in
setsockopt s SO_REUSEADDR true ;
bind s (ADDR_INET (Unix.inet_addr_any, port)) >|= fun () ->
listen s 10 ;
s in
let handle channels =
async @@ fun () ->
Lwt.catch (fun () -> callback channels >>= fun () -> yap ~tag "<- handler done")
(function
| Tls_lwt.Tls_alert a ->
yap ~tag @@ "handler: " ^ Tls.Packet.alert_type_to_string a
| Tls_lwt.Tls_failure a ->
yap ~tag @@ "handler: " ^ Tls.Engine.string_of_failure a
| Unix.Unix_error (e, f, p) ->
yap ~tag @@ "handler: " ^ (string_of_unix_err e f p)
| _exn -> yap ~tag "handler: exception")
in
yap ~tag ("-> start @ " ^ string_of_int port) >>= fun () ->
let rec loop s =
let authenticator ?ip:_ ~host:_ _ = Ok None in
let config = get_ok (Tls.Config.server ~certificates:(`Single cert) ~ticket_cache ~authenticator ()) in
(Lwt.catch
(fun () ->
Lwt_unix.accept s >>= fun (s, addr) ->
let txt = Unix.(match addr with
| ADDR_UNIX x -> "unix-" ^ x
| ADDR_INET (ip, p) -> string_of_inet_addr ip ^ ":" ^ string_of_int p)
in
yap ~tag:"client-connect" txt >>= fun () ->
Tls_lwt.Unix.server_of_fd config s >|= fun t -> `R t)
(function
| Unix.Unix_error (e, f, p) -> return (`L (string_of_unix_err e f p))
| Tls_lwt.Tls_alert a -> return (`L (Tls.Packet.alert_type_to_string a))
| Tls_lwt.Tls_failure f -> return (`L (Tls.Engine.string_of_failure f))
| exn -> let str = Printexc.to_string exn in return (`L ("loop: exception " ^ str)))) >>= function
| `R t ->
yap ~tag "-> connect" >>= fun () ->
handle (Tls_lwt.of_t t); loop s
| `L msg ->
yap ~tag ("server socket: " ^ msg) >>= fun () -> loop s
in
server_s () >>= fun s ->
loop s
let echo_server port =
serve_ssl port @@ fun (ic, oc) ->
lines ic |> Lwt_stream.iter_s (fun line ->
yap ~tag:"handler" ("+ " ^ string_of_int (String.length line)) >>= fun () ->
Lwt_io.write_line oc line)
let () =
let port =
try int_of_string Sys.argv.(1) with _ -> 4433
in
Lwt_main.run (echo_server port)

View file

@ -0,0 +1,74 @@
open Lwt.Infix
open Ex_common
let capability = "[CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE STARTTLS AUTH=PLAIN] server ready.\r\n"
let ok_starttls = "OK STARTTLS\r\n"
let cert () =
X509_lwt.private_of_pems
~cert:"./certificates/server.pem"
~priv_key:"./certificates/server.key"
let init_socket addr port =
let sockaddr = Unix.ADDR_INET (Unix.inet_addr_of_string addr, port) in
let socket = Lwt_unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
Lwt_unix.setsockopt socket Unix.SO_REUSEADDR true;
Lwt_unix.bind socket sockaddr >|= fun () ->
socket
let create_srv_socket addr port =
init_socket addr port >|= fun socket ->
Lwt_unix.listen socket 10;
socket
let accept sock =
Lwt_unix.accept sock >>= fun (sock_cl, addr) ->
let ic = Lwt_io.of_fd ~close:(fun () -> Lwt.return_unit) ~mode:Lwt_io.input sock_cl in
let oc = Lwt_io.of_fd ~close:(fun () -> Lwt.return_unit) ~mode:Lwt_io.output sock_cl in
Lwt.return ((ic,oc), addr, sock_cl)
let start_server () =
let write oc buff =
Lwt_io.write oc buff >>= fun () -> Lwt_io.flush oc
in
let read ic =
Lwt_io.read ic ~count:2048 >>= fun buff ->
Printf.printf "%s%!" buff;
Lwt.return buff
in
let parse buff =
match String.index buff ' ' with
| exception Not_found -> "", ""
| idx ->
let l = String.length buff in
String.sub buff 0 idx, String.sub buff (succ idx) (l - succ idx)
in
let rec wait_cmd sock_cl ic oc =
read ic >>= fun buff ->
let tag,cmd = parse buff in
match cmd with
| "CAPABILITY" ->
write oc ("* " ^ capability ^ tag ^ " OK CAPABILITY\r\n") >>= fun () ->
wait_cmd sock_cl ic oc
| "STARTTLS" ->
write oc (tag ^ ok_starttls) >>= fun () ->
Lwt_io.close ic >>= fun () ->
Lwt_io.close oc >>= fun () ->
cert () >>= fun cert ->
Tls_lwt.Unix.server_of_fd
(get_ok (Tls.Config.server ~certificates:(`Single cert) ())) sock_cl >>= fun s ->
let ic,oc = Tls_lwt.of_t s in
write oc ("* OK " ^ capability) >>= fun () ->
wait_cmd sock_cl ic oc
| _ ->
write oc ("BAD\r\n") >>= fun () ->
wait_cmd sock_cl ic oc
in
create_srv_socket "127.0.0.1" 143 >>= fun sock ->
accept sock >>= fun ((ic,oc), _addr, sock_cl) ->
write oc ("* OK " ^ capability) >>= fun () ->
wait_cmd sock_cl ic oc
let () =
Lwt_main.run (start_server ())

View file

@ -0,0 +1,49 @@
open Lwt
open Ex_common
let mypsk = ref None
let ticket_cache = {
Tls.Config.lookup = (fun _ -> None) ;
ticket_granted = (fun psk epoch -> mypsk := Some (psk, epoch)) ;
lifetime = 0l ;
timestamp = Ptime_clock.now
}
let test_client _ =
(* X509_lwt.private_of_pems
~cert:server_cert
~priv_key:server_key >>= fun cert -> *)
let port = 4433 in
let host = "127.0.0.1" in
let authenticator = null_auth in
Tls_lwt.Unix.connect
(get_ok Tls.Config.(client ~version:(`TLS_1_0, `TLS_1_3) (* ~certificates:(`Single cert) *) ?cached_ticket:!mypsk ~ticket_cache ~authenticator ~ciphers:Ciphers.supported ()))
(host, port) >>= fun t ->
let (ic, oc) = Tls_lwt.of_t t in
let req = String.concat "\r\n" [
"GET / HTTP/1.1" ; "Host: " ^ host ; "Connection: close" ; "" ; ""
] in
Lwt_io.(write oc req >>= fun () ->
read ~count:3 ic >>= print >>= fun () ->
close oc >>= fun () ->
printf "++ done.\n%!")
let jump _ =
try
Lwt_main.run (test_client ()) ; `Ok ()
with
| Tls_lwt.Tls_alert alert as exn ->
print_alert "remote end" alert ; raise exn
| Tls_lwt.Tls_failure alert as exn ->
print_fail "our end" alert ; raise exn
open Cmdliner
let cmd =
let term = Term.(ret (const jump $ setup_log))
and info = Cmd.info "test_client" ~version:"2.0.3"
in
Cmd.v info term
let () = exit (Cmd.eval cmd)

View file

@ -0,0 +1,47 @@
open Lwt
open Ex_common
let serve_ssl port callback =
let tag = "server" in
X509_lwt.private_of_pems
~cert:server_cert
~priv_key:server_key >>= fun certificate ->
X509_lwt.private_of_pems
~cert:server_ec_cert
~priv_key:server_ec_key >>= fun ec_certificate ->
let certificates = `Multiple [ certificate ; ec_certificate ] in
let config =
get_ok (Tls.Config.(server ~version:(`TLS_1_0, `TLS_1_3) ~certificates ~ciphers:Ciphers.supported ()))
in
let server_s =
let open Lwt_unix in
let s = socket PF_INET SOCK_STREAM 0 in
setsockopt s Unix.SO_REUSEADDR true ;
bind s (ADDR_INET (Unix.inet_addr_any, port)) >|= fun () ->
listen s 10 ;
s in
yap ~tag ("-> start @ " ^ string_of_int port) >>= fun () ->
server_s >>= fun s ->
Tls_lwt.Unix.accept config s >>= fun (t, addr) ->
let channels = Tls_lwt.of_t t in
yap ~tag "-> connect" >>= fun () ->
callback channels addr >>= fun () ->
yap ~tag "<- handler done"
let test_server port =
serve_ssl port @@ fun (ic, oc) _addr ->
yap ~tag:"handler" "accepted" >>= fun () ->
Lwt_io.read_line ic >>= fun line ->
yap ~tag:"handler" ("+ " ^ line) >>= fun () ->
Lwt_io.write_line oc line
let () =
let port =
try int_of_string Sys.argv.(1) with _ -> 4433
in
Lwt_main.run (test_server port)

View file

@ -0,0 +1,70 @@
open Lwt
open Ex_common
let hostname = "mirage.io"
let proxy = "127.0.0.1", 3129
(* To test TLS-over-TLS, the `squid` proxy can be installed locally and configured to support HTTPS:
- Generate a certificate for localhost: https://gist.github.com/cecilemuller/9492b848eb8fe46d462abeb26656c4f8
$ openssl req -x509 -nodes -new -sha256 -days 1024 -newkey rsa:2048 -keyout RootCA.key -out RootCA.pem -subj "/C=US/CN=Example-Root-CA"
$ openssl x509 -outform pem -in RootCA.pem -out RootCA.crt
$ cat <<EOF > domains.ext
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
EOF
$ openssl req -new -nodes -newkey rsa:2048 -keyout localhost.key -out localhost.csr -subj "/C=US/ST=YourState/L=YourCity/O=Example-Certificates/CN=localhost.local"
$ openssl x509 -req -sha256 -days 1024 -in localhost.csr -CA RootCA.pem -CAkey RootCA.key -CAcreateserial -extfile domains.ext -out localhost.crt
- Configure squid by adding HTTPS support on port 3129 in /etc/squid/squid.conf :
https_port 3129 tls-cert=/path/to/localhost.crt tls-key=/path/to/localhost.key
*)
let client = get_ok (Tls.Config.client ~authenticator:null_auth ())
let string_prefix ~prefix msg =
let len = String.length prefix in
String.length msg >= len && String.sub msg 0 len = prefix
let host = Result.get_ok (Domain_name.of_string hostname)
let host = Result.get_ok (Domain_name.host host)
let test_client _ =
(* Connect to proxy *)
Tls_lwt.Unix.connect client proxy >>= fun t ->
let (ic, oc) = Tls_lwt.of_t t in
(* Request proxy to connect to hostname *)
let req =
Printf.sprintf "CONNECT %s:443 HTTP/1.1\r\nHost: %s\r\n\r\n"
hostname hostname
in
Lwt_io.write oc req >>= fun () ->
Lwt_io.read ic ~count:1024 >>= fun msg ->
assert (string_prefix ~prefix:"HTTP/1.1 200 " msg) ;
(* TLS with hostname, over the TLS connection with the proxy *)
Tls_lwt.Unix.client_of_channels client ~host (ic, oc) >>= fun t ->
let (ic, oc) = Tls_lwt.of_t t in
(* Request homepage from host *)
let req =
Printf.sprintf "GET / HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n"
hostname
in
Lwt_io.(write oc req >>= fun () ->
read ~count:1024 ic >>= print >>= fun () ->
read ~count:1024 ic >>= print >>= fun () ->
close oc >>= fun () ->
printf "++ done.\n%!")
let () = Lwt_main.run (test_client ())