-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
feat(x/accounts/base): Add passkey support to base account type. #21755
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package authn | ||
|
||
import ( | ||
"bytes" | ||
"crypto" | ||
ecdsa "crypto/ecdsa" | ||
"crypto/elliptic" | ||
"crypto/sha256" | ||
"encoding/base64" | ||
"encoding/hex" | ||
"encoding/json" | ||
"fmt" | ||
|
||
cometcrypto "github.com/cometbft/cometbft/crypto" | ||
"github.com/cosmos/gogoproto/proto" | ||
|
||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" | ||
"github.com/cosmos/cosmos-sdk/types/address" | ||
) | ||
|
||
type Signature struct { | ||
AuthenticatorData string `json:"authenticatorData"` | ||
ClientDataJSON string `json:"clientDataJSON"` | ||
Signature string `json:"signature"` | ||
} | ||
|
||
const ( | ||
keyType = "authn" | ||
PubKeyName = "tendermint/PubKeyAuthn" | ||
) | ||
|
||
var ( | ||
_ cryptotypes.PubKey = (*AuthnPubKey)(nil) | ||
) | ||
|
||
const AuthnPubKeySize = 33 | ||
|
||
func (pubKey *AuthnPubKey) Address() cometcrypto.Address { | ||
if len(pubKey.Key) != AuthnPubKeySize { | ||
panic("length of pubkey is incorrect") | ||
Check warning Code scanning / CodeQL Panic in BeginBock or EndBlock consensus methods Warning
Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
|
||
} | ||
|
||
return address.Hash(proto.MessageName(pubKey), pubKey.Key) | ||
} | ||
Comment on lines
+38
to
+44
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid using According to the Uber Go Style Guide, panics should be avoided in library code. Instead of panicking when the key length is incorrect, consider validating the key length upon creation of the ToolsGitHub Check: CodeQL
|
||
|
||
func (pubKey *AuthnPubKey) Bytes() []byte { | ||
return pubKey.Key | ||
} | ||
|
||
func (pubKey *AuthnPubKey) String() string { | ||
return fmt.Sprintf("PubKeyAuthn{%X}", pubKey.Key) | ||
} | ||
|
||
func (pubKey *AuthnPubKey) Type() string { | ||
return keyType | ||
} | ||
|
||
func (pubKey *AuthnPubKey) Equals(other cryptotypes.PubKey) bool { | ||
return pubKey.Type() == other.Type() && bytes.Equal(pubKey.Bytes(), other.Bytes()) | ||
} | ||
|
||
func (pubKey *AuthnPubKey) VerifySignature(msg, sigStr []byte) bool { | ||
sig := Signature{} | ||
err := json.Unmarshal(sigStr, &sig) | ||
if err != nil { | ||
return false | ||
} | ||
|
||
clientDataJSON, err := hex.DecodeString(sig.ClientDataJSON) | ||
if err != nil { | ||
return false | ||
} | ||
Comment on lines
+69
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Verify that the correct decoding functions are used for Currently, Also applies to: 106-109 |
||
|
||
clientData := make(map[string]interface{}) | ||
err = json.Unmarshal(clientDataJSON, &clientData) | ||
if err != nil { | ||
return false | ||
} | ||
Comment on lines
+74
to
+78
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Use typed structs instead of Employing a typed struct for unmarshalling |
||
|
||
challengeBase64, ok := clientData["challenge"].(string) | ||
if !ok { | ||
return false | ||
} | ||
challenge, err := base64.RawURLEncoding.DecodeString(challengeBase64) | ||
if err != nil { | ||
return false | ||
} | ||
|
||
// Check challenge == msg | ||
if !bytes.Equal(challenge, msg) { | ||
return false | ||
} | ||
|
||
publicKey := &ecdsa.PublicKey{Curve: elliptic.P256()} | ||
|
||
publicKey.X, publicKey.Y = elliptic.UnmarshalCompressed(elliptic.P256(), pubKey.Key) | ||
if publicKey.X == nil || publicKey.Y == nil { | ||
return false | ||
} | ||
|
||
signatureBytes, err := hex.DecodeString(sig.Signature) | ||
if err != nil { | ||
return false | ||
} | ||
|
||
authenticatorData, err := hex.DecodeString(sig.AuthenticatorData) | ||
if err != nil { | ||
return false | ||
} | ||
|
||
// check authenticatorData length | ||
if len(authenticatorData) < 37 { | ||
return false | ||
} | ||
|
||
clientDataHash := sha256.Sum256(clientDataJSON) | ||
payload := append(authenticatorData, clientDataHash[:]...) | ||
|
||
h := crypto.SHA256.New() | ||
h.Write(payload) | ||
|
||
return ecdsa.VerifyASN1(publicKey, h.Sum(nil), signatureBytes) | ||
} | ||
Comment on lines
+62
to
+123
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider refactoring The |
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.
Implement validation logic in
WithPubKeyWithValidationFunc
The validation function for
authn.AuthnPubKey
at lines 99-101 currently returnsnil
without performing any checks. Implementing validation logic ensures that public keys meet expected criteria and helps detect invalid keys during testing.Apply this diff to add basic validation:
Committable suggestion