123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- 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 generated 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 a 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, though the FIDO2
- standard specifies additional key types, including one based on Ed25519.
- Use of U2F security keys does not automatically imply multi-factor
- authentication. From sshd's perspective, a security key constitutes a
- single factor of authentication, even if protected by a PIN or biometric
- authentication. To enable multi-factor authentication in ssh, please
- refer to the AuthenticationMethods option in sshd_config(5).
- SSH U2F Key formats
- -------------------
- OpenSSH integrates U2F as new key and corresponding certificate types:
- sk-ecdsa-sha2-nistp256@openssh.com
- sk-ecdsa-sha2-nistp256-cert-v01@openssh.com
- sk-ssh-ed25519@openssh.com
- sk-ssh-ed25519-cert-v01@openssh.com
- 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@openssh.com public key is:
- string "sk-ecdsa-sha2-nistp256@openssh.com"
- string curve name
- ec_point Q
- string application (user-specified, but typically "ssh:")
- The corresponding private key contains:
- string "sk-ecdsa-sha2-nistp256@openssh.com"
- string curve name
- ec_point Q
- string application (user-specified, but typically "ssh:")
- uint8 flags
- string key_handle
- string reserved
- The format of a sk-ssh-ed25519@openssh.com public key is:
- string "sk-ssh-ed25519@openssh.com"
- string public key
- string application (user-specified, but typically "ssh:")
- With a private half consisting of:
- string "sk-ssh-ed25519@openssh.com"
- string public key
- string application (user-specified, but typically "ssh:")
- uint8 flags
- string key_handle
- string reserved
- The certificate form for SSH U2F keys appends the usual certificate
- information to the public key:
- string "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
- string nonce
- string curve name
- 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
- and for security key ed25519 certificates:
- string "sk-ssh-ed25519-cert-v01@openssh.com"
- string nonce
- string public key
- 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
- Both security key certificates use the following encoding for private keys:
- string type (e.g. "sk-ssh-ed25519-cert-v01@openssh.com")
- string pubkey (the above key/cert structure)
- string application
- uint8 flags
- string key_handle
- string reserved
- 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 useful for out-of-band key and certificate
- registration workflows, e.g. proving to a CA that a key is backed
- by trusted hardware before it will issue a certificate. To support this
- case, OpenSSH optionally allows retaining the attestation information
- at the time of key generation. It will take the following format:
- string "ssh-sk-attest-v01"
- string attestation certificate
- string enrollment signature
- string authenticator data (CBOR encoded)
- uint32 reserved flags
- string reserved string
- A previous version of this format, emitted prior to OpenSSH 8.4 omitted
- the authenticator data.
- string "ssh-sk-attest-v00"
- string attestation certificate
- string enrollment signature
- uint32 reserved flags
- string reserved string
- OpenSSH treats the attestation certificate and enrollment signatures as
- opaque objects and does no interpretation of them itself.
- SSH U2F signatures
- ------------------
- In addition to the message to be signed, the U2F signature operation
- requires the key handle and a few additional parameters. The 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)
- No extensions are yet defined for SSH use. If any are defined in the future,
- it will be possible to infer their presence from the contents of the "flags"
- value.
- The signature returned from U2F hardware takes the following format:
- byte flags (including "user present")
- uint32 counter
- byte[] 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 to better match the existing signature encoding:
- string "sk-ecdsa-sha2-nistp256@openssh.com"
- string ecdsa_signature
- byte flags
- uint32 counter
- Where the "ecdsa_signature" field follows the RFC5656 ECDSA signature
- encoding:
- mpint r
- mpint s
- For Ed25519 keys the signature is encoded as:
- string "sk-ssh-ed25519@openssh.com"
- string signature
- byte flags
- uint32 counter
- webauthn signatures
- -------------------
- The W3C/FIDO webauthn[1] standard defines a mechanism for a web browser to
- interact with FIDO authentication tokens. This standard builds upon the
- FIDO standards, but requires different signature contents to raw FIDO
- messages. OpenSSH supports ECDSA/p256 webauthn signatures through the
- "webauthn-sk-ecdsa-sha2-nistp256@openssh.com" signature algorithm.
- The wire encoding for a webauthn-sk-ecdsa-sha2-nistp256@openssh.com
- signature is similar to the sk-ecdsa-sha2-nistp256@openssh.com format:
- string "webauthn-sk-ecdsa-sha2-nistp256@openssh.com"
- string ecdsa_signature
- byte flags
- uint32 counter
- string origin
- string clientData
- string extensions
- Where "origin" is the HTTP origin making the signature, "clientData" is
- the JSON-like structure signed by the browser and "extensions" are any
- extensions used in making the signature.
- [1] https://www.w3.org/TR/webauthn-2/
- ssh-agent protocol extensions
- -----------------------------
- ssh-agent requires a 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 wholly new messages to the agent
- protocol, we will use the existing SSH2_AGENTC_ADD_ID_CONSTRAINED message
- with a new 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-provider@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 support a dynamically-
- loaded middleware libraries to communicate with security keys, but offer
- support for the common case of USB HID security keys internally.
- The middleware library need only expose a handful of functions and
- numbers listed in sk-api.h. Included in the defined numbers is a
- SSH_SK_VERSION_MAJOR that should be incremented for each incompatible
- API change.
- miscellaneous options may be passed to the middleware as a NULL-
- terminated array of pointers to struct sk_option. The middleware may
- ignore unsupported or unknown options unless the "required" flag is set,
- in which case it should return failure if an unsupported option is
- requested.
- At present the following options names are supported:
- "device"
- Specifies a specific FIDO device on which to perform the
- operation. The value in this field is interpreted by the
- middleware but it would be typical to specify a path to
- a /dev node for the device in question.
- "user"
- Specifies the FIDO2 username used when enrolling a key,
- overriding OpenSSH's default of using an all-zero username.
- In OpenSSH, the middleware will be invoked by using a similar mechanism to
- ssh-pkcs11-helper to provide address-space containment of the
- middleware from ssh-agent.
- $OpenBSD: PROTOCOL.u2f,v 1.26 2020/09/09 03:08:01 djm Exp $
|