xref: /openbsd/usr.bin/ssh/PROTOCOL.u2f (revision 039d6aae)
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 specified additional key types include one based on Ed25519.
41
42SSH U2F Key formats
43-------------------
44
45OpenSSH integrates U2F as new key and corresponding certificate types:
46
47	sk-ecdsa-sha2-nistp256@openssh.com
48	sk-ecdsa-sha2-nistp256-cert-v01@openssh.com
49	sk-ssh-ed25519@openssh.com
50	sk-ssh-ed25519-cert-v01@openssh.com
51
52These key types are supported only for user authentication with the
53"publickey" method. They are not used for host-based user authentication
54or server host key authentication.
55
56While each uses ecdsa-sha256-nistp256 as the underlying signature primitive,
57keys require extra information in the public and private keys, and in
58the signature object itself. As such they cannot be made compatible with
59the existing ecdsa-sha2-nistp* key types.
60
61The format of a sk-ecdsa-sha2-nistp256@openssh.com public key is:
62
63	string		"sk-ecdsa-sha2-nistp256@openssh.com"
64	string		curve name
65	ec_point	Q
66	string		application (user-specified, but typically "ssh:")
67
68The corresponding private key contains:
69
70	string		"sk-ecdsa-sha2-nistp256@openssh.com"
71	string		curve name
72	ec_point	Q
73	string		application (user-specified, but typically "ssh:")
74	uint8		flags
75	string		key_handle
76	string		reserved
77
78The format of a sk-ssh-ed25519@openssh.com public key is:
79
80	string		"sk-ssh-ed25519@openssh.com"
81	string		public key
82	string		application (user-specified, but typically "ssh:")
83
84With a private half consisting of:
85
86	string		"sk-ssh-ed25519@openssh.com"
87	string		public key
88	string		application (user-specified, but typically "ssh:")
89	uint32		flags
90	string		key_handle
91	string		reserved
92
93The certificate form for SSH U2F keys appends the usual certificate
94information to the public key:
95
96	string		"sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
97	string		nonce
98	string		curve name
99	ec_point	Q
100	string		application
101	uint64		serial
102	uint32		type
103	string		key id
104	string		valid principals
105	uint64		valid after
106	uint64		valid before
107	string		critical options
108	string		extensions
109	string		reserved
110	string		signature key
111	string		signature
112
113	string		"sk-ssh-ed25519-cert-v01@openssh.com"
114	string		nonce
115	string		public key
116	string		application
117	uint64		serial
118	uint32		type
119	string		key id
120	string		valid principals
121	uint64		valid after
122	uint64		valid before
123	string		critical options
124	string		extensions
125	string		reserved
126	string		signature key
127	string		signature
128
129During key generation, the hardware also returns attestation information
130that may be used to cryptographically prove that a given key is
131hardware-backed. Unfortunately, the protocol required for this proof is
132not privacy-preserving and may be used to identify U2F tokens with at
133least manufacturer and batch number granularity. For this reason, we
134choose not to include this information in the public key or save it by
135default.
136
137Attestation information is very useful however in an organisational
138context, where it may be used by a CA as part of certificate
139issuance. In this case, exposure to the CA of hardware identity is
140desirable. To support this case, OpenSSH optionally allows retaining the
141attestation information at the time of key generation. It will take the
142following format:
143
144	string		"sk-attest-v00"
145	uint32		version		(1 for U2F, 2 for FIDO2 in future)
146	string		attestation certificate
147	string		enrollment signature
148
149SSH U2F signatures
150------------------
151
152In addition to the message to be signed, the U2F signature operation
153requires a few additional parameters:
154
155	byte		control bits (e.g. "user presence required" flag)
156	byte[32]	SHA256(message)
157	byte[32]	SHA256(application)
158	byte		key_handle length
159	byte[]		key_handle
160
161This signature is signed over a blob that consists of:
162
163	byte[32]	SHA256(application)
164	byte		flags (including "user present", extensions present)
165	uint32		counter
166	byte[]		extensions
167	byte[32]	SHA256(message)
168
169The signature returned from U2F hardware takes the following format:
170
171	byte		flags (including "user present")
172	uint32		counter
173	byte[32]	ecdsa_signature (in X9.62 format).
174
175For use in the SSH protocol, we wish to avoid server-side parsing of ASN.1
176format data in the pre-authentication attack surface. Therefore, the
177signature format used on the wire in SSH2_USERAUTH_REQUEST packets will
178be reformatted to better match the existing signature encoding:
179
180	string		"sk-ecdsa-sha2-nistp256@openssh.com"
181	string		ecdsa_signature
182	byte		flags
183	uint32		counter
184
185Where the "ecdsa_signature" field follows the RFC5656 ECDSA signature
186encoding:
187
188	mpint		r
189	mpint		s
190
191For Ed25519 keys the signature is encoded as:
192
193	string		"sk-ssh-ed25519@openssh.com"
194	string		signature
195	byte		flags
196	uint32		counter
197
198
199ssh-agent protocol extensions
200-----------------------------
201
202ssh-agent requires a protocol extension to support U2F keys. At
203present the closest analogue to Security Keys in ssh-agent are PKCS#11
204tokens, insofar as they require a middleware library to communicate with
205the device that holds the keys. Unfortunately, the protocol message used
206to add PKCS#11 keys to ssh-agent does not include any way to send the
207key handle to the agent as U2F keys require.
208
209To avoid this, without having to add wholly new messages to the agent
210protocol, we will use the existing SSH2_AGENTC_ADD_ID_CONSTRAINED message
211with a new key constraint extension to encode a path to the middleware
212library for the key. The format of this constraint extension would be:
213
214	byte		SSH_AGENT_CONSTRAIN_EXTENSION
215	string		sk@openssh.com
216	string		middleware path
217
218This constraint-based approach does not present any compatibility
219problems.
220
221OpenSSH integration
222-------------------
223
224U2F tokens may be attached via a number of means, including USB and NFC.
225The USB interface is standardised around a HID protocol, but we want to
226be able to support other transports as well as dummy implementations for
227regress testing. For this reason, OpenSSH shall support a dynamically-
228loaded middleware libraries to communicate with security keys, but offer
229support for the common case of USB HID security keys internally.
230
231The middleware library need only expose a handful of functions:
232
233	/* Flags */
234	#define SSH_SK_USER_PRESENCE_REQD	0x01
235
236	/* Algs */
237	#define SSH_SK_ECDSA                   0x00
238	#define SSH_SK_ED25519                 0x01
239
240	struct sk_enroll_response {
241		uint8_t *public_key;
242		size_t public_key_len;
243		uint8_t *key_handle;
244		size_t key_handle_len;
245		uint8_t *signature;
246		size_t signature_len;
247		uint8_t *attestation_cert;
248		size_t attestation_cert_len;
249	};
250
251	struct sk_sign_response {
252		uint8_t flags;
253		uint32_t counter;
254		uint8_t *sig_r;
255		size_t sig_r_len;
256		uint8_t *sig_s;
257		size_t sig_s_len;
258	};
259
260	/* Return the version of the middleware API */
261	uint32_t sk_api_version(void);
262
263	/* Enroll a U2F key (private key generation) */
264	int sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len,
265	    const char *application, uint8_t flags,
266	    struct sk_enroll_response **enroll_response);
267
268	/* Sign a challenge */
269	int sk_sign(int alg, const uint8_t *message, size_t message_len,
270	    const char *application,
271	    const uint8_t *key_handle, size_t key_handle_len,
272	    uint8_t flags, struct sk_sign_response **sign_response);
273
274In OpenSSH, these will be invoked by generalising the existing
275ssh-pkcs11-helper mechanism to provide containment of the middleware from
276ssh-agent.
277
278