forked from openssh/openssh-portable
-
Notifications
You must be signed in to change notification settings - Fork 2
/
PROTOCOL.u2f
309 lines (243 loc) · 10.8 KB
/
PROTOCOL.u2f
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
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
This document describes OpenSSH's support for U2F/FIDO security keys.
Background
----------
U2F is an open standard for two-factor authentication hardware, widely
used for user authentication to websites. U2F tokens are ubiquitous,
available from a number of manufacturers and are currently by far the
cheapest way for users to achieve hardware-backed credential storage.
The U2F protocol however cannot be trivially used as an SSH protocol key
type as both the inputs to the signature operation and the resultant
signature differ from those specified for SSH. For similar reasons,
integration of U2F devices cannot be achieved via the PKCS#11 API.
U2F also offers a number of features that are attractive in the context
of SSH authentication. They can be configured to require indication
of "user presence" for each signature operation (typically achieved
by requiring the user touch the key). They also offer an attestation
mechanism at key enrollment time that can be used to prove that a
given key is backed by hardware. Finally the signature format includes
a monotonic signature counter that can be used (at scale) to detect
concurrent use of a private key, should it be extracted from hardware.
U2F private keys are generated through an enrollment operation,
which takes an application ID - a URL-like string, typically "ssh:"
in this case, but a HTTP origin for the case of web authentication,
and a challenge string (typically randomly generated). The enrollment
operation returns a public key, a key handle that must be used to invoke
the hardware-backed private key, some flags and signed attestation
information that may be used to verify that a private key is hosted on a
particular hardware instance.
It is common for U2F hardware to derive private keys from the key handle
in conjunction with a small per-device secret that is unique to the
hardware, thus requiring little on-device storage for an effectively
unlimited number of supported keys. This drives the requirement that
the key handle be supplied for each signature operation. U2F tokens
primarily use ECDSA signatures in the NIST-P256 field, though the FIDO2
standard specifies additional key types, including one based on Ed25519.
Use of U2F security keys does not automatically imply multi-factor
authentication. From sshd's perspective, a security key constitutes a
single factor of authentication, even if protected by a PIN or biometric
authentication. To enable multi-factor authentication in ssh, please
refer to the AuthenticationMethods option in sshd_config(5).
SSH U2F Key formats
-------------------
OpenSSH integrates U2F as new key and corresponding certificate types:
While each uses ecdsa-sha256-nistp256 as the underlying signature primitive,
keys require extra information in the public and private keys, and in
the signature object itself. As such they cannot be made compatible with
the existing ecdsa-sha2-nistp* key types.
The format of a [email protected] public key is:
string "[email protected]"
string curve name
ec_point Q
string application (user-specified, but typically "ssh:")
The corresponding private key contains:
string "[email protected]"
string curve name
ec_point Q
string application (user-specified, but typically "ssh:")
uint8 flags
string key_handle
string reserved
The format of a [email protected] public key is:
string "[email protected]"
string public key
string application (user-specified, but typically "ssh:")
With a private half consisting of:
string "[email protected]"
string public key
string application (user-specified, but typically "ssh:")
uint8 flags
string key_handle
string reserved
The certificate form for SSH U2F keys appends the usual certificate
information to the public key:
string "[email protected]"
string nonce
string curve name
ec_point Q
string application
uint64 serial
uint32 type
string key id
string valid principals
uint64 valid after
uint64 valid before
string critical options
string extensions
string reserved
string signature key
string signature
and for security key ed25519 certificates:
string "[email protected]"
string nonce
string public key
string application
uint64 serial
uint32 type
string key id
string valid principals
uint64 valid after
uint64 valid before
string critical options
string extensions
string reserved
string signature key
string signature
Both security key certificates use the following encoding for private keys:
string type (e.g. "[email protected]")
string pubkey (the above key/cert structure)
string application
uint8 flags
string key_handle
string reserved
During key generation, the hardware also returns attestation information
that may be used to cryptographically prove that a given key is
hardware-backed. Unfortunately, the protocol required for this proof is
not privacy-preserving and may be used to identify U2F tokens with at
least manufacturer and batch number granularity. For this reason, we
choose not to include this information in the public key or save it by
default.
Attestation information is useful for out-of-band key and certificate
registration workflows, e.g. proving to a CA that a key is backed
by trusted hardware before it will issue a certificate. To support this
case, OpenSSH optionally allows retaining the attestation information
at the time of key generation. It will take the following format:
string "ssh-sk-attest-v01"
string attestation certificate
string enrollment signature
string authenticator data (CBOR encoded)
uint32 reserved flags
string reserved string
A previous version of this format, emitted prior to OpenSSH 8.4 omitted
the authenticator data.
string "ssh-sk-attest-v00"
string attestation certificate
string enrollment signature
uint32 reserved flags
string reserved string
OpenSSH treats the attestation certificate and enrollment signatures as
opaque objects and does no interpretation of them itself.
SSH U2F signatures
------------------
In addition to the message to be signed, the U2F signature operation
requires the key handle and a few additional parameters. The signature
is signed over a blob that consists of:
byte[32] SHA256(application)
byte flags (including "user present", extensions present)
uint32 counter
byte[] extensions
byte[32] SHA256(message)
No extensions are yet defined for SSH use. If any are defined in the future,
it will be possible to infer their presence from the contents of the "flags"
value.
The signature returned from U2F hardware takes the following format:
byte flags (including "user present")
uint32 counter
byte[] ecdsa_signature (in X9.62 format).
For use in the SSH protocol, we wish to avoid server-side parsing of ASN.1
format data in the pre-authentication attack surface. Therefore, the
signature format used on the wire in SSH2_USERAUTH_REQUEST packets will
be reformatted to better match the existing signature encoding:
string "[email protected]"
string ecdsa_signature
byte flags
uint32 counter
Where the "ecdsa_signature" field follows the RFC5656 ECDSA signature
encoding:
mpint r
mpint s
For Ed25519 keys the signature is encoded as:
string "[email protected]"
string signature
byte flags
uint32 counter
webauthn signatures
-------------------
The W3C/FIDO webauthn[1] standard defines a mechanism for a web browser to
interact with FIDO authentication tokens. This standard builds upon the
FIDO standards, but requires different signature contents to raw FIDO
messages. OpenSSH supports ECDSA/p256 webauthn signatures through the
"[email protected]" signature algorithm.
The wire encoding for a [email protected]
signature is similar to the [email protected] format:
string "[email protected]"
string ecdsa_signature
byte flags
uint32 counter
string origin
string clientData
string extensions
Where "origin" is the HTTP origin making the signature, "clientData" is
the JSON-like structure signed by the browser and "extensions" are any
extensions used in making the signature.
[1] https://www.w3.org/TR/webauthn-2/
ssh-agent protocol extensions
-----------------------------
ssh-agent requires a protocol extension to support U2F keys. At
present the closest analogue to Security Keys in ssh-agent are PKCS#11
tokens, insofar as they require a middleware library to communicate with
the device that holds the keys. Unfortunately, the protocol message used
to add PKCS#11 keys to ssh-agent does not include any way to send the
key handle to the agent as U2F keys require.
To avoid this, without having to add wholly new messages to the agent
protocol, we will use the existing SSH2_AGENTC_ADD_ID_CONSTRAINED message
with a new key constraint extension to encode a path to the middleware
library for the key. The format of this constraint extension would be:
byte SSH_AGENT_CONSTRAIN_EXTENSION
string [email protected]
string middleware path
This constraint-based approach does not present any compatibility
problems.
OpenSSH integration
-------------------
U2F tokens may be attached via a number of means, including USB and NFC.
The USB interface is standardised around a HID protocol, but we want to
be able to support other transports as well as dummy implementations for
regress testing. For this reason, OpenSSH shall support a dynamically-
loaded middleware libraries to communicate with security keys, but offer
support for the common case of USB HID security keys internally.
The middleware library need only expose a handful of functions and
numbers listed in sk-api.h. Included in the defined numbers is a
SSH_SK_VERSION_MAJOR that should be incremented for each incompatible
API change.
miscellaneous options may be passed to the middleware as a NULL-
terminated array of pointers to struct sk_option. The middleware may
ignore unsupported or unknown options unless the "required" flag is set,
in which case it should return failure if an unsupported option is
requested.
At present the following options names are supported:
"device"
Specifies a specific FIDO device on which to perform the
operation. The value in this field is interpreted by the
middleware but it would be typical to specify a path to
a /dev node for the device in question.
"user"
Specifies the FIDO2 username used when enrolling a key,
overriding OpenSSH's default of using an all-zero username.
In OpenSSH, the middleware will be invoked by using a similar mechanism to
ssh-pkcs11-helper to provide address-space containment of the
middleware from ssh-agent.
$OpenBSD: PROTOCOL.u2f,v 1.26 2020/09/09 03:08:01 djm Exp $