let ( let* ) = Result.bind type t = ?ip:Ipaddr.t -> host:[`host] Domain_name.t option -> Certificate.t list -> Validation.r (* XXX * Authenticator just hands off a list of certs. Should be indexed. * *) let chain_of_trust ~time ?crls ?(allowed_hashes = Validation.sha2) cas = let revoked = match crls with | None -> None | Some crls -> Some (Crl.is_revoked crls ~allowed_hashes) in fun ?ip ~host certificates -> Validation.verify_chain_of_trust ?ip ~host ~time ?revoked ~allowed_hashes ~anchors:cas certificates let key_fingerprint ~time ~hash ~fingerprint = fun ?ip ~host certificates -> Validation.trust_key_fingerprint ?ip ~host ~time ~hash ~fingerprint certificates let cert_fingerprint ~time ~hash ~fingerprint = fun ?ip ~host certificates -> Validation.trust_cert_fingerprint ?ip ~host ~time ~hash ~fingerprint certificates let hash_of_string = function | "sha224" -> Ok `SHA224 | "sha256" -> Ok `SHA256 | "sha384" -> Ok `SHA384 | "sha512" -> Ok `SHA512 | hash -> Error (`Msg (Fmt.str "Unknown hash algorithm %S" hash)) let fingerprint_of_string s = let* d = Result.map_error (function `Msg m -> `Msg (Fmt.str "Invalid base64 encoding in fingerprint (%s): %S" m s)) (Base64.decode ~pad:false s) in Ok d let format = {| The format of an authenticator is: - [none]: no authentication - [key-fp(:?):]: to authenticate a peer via its key fingerprintf (hash is optional and defaults to SHA256) - [cert-fp(:?):]: to authenticate a peer via its certificate fingerprint (hash is optional and defaults to SHA256) - [trust-anchor(:)+] to authenticate a peer from a list of certificates (certificate must be in PEM format witthout header and footer (----BEGIN CERTIFICATE----) and without newlines). |} let of_string str = begin match String.split_on_char ':' str with | [ "key-fp" ; hash ; tls_key_fingerprint ] -> let* hash = hash_of_string (String.lowercase_ascii hash) in let* fingerprint = fingerprint_of_string tls_key_fingerprint in Ok (fun time -> key_fingerprint ~time ~hash ~fingerprint) | [ "key-fp" ; tls_key_fingerprint ] -> let* fingerprint = fingerprint_of_string tls_key_fingerprint in Ok (fun time -> key_fingerprint ~time ~hash:`SHA256 ~fingerprint) | [ "cert-fp" ; hash ; tls_cert_fingerprint ] -> let* hash = hash_of_string (String.lowercase_ascii hash) in let* fingerprint = fingerprint_of_string tls_cert_fingerprint in Ok (fun time -> cert_fingerprint ~time ~hash ~fingerprint) | [ "cert-fp" ; tls_cert_fingerprint ] -> let* fingerprint = fingerprint_of_string tls_cert_fingerprint in Ok (fun time -> cert_fingerprint ~time ~hash:`SHA256 ~fingerprint) | "trust-anchor" :: certs -> let* anchors = List.fold_left (fun acc s -> let* acc = acc in let* der = Base64.decode ~pad:false s in let* cert = Certificate.decode_der der in Ok (cert :: acc)) (Ok []) certs in Ok (fun time -> chain_of_trust ~time (List.rev anchors)) | [ "none" ] -> Ok (fun _ ?ip:_ ~host:_ _ -> Ok None) | _ -> Error (`Msg (Fmt.str "Invalid TLS authenticator: %S" str)) end |> Result.map_error (function `Msg e -> `Msg (e ^ format))