Source file x509_async.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
open! Core
open! Async
let file_contents file =
Deferred.Or_error.try_with ~name:(sprintf "read %s" file) (fun () ->
Reader.file_contents file)
;;
let load_all_in_directory ~directory ~f =
let open Deferred.Or_error.Let_syntax in
let%bind files = Deferred.Or_error.try_with (fun () -> Sys.ls_dir directory) in
Deferred.Or_error.List.map ~how:`Sequential files ~f:(fun file ->
let%bind contents = file_contents (directory ^/ file) in
f ~contents)
;;
module Or_error = struct
include Or_error
let of_result ~to_string = Result.map_error ~f:(Fn.compose Error.of_string to_string)
let of_result_msg x = of_result x ~to_string:(fun (`Msg msg) -> msg)
let lift_result_msg_of_string f ~contents =
f contents |> of_result_msg
;;
let lift_asn_error_of_string f ~contents =
f contents |> of_result ~to_string:(fun (`Parse msg) -> msg)
;;
end
module CRL = struct
include X509.CRL
let decode_der = Or_error.lift_result_msg_of_string decode_der
let revoke ?digest ~issuer ~this_update ?next_update ?extensions revoked_certs key =
revoke ?digest ~issuer ~this_update ?next_update ?extensions revoked_certs key
|> Or_error.of_result_msg
;;
let revoke_certificate revoked ~this_update ?next_update crl key =
revoke_certificate revoked ~this_update ?next_update crl key |> Or_error.of_result_msg
;;
let revoke_certificates revoked ~this_update ?next_update crl key =
revoke_certificates revoked ~this_update ?next_update crl key
|> Or_error.of_result_msg
;;
let of_pem_dir ~directory =
load_all_in_directory ~directory ~f:(fun ~contents ->
decode_der ~contents |> Deferred.return)
;;
end
module Certificate = struct
include X509.Certificate
open Deferred.Or_error.Let_syntax
let decode_pem_multiple = Or_error.lift_result_msg_of_string decode_pem_multiple
let decode_pem = Or_error.lift_result_msg_of_string decode_pem
let decode_der = Or_error.lift_result_msg_of_string decode_der
let of_pem_file ca_file =
let%bind contents = file_contents ca_file in
decode_pem_multiple ~contents |> Deferred.return
;;
let of_pem_directory ~directory =
load_all_in_directory ~directory ~f:(fun ~contents ->
decode_pem_multiple ~contents |> Deferred.return)
>>| List.concat
;;
end
module Authenticator = struct
include X509.Authenticator
module Param = struct
module Chain_of_trust = struct
type t =
{ trust_anchors : [ `File of Filename.t | `Directory of Filename.t ]
; allowed_hashes : Digestif.hash' list option
; crls : Filename.t option
}
let to_certs = function
| `File file -> Certificate.of_pem_file file
| `Directory directory -> Certificate.of_pem_directory ~directory
;;
end
type t =
| Chain_of_trust of Chain_of_trust.t
| Cert_fingerprint of Digestif.hash' * string
| Key_fingerprint of Digestif.hash' * string
let ca_file ?allowed_hashes ?crls filename () =
let trust_anchors = `File filename in
Chain_of_trust { trust_anchors; allowed_hashes; crls }
;;
let ca_dir ?allowed_hashes ?crls directory_name () =
let trust_anchors = `Directory directory_name in
Chain_of_trust { trust_anchors; allowed_hashes; crls }
;;
let cert_fingerprint hash fingerprint = Cert_fingerprint (hash, fingerprint)
let key_fingerprint hash fingerprint = Key_fingerprint (hash, fingerprint)
let cleanup_fingerprint fingerprint =
let known_delimiters = [ ':'; ' ' ] in
String.filter fingerprint ~f:(fun c ->
not (List.exists known_delimiters ~f:(Char.equal c)))
|> Ohex.decode
;;
let of_cas ~time ({ trust_anchors; allowed_hashes; crls } : Chain_of_trust.t) =
let open Deferred.Or_error.Let_syntax in
let%bind cas = Chain_of_trust.to_certs trust_anchors in
let%map crls =
match crls with
| Some directory ->
let%map crls = CRL.of_pem_dir ~directory in
Some crls
| None -> return None
in
X509.Authenticator.chain_of_trust ?allowed_hashes ?crls ~time cas
;;
let of_cert_fingerprint ~time hash fingerprint =
let fingerprint = cleanup_fingerprint fingerprint in
X509.Authenticator.cert_fingerprint ~time ~hash ~fingerprint
;;
let of_key_fingerprint ~time hash fingerprint =
let fingerprint = cleanup_fingerprint fingerprint in
X509.Authenticator.key_fingerprint ~time ~hash ~fingerprint
;;
let time = Fn.compose Ptime.of_float_s Unix.gettimeofday
let to_authenticator ~time param =
match param with
| Chain_of_trust chain_of_trust -> of_cas ~time chain_of_trust
| Cert_fingerprint (hash, fingerprint) ->
of_cert_fingerprint ~time hash fingerprint |> Deferred.Or_error.return
| Key_fingerprint (hash, fingerprint) ->
of_key_fingerprint ~time hash fingerprint |> Deferred.Or_error.return
;;
end
end
module Distinguished_name = struct
include X509.Distinguished_name
let decode_der = Or_error.lift_result_msg_of_string decode_der
end
module OCSP = struct
include X509.OCSP
module Request = struct
include Request
let create ?certs ?digest ?requestor_name ?key cert_ids =
create ?certs ?digest ?requestor_name ?key cert_ids |> Or_error.of_result_msg
;;
let decode_der = Or_error.lift_asn_error_of_string decode_der
end
module Response = struct
include Response
let create_success
?digest
?certs
?response_extensions
private_key
responderID
producedAt
responses
=
create_success
?digest
?certs
?response_extensions
private_key
responderID
producedAt
responses
|> Or_error.of_result_msg
;;
let responses t = responses t |> Or_error.of_result_msg
let decode_der = Or_error.lift_asn_error_of_string decode_der
end
end
module PKCS12 = struct
include X509.PKCS12
let decode_der = Or_error.lift_result_msg_of_string decode_der
let verify password t = verify password t |> Or_error.of_result_msg
end
module Private_key = struct
include X509.Private_key
let sign hash ?scheme key data =
sign hash ?scheme key data
|> Or_error.of_result_msg
;;
let decode_der = Or_error.lift_result_msg_of_string decode_der
let decode_pem = Or_error.lift_result_msg_of_string decode_pem
let of_pem_file file =
let%map contents = Reader.file_contents file in
decode_pem ~contents
;;
end
module Public_key = struct
include X509.Public_key
let verify hash ?scheme ~signature key data =
verify hash ?scheme ~signature key data |> Or_error.of_result_msg
;;
let decode_der = Or_error.lift_result_msg_of_string decode_der
let decode_pem = Or_error.lift_result_msg_of_string decode_pem
end
module Signing_request = struct
include X509.Signing_request
let decode_der ?allowed_hashes der =
decode_der ?allowed_hashes der |> Or_error.of_result_msg
;;
let decode_pem pem = decode_pem pem |> Or_error.of_result_msg
let create subject ?digest ?extensions key =
create subject ?digest ?extensions key |> Or_error.of_result_msg
;;
let sign
?allowed_hashes
?digest
?serial
?extensions
t
key
issuer
~valid_from
~valid_until
=
sign ?allowed_hashes ?digest ?serial ?extensions t key issuer ~valid_from ~valid_until
|> Or_error.of_result ~to_string:(Fmt.to_to_string X509.Validation.pp_signature_error)
;;
end
module Extension = X509.Extension
module General_name = X509.General_name
module Host = X509.Host
module Key_type = X509.Key_type
module Validation = X509.Validation