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 using a similar mechanism to 275ssh-pkcs11-helper to provide address-space containment of the 276middleware from ssh-agent. 277 278