Source file conduit_lwt_unix_ssl.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# 1 "src/conduit-lwt-unix/conduit_lwt_unix_ssl.real.ml"
[@@@alert "-deprecated"]
open Lwt.Infix
let () = Ssl.init ()
let chans_of_fd sock =
let is_open = ref true in
let shutdown () =
if !is_open then Lwt_ssl.ssl_shutdown sock else Lwt.return_unit
in
let close () =
is_open := false;
Lwt_ssl.close sock
in
let oc =
Lwt_io.make ~mode:Lwt_io.output ~close:shutdown (Lwt_ssl.write_bytes sock)
in
let ic = Lwt_io.make ~mode:Lwt_io.input ~close (Lwt_ssl.read_bytes sock) in
(Lwt_ssl.get_fd sock, ic, oc)
module Client = struct
type context = Ssl.context
let create_ctx ?certfile ?keyfile ?password () =
let ctx = Ssl.create_context Ssl.SSLv23 Ssl.Client_context in
Ssl.disable_protocols ctx [ Ssl.SSLv23 ];
ignore (Ssl.set_default_verify_paths ctx);
Ssl.set_verify ctx [ Ssl.Verify_peer ] None;
(match (certfile, keyfile) with
| Some certfile, Some keyfile -> Ssl.use_certificate ctx certfile keyfile
| None, _ | _, None -> ());
(match password with
| Some password -> Ssl.set_password_callback ctx password
| None -> ());
ctx
let default_ctx = create_ctx ()
type verify = { hostname : bool; ip : bool }
let default_verify = { hostname = true; ip = false }
let validate_hostname host_addr =
try
let _ = Domain_name.(host_exn (of_string_exn host_addr)) in
host_addr
with Invalid_argument msg ->
let s =
Printf.sprintf "couldn't convert %s to a [`host] Domain_name.t: %s"
host_addr msg
in
invalid_arg s
let verification { hostname; ip } = function
| None, _ when hostname -> invalid_arg "impossible to verify hostname"
| _, None when ip -> invalid_arg "impossible to verify ip"
| h, i ->
let hostname =
if hostname && h <> None then Option.map validate_hostname h else None
in
let ip = if ip && i <> None then i else None in
(hostname, ip)
let connect ?(ctx = default_ctx) ?src ?hostname ?ip ?verify sa =
let verify = Option.value ~default:default_verify verify in
let to_verify = verification verify (hostname, ip) in
Conduit_lwt_server.with_socket sa (fun fd ->
(match src with
| None -> Lwt.return_unit
| Some src_sa -> Lwt_unix.bind fd src_sa)
>>= fun () ->
Lwt_unix.connect fd sa >>= fun () ->
let with_socket f =
let s = Lwt_ssl.embed_uninitialized_socket fd ctx in
let socket = Lwt_ssl.ssl_socket_of_uninitialized_socket s in
f socket;
Lwt_ssl.ssl_perform_handshake s
in
let maybe_verify ssl = function
| Some hostname, Some ip ->
Ssl.set_hostflags ssl [ Ssl.No_partial_wildcards ];
Ssl.set_client_SNI_hostname ssl hostname;
Ssl.set_host ssl hostname;
Ssl.set_ip ssl (Ipaddr.to_string ip)
| Some hostname, None ->
Ssl.set_hostflags ssl [ Ssl.No_partial_wildcards ];
Ssl.set_client_SNI_hostname ssl hostname;
Ssl.set_host ssl hostname
| None, Some ip -> Ssl.set_ip ssl (Ipaddr.to_string ip)
| None, None -> ()
in
with_socket (fun ssl -> maybe_verify ssl to_verify) >>= fun sock ->
Lwt.return (chans_of_fd sock))
end
module Server = struct
let default_ctx = Ssl.create_context Ssl.SSLv23 Ssl.Server_context
let () = Ssl.disable_protocols default_ctx [ Ssl.SSLv23 ]
let listen ?(ctx = default_ctx) ?backlog ?password ~certfile ~keyfile sa =
let fd = Conduit_lwt_server.listen ?backlog sa in
(match password with
| None -> ()
| Some fn -> Ssl.set_password_callback ctx fn);
Ssl.use_certificate ctx certfile keyfile;
fd
let init ?(ctx = default_ctx) ?backlog ?password ~certfile ~keyfile ?stop
?timeout sa cb =
sa
|> listen ~ctx ?backlog ?password ~certfile ~keyfile
>>= Conduit_lwt_server.init ?stop (fun (fd, addr) ->
Lwt.try_bind
(fun () -> Lwt_ssl.ssl_accept fd ctx)
(fun sock -> Lwt.return (chans_of_fd sock))
(fun exn -> Lwt_unix.close fd >>= fun () -> Lwt.reraise exn)
>>= Conduit_lwt_server.process_accept ?timeout (cb addr))
end
let available = true