Source file netsys_tls.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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
open Printf
module Debug = struct
let enable = ref false
end
let dlog = Netlog.Debug.mk_dlog "Netsys_tls" Debug.enable
let dlogr = Netlog.Debug.mk_dlogr "Netsys_tls" Debug.enable
let () =
Netlog.Debug.register_module "Netsys_tls" Debug.enable
type dh_params =
[ `PKCS3_PEM_file of string
| `PKCS3_DER of string
| `Generate of int
]
type crt_list =
[`PEM_file of string | `DER of string list]
type crl_list =
[`PEM_file of string | `DER of string list]
type private_key =
[ `PEM_file of string
| `RSA of string
| `DSA of string
| `EC of string
| `PKCS8 of string
| `PKCS8_encrypted of string
]
let debug_backtrace fn exn bt =
dlog (sprintf "Exception in function Netsys_tls.%s: %s - backtrace: %s"
fn (Netexn.to_string exn) bt
)
let error_message tls code =
let module P = (val tls : Netsys_crypto_types.TLS_PROVIDER) in
P.error_message code
let create_x509_config
?algorithms ?dh_params
?(verify = fun _ cert_ok name_ok -> cert_ok && name_ok)
?system_trust ?trust ?revoke ?keys
~peer_auth tls =
let module P = (val tls : Netsys_crypto_types.TLS_PROVIDER) in
let verify ep cert_ok name_ok =
let module EP = struct
module TLS = P
let endpoint = ep
end in
verify (module EP : Netsys_crypto_types.TLS_ENDPOINT) cert_ok name_ok in
try
let credentials =
P.create_x509_credentials ?system_trust ?trust ?revoke ?keys () in
let config =
P.create_config
?algorithms ?dh_params ~verify
~peer_auth ~credentials () in
let module Config = struct
module TLS = P
let config = config
end in
(module Config : Netsys_crypto_types.TLS_CONFIG)
with
| exn ->
if !Debug.enable then
debug_backtrace "create_x509_config" exn (Printexc.get_backtrace());
raise exn
let create_file_endpoint ?resume ~role ~rd ~wr ~peer_name config =
let module Config = (val config : Netsys_crypto_types.TLS_CONFIG) in
let module P = Config.TLS in
try
let recv buf =
let n = Netsys_mem.mem_recv rd buf 0 (Bigarray.Array1.dim buf) [] in
dlogr (fun () -> sprintf "Netsys_tls: Unix.recv n=%d" n);
n in
let send buf size =
let n = Netsys_mem.mem_send wr buf 0 size [] in
dlogr (fun () -> sprintf "Netsys_tls: Unix.send n=%d" n);
n in
let ep =
match resume with
| None ->
P.create_endpoint ~role ~recv ~send ~peer_name Config.config
| Some data ->
if role <> `Client then
failwith
"Netsys_tls.create_file_endpoint: can only resume clients";
P.resume_client ~recv ~send ~peer_name Config.config data in
let module Endpoint = struct
module TLS = P
let endpoint = ep
let rd_file = rd
let wr_file = wr
end in
(module Endpoint : Netsys_crypto_types.FILE_TLS_ENDPOINT)
with
| exn ->
if !Debug.enable then
debug_backtrace "create_file_endpoint"
exn (Printexc.get_backtrace());
raise exn
let at_transport_eof ep =
let module Endpoint =
(val ep : Netsys_crypto_types.TLS_ENDPOINT) in
let module P = Endpoint.TLS in
try
P.at_transport_eof Endpoint.endpoint
with
| exn ->
if !Debug.enable then
debug_backtrace "at_transport_eof" exn (Printexc.get_backtrace());
raise exn
let endpoint ep =
let module File_endpoint =
(val ep : Netsys_crypto_types.FILE_TLS_ENDPOINT) in
(module File_endpoint : Netsys_crypto_types.TLS_ENDPOINT)
let state_driven_action endpoint =
let module Endpoint =
(val endpoint : Netsys_crypto_types.TLS_ENDPOINT) in
let module P = Endpoint.TLS in
try
match P.get_state Endpoint.endpoint with
| `Start | `Handshake ->
dlog "Netsys_tls: hello";
P.hello Endpoint.endpoint;
dlog "Netsys_tls: verify";
P.verify Endpoint.endpoint
| `Accepting ->
dlog "Netsys_tls: accept_switch";
P.accept_switch Endpoint.endpoint (P.get_config Endpoint.endpoint)
| `Refusing ->
dlog "Netsys_tls: refuse_switch";
P.refuse_switch Endpoint.endpoint
| `Switching ->
dlog "Netsys_tls: switch";
P.switch Endpoint.endpoint (P.get_config Endpoint.endpoint);
dlog "Netsys_tls: hello";
P.hello Endpoint.endpoint;
dlog "Netsys_tls: verify";
P.verify Endpoint.endpoint
| _ ->
()
with
| P.Exc.EAGAIN_RD as exn ->
dlog "Netsys_tls: EAGAIN_RD"; raise exn
| P.Exc.EAGAIN_WR as exn ->
dlog "Netsys_tls: EAGAIN_WR"; raise exn
| exn ->
if !Debug.enable then
debug_backtrace "state_driven_action" exn (Printexc.get_backtrace());
raise exn
let handshake endpoint =
let module Endpoint =
(val endpoint : Netsys_crypto_types.TLS_ENDPOINT) in
let module P = Endpoint.TLS in
let state = P.get_state Endpoint.endpoint in
if state = `Start || state = `Handshake then
state_driven_action endpoint;
dlog "Netsys_tls: handshake done"
let mem_recv ?(on_rehandshake=fun _ -> true) endpoint buf pos len =
let module Endpoint =
(val endpoint : Netsys_crypto_types.TLS_ENDPOINT) in
let module P = Endpoint.TLS in
state_driven_action endpoint;
let buf' =
if pos=0 && len=Bigarray.Array1.dim buf then
buf
else
Bigarray.Array1.sub buf pos len in
try
dlog "Netsys_tls: recv";
let n = P.recv Endpoint.endpoint buf' in
dlogr (fun () -> sprintf "Netsys_tls: recv done (n=%d)" n);
n
with
| P.Exc.TLS_switch_request ->
if on_rehandshake endpoint then
P.accept_switch Endpoint.endpoint (P.get_config Endpoint.endpoint)
else
P.refuse_switch Endpoint.endpoint;
raise Netsys_types.EAGAIN_RD
| P.Exc.EAGAIN_RD as exn ->
dlog "Netsys_tls: EAGAIN_RD"; raise exn
| P.Exc.EAGAIN_WR as exn ->
dlog "Netsys_tls: EAGAIN_WR"; raise exn
| exn ->
if !Debug.enable then
debug_backtrace "mem_recv" exn (Printexc.get_backtrace());
raise exn
let recv ?on_rehandshake endpoint buf pos len =
let mem, return = Netsys_mem.pool_alloc_memory2 Netsys_mem.default_pool in
try
let mem_len = min len (Bigarray.Array1.dim mem) in
let n = mem_recv ?on_rehandshake endpoint mem 0 mem_len in
Netsys_mem.blit_memory_to_bytes mem 0 buf pos n;
return();
n
with
| exn -> return(); raise exn
let mem_send endpoint buf pos len =
let module Endpoint =
(val endpoint : Netsys_crypto_types.TLS_ENDPOINT) in
let module P = Endpoint.TLS in
state_driven_action endpoint;
let buf' =
if pos=0 then
buf
else
Bigarray.Array1.sub buf pos len in
try
dlog "Netsys_tls: send";
let n = P.send Endpoint.endpoint buf' len in
dlogr (fun () -> sprintf "Netsys_tls: send done (n=%d)" n);
n
with
| P.Exc.EAGAIN_RD as exn ->
dlog "Netsys_tls: EAGAIN_RD"; raise exn
| P.Exc.EAGAIN_WR as exn ->
dlog "Netsys_tls: EAGAIN_WR"; raise exn
| exn ->
if !Debug.enable then
debug_backtrace "mem_send" exn (Printexc.get_backtrace());
raise exn
let send endpoint buf pos len =
state_driven_action endpoint;
let mem, return = Netsys_mem.pool_alloc_memory2 Netsys_mem.default_pool in
try
let mem_len = min len (Bigarray.Array1.dim mem) in
Netsys_mem.blit_bytes_to_memory buf pos mem 0 mem_len;
let n = mem_send endpoint mem 0 mem_len in
return();
n
with
| exn -> return(); raise exn
let str_send endpoint buf pos len =
send endpoint (Bytes.unsafe_of_string buf) pos len
let shutdown endpoint how =
let module Endpoint =
(val endpoint : Netsys_crypto_types.TLS_ENDPOINT) in
let module P = Endpoint.TLS in
state_driven_action endpoint;
try
dlog "Netsys_tls: bye";
P.bye Endpoint.endpoint how;
dlog "Netsys_tls: bye done";
with
| P.Exc.EAGAIN_RD as exn ->
dlog "Netsys_tls: EAGAIN_RD"; raise exn
| P.Exc.EAGAIN_WR as exn ->
dlog "Netsys_tls: EAGAIN_WR"; raise exn
| exn ->
if !Debug.enable then
debug_backtrace "shutdown" exn (Printexc.get_backtrace());
raise exn