[openssh-commits] [openssh] 02/14: upstream: Protocol documentation for U2F/FIDO keys in OpenSSH

git+noreply at mindrot.org git+noreply at mindrot.org
Fri Nov 1 09:47:11 AEDT 2019


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

commit 57ecc10628b04c384cbba2fbc87d38b74cd1199d
Author: djm at openbsd.org <djm at openbsd.org>
Date:   Thu Oct 31 21:14:17 2019 +0000

    upstream: Protocol documentation for U2F/FIDO keys in OpenSSH
    
    OpenBSD-Commit-ID: 8f3247317c2909870593aeb306dff848bc427915
---
 PROTOCOL.u2f | 224 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 224 insertions(+)

diff --git a/PROTOCOL.u2f b/PROTOCOL.u2f
new file mode 100644
index 00000000..ab9e3e33
--- /dev/null
+++ b/PROTOCOL.u2f
@@ -0,0 +1,224 @@
+This document describes OpenSSH's support for U2F/FIDO security keys.
+
+Background
+----------
+
+U2F is an open standard for two-factor authentication hardware, widely
+used for user authentication to websites. U2F tokens are ubiquitous,
+available from a number of manufacturers and are currently by far the
+cheapest way for users to achieve hardware-backed credential storage.
+
+The U2F protocol however cannot be trivially used as an SSH protocol key
+type as both the inputs to the signature operation and the resultant
+signature differ from those specified for SSH. For similar reasons,
+integration of U2F devices cannot be achieved via the PKCS#11 API.
+
+U2F also offers a number of features that are attractive in the context
+of SSH authentication. They can be configured to require indication
+of "user presence" for each signature operation (typically achieved
+by requiring the user touch the key). They also offer an attestation
+mechanism at key enrollment time that can be used to prove that a
+given key is backed by hardware. Finally the signature format includes
+a monotonic signature counter that can be used (at scale) to detect
+concurrent use of a private key, should it be extracted from hardware.
+
+U2F private keys are generatted through an enrollment operation,
+which takes an application ID - a URL-like string, typically "ssh:"
+in this case, but a HTTP origin for the case of web authentication,
+and a challenge string (typically randomly generated). The enrollment
+operation returns a public key, a key handle that must be used to invoke
+the hardware-backed private key, some flags and signed attestation
+information that may be used to verify that private key is hosted on a
+particular hardware instance.
+
+It is common for U2F hardware to derive private keys from the key handle
+in conjunction with a small per-device secret that is unique to the
+hardware, thus requiring little on-device storage for an effectively
+unlimited number of supported keys. This drives the requirement that
+the key handle be supplied for each signature operation. U2F tokens
+primarily use ECDSA signatures in the NIST-P256 field.
+
+SSH U2F Key formats
+-------------------
+
+OpenSSH integrates U2F as a new key and corresponding certificate type:
+
+	sk-ecdsa-sha2-nistp256 at openssh.com
+	sk-ecdsa-sha2-nistp256-cert-v01 at openssh.com
+
+These key types are supported only for user authentication with the
+"publickey" method. They are not used for host-based user authentication
+or server host key authentication.
+
+While each uses ecdsa-sha256-nistp256 as the underlying signature primitive,
+keys require extra information in the public and private keys, and in
+the signature object itself. As such they cannot be made compatible with
+the existing ecdsa-sha2-nistp* key types.
+
+The format of a sk-ecdsa-sha2-nistp256 at openssh.com public key is:
+
+	string		"sk-ecdsa-sha2-nistp256 at openssh.com"
+	ec_point	Q
+	string		application (user-specified, but typically "ssh:")
+
+The corresponding private key contains:
+
+	string		"sk-ecdsa-sha2-nistp256 at openssh.com"
+	ec_point	Q
+	string		application (user-specified, but typically "ssh:")
+	string		key_handle
+	uint32		flags
+	string		reserved
+
+The certificate form of a SSH U2F key appends the usual certificate
+information to the public key:
+
+	string		"sk-ecdsa-sha2-nistp256 at openssh.com"
+	string		nonce
+	ec_point	Q
+	string		application
+	uint64		serial
+	uint32		type
+	string		key id
+	string		valid principals
+	uint64		valid after
+	uint64		valid before
+	string		critical options
+	string		extensions
+	string		reserved
+	string		signature key
+	string		signature
+
+During key generation, the hardware also returns attestation information
+that may be used to cryptographically prove that a given key is
+hardware-backed. Unfortunately, the protocol required for this proof is
+not privacy-preserving and may be used to identify U2F tokens with at
+least manufacturer and batch number granularity. For this reason, we
+choose not to include this information in the public key or save it by
+default.
+
+Attestation information is very useful however in an organisational
+context, where it may be used by an CA as part of certificate
+issuance. In this case, exposure to the CA of hardware identity is
+desirable. To support this case, OpenSSH optionally allows retaining the
+attestation information at the time of key generation. It will take the
+following format:
+
+	string		"sk-attest-v00"
+	uint32		version		(1 for U2F, 2 for FIDO2 in future)
+	string		attestation certificate
+	string		enrollment signature
+
+SSH U2F signatures
+------------------
+
+In addition to the message to be signed, the U2F signature operation 
+requires a few additional parameters:
+
+	byte		control bits (e.g. "user presence required" flag)
+	byte[32]	SHA256(message)
+	byte[32]	SHA256(application)
+	byte		key_handle length
+	byte[]		key_handle
+
+This signature is signed over a blob that consists of:
+
+	byte[32]	SHA256(application)
+	byte		flags (including "user present", extensions present)
+	uint32		counter
+	byte[]		extensions
+	byte[32]	SHA256(message)
+
+The signature returned from U2F hardware takes the following format:
+
+	byte		flags (including "user present")
+	uint32		counter
+	byte[32]	ecdsa_signature (in X9.62 format).
+
+For use in the SSH protocol, we wish to avoid server-side parsing of ASN.1
+format data in the pre-authentication attack surface. Therefore, the
+signature format used on the wire in SSH2_USERAUTH_REQUEST packets will
+be reformatted slightly:
+
+	mpint		r
+	mpint		s
+	byte		flags
+	uint32		counter
+
+Where 'r' and 's' are extracted by the client or token middleware from the
+ecdsa_signature field returned from the hardware.
+
+ssh-agent protocol extensions
+-----------------------------
+
+ssh-agent requires some protocol extension to support U2F keys. At
+present the closest analogue to Security Keys in ssh-agent are PKCS#11
+tokens, insofar as they require a middleware library to communicate with
+the device that holds the keys. Unfortunately, the protocol message used
+to add PKCS#11 keys to ssh-agent does not include any way to send the
+key handle to the agent as U2F keys require.
+
+To avoid this, without having to add wholy new messages to the agent
+protocol we will use the existing SSH2_AGENTC_ADD_ID_CONSTRAINED message
+with a new a key constraint extension to encode a path to the middleware
+library for the key. The format of this constraint extension would be:
+
+	byte		SSH_AGENT_CONSTRAIN_EXTENSION
+	string		sk at openssh.com
+	string		middleware path
+
+This constraint-based approach does not present any compatibility
+problems.
+
+OpenSSH integration
+-------------------
+
+U2F tokens may be attached via a number of means, including USB and NFC.
+The USB interface is standardised around a HID protocol, but we want to
+be able to support other transports as well as dummy implementations for
+regress testing. For this reason, OpenSSH shall perform all U2F operations
+via a dynamically-loaded middleware library.
+
+The middleware library need only expose a handful of functions:
+
+	/* Flags */
+	#define SSH_SK_USER_PRESENCE_REQD	0x01
+
+	struct sk_enroll_response {
+		uint8_t *public_key;
+		size_t public_key_len;
+		uint8_t *key_handle;
+		size_t key_handle_len;
+		uint8_t *signature;
+		size_t signature_len;
+		uint8_t *attestation_cert;
+		size_t attestation_cert_len;
+	};
+
+	struct sk_sign_response {
+		uint8_t flags;
+		uint32_t counter;
+		uint8_t *sig_r;
+		size_t sig_r_len;
+		uint8_t *sig_s;
+		size_t sig_s_len;
+	};
+
+	/* Return the version of the middleware API */
+	uint32_t sk_api_version(void);
+
+	/* Enroll a U2F key (private key generation) */
+	int sk_enroll(const uint8_t *challenge, size_t challenge_len,
+	    const char *application, uint8_t flags,
+	    struct sk_enroll_response **enroll_response);
+
+	/* Sign a challenge */
+	int sk_sign(const uint8_t *message, size_t message_len,
+	    const char *application,
+	    const uint8_t *key_handle, size_t key_handle_len,
+	    uint8_t flags, struct sk_sign_response **sign_response);
+
+In OpenSSH, these will be invoked by generalising the existing
+ssh-pkcs11-helper mechanism to provide containment of the middleware from
+ssh-agent.
+

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list