xref: /openbsd/usr.bin/ssh/PROTOCOL.u2f (revision 09467b48)
1This document describes OpenSSH's support for U2F/FIDO security keys.
2
3Background
4----------
5
6U2F is an open standard for two-factor authentication hardware, widely
7used for user authentication to websites. U2F tokens are ubiquitous,
8available from a number of manufacturers and are currently by far the
9cheapest way for users to achieve hardware-backed credential storage.
10
11The U2F protocol however cannot be trivially used as an SSH protocol key
12type as both the inputs to the signature operation and the resultant
13signature differ from those specified for SSH. For similar reasons,
14integration of U2F devices cannot be achieved via the PKCS#11 API.
15
16U2F also offers a number of features that are attractive in the context
17of SSH authentication. They can be configured to require indication
18of "user presence" for each signature operation (typically achieved
19by requiring the user touch the key). They also offer an attestation
20mechanism at key enrollment time that can be used to prove that a
21given key is backed by hardware. Finally the signature format includes
22a monotonic signature counter that can be used (at scale) to detect
23concurrent use of a private key, should it be extracted from hardware.
24
25U2F private keys are generated through an enrollment operation,
26which takes an application ID - a URL-like string, typically "ssh:"
27in this case, but a HTTP origin for the case of web authentication,
28and a challenge string (typically randomly generated). The enrollment
29operation returns a public key, a key handle that must be used to invoke
30the hardware-backed private key, some flags and signed attestation
31information that may be used to verify that a private key is hosted on a
32particular hardware instance.
33
34It is common for U2F hardware to derive private keys from the key handle
35in conjunction with a small per-device secret that is unique to the
36hardware, thus requiring little on-device storage for an effectively
37unlimited number of supported keys. This drives the requirement that
38the key handle be supplied for each signature operation. U2F tokens
39primarily use ECDSA signatures in the NIST-P256 field, though the FIDO2
40standard specifies additional key types, including one based on Ed25519.
41
42Use of U2F security keys does not automatically imply multi-factor
43authentication. From sshd's perspective, a security key constitutes a
44single factor of authentication, even if protected by a PIN or biometric
45authentication.  To enable multi-factor authentication in ssh, please
46refer to the AuthenticationMethods option in sshd_config(5).
47
48
49SSH U2F Key formats
50-------------------
51
52OpenSSH integrates U2F as new key and corresponding certificate types:
53
54	sk-ecdsa-sha2-nistp256@openssh.com
55	sk-ecdsa-sha2-nistp256-cert-v01@openssh.com
56	sk-ssh-ed25519@openssh.com
57	sk-ssh-ed25519-cert-v01@openssh.com
58
59While each uses ecdsa-sha256-nistp256 as the underlying signature primitive,
60keys require extra information in the public and private keys, and in
61the signature object itself. As such they cannot be made compatible with
62the existing ecdsa-sha2-nistp* key types.
63
64The format of a sk-ecdsa-sha2-nistp256@openssh.com public key is:
65
66	string		"sk-ecdsa-sha2-nistp256@openssh.com"
67	string		curve name
68	ec_point	Q
69	string		application (user-specified, but typically "ssh:")
70
71The corresponding private key contains:
72
73	string		"sk-ecdsa-sha2-nistp256@openssh.com"
74	string		curve name
75	ec_point	Q
76	string		application (user-specified, but typically "ssh:")
77	uint8		flags
78	string		key_handle
79	string		reserved
80
81The format of a sk-ssh-ed25519@openssh.com public key is:
82
83	string		"sk-ssh-ed25519@openssh.com"
84	string		public key
85	string		application (user-specified, but typically "ssh:")
86
87With a private half consisting of:
88
89	string		"sk-ssh-ed25519@openssh.com"
90	string		public key
91	string		application (user-specified, but typically "ssh:")
92	uint8		flags
93	string		key_handle
94	string		reserved
95
96The certificate form for SSH U2F keys appends the usual certificate
97information to the public key:
98
99	string		"sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
100	string		nonce
101	string		curve name
102	ec_point	Q
103	string		application
104	uint64		serial
105	uint32		type
106	string		key id
107	string		valid principals
108	uint64		valid after
109	uint64		valid before
110	string		critical options
111	string		extensions
112	string		reserved
113	string		signature key
114	string		signature
115
116and for security key ed25519 certificates:
117
118	string		"sk-ssh-ed25519-cert-v01@openssh.com"
119	string		nonce
120	string		public key
121	string		application
122	uint64		serial
123	uint32		type
124	string		key id
125	string		valid principals
126	uint64		valid after
127	uint64		valid before
128	string		critical options
129	string		extensions
130	string		reserved
131	string		signature key
132	string		signature
133
134Both security key certificates use the following encoding for private keys:
135
136	string		type (e.g. "sk-ssh-ed25519-cert-v01@openssh.com")
137	string		pubkey (the above key/cert structure)
138	string		application
139	uint8		flags
140	string		key_handle
141	string		reserved
142
143During key generation, the hardware also returns attestation information
144that may be used to cryptographically prove that a given key is
145hardware-backed. Unfortunately, the protocol required for this proof is
146not privacy-preserving and may be used to identify U2F tokens with at
147least manufacturer and batch number granularity. For this reason, we
148choose not to include this information in the public key or save it by
149default.
150
151Attestation information is useful for out-of-band key and certificate
152registration workflows, e.g. proving to a CA that a key is backed
153by trusted hardware before it will issue a certificate. To support this
154case, OpenSSH optionally allows retaining the attestation information
155at the time of key generation. It will take the following format:
156
157	string		"ssh-sk-attest-v00"
158	string		attestation certificate
159	string		enrollment signature
160	uint32		reserved flags
161	string		reserved string
162
163OpenSSH treats the attestation certificate and enrollment signatures as
164opaque objects and does no interpretation of them itself.
165
166SSH U2F signatures
167------------------
168
169In addition to the message to be signed, the U2F signature operation
170requires the key handle and a few additional parameters. The signature
171is signed over a blob that consists of:
172
173	byte[32]	SHA256(application)
174	byte		flags (including "user present", extensions present)
175	uint32		counter
176	byte[]		extensions
177	byte[32]	SHA256(message)
178
179No extensions are yet defined for SSH use. If any are defined in the future,
180it will be possible to infer their presence from the contents of the "flags"
181value.
182
183The signature returned from U2F hardware takes the following format:
184
185	byte		flags (including "user present")
186	uint32		counter
187	byte[]		ecdsa_signature (in X9.62 format).
188
189For use in the SSH protocol, we wish to avoid server-side parsing of ASN.1
190format data in the pre-authentication attack surface. Therefore, the
191signature format used on the wire in SSH2_USERAUTH_REQUEST packets will
192be reformatted to better match the existing signature encoding:
193
194	string		"sk-ecdsa-sha2-nistp256@openssh.com"
195	string		ecdsa_signature
196	byte		flags
197	uint32		counter
198
199Where the "ecdsa_signature" field follows the RFC5656 ECDSA signature
200encoding:
201
202	mpint		r
203	mpint		s
204
205For Ed25519 keys the signature is encoded as:
206
207	string		"sk-ssh-ed25519@openssh.com"
208	string		signature
209	byte		flags
210	uint32		counter
211
212webauthn signatures
213-------------------
214
215The W3C/FIDO webauthn[1] standard defines a mechanism for a web browser to
216interact with FIDO authentication tokens. This standard builds upon the
217FIDO standards, but requires different signature contents to raw FIDO
218messages. OpenSSH supports ECDSA/p256 webauthn signatures through the
219"webauthn-sk-ecdsa-sha2-nistp256@openssh.com" signature algorithm.
220
221The wire encoding for a webauthn-sk-ecdsa-sha2-nistp256@openssh.com
222signature is similar to the sk-ecdsa-sha2-nistp256@openssh.com format:
223
224	string		"webauthn-sk-ecdsa-sha2-nistp256@openssh.com"
225	string		ecdsa_signature
226	byte		flags
227	uint32		counter
228	string		origin
229	string		clientData
230	string		extensions
231
232Where "origin" is the HTTP origin making the signature, "clientData" is
233the JSON-like structure signed by the browser and "extensions" are any
234extensions used in making the signature.
235
236[1] https://www.w3.org/TR/webauthn-2/
237
238ssh-agent protocol extensions
239-----------------------------
240
241ssh-agent requires a protocol extension to support U2F keys. At
242present the closest analogue to Security Keys in ssh-agent are PKCS#11
243tokens, insofar as they require a middleware library to communicate with
244the device that holds the keys. Unfortunately, the protocol message used
245to add PKCS#11 keys to ssh-agent does not include any way to send the
246key handle to the agent as U2F keys require.
247
248To avoid this, without having to add wholly new messages to the agent
249protocol, we will use the existing SSH2_AGENTC_ADD_ID_CONSTRAINED message
250with a new key constraint extension to encode a path to the middleware
251library for the key. The format of this constraint extension would be:
252
253	byte		SSH_AGENT_CONSTRAIN_EXTENSION
254	string		sk-provider@openssh.com
255	string		middleware path
256
257This constraint-based approach does not present any compatibility
258problems.
259
260OpenSSH integration
261-------------------
262
263U2F tokens may be attached via a number of means, including USB and NFC.
264The USB interface is standardised around a HID protocol, but we want to
265be able to support other transports as well as dummy implementations for
266regress testing. For this reason, OpenSSH shall support a dynamically-
267loaded middleware libraries to communicate with security keys, but offer
268support for the common case of USB HID security keys internally.
269
270The middleware library need only expose a handful of functions:
271
272	#define SSH_SK_VERSION_MAJOR		0x00050000 /* API version */
273	#define SSH_SK_VERSION_MAJOR_MASK	0xffff0000
274
275	/* Flags */
276	#define SSH_SK_USER_PRESENCE_REQD	0x01
277	#define SSH_SK_USER_VERIFICATION_REQD	0x04
278	#define SSH_SK_RESIDENT_KEY		0x20
279
280	/* Algs */
281	#define SSH_SK_ECDSA                   0x00
282	#define SSH_SK_ED25519                 0x01
283
284	/* Error codes */
285	#define SSH_SK_ERR_GENERAL		-1
286	#define SSH_SK_ERR_UNSUPPORTED		-2
287	#define SSH_SK_ERR_PIN_REQUIRED		-3
288	#define SSH_SK_ERR_DEVICE_NOT_FOUND	-4
289
290	struct sk_enroll_response {
291		uint8_t *public_key;
292		size_t public_key_len;
293		uint8_t *key_handle;
294		size_t key_handle_len;
295		uint8_t *signature;
296		size_t signature_len;
297		uint8_t *attestation_cert;
298		size_t attestation_cert_len;
299	};
300
301	struct sk_sign_response {
302		uint8_t flags;
303		uint32_t counter;
304		uint8_t *sig_r;
305		size_t sig_r_len;
306		uint8_t *sig_s;
307		size_t sig_s_len;
308	};
309
310	struct sk_resident_key {
311		uint32_t alg;
312		size_t slot;
313		char *application;
314		struct sk_enroll_response key;
315	};
316
317	struct sk_option {
318		char *name;
319		char *value;
320		uint8_t important;
321	};
322
323	/* Return the version of the middleware API */
324	uint32_t sk_api_version(void);
325
326	/* Enroll a U2F key (private key generation) */
327	int sk_enroll(uint32_t alg,
328	    const uint8_t *challenge, size_t challenge_len,
329	    const char *application, uint8_t flags, const char *pin,
330	    struct sk_option **options,
331	    struct sk_enroll_response **enroll_response);
332
333	/* Sign a challenge */
334	int sk_sign(uint32_t alg, const uint8_t *message, size_t message_len,
335	    const char *application,
336	    const uint8_t *key_handle, size_t key_handle_len,
337	    uint8_t flags, const char *pin, struct sk_option **options,
338	    struct sk_sign_response **sign_response);
339
340	/* Enumerate all resident keys */
341	int sk_load_resident_keys(const char *pin, struct sk_option **options,
342	    struct sk_resident_key ***rks, size_t *nrks);
343
344The SSH_SK_VERSION_MAJOR should be incremented for each incompatible
345API change.
346
347The options may be used to pass miscellaneous options to the middleware
348as a NULL-terminated array of pointers to struct sk_option. The middleware
349may ignore unsupported or unknown options unless the "important" flag is
350set, in which case it should return failure if an unsupported option is
351requested.
352
353At present the following options names are supported:
354
355	"device"
356
357	Specifies a specific FIDO device on which to perform the
358	operation. The value in this field is interpreted by the
359	middleware but it would be typical to specify a path to
360	a /dev node for the device in question.
361
362	"user"
363
364	Specifies the FIDO2 username used when enrolling a key,
365	overriding OpenSSH's default of using an all-zero username.
366
367In OpenSSH, the middleware will be invoked by using a similar mechanism to
368ssh-pkcs11-helper to provide address-space containment of the
369middleware from ssh-agent.
370
371