From 6fa6e1f237bc8c9e6be1dcfe976ca0043ed7f16f Mon Sep 17 00:00:00 2001 From: ale <ale@incal.net> Date: Sat, 4 Dec 2021 16:04:51 +0000 Subject: [PATCH] Do not log unused webauthn credential --- server/authserver.go | 12 +--- .../ldap/compositetypes/composite_types.go | 59 ++++++++++++------- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/server/authserver.go b/server/authserver.go index 02b95f32..9b257450 100644 --- a/server/authserver.go +++ b/server/authserver.go @@ -548,18 +548,12 @@ func (s *Server) finishWebAuthnLogin(user *backend.User, sessionData *webauthn.S wuser := newWebAuthnUser(user) // Attempt non-legacy validation first. - cred, err := s.webAuthnHandler.ValidateLogin(wuser, *sessionData, parsedResponse) + _, err := s.webAuthnHandler.ValidateLogin(wuser, *sessionData, parsedResponse) if err != nil { - cred, err = s.compatWebAuthnHandler.ValidateLogin(wuser, *sessionData, parsedResponse) - if err != nil { - return err - } + _, err = s.compatWebAuthnHandler.ValidateLogin(wuser, *sessionData, parsedResponse) } - // What do we do with this credential? - log.Printf("cred: %v", cred) - - return nil + return err } func checkPassword(password, hash []byte) bool { diff --git a/vendor/git.autistici.org/ai3/go-common/ldap/compositetypes/composite_types.go b/vendor/git.autistici.org/ai3/go-common/ldap/compositetypes/composite_types.go index 1ba73db9..25b1097f 100644 --- a/vendor/git.autistici.org/ai3/go-common/ldap/compositetypes/composite_types.go +++ b/vendor/git.autistici.org/ai3/go-common/ldap/compositetypes/composite_types.go @@ -106,17 +106,12 @@ func UnmarshalEncryptedKey(s string) (*EncryptedKey, error) { // U2FRegistration stores information on a single WebAuthN/U2F device // registration. // -// This type supports both legacy U2F registrations, as well as newer -// WebAuthN registrations. These have different serialization formats. -// The legacy U2F serialized format follows part of the U2F standard -// and just stores 64 bytes of the public key immediately followed by -// the key handle data, with no encoding. Note that the public key -// itself is a serialization of the elliptic curve parameters. The -// newer serialization format is JSON, for extensibility. Marshaling -// always happens in JSON, legacy format is read-only. +// The public key is expected to be in raw COSE format. Note that on +// the wire (i.e. when serialized as JSON) both the public key and the +// key handle are base64-encoded. // -// The data in U2FRegistration is still encoded, but it can be turned -// into a usable run-time form by calling Decode(). +// It is possible to obtain a usable webauthn.Credential object at +// run-time by calling Decode(). type U2FRegistration struct { KeyHandle []byte `json:"key_handle"` PublicKey []byte `json:"public_key"` @@ -133,6 +128,11 @@ func (r *U2FRegistration) Marshal() string { return string(data) } +const ( + legacySerializedU2FKeySize = 65 + minU2FKeySize = 64 +) + // UnmarshalU2FRegistration parses a U2FRegistration from its serialized format. func UnmarshalU2FRegistration(s string) (*U2FRegistration, error) { // Try JSON first. @@ -143,13 +143,13 @@ func UnmarshalU2FRegistration(s string) (*U2FRegistration, error) { // Deserialize legacy format, and perform a conversion of the // public key to COSE format. - if len(s) < 65 { + if len(s) < legacySerializedU2FKeySize { return nil, errors.New("badly encoded u2f registration") } b := []byte(s) return &U2FRegistration{ - PublicKey: u2fToCOSE(b[:65]), - KeyHandle: b[65:], + PublicKey: u2fToCOSE(b[:legacySerializedU2FKeySize]), + KeyHandle: b[legacySerializedU2FKeySize:], Legacy: true, }, nil } @@ -171,6 +171,14 @@ func ParseLegacyU2FRegistrationFromStrings(keyHandle, publicKey string) (*U2FReg return nil, fmt.Errorf("error decoding public key: %w", err) } + // Simple sanity check for non-empty fields. + if len(kh) == 0 { + return nil, errors.New("missing key handle") + } + if len(pk) < minU2FKeySize { + return nil, errors.New("public key missing or too short") + } + return &U2FRegistration{ PublicKey: u2fToCOSE(pk), KeyHandle: kh, @@ -181,7 +189,7 @@ func ParseLegacyU2FRegistrationFromStrings(keyHandle, publicKey string) (*U2FReg // ParseU2FRegistrationFromStrings parses the U2F registration format // used in manual key specifications that is used by Fido2-aware // programs such as pamu2fcfg >= 1.0.0. Both parameters are -// base64-encoded. +// base64-encoded, public key should be in COSE format. func ParseU2FRegistrationFromStrings(keyHandle, publicKey string) (*U2FRegistration, error) { kh, err := base64.StdEncoding.DecodeString(keyHandle) if err != nil { @@ -192,6 +200,14 @@ func ParseU2FRegistrationFromStrings(keyHandle, publicKey string) (*U2FRegistrat return nil, fmt.Errorf("error decoding public key: %w", err) } + // Simple sanity check for non-empty fields. + if len(kh) == 0 { + return nil, errors.New("missing key handle") + } + if len(pk) < minU2FKeySize { + return nil, errors.New("public key missing or too short") + } + return &U2FRegistration{ PublicKey: pk, KeyHandle: kh, @@ -207,17 +223,18 @@ func (r *U2FRegistration) Decode() (webauthn.Credential, error) { }, nil } +// Convert a legacy U2F public key to COSE format. func u2fToCOSE(pk []byte) []byte { - var parsed webauthncose.EC2PublicKeyData - parsed.KeyType = int64(webauthncose.EllipticKey) - parsed.Algorithm = int64(webauthncose.AlgES256) - parsed.XCoord = pk[1:33] - parsed.YCoord = pk[33:] - data, _ := cbor.Marshal(&parsed) // nolint: errcheck + var key webauthncose.EC2PublicKeyData + key.KeyType = int64(webauthncose.EllipticKey) + key.Algorithm = int64(webauthncose.AlgES256) + key.XCoord = pk[1:33] + key.YCoord = pk[33:] + data, _ := cbor.Marshal(&key) // nolint: errcheck return data } -// Faster, but more questionable, implementation: +// Faster, but more questionable, implementation of the above: // // func u2fToCOSE(pk []byte) []byte { // x := pk[1:33] -- GitLab