-
Notifications
You must be signed in to change notification settings - Fork 178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add "sign" extension #2078
base: main
Are you sure you want to change the base?
Add "sign" extension #2078
Conversation
Have you looked at https://github.com/WebKit/explainers/tree/main/remote-cryptokeys? Is there some overlap? |
Thanks, I was not aware of that. There is some overlap, and it should be fairly straightforward to make the CTAP layer of this "sign" extension compatible as a key store backend for remote CryptoKeys. However, remote CryptoKeys doesn't address all the concerns that informed the design of the "sign" extension:
I do agree that WebCrypto is in some ways a more appropriate home for these features. But on the other hand, one powerful benefit of doing this in WebAuthn instead, with algorithm identifiers etc. sent to and interpreted only by the authenticator, is that authenticators can introduce support for new algorithms without the client explicitly supporting it. For example, we want to be able to create signatures using a key derived by ARKG - in the "sign" extension this only needs a new |
What we are trying to do is create a standardized API for a WSCD https://github.com/eu-digital-identity-wallet/eudi-doc-architecture-and-reference-framework/blob/v1.4.0/docs/arf.md#42-reference-architecture The EU has strict certification requirements for the storage of private keys. These are requirements met by only a handful of mobile phones. This gives Fido/Passkeys an opening to provide the crypto functionality used by EUDI wallets. Attestation is an important part of the value proposition to make this work for EUDI. While exposing this via webcrypto would be interesting, the larger use is actually for native applications, which will have to use cloud HSM for the storage unless we come up with a local alternative. This extension would also ideally be provided by the platform authenticator and could be CC certified. |
Passkeys would be an ideal use case for the EUDI wallet, but it would be great to prevent the keys from being exposed to Javascript for instance. Also support for different schemes would be ideal, especially in order to provide ZK proofs (I'm thinking EdDSA with different curves). |
Indeed, this is precisely the goal of this extension.
We've designed the extension with some algorithm agility to hopefully support this, but this would of course still rely on standardization of algorithm IDs and data interchange formats. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I support this idea. Where are we on implementations?
Thank you @selfissued!
Only barely started, I'm afraid. We (Yubico) have some rough internal proof-of-concept prototypes (of all three of authenticator, client and RP), but nothing yet ready to share. No commitments from other WG participants at this point. |
Note that as noted in the inline `ISSUE` annotations, what "pre-hashed" means is currently underspecified and will need to be clarified.
I'm excited to see this proposal, its an API I have wanted for a long time. I've implemented hacks around Digital Credential wallets, binding credentials to passkeys, by proxying information in and out of frames, and overloading the "challenge" to sign arbitrary data... Its all gross, this API would lead to a much better experience. I've implemented hash and then sign for We've been considering, how to communicate about the various different layers which are relevant for hash and then sign, you can see some background here: https://mailarchive.ietf.org/arch/msg/cose/JonuJfnRwpR7wlmZ40Vyt-uuwoY/ If we are talking only about the WebCrypto API side of this, here's some high level pseudocode, showing how the current APIs work for generating JOSE and COSE compliant signatures, using IANA registered algorithms: Start by implementing a generic signer pattern, so your code can pair with web crypto or remote signers: const signer = (privateKey) => {
return {
sign: async (toBeSigned: UInt8Array): Promise<UInt8Array> => {
// skip this step if you are passing a non exportable private key reference
const signingKey = await window.crypto.subtle.importKey(
"jwk",
privateKey, // JWK, other formats
{
name: "ECDSA",
namedCurve: "P-256",
},
true,
["sign"],
)
const signature = await window.crypto.subtle.sign(
{
name: "ECDSA",
hash: { name: "SHA-256" },
},
signingKey,
toBeSigned,
);
return signature;
}
}
} This signer can then be passed to a JWS or COSE_Sign1. Lets look at the remote kms API that pairs with this, the code will be different with Google, Microsoft or Amazon KMS interfaces but the general idea will be the same: export const signer = ({ name, client }: RequestRemoteSigner): { sign: (bytes: UInt8Array) => Promise<UInt8Array> } => {
return {
sign: async (bytes: ArrayBuffer) => {
// on the client before calling the remote signer
const digest = crypto.createHash("SHA-256")
digest.update(Buffer.from(bytes))
const digested = digest.digest()
// calling the remote signer
const [{ signature }] = await client.asymmetricSign({
name: name, // identifier for the remote key to be used
digest: {
sha256: digested,
},
})
// sometimes need to convert response signature from DER
return Buffer.from(format.derToJose(Buffer.from(signature)), 'base64')
},
}
} As I understand it you are proposing a remote signing API that would treat the device as basically a remote KMS, that can be called from the browser, but where some state from the browser flows to the device. So you would have some provider setup:
And then the call to the remote signer would look like this:
Afterwards, you would construct the JWS or COSE_Sign1 from the result. Depending on which crypto the hardware signer supports you would have to map parameters to algorithm names. So if you are doing EdDSA with Ed25519 (no prehash) You would use 1 : -8 in the header in COSE, but "alg: EdDSA" in the header in JOSE. The algorithm identifiers in JOSE and COSE will either be compatible with the cryptographic capabilities of the device, or they won't. Regarding Pre-Hashing, see Section 5.4 of https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf for some recent guidance on this subject, especially the bottom part about how to construct a pre hash signature with ML-DSA:
With ES256 there is no way to tell if the content was hashed on the client or server, and there is no domain separation required in the algorithm, or binding to the hash function used. If you wanted to make a pre hash version of ES256 where there was domain separation, you would start by constructing the toBeSigned bytes like so:
(this is just an example) In COSE, ES256 means SHA-256, prehash (no domain separation), but ECDSA with P-256 / P-384 / P-521. In COSE, ES256 means SHA-256, prehash (no domain separation), but with ONLY P-256. If your goal is to support these algorithms, in COSE, without creating any new algorithm identifiers, you can expose the following interface instead of a fully specified algorithm identifier (which don't exist in COSE as of this post): { kty, crv, alg } -> [ 1, 1, -7 ] / 0x83010126 -> ECDSA with P-256 and SHA-256, your API can map the fully specified parameters your hardware needs, to the parameterization that a COSE API needs. In the long term, it would be better to fully specify the signing algorithm, so that a single identifier can be used to negotiate capabilities between the devices and web authn. |
Hi @OR13 - is this a reply to my email to the COSE/JOSE mail lists? |
Yes, but also to the part of the PR that questions how much details you need for pre hash. |
This extension allows for signing arbitrary data using a key associated with but different from a WebAuthn credential key pair. Motivating use cases of this include:
By "signing arbitrary data" we mean a distinction from a WebAuthn assertion signature, which signs not over the
challenge
parameter provided by the RP or client, but over the concatenation of authenticator data and a hash of a JSON object embedding that challenge. In contrast, signatures returned from this extension are made over the given input unaltered. The signing key pair is distinct from its parent WebAuthn credential key pair, so this arbitrary input cannot be used to bypass the domain binding restrictions for WebAuthn credentials.This addresses some of the same use cases as #1895 would, but goes a step further to enable truly hardware-bound keys. As discussed at some length in #1945, WebCrypto keys are never truly unextractable unless the client enforces domain separation before converting PRF outputs to
CryptoKey
s. Even then, those keys are not hardware-bound as they are exposed to the client process. This PR is what was meant by "pursuing [...] other ways" in #1945 (comment).This extension does not cover encryption use cases as #1895 and #1945 would, but instead we intend to also propose an architecturally analogous
kem
(key encapsulation mechanism) extension to address those use cases.Preview | Diff