blob: 32bfa20f3160b1eeccd718f1914dbe5e1022311c [file] [log] [blame]
djm@openbsd.org57ecc102019-10-31 21:14:17 +00001This 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
naddy@openbsd.orgad384062019-11-01 12:10:43 +000025U2F private keys are generated through an enrollment operation,
djm@openbsd.org57ecc102019-10-31 21:14:17 +000026which 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
naddy@openbsd.orgad384062019-11-01 12:10:43 +000031information that may be used to verify that a private key is hosted on a
djm@openbsd.org57ecc102019-10-31 21:14:17 +000032particular 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
djm@openbsd.org13066432019-11-18 04:34:47 +000039primarily use ECDSA signatures in the NIST-P256 field, though the FIDO2
40standard specified additional key types include one based on Ed25519.
djm@openbsd.org57ecc102019-10-31 21:14:17 +000041
42SSH U2F Key formats
43-------------------
44
djm@openbsd.org13066432019-11-18 04:34:47 +000045OpenSSH integrates U2F as new key and corresponding certificate types:
djm@openbsd.org57ecc102019-10-31 21:14:17 +000046
47 sk-ecdsa-sha2-nistp256@openssh.com
48 sk-ecdsa-sha2-nistp256-cert-v01@openssh.com
djm@openbsd.org13066432019-11-18 04:34:47 +000049 sk-ssh-ed25519@openssh.com
50 sk-ssh-ed25519-cert-v01@openssh.com
djm@openbsd.org57ecc102019-10-31 21:14:17 +000051
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"
djm@openbsd.org93fa2a62019-11-18 04:16:53 +000064 string curve name
djm@openbsd.org57ecc102019-10-31 21:14:17 +000065 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"
djm@openbsd.org93fa2a62019-11-18 04:16:53 +000071 string curve name
djm@openbsd.org57ecc102019-10-31 21:14:17 +000072 ec_point Q
73 string application (user-specified, but typically "ssh:")
djm@openbsd.org71856e12019-11-18 04:29:50 +000074 uint8 flags
djm@openbsd.org57ecc102019-10-31 21:14:17 +000075 string key_handle
djm@openbsd.org57ecc102019-10-31 21:14:17 +000076 string reserved
77
djm@openbsd.org13066432019-11-18 04:34:47 +000078The 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:")
djm@openbsd.orga62f4e12019-12-10 23:37:31 +000089 uint8 flags
djm@openbsd.org13066432019-11-18 04:34:47 +000090 string key_handle
91 string reserved
92
93The certificate form for SSH U2F keys appends the usual certificate
djm@openbsd.org57ecc102019-10-31 21:14:17 +000094information to the public key:
95
naddy@openbsd.orgad384062019-11-01 12:10:43 +000096 string "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
djm@openbsd.org57ecc102019-10-31 21:14:17 +000097 string nonce
djm@openbsd.org93fa2a62019-11-18 04:16:53 +000098 string curve name
djm@openbsd.org57ecc102019-10-31 21:14:17 +000099 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
djm@openbsd.orga62f4e12019-12-10 23:37:31 +0000113and for security key ed25519 certificates:
114
djm@openbsd.org13066432019-11-18 04:34:47 +0000115 string "sk-ssh-ed25519-cert-v01@openssh.com"
116 string nonce
117 string public key
118 string application
119 uint64 serial
120 uint32 type
121 string key id
122 string valid principals
123 uint64 valid after
124 uint64 valid before
125 string critical options
126 string extensions
127 string reserved
128 string signature key
129 string signature
130
djm@openbsd.orga62f4e12019-12-10 23:37:31 +0000131Both security key certificates use the following encoding for private keys:
132
133 string type (e.g. "sk-ssh-ed25519-cert-v01@openssh.com")
134 string pubkey (the above key/cert structure)
135 string application
136 uint8 flags
137 string key_handle
138 string reserved
139
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000140During key generation, the hardware also returns attestation information
141that may be used to cryptographically prove that a given key is
142hardware-backed. Unfortunately, the protocol required for this proof is
143not privacy-preserving and may be used to identify U2F tokens with at
144least manufacturer and batch number granularity. For this reason, we
145choose not to include this information in the public key or save it by
146default.
147
148Attestation information is very useful however in an organisational
naddy@openbsd.orgad384062019-11-01 12:10:43 +0000149context, where it may be used by a CA as part of certificate
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000150issuance. In this case, exposure to the CA of hardware identity is
151desirable. To support this case, OpenSSH optionally allows retaining the
152attestation information at the time of key generation. It will take the
153following format:
154
155 string "sk-attest-v00"
156 uint32 version (1 for U2F, 2 for FIDO2 in future)
157 string attestation certificate
158 string enrollment signature
159
160SSH U2F signatures
161------------------
162
djm@openbsd.org18e84bf2019-11-28 05:20:54 +0000163In addition to the message to be signed, the U2F signature operation
djm@openbsd.orgc4036fe2019-12-10 22:36:08 +0000164requires the key handle and a few additional parameters. The signature
165is signed over a blob that consists of:
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000166
167 byte[32] SHA256(application)
168 byte flags (including "user present", extensions present)
169 uint32 counter
170 byte[] extensions
171 byte[32] SHA256(message)
172
173The signature returned from U2F hardware takes the following format:
174
175 byte flags (including "user present")
176 uint32 counter
djm@openbsd.orgc4036fe2019-12-10 22:36:08 +0000177 byte[] ecdsa_signature (in X9.62 format).
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000178
179For use in the SSH protocol, we wish to avoid server-side parsing of ASN.1
180format data in the pre-authentication attack surface. Therefore, the
181signature format used on the wire in SSH2_USERAUTH_REQUEST packets will
djm@openbsd.orga70d92f2019-11-19 22:23:19 +0000182be reformatted to better match the existing signature encoding:
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000183
djm@openbsd.orga70d92f2019-11-19 22:23:19 +0000184 string "sk-ecdsa-sha2-nistp256@openssh.com"
185 string ecdsa_signature
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000186 byte flags
187 uint32 counter
188
djm@openbsd.orga70d92f2019-11-19 22:23:19 +0000189Where the "ecdsa_signature" field follows the RFC5656 ECDSA signature
190encoding:
191
192 mpint r
193 mpint s
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000194
markus@openbsd.orgb556cc32019-11-12 19:34:40 +0000195For Ed25519 keys the signature is encoded as:
196
197 string "sk-ssh-ed25519@openssh.com"
198 string signature
199 byte flags
200 uint32 counter
201
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000202ssh-agent protocol extensions
203-----------------------------
204
naddy@openbsd.orgad384062019-11-01 12:10:43 +0000205ssh-agent requires a protocol extension to support U2F keys. At
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000206present the closest analogue to Security Keys in ssh-agent are PKCS#11
207tokens, insofar as they require a middleware library to communicate with
208the device that holds the keys. Unfortunately, the protocol message used
209to add PKCS#11 keys to ssh-agent does not include any way to send the
210key handle to the agent as U2F keys require.
211
naddy@openbsd.orgad384062019-11-01 12:10:43 +0000212To avoid this, without having to add wholly new messages to the agent
213protocol, we will use the existing SSH2_AGENTC_ADD_ID_CONSTRAINED message
214with a new key constraint extension to encode a path to the middleware
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000215library for the key. The format of this constraint extension would be:
216
217 byte SSH_AGENT_CONSTRAIN_EXTENSION
djm@openbsd.org22d4beb2019-12-10 23:21:56 +0000218 string sk-provider@openssh.com
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000219 string middleware path
220
221This constraint-based approach does not present any compatibility
222problems.
223
224OpenSSH integration
225-------------------
226
227U2F tokens may be attached via a number of means, including USB and NFC.
228The USB interface is standardised around a HID protocol, but we want to
229be able to support other transports as well as dummy implementations for
djm@openbsd.org13066432019-11-18 04:34:47 +0000230regress testing. For this reason, OpenSSH shall support a dynamically-
231loaded middleware libraries to communicate with security keys, but offer
232support for the common case of USB HID security keys internally.
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000233
234The middleware library need only expose a handful of functions:
235
236 /* Flags */
237 #define SSH_SK_USER_PRESENCE_REQD 0x01
238
markus@openbsd.orgfd1a3b52019-11-12 19:32:30 +0000239 /* Algs */
240 #define SSH_SK_ECDSA 0x00
241 #define SSH_SK_ED25519 0x01
242
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000243 struct sk_enroll_response {
244 uint8_t *public_key;
245 size_t public_key_len;
246 uint8_t *key_handle;
247 size_t key_handle_len;
248 uint8_t *signature;
249 size_t signature_len;
250 uint8_t *attestation_cert;
251 size_t attestation_cert_len;
252 };
253
254 struct sk_sign_response {
255 uint8_t flags;
256 uint32_t counter;
257 uint8_t *sig_r;
258 size_t sig_r_len;
259 uint8_t *sig_s;
260 size_t sig_s_len;
261 };
262
263 /* Return the version of the middleware API */
264 uint32_t sk_api_version(void);
265
266 /* Enroll a U2F key (private key generation) */
markus@openbsd.orgfd1a3b52019-11-12 19:32:30 +0000267 int sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len,
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000268 const char *application, uint8_t flags,
269 struct sk_enroll_response **enroll_response);
270
271 /* Sign a challenge */
markus@openbsd.orgfd1a3b52019-11-12 19:32:30 +0000272 int sk_sign(int alg, const uint8_t *message, size_t message_len,
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000273 const char *application,
274 const uint8_t *key_handle, size_t key_handle_len,
275 uint8_t flags, struct sk_sign_response **sign_response);
276
djm@openbsd.org18e84bf2019-11-28 05:20:54 +0000277In OpenSSH, these will be invoked by using a similar mechanism to
278ssh-pkcs11-helper to provide address-space containment of the
279middleware from ssh-agent.
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000280