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)