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