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
272
273
274
275
276
277
278
279
280
281
282
283
284
285
module Events = Signer_events
open Client_keys
open Signer_messages
let tcp_scheme = "tcp"
let unix_scheme = "unix"
module Make (P : sig
val authenticate :
Tezos_crypto.Signature.Public_key_hash.t list ->
Bytes.t ->
Tezos_crypto.Signature.t tzresult Lwt.t
end) =
struct
open P
type request_type =
| Sign_request
| Deterministic_nonce_request
| Deterministic_nonce_hash_request
let build_request pkh data signature = function
| Sign_request -> Request.Sign {Sign.Request.pkh; data; signature}
| Deterministic_nonce_request ->
Request.Deterministic_nonce
{Deterministic_nonce.Request.pkh; data; signature}
| Deterministic_nonce_hash_request ->
Request.Deterministic_nonce_hash
{Deterministic_nonce_hash.Request.pkh; data; signature}
let maybe_authenticate pkh msg conn =
let open Lwt_result_syntax in
let* () =
Tezos_base_unix.Socket.send conn Request.encoding Request.Authorized_keys
in
let* authorized_keys =
Tezos_base_unix.Socket.recv
conn
(result_encoding Authorized_keys.Response.encoding)
in
let* v = Lwt.return authorized_keys in
match v with
| No_authentication -> return_none
| Authorized_keys authorized_keys ->
let* signature =
authenticate authorized_keys (Sign.Request.to_sign ~pkh ~data:msg)
in
return_some signature
let with_signer_operation path pkh msg request_type enc =
let open Lwt_result_syntax in
let f () =
Tezos_base_unix.Socket.with_connection path (fun conn ->
let* signature = maybe_authenticate pkh msg conn in
let req = build_request pkh msg signature request_type in
let* () = Tezos_base_unix.Socket.send conn Request.encoding req in
Tezos_base_unix.Socket.recv conn (result_encoding enc))
in
let rec loop n =
let*! r = protect (fun () -> f ()) in
match r with
| Error trace as e
when List.exists
(function Exn Lwt_unix.Timeout -> true | _ -> false)
trace ->
if n = 0 then Lwt.return e
else
let*! () = Events.(emit Socket.signer_timeout) (pred n) in
loop (pred n)
| Error _ as e -> Lwt.return e
| Ok v -> Lwt.return v
in
loop 3
let sign ?watermark path pkh msg =
let msg =
match watermark with
| None -> msg
| Some watermark ->
Bytes.cat (Tezos_crypto.Signature.bytes_of_watermark watermark) msg
in
with_signer_operation path pkh msg Sign_request Sign.Response.encoding
let deterministic_nonce path pkh msg =
with_signer_operation
path
pkh
msg
Deterministic_nonce_request
Deterministic_nonce.Response.encoding
let deterministic_nonce_hash path pkh msg =
with_signer_operation
path
pkh
msg
Deterministic_nonce_hash_request
Deterministic_nonce_hash.Response.encoding
let supports_deterministic_nonces path pkh =
let open Lwt_result_syntax in
Tezos_base_unix.Socket.with_connection path (fun conn ->
let* () =
Tezos_base_unix.Socket.send
conn
Request.encoding
(Request.Supports_deterministic_nonces pkh)
in
let* supported =
Tezos_base_unix.Socket.recv
conn
(result_encoding Supports_deterministic_nonces.Response.encoding)
in
Lwt.return supported)
let public_key path pkh =
let open Lwt_result_syntax in
Tezos_base_unix.Socket.with_connection path (fun conn ->
let* () =
Tezos_base_unix.Socket.send
conn
Request.encoding
(Request.Public_key pkh)
in
let encoding = result_encoding Public_key.Response.encoding in
let* pk = Tezos_base_unix.Socket.recv conn encoding in
Lwt.return pk)
module Unix = struct
let scheme = unix_scheme
let title =
"Built-in tezos-signer using remote signer through hardcoded unix socket."
let description =
"Valid locators are of the form\n - unix:/path/to/socket?pkh=tz1..."
include Client_keys.Signature_type
let parse uri =
let open Result_syntax in
assert (Uri.scheme uri = Some scheme) ;
match Uri.get_query_param uri "pkh" with
| None -> error_with "Missing the query parameter: 'pkh=tz1...'"
| Some key ->
let+ key = Tezos_crypto.Signature.Public_key_hash.of_b58check key in
(Tezos_base_unix.Socket.Unix (Uri.path uri), key)
let parse uri = parse uri |> record_trace (Invalid_uri uri) |> Lwt.return
let public_key uri =
let open Lwt_result_syntax in
let* path, pkh = parse (uri : pk_uri :> Uri.t) in
public_key path pkh
let neuterize uri =
let open Lwt_result_syntax in
let*? v = Client_keys.make_pk_uri (uri : sk_uri :> Uri.t) in
return v
let public_key_hash uri =
let open Lwt_result_syntax in
let* pk = public_key uri in
return (Tezos_crypto.Signature.Public_key.hash pk, Some pk)
let import_secret_key ~io:_ = public_key_hash
let sign ?watermark uri msg =
let open Lwt_result_syntax in
let* path, pkh = parse (uri : sk_uri :> Uri.t) in
sign ?watermark path pkh msg
let deterministic_nonce uri msg =
let open Lwt_result_syntax in
let* path, pkh = parse (uri : sk_uri :> Uri.t) in
deterministic_nonce path pkh msg
let deterministic_nonce_hash uri msg =
let open Lwt_result_syntax in
let* path, pkh = parse (uri : sk_uri :> Uri.t) in
deterministic_nonce_hash path pkh msg
let supports_deterministic_nonces uri =
let open Lwt_result_syntax in
let* path, pkh = parse (uri : sk_uri :> Uri.t) in
supports_deterministic_nonces path pkh
end
module Tcp = struct
let scheme = tcp_scheme
let title =
"Built-in tezos-signer using remote signer through hardcoded tcp socket."
let description =
"Valid locators are of the form\n - tcp://host:port/tz1..."
include Client_keys.Signature_type
let parse uri =
let open Result_syntax in
assert (Uri.scheme uri = Some scheme) ;
match (Uri.host uri, Uri.port uri) with
| None, _ -> error_with "Missing host address"
| _, None -> error_with "Missing host port"
| Some path, Some port ->
let pkh = Uri.path uri in
let pkh = try String.(sub pkh 1 (length pkh - 1)) with _ -> "" in
let+ pkh = Tezos_crypto.Signature.Public_key_hash.of_b58check pkh in
let tcp_socket =
Tezos_base_unix.Socket.Tcp
(path, string_of_int port, [Lwt_unix.AI_SOCKTYPE SOCK_STREAM])
in
(tcp_socket, pkh)
let parse uri = parse uri |> record_trace (Invalid_uri uri) |> Lwt.return
let public_key uri =
let open Lwt_result_syntax in
let* path, pkh = parse (uri : pk_uri :> Uri.t) in
public_key path pkh
let neuterize uri =
let open Lwt_result_syntax in
let*? v = Client_keys.make_pk_uri (uri : sk_uri :> Uri.t) in
return v
let public_key_hash uri =
let open Lwt_result_syntax in
let* pk = public_key uri in
return (Tezos_crypto.Signature.Public_key.hash pk, Some pk)
let import_secret_key ~io:_ = public_key_hash
let sign ?watermark uri msg =
let open Lwt_result_syntax in
let* path, pkh = parse (uri : sk_uri :> Uri.t) in
sign ?watermark path pkh msg
let deterministic_nonce uri msg =
let open Lwt_result_syntax in
let* path, pkh = parse (uri : sk_uri :> Uri.t) in
deterministic_nonce path pkh msg
let deterministic_nonce_hash uri msg =
let open Lwt_result_syntax in
let* path, pkh = parse (uri : sk_uri :> Uri.t) in
deterministic_nonce_hash path pkh msg
let supports_deterministic_nonces uri =
let open Lwt_result_syntax in
let* path, pkh = parse (uri : sk_uri :> Uri.t) in
supports_deterministic_nonces path pkh
end
end
let make_unix_base path = Uri.make ~scheme:unix_scheme ~path ()
let make_tcp_base host port = Uri.make ~scheme:tcp_scheme ~host ~port ()