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
open Conex_utils
open Conex_resource

type verification_error = [
  | `InvalidBase64Encoding
  | `InvalidSignature
  | `InvalidPublicKey
]

(*BISECT-IGNORE-BEGIN*)
let pp_verification_error ppf = function
  | `InvalidBase64Encoding -> Format.fprintf ppf "signature: no valid base64 encoding"
  | `InvalidSignature -> Format.fprintf ppf "signature: invalid"
  | `InvalidPublicKey -> Format.fprintf ppf "invalid public key"
(*BISECT-IGNORE-END*)

module type VERIFY_BACK = sig
  val verify_rsa_pss : key:string -> data:string -> signature:string -> (unit, [> verification_error ]) result

  val b64sha256 : string -> string
end

module type VERIFY = sig
  val raw_digest : string -> Digest.t

  val digest : Wire.t -> Digest.t

  val keyid : identifier -> Key.t -> Digest.t

  val verify : Author.t -> (unit, [> verification_error ]) result
end

(** Instantiation. *)
module Make_verify (C : VERIFY_BACK) = struct

  let raw_digest data = `SHA256, C.b64sha256 data

  let digest data =
    raw_digest (Wire.to_string data)

  let keyid id k = digest (Key.wire id k)

  let verify_signature data name key (hdr, sigval) =
    let data = Signature.wire name hdr data in
    let key = match key with `RSA, k, _ -> k in
    C.verify_rsa_pss ~key ~data:(Wire.to_string data) ~signature:sigval

  let verify author =
    let tbv = Wire.to_string (Author.wire_raw author) in
    foldM
      (fun () (k, s) -> verify_signature tbv author.Author.name k s)
      () author.Author.keys
end

module type SIGN_BACK = sig
  val pub_of_priv_rsa : string -> (string, string) result

  val bits_rsa : string -> (int, string) result

  val generate_rsa : ?bits:int -> unit -> string

  val sign_rsa_pss : key:string -> string -> (string, string) result
end

module type SIGN = sig
  val generate : ?bits:int -> Uint.t -> unit -> Key.priv

  val pub_of_priv : Key.priv -> (Key.t, string) result

  val bits : Key.t -> (int, string) result

  val sign : Uint.t -> Author.t -> Key.priv -> (Author.t, string) result
end

module Make_sign (C : SIGN_BACK) = struct
  let generate ?bits time () =
    let key = C.generate_rsa ?bits () in
    `Priv (`RSA, key, time)

  let pub_of_priv key = match key with
    | `Priv (`RSA, key, created) ->
      C.pub_of_priv_rsa key >>= fun pub ->
      Ok (`RSA, String.trim pub, created)

  let bits = function
    | `RSA, key, _ -> C.bits_rsa key

  let sign now idx priv =
    let idx, _overflow = Author.prep_sig idx in
    let data = Wire.to_string (Author.wire_raw idx)
    and id = idx.Author.name
    in
    let hdr = `RSA_PSS_SHA256, now in
    let data = Wire.to_string (Signature.wire id hdr data) in
    (match priv with
     | `Priv (`RSA, key, _) -> C.sign_rsa_pss ~key data) >>= fun signature ->
    pub_of_priv priv >>= fun key ->
    Ok (Author.replace_sig idx (key, (hdr, signature)))
end