[BACK]Return to PROTOCOL.u2f CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/PROTOCOL.u2f, Revision 1.26

1.1       djm         1: This document describes OpenSSH's support for U2F/FIDO security keys.
                      2:
                      3: Background
                      4: ----------
                      5:
                      6: U2F is an open standard for two-factor authentication hardware, widely
                      7: used for user authentication to websites. U2F tokens are ubiquitous,
                      8: available from a number of manufacturers and are currently by far the
                      9: cheapest way for users to achieve hardware-backed credential storage.
                     10:
                     11: The U2F protocol however cannot be trivially used as an SSH protocol key
                     12: type as both the inputs to the signature operation and the resultant
                     13: signature differ from those specified for SSH. For similar reasons,
                     14: integration of U2F devices cannot be achieved via the PKCS#11 API.
                     15:
                     16: U2F also offers a number of features that are attractive in the context
                     17: of SSH authentication. They can be configured to require indication
                     18: of "user presence" for each signature operation (typically achieved
                     19: by requiring the user touch the key). They also offer an attestation
                     20: mechanism at key enrollment time that can be used to prove that a
                     21: given key is backed by hardware. Finally the signature format includes
                     22: a monotonic signature counter that can be used (at scale) to detect
                     23: concurrent use of a private key, should it be extracted from hardware.
                     24:
1.2       naddy      25: U2F private keys are generated through an enrollment operation,
1.1       djm        26: which takes an application ID - a URL-like string, typically "ssh:"
                     27: in this case, but a HTTP origin for the case of web authentication,
                     28: and a challenge string (typically randomly generated). The enrollment
                     29: operation returns a public key, a key handle that must be used to invoke
                     30: the hardware-backed private key, some flags and signed attestation
1.2       naddy      31: information that may be used to verify that a private key is hosted on a
1.1       djm        32: particular hardware instance.
                     33:
                     34: It is common for U2F hardware to derive private keys from the key handle
                     35: in conjunction with a small per-device secret that is unique to the
                     36: hardware, thus requiring little on-device storage for an effectively
                     37: unlimited number of supported keys. This drives the requirement that
                     38: the key handle be supplied for each signature operation. U2F tokens
1.7       djm        39: primarily use ECDSA signatures in the NIST-P256 field, though the FIDO2
1.14      naddy      40: standard specifies additional key types, including one based on Ed25519.
1.1       djm        41:
1.22      djm        42: Use of U2F security keys does not automatically imply multi-factor
1.23      djm        43: authentication. From sshd's perspective, a security key constitutes a
1.22      djm        44: single factor of authentication, even if protected by a PIN or biometric
                     45: authentication.  To enable multi-factor authentication in ssh, please
                     46: refer to the AuthenticationMethods option in sshd_config(5).
                     47:
                     48:
1.1       djm        49: SSH U2F Key formats
                     50: -------------------
                     51:
1.7       djm        52: OpenSSH integrates U2F as new key and corresponding certificate types:
1.1       djm        53:
                     54:        sk-ecdsa-sha2-nistp256@openssh.com
                     55:        sk-ecdsa-sha2-nistp256-cert-v01@openssh.com
1.7       djm        56:        sk-ssh-ed25519@openssh.com
                     57:        sk-ssh-ed25519-cert-v01@openssh.com
1.1       djm        58:
                     59: While each uses ecdsa-sha256-nistp256 as the underlying signature primitive,
                     60: keys require extra information in the public and private keys, and in
                     61: the signature object itself. As such they cannot be made compatible with
                     62: the existing ecdsa-sha2-nistp* key types.
                     63:
                     64: The format of a sk-ecdsa-sha2-nistp256@openssh.com public key is:
                     65:
                     66:        string          "sk-ecdsa-sha2-nistp256@openssh.com"
1.5       djm        67:        string          curve name
1.1       djm        68:        ec_point        Q
                     69:        string          application (user-specified, but typically "ssh:")
                     70:
                     71: The corresponding private key contains:
                     72:
                     73:        string          "sk-ecdsa-sha2-nistp256@openssh.com"
1.5       djm        74:        string          curve name
1.1       djm        75:        ec_point        Q
                     76:        string          application (user-specified, but typically "ssh:")
1.6       djm        77:        uint8           flags
1.1       djm        78:        string          key_handle
                     79:        string          reserved
                     80:
