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
open Eio.Std
module Path = Eio.Path
let (</>) = Path.( / )
let extension str =
let n = String.length str in
let rec scan = function
| i when i = 0 -> None
| i when str.[i - 1] = '.' ->
Some (String.sub str i (n - i))
| i -> scan (pred i) in
scan n
let private_of_pems ~cert ~priv_key =
let certs =
try
let pem = Path.load cert in
match X509.Certificate.decode_pem_multiple pem with
| Ok cs -> cs
| Error (`Msg m) -> invalid_arg ("failed to parse certificates " ^ m)
with Invalid_argument m ->
Fmt.failwith "Private certificates %a: %s" Path.pp cert m
in
let pk =
try
let pem = Path.load priv_key in
match X509.Private_key.decode_pem pem with
| Ok key -> key
| Error (`Msg m) -> invalid_arg ("failed to parse private key " ^ m)
with Invalid_argument m ->
Fmt.failwith "Private key (%a): %s" Path.pp priv_key m
in
(certs, pk)
let certs_of_pem path =
try
let pem = Path.load path in
match X509.Certificate.decode_pem_multiple pem with
| Ok cs -> cs
| Error (`Msg m) -> invalid_arg ("failed to parse certificates " ^ m)
with Invalid_argument m ->
Fmt.failwith "Certificates in %a: %s" Path.pp path m
let certs_of_pem_dir path =
Path.read_dir path
|> List.filter (fun file -> extension file = Some "crt")
|> Fiber.List.map (fun file -> certs_of_pem (path </> file))
|> List.concat
let crl_of_pem path =
try
let data = Path.load path in
match X509.CRL.decode_der data with
| Ok cs -> cs
| Error (`Msg m) -> invalid_arg ("failed to parse CRL " ^ m)
with Invalid_argument m ->
Fmt.failwith "CRL in %a: %s" Path.pp path m
let crls_of_pem_dir path =
Path.read_dir path
|> Fiber.List.map (fun file -> crl_of_pem (path </> file))
let authenticator ?allowed_hashes ?crls param =
let time () = Some (Ptime_clock.now ()) in
let of_cas cas =
let crls = Option.map crls_of_pem_dir crls in
X509.Authenticator.chain_of_trust ?allowed_hashes ?crls ~time cas
and dotted_hex_to_cs hex =
Cstruct.to_string (Cstruct.of_hex (String.map (function ':' -> ' ' | x -> x) hex))
and fingerp hash fingerprint =
X509.Authenticator.key_fingerprint ~time ~hash ~fingerprint
and cert_fingerp hash fingerprint =
X509.Authenticator.cert_fingerprint ~time ~hash ~fingerprint
in
match param with
| `Ca_file path -> certs_of_pem path |> of_cas
| `Ca_dir path -> certs_of_pem_dir path |> of_cas
| `Key_fingerprint (hash, fp) -> fingerp hash fp
| `Hex_key_fingerprint (hash, fp) ->
let fp = dotted_hex_to_cs fp in
fingerp hash fp
| `Cert_fingerprint (hash, fp) -> cert_fingerp hash fp
| `Hex_cert_fingerprint (hash, fp) ->
let fp = dotted_hex_to_cs fp in
cert_fingerp hash fp