blob: ca55c42972ef84d726cddf3d8fbaa7a453ef9b32 [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
39primarily use ECDSA signatures in the NIST-P256 field.
40
41SSH U2F Key formats
42-------------------
43
44OpenSSH integrates U2F as a new key and corresponding certificate type:
45
46 sk-ecdsa-sha2-nistp256@openssh.com
47 sk-ecdsa-sha2-nistp256-cert-v01@openssh.com
48
49These key types are supported only for user authentication with the
50"publickey" method. They are not used for host-based user authentication
51or server host key authentication.
52
53While each uses ecdsa-sha256-nistp256 as the underlying signature primitive,
54keys require extra information in the public and private keys, and in
55the signature object itself. As such they cannot be made compatible with
56the existing ecdsa-sha2-nistp* key types.
57
58The format of a sk-ecdsa-sha2-nistp256@openssh.com public key is:
59
60 string "sk-ecdsa-sha2-nistp256@openssh.com"
61 ec_point Q
62 string application (user-specified, but typically "ssh:")
63
64The corresponding private key contains:
65
66 string "sk-ecdsa-sha2-nistp256@openssh.com"
67 ec_point Q
68 string application (user-specified, but typically "ssh:")
69 string key_handle
70 uint32 flags
71 string reserved
72
73The certificate form of a SSH U2F key appends the usual certificate
74information to the public key:
75
naddy@openbsd.orgad384062019-11-01 12:10:43 +000076 string "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
djm@openbsd.org57ecc102019-10-31 21:14:17 +000077 string nonce
78 ec_point Q
79 string application
80 uint64 serial
81 uint32 type
82 string key id
83 string valid principals
84 uint64 valid after
85 uint64 valid before
86 string critical options
87 string extensions
88 string reserved
89 string signature key
90 string signature
91
92During key generation, the hardware also returns attestation information
93that may be used to cryptographically prove that a given key is
94hardware-backed. Unfortunately, the protocol required for this proof is
95not privacy-preserving and may be used to identify U2F tokens with at
96least manufacturer and batch number granularity. For this reason, we
97choose not to include this information in the public key or save it by
98default.
99
100Attestation information is very useful however in an organisational
naddy@openbsd.orgad384062019-11-01 12:10:43 +0000101context, where it may be used by a CA as part of certificate
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000102issuance. In this case, exposure to the CA of hardware identity is
103desirable. To support this case, OpenSSH optionally allows retaining the
104attestation information at the time of key generation. It will take the
105following format:
106
107 string "sk-attest-v00"
108 uint32 version (1 for U2F, 2 for FIDO2 in future)
109 string attestation certificate
110 string enrollment signature
111
112SSH U2F signatures
113------------------
114
115In addition to the message to be signed, the U2F signature operation
116requires a few additional parameters:
117
118 byte control bits (e.g. "user presence required" flag)
119 byte[32] SHA256(message)
120 byte[32] SHA256(application)
121 byte key_handle length
122 byte[] key_handle
123
124This signature is signed over a blob that consists of:
125
126 byte[32] SHA256(application)
127 byte flags (including "user present", extensions present)
128 uint32 counter
129 byte[] extensions
130 byte[32] SHA256(message)
131
132The signature returned from U2F hardware takes the following format:
133
134 byte flags (including "user present")
135 uint32 counter
136 byte[32] ecdsa_signature (in X9.62 format).
137
138For use in the SSH protocol, we wish to avoid server-side parsing of ASN.1
139format data in the pre-authentication attack surface. Therefore, the
140signature format used on the wire in SSH2_USERAUTH_REQUEST packets will
markus@openbsd.orgfd1a3b52019-11-12 19:32:30 +0000141be reformatted slightly and the ecdsa_signature_blob value has the encoding:
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000142
143 mpint r
144 mpint s
145 byte flags
146 uint32 counter
147
148Where 'r' and 's' are extracted by the client or token middleware from the
149ecdsa_signature field returned from the hardware.
150
markus@openbsd.orgb556cc32019-11-12 19:34:40 +0000151For Ed25519 keys the signature is encoded as:
152
153 string "sk-ssh-ed25519@openssh.com"
154 string signature
155 byte flags
156 uint32 counter
157
158
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000159ssh-agent protocol extensions
160-----------------------------
161
naddy@openbsd.orgad384062019-11-01 12:10:43 +0000162ssh-agent requires a protocol extension to support U2F keys. At
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000163present the closest analogue to Security Keys in ssh-agent are PKCS#11
164tokens, insofar as they require a middleware library to communicate with
165the device that holds the keys. Unfortunately, the protocol message used
166to add PKCS#11 keys to ssh-agent does not include any way to send the
167key handle to the agent as U2F keys require.
168
naddy@openbsd.orgad384062019-11-01 12:10:43 +0000169To avoid this, without having to add wholly new messages to the agent
170protocol, we will use the existing SSH2_AGENTC_ADD_ID_CONSTRAINED message
171with a new key constraint extension to encode a path to the middleware
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000172library for the key. The format of this constraint extension would be:
173
174 byte SSH_AGENT_CONSTRAIN_EXTENSION
175 string sk@openssh.com
176 string middleware path
177
178This constraint-based approach does not present any compatibility
179problems.
180
181OpenSSH integration
182-------------------
183
184U2F tokens may be attached via a number of means, including USB and NFC.
185The USB interface is standardised around a HID protocol, but we want to
186be able to support other transports as well as dummy implementations for
187regress testing. For this reason, OpenSSH shall perform all U2F operations
188via a dynamically-loaded middleware library.
189
190The middleware library need only expose a handful of functions:
191
192 /* Flags */
193 #define SSH_SK_USER_PRESENCE_REQD 0x01
194
markus@openbsd.orgfd1a3b52019-11-12 19:32:30 +0000195 /* Algs */
196 #define SSH_SK_ECDSA 0x00
197 #define SSH_SK_ED25519 0x01
198
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000199 struct sk_enroll_response {
200 uint8_t *public_key;
201 size_t public_key_len;
202 uint8_t *key_handle;
203 size_t key_handle_len;
204 uint8_t *signature;
205 size_t signature_len;
206 uint8_t *attestation_cert;
207 size_t attestation_cert_len;
208 };
209
210 struct sk_sign_response {
211 uint8_t flags;
212 uint32_t counter;
213 uint8_t *sig_r;
214 size_t sig_r_len;
215 uint8_t *sig_s;
216 size_t sig_s_len;
217 };
218
219 /* Return the version of the middleware API */
220 uint32_t sk_api_version(void);
221
222 /* Enroll a U2F key (private key generation) */
markus@openbsd.orgfd1a3b52019-11-12 19:32:30 +0000223 int sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len,
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000224 const char *application, uint8_t flags,
225 struct sk_enroll_response **enroll_response);
226
227 /* Sign a challenge */
markus@openbsd.orgfd1a3b52019-11-12 19:32:30 +0000228 int sk_sign(int alg, const uint8_t *message, size_t message_len,
djm@openbsd.org57ecc102019-10-31 21:14:17 +0000229 const char *application,
230 const uint8_t *key_handle, size_t key_handle_len,
231 uint8_t flags, struct sk_sign_response **sign_response);
232
233In OpenSSH, these will be invoked by generalising the existing
234ssh-pkcs11-helper mechanism to provide containment of the middleware from
235ssh-agent.
236