1.7       djm        81: The 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:
                     87: With 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:")
1.12      djm        92:        uint8           flags
1.7       djm        93:        string          key_handle
                     94:        string          reserved
                     95:
                     96: The certificate form for SSH U2F keys appends the usual certificate
1.1       djm        97: information to the public key:
                     98:
1.2       naddy      99:        string          "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
1.1       djm       100:        string          nonce
1.5       djm       101:        string          curve name
1.1       djm       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:
1.12      djm       116: and for security key ed25519 certificates:
                    117:
1.7       djm       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:
1.12      djm       134: Both 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:
1.1       djm       143: During key generation, the hardware also returns attestation information
                    144: that may be used to cryptographically prove that a given key is
                    145: hardware-backed. Unfortunately, the protocol required for this proof is
                    146: not privacy-preserving and may be used to identify U2F tokens with at
                    147: least manufacturer and batch number granularity. For this reason, we
                    148: choose not to include this information in the public key or save it by
                    149: default.
                    150:
1.19      djm       151: Attestation information is useful for out-of-band key and certificate
1.20      dtucker   152: registration workflows, e.g. proving to a CA that a key is backed
1.19      djm       153: by trusted hardware before it will issue a certificate. To support this
                    154: case, OpenSSH optionally allows retaining the attestation information
                    155: at the time of key generation. It will take the following format:
1.1       djm       156:
1.26    ! djm       157:        string          "ssh-sk-attest-v01"
        !           158:        string          attestation certificate
        !           159:        string          enrollment signature
        !           160:        string          authenticator data (CBOR encoded)
        !           161:        uint32          reserved flags
        !           162:        string          reserved string
        !           163:
        !           164: A previous version of this format, emitted prior to OpenSSH 8.4 omitted
        !           165: the authenticator data.
        !           166:
1.19      djm       167:        string          "ssh-sk-attest-v00"
1.1       djm       168:        string          attestation certificate
                    169:        string          enrollment signature
1.19      djm       170:        uint32          reserved flags
                    171:        string          reserved string
                    172:
                    173: OpenSSH treats the attestation certificate and enrollment signatures as
                    174: opaque objects and does no interpretation of them itself.
1.1       djm       175:
                    176: SSH U2F signatures
                    177: ------------------
                    178:
1.9       djm       179: In addition to the message to be signed, the U2F signature operation
1.10      djm       180: requires the key handle and a few additional parameters. The signature
                    181: is signed over a blob that consists of:
1.1       djm       182:
                    183:        byte[32]        SHA256(application)
                    184:        byte            flags (including "user present", extensions present)
                    185:        uint32          counter
                    186:        byte[]          extensions
                    187:        byte[32]        SHA256(message)
                    188:
1.20      dtucker   189: No extensions are yet defined for SSH use. If any are defined in the future,
1.13      djm       190: it will be possible to infer their presence from the contents of the "flags"
                    191: value.
                    192:
1.1       djm       193: The signature returned from U2F hardware takes the following format:
                    194:
                    195:        byte            flags (including "user present")
                    196:        uint32          counter
1.10      djm       197:        byte[]          ecdsa_signature (in X9.62 format).
1.1       djm       198:
                    199: For use in the SSH protocol, we wish to avoid server-side parsing of ASN.1
                    200: format data in the pre-authentication attack surface. Therefore, the
                    201: signature format used on the wire in SSH2_USERAUTH_REQUEST packets will
1.8       djm       202: be reformatted to better match the existing signature encoding:
1.1       djm       203:
1.8       djm       204:        string          "sk-ecdsa-sha2-nistp256@openssh.com"
                    205:        string          ecdsa_signature
1.1       djm       206:        byte            flags
                    207:        uint32          counter
                    208:
1.8       djm       209: Where the "ecdsa_signature" field follows the RFC5656 ECDSA signature
                    210: encoding:
                    211:
                    212:        mpint           r
                    213:        mpint           s
1.1       djm       214:
1.4       markus    215: For Ed25519 keys the signature is encoded as:
                    216:
                    217:        string          "sk-ssh-ed25519@openssh.com"
                    218:        string          signature
                    219:        byte            flags
                    220:        uint32          counter
                    221:
