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