Skip to content
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

proposal: crypto/webauthn: webauthn signature verification API #71095

Open
arianvp opened this issue Jan 2, 2025 · 6 comments
Open

proposal: crypto/webauthn: webauthn signature verification API #71095

arianvp opened this issue Jan 2, 2025 · 6 comments
Labels
Proposal Proposal-Crypto Proposal related to crypto packages or other security issues
Milestone

Comments

@arianvp
Copy link

arianvp commented Jan 2, 2025

Proposal Details

Passkey Authentication is seeing wide-spread industry adoption for authenticating users on websites and is implemented through the https://w3c.github.io/webauthn specification.

It would be great if Golang would support this authentication mechanism out of the box.

As a first step towards this path, I would like to propose introducing WebAuthn signature verification to Golang. The verification algorithm should follow the steps outlined in https://w3c.github.io/webauthn/#sctn-verifying-assertion

WebAuthn registration is a lot more specific to people's usecases (e.g. need to think about attestation and whatnot) so I would leave it out of scope for the first draft.

Related proposals:

WebAuthn is also used for the ecdsa-sk keytype in SSH and somebody asked for support for that here: #69999 . In order to implement that we need this proposal.

Initial design

Interface

type CoseAlgorithmIdentifier int64

const (
	EdDSA CoseAlgorithmIdentifier = -8
	ES256 CoseAlgorithmIdentifier = -7
	ES384 CoseAlgorithmIdentifier = -35
	ES512 CoseAlgorithmIdentifier = -36
	PS256 CoseAlgorithmIdentifier = -37
	RS256 CoseAlgorithmIdentifier = -257
)

type OriginInfo struct {
	Origin      string
	CrossOrigin bool
	TopOrigin   string
}
type OriginPolicy func(OriginInfo) error

func OriginWhitelist(origins ...string) OriginPolicy

type AuthenticatorFlags uint8

const (
	FlagUserPresent AuthenticatorFlags = 1 << iota
	_
	FlagUserVerified
	FlagBackupEligibility
	FlagBackupState
	_
	FlagAttestedCredentialData
	FlagExtensionData
)

type AuthenticatorAssertionResponse struct {
	ClientDataJson []byte
	AuthenticatorData []byte
	Signature         []byte
}

type AuthenticatorData struct {
	RpIdHash [32]byte
	Flags    AuthenticatorFlags
	Count    uint32
	// NOTE: Contains variable length AttestedCredentialData if FlagAttestedCredentialData is set
	// Because we only do assertion, this field is currently always nil
	AttestedCredentialData []byte

	// NOTE: Contains variable length ExtensionData if FlagExtensionData is set
	ExtensionData []byte
}

type VerifyOptions struct {
	RpId                     string
	OriginPolicy             OriginPolicy
	UserVerificationRequired bool
	UserPresenceRequired     bool
}

// Verify verifies the signature of the assertion response and returns the
// parsed authenticator data which can be processed further by the caller.
func (r *AuthenticatorAssertionResponse) Verify(challenge []byte, key crypto.PublicKey, alg CoseAlgorithmIdentifier, opts VerifyOptions) (*AuthenticatorData, error)

Example implementation

golang/crypto@master...arianvp:crypto:webauthn

@gopherbot gopherbot added this to the Proposal milestone Jan 2, 2025
@arianvp
Copy link
Author

arianvp commented Jan 2, 2025

Suggestions to make the interface different highly appreciated. This is just a first draft

@rolandshoemaker
Copy link
Member

Thanks for this. Haven't had a chance to fully digest the API proposal yet, but one immediate note is that we aren't introducing new golang.org/x/crypto packages. If we were to add this, it would be in the standard library crypto/ tree.

@arianvp
Copy link
Author

arianvp commented Jan 2, 2025

Note to self: it might be worth having a separate Verify and VerifyWebAuthn function.

The only difference between the two is that VerifyWebAuthn uses authData|sha256(clientDataJson) as the signature payload where clientdataJson is a json structure with the origin and the challenge string whilst Verify uses authData|sha256(challenge) as the signature payload.

This is also the difference between [email protected] and [email protected] signatures in ssh.

this way we can support both signature schemes.

@ianlancetaylor ianlancetaylor moved this to Incoming in Proposals Jan 2, 2025
@ianlancetaylor ianlancetaylor added the Proposal-Crypto Proposal related to crypto packages or other security issues label Jan 2, 2025
@seankhliao seankhliao changed the title proposal: x/crypto/webauthn: Introduce webauthn signature verification API proposal: crypto/webauthn: webauthn signature verification API Jan 4, 2025
@seankhliao
Copy link
Member

How useful is this on its own, vs as part of a more complete api like for github.com/go-webauthn/webauthn/webauthn?
Having only used go-webauthn, I get the feeling that this api exposes too much I wouldn't normally need to care about?

I do think it's a bit unnatural to hang Verify off the response, I would have expected it to either be a method of VerifyOptions or a standalone function.

@arianvp
Copy link
Author

arianvp commented Jan 5, 2025

How useful is this on its own, vs as part of a more complete api like for github.com/go-webauthn/webauthn/webauthn? Having only used go-webauthn, I get the feeling that this api exposes too much I wouldn't normally need to care about?

reason why I want to have the signature scheme is because it’s useful on its own. As it’s used for e.g. OpenSSH security key support (issue linked ) and for things like Apple AppAttest, and ACME device verification.

whether the proposal should be more than just the signature scheme and should have the whole webauthn flow in scope is definitely something we can discuss

I do think it's a bit unnatural to hang Verify off the response, I would have expected it to either be a method of VerifyOptions or a standalone function.

yeh I think I agree. The API is definitely up in the air. This is just what I am using internally in my own code as

@arianvp
Copy link
Author

arianvp commented Jan 5, 2025

I get the feeling that this api exposes too much I wouldn't normally need to care about?

I tried to keep it at the minimum. We could remove the clientDataJson and origin checking parts though and make this a raw ctap/fido2 signature format. That might reduce it in scope enough? Though #69999 specifically asked for the webauthn signature format as opposed to fido2 even though openssh supports both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Proposal Proposal-Crypto Proposal related to crypto packages or other security issues
Projects
Status: Incoming
Development

No branches or pull requests

5 participants