1.24      djm       222: webauthn signatures
                    223: -------------------
                    224:
                    225: The W3C/FIDO webauthn[1] standard defines a mechanism for a web browser to
                    226: interact with FIDO authentication tokens. This standard builds upon the
                    227: FIDO standards, but requires different signature contents to raw FIDO
                    228: messages. OpenSSH supports ECDSA/p256 webauthn signatures through the
                    229: "webauthn-sk-ecdsa-sha2-nistp256@openssh.com" signature algorithm.
                    230:
                    231: The wire encoding for a webauthn-sk-ecdsa-sha2-nistp256@openssh.com
                    232: signature is similar to the sk-ecdsa-sha2-nistp256@openssh.com format:
                    233:
                    234:        string          "webauthn-sk-ecdsa-sha2-nistp256@openssh.com"
                    235:        string          ecdsa_signature
                    236:        byte            flags
                    237:        uint32          counter
                    238:        string          origin
                    239:        string          clientData
                    240:        string          extensions
                    241:
                    242: Where "origin" is the HTTP origin making the signature, "clientData" is
                    243: the JSON-like structure signed by the browser and "extensions" are any
                    244: extensions used in making the signature.
                    245:
                    246: [1] https://www.w3.org/TR/webauthn-2/
                    247:
1.1       djm       248: ssh-agent protocol extensions
                    249: -----------------------------
                    250:
1.2       naddy     251: ssh-agent requires a protocol extension to support U2F keys. At
1.1       djm       252: present the closest analogue to Security Keys in ssh-agent are PKCS#11
                    253: tokens, insofar as they require a middleware library to communicate with
                    254: the device that holds the keys. Unfortunately, the protocol message used
                    255: to add PKCS#11 keys to ssh-agent does not include any way to send the
                    256: key handle to the agent as U2F keys require.
                    257:
1.2       naddy     258: To avoid this, without having to add wholly new messages to the agent
                    259: protocol, we will use the existing SSH2_AGENTC_ADD_ID_CONSTRAINED message
                    260: with a new key constraint extension to encode a path to the middleware
1.1       djm       261: library for the key. The format of this constraint extension would be:
                    262:
                    263:        byte            SSH_AGENT_CONSTRAIN_EXTENSION
1.11      djm       264:        string          sk-provider@openssh.com
1.1       djm       265:        string          middleware path
                    266:
                    267: This constraint-based approach does not present any compatibility
                    268: problems.
                    269:
                    270: OpenSSH integration
                    271: -------------------
                    272:
                    273: U2F tokens may be attached via a number of means, including USB and NFC.
                    274: The USB interface is standardised around a HID protocol, but we want to
                    275: be able to support other transports as well as dummy implementations for
1.7       djm       276: regress testing. For this reason, OpenSSH shall support a dynamically-
                    277: loaded middleware libraries to communicate with security keys, but offer
                    278: support for the common case of USB HID security keys internally.
1.1       djm       279:
1.26    ! djm       280: The middleware library need only expose a handful of functions and
        !           281: numbers listed in sk-api.h. Included in the defined numbers is a
        !           282: SSH_SK_VERSION_MAJOR that should be incremented for each incompatible
1.16      djm       283: API change.
1.1       djm       284:
1.26    ! djm       285: miscellaneous options may be passed to the middleware as a NULL-
        !           286: terminated array of pointers to struct sk_option. The middleware may
        !           287: ignore unsupported or unknown options unless the "required" flag is set,
        !           288: in which case it should return failure if an unsupported option is
1.17      djm       289: requested.
                    290:
                    291: At present the following options names are supported:
                    292:
                    293:        "device"
                    294:
                    295:        Specifies a specific FIDO device on which to perform the
                    296:        operation. The value in this field is interpreted by the
                    297:        middleware but it would be typical to specify a path to
                    298:        a /dev node for the device in question.
                    299:
                    300:        "user"
                    301:
                    302:        Specifies the FIDO2 username used when enrolling a key,
                    303:        overriding OpenSSH's default of using an all-zero username.
                    304:
                    305: In OpenSSH, the middleware will be invoked by using a similar mechanism to
1.9       djm       306: ssh-pkcs11-helper to provide address-space containment of the
                    307: middleware from ssh-agent.
1.1       djm       308:
1.26    ! djm       309: $OpenBSD: PROTOCOL.u2f,v 1.25 2020/08/31 00:17:41 djm Exp $