Skip to content
This repository was archived by the owner on Oct 20, 2024. It is now read-only.

Commit dffb21c

Browse files
committed
Add support for the packed format as used by the Yubico Security Key
1 parent 13d1e93 commit dffb21c

File tree

3 files changed

+225
-62
lines changed

3 files changed

+225
-62
lines changed

protocol/attestation_packed.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package protocol
2+
3+
import (
4+
"bytes"
5+
"crypto/x509"
6+
"encoding/asn1"
7+
"fmt"
8+
)
9+
10+
func init() {
11+
RegisterFormat("packed", verifyPacked)
12+
}
13+
14+
var extensionIDFIDOGenCAAAGUID = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 45724, 1, 1, 4}
15+
16+
func verifyPacked(a Attestation, clientDataHash []byte) error {
17+
rawAlg, ok := a.AttStmt["alg"]
18+
if !ok {
19+
return ErrInvalidAttestation.WithDebug("missing alg for packed")
20+
}
21+
algInt, ok := rawAlg.(int64)
22+
if !ok {
23+
return ErrInvalidAttestation.WithDebugf("invalid alg for packed, is of invalid type %T", rawAlg)
24+
}
25+
26+
alg := COSEAlgorithmIdentifier(algInt)
27+
28+
rawSig, ok := a.AttStmt["sig"]
29+
if !ok {
30+
return ErrInvalidAttestation.WithDebug("missing sig for packed")
31+
}
32+
sig, ok := rawSig.([]byte)
33+
if !ok {
34+
return ErrInvalidAttestation.WithDebug("invalid sig for packed")
35+
}
36+
37+
// 2. If x5c is present, this indicates that the attestation type is not ECDAA. In this case:
38+
if _, ok := a.AttStmt["x5c"]; ok {
39+
return verifyPackedBasic(a, clientDataHash, alg, sig)
40+
}
41+
42+
// 3. If ecdaaKeyId is present, then the attestation type is ECDAA. In this case:
43+
if _, ok := a.AttStmt["ecdaaKeyId"]; ok {
44+
return verifyPackedECDAA(a, clientDataHash, alg, sig)
45+
}
46+
47+
// 4. If neither x5c nor ecdaaKeyId is present, self attestation is in use.
48+
return fmt.Errorf("unsupported format self attestation")
49+
}
50+
51+
func verifyPackedBasic(a Attestation, clientDataHash []byte, alg COSEAlgorithmIdentifier, sig []byte) error {
52+
x5c, ok := a.AttStmt["x5c"].([]interface{})
53+
if !ok {
54+
return ErrInvalidAttestation.WithDebug("invalid x5c for packed")
55+
}
56+
57+
// let attCert be that element
58+
attestnCert, ok := x5c[0].([]byte)
59+
if !ok {
60+
return ErrInvalidAttestation.WithDebug("invalid x5c for packed")
61+
}
62+
63+
// Let certificate public key be the public key conveyed by attCert
64+
cert, err := x509.ParseCertificate(attestnCert)
65+
if err != nil {
66+
return ErrInvalidAttestation.WithDebugf("invalid x5c for packed: %v", err)
67+
}
68+
69+
// 2.1 Verify that sig is a valid signature over the concatenation of authenticatorData and clientDataHash using
70+
// the attestation public key in attestnCert with the algorithm specified in alg.
71+
signedBytes := append(a.AuthData.Raw, clientDataHash...)
72+
if err := cert.CheckSignature(cert.SignatureAlgorithm, signedBytes, sig); err != nil {
73+
// Fallback to ECDSAWithSA256 if signature algorithm is incorret, as is the case with Yubico's keys
74+
err = cert.CheckSignature(x509.ECDSAWithSHA256, signedBytes, sig)
75+
if err != nil {
76+
return ErrInvalidAttestation.WithDebugf("invalid signature for packed: %v", err)
77+
}
78+
}
79+
80+
// 2.2 Verify that attestnCert meets the requirements in §8.2.1 Packed attestation statement certificate requirements.
81+
82+
// Version MUST be set to 3 (which is indicated by an ASN.1 INTEGER with value 2).
83+
if cert.Version != 3 {
84+
return ErrInvalidAttestation.WithDebug("invalid version for certificate")
85+
}
86+
87+
// The Basic Constraints extension MUST have the CA component set to false.
88+
if cert.IsCA {
89+
return ErrInvalidAttestation.WithDebug("CA is set for certificate")
90+
}
91+
92+
var aaguidValue []byte
93+
94+
for _, ext := range cert.Extensions {
95+
// If the related attestation root certificate is used for multiple authenticator models, the Extension
96+
// OID 1.3.6.1.4.1.45724.1.1.4 (id-fido-gen-ce-aaguid) MUST be present, containing the AAGUID as a 16-byte
97+
// OCTET STRING.
98+
if ext.Id.Equal(extensionIDFIDOGenCAAAGUID) {
99+
// The extension MUST NOT be marked as critical.
100+
if ext.Critical {
101+
return ErrInvalidAttestation.WithDebugf("extension id-fido-gen-ce-aaguid is present, but is marked as critical")
102+
}
103+
aaguidValue = ext.Value
104+
}
105+
}
106+
107+
// 2.3 If attestnCert contains an extension with OID 1.3.6.1.4.1.45724.1.1.4 (id-fido-gen-ce-aaguid) verify that
108+
// the value of this extension matches the aaguid in authenticatorData.
109+
if len(aaguidValue) > 0 {
110+
// Note that an X.509 Extension encodes the DER-encoding of the value in an OCTET STRING. Thus, the AAGUID MUST
111+
// be wrapped in two OCTET STRINGS to be valid
112+
var aaguid []byte
113+
if _, err := asn1.Unmarshal(aaguidValue, &aaguid); err != nil {
114+
return ErrInvalidAttestation.WithDebugf("invalid AAGUID: %v", err)
115+
}
116+
117+
if !bytes.Equal(a.AuthData.AttestedCredentialData.AAGUID, aaguid) {
118+
return ErrInvalidAttestation.WithDebugf("invalid AAGUID")
119+
}
120+
121+
}
122+
123+
// If successful, return attestation type Basic and attestation trust path x5c.
124+
return nil
125+
}
126+
127+
func verifyPackedECDAA(a Attestation, clientDataHash []byte, alg COSEAlgorithmIdentifier, sig []byte) error {
128+
return ErrInvalidAttestation.WithDebugf("unsupported packed format ECDAA")
129+
}

protocol/common.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ type AuthenticatorData struct {
146146
// attested credential data (if present). See §6.4.1 Attested credential data for details. Its length depends on the
147147
// length of the credential ID and credential public key being attested.
148148
AttestedCredentialData AttestedCredentialData
149+
// Raw contains the raw bytes of this AuthenticatorData.
150+
Raw []byte
149151
}
150152

151153
// IsValid checks whether the AuthenticatorData is valid. If relyingPartyID is empty, the relying party will not be
@@ -191,6 +193,8 @@ func (a *AuthenticatorData) UnmarshalBinary(authData []byte) error {
191193
}
192194
}
193195

196+
a.Raw = authData
197+
194198
return nil
195199
}
196200

protocol/webauthn_test.go

Lines changed: 92 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,84 +4,114 @@ import (
44
"crypto/x509"
55
"encoding/json"
66
"encoding/pem"
7+
"fmt"
78
"testing"
89

910
"github.com/koesie10/webauthn/protocol"
1011
)
1112

1213
func TestIsValidAttestation(t *testing.T) {
13-
r := protocol.CredentialCreationOptions{}
14-
if err := json.Unmarshal([]byte(attestationRequest), &r); err != nil {
15-
t.Fatal(err)
16-
}
17-
18-
b := protocol.AttestationResponse{}
19-
if err := json.Unmarshal([]byte(attestationResponse), &b); err != nil {
20-
t.Fatal(err)
21-
}
22-
23-
p, err := protocol.ParseAttestationResponse(b)
24-
if err != nil {
25-
t.Fatal(err)
26-
}
27-
28-
d, err := protocol.IsValidAttestation(p, r.PublicKey.Challenge, "", "")
29-
if err != nil {
30-
t.Fatal(err)
31-
}
32-
33-
if !d {
34-
t.Fatal("is not valid")
14+
for i := range attestationRequests {
15+
t.Run(fmt.Sprintf("Run %d", i), func(t *testing.T) {
16+
r := protocol.CredentialCreationOptions{}
17+
if err := json.Unmarshal([]byte(attestationRequests[i]), &r); err != nil {
18+
t.Fatal(err)
19+
}
20+
21+
b := protocol.AttestationResponse{}
22+
if err := json.Unmarshal([]byte(attestationResponses[i]), &b); err != nil {
23+
t.Fatal(err)
24+
}
25+
26+
p, err := protocol.ParseAttestationResponse(b)
27+
if err != nil {
28+
t.Fatal(err)
29+
}
30+
31+
d, err := protocol.IsValidAttestation(p, r.PublicKey.Challenge, "", "")
32+
if err != nil {
33+
e := protocol.ToWebAuthnError(err)
34+
t.Fatal(fmt.Sprintf("%s, %s: %s", e.Name, e.Description, e.Debug))
35+
}
36+
37+
if !d {
38+
t.Fatal("is not valid")
39+
}
40+
})
3541
}
3642
}
3743

3844
func TestIsValidAssertion(t *testing.T) {
39-
block, _ := pem.Decode([]byte(attestationPublicKey))
40-
if block == nil {
41-
t.Fatal("invalid public key")
42-
}
43-
44-
publicKey, err := x509.ParsePKIXPublicKey(block.Bytes)
45-
if err != nil {
46-
t.Fatal(err)
47-
}
48-
49-
cert := &x509.Certificate{
50-
PublicKey: publicKey,
51-
}
52-
53-
r := protocol.CredentialCreationOptions{}
54-
if err := json.Unmarshal([]byte(assertionRequest), &r); err != nil {
55-
t.Fatal(err)
56-
}
57-
58-
b := protocol.AssertionResponse{}
59-
if err := json.Unmarshal([]byte(assertionResponse), &b); err != nil {
60-
t.Fatal(err)
61-
}
62-
63-
p, err := protocol.ParseAssertionResponse(b)
64-
if err != nil {
65-
t.Fatal(err)
45+
for i := range assertionRequests {
46+
t.Run(fmt.Sprintf("Run %d", i), func(t *testing.T) {
47+
block, _ := pem.Decode([]byte(attestationPublicKeys[i]))
48+
if block == nil {
49+
t.Fatal("invalid public key")
50+
}
51+
52+
publicKey, err := x509.ParsePKIXPublicKey(block.Bytes)
53+
if err != nil {
54+
t.Fatal(err)
55+
}
56+
57+
cert := &x509.Certificate{
58+
PublicKey: publicKey,
59+
}
60+
61+
r := protocol.CredentialCreationOptions{}
62+
if err := json.Unmarshal([]byte(assertionRequests[i]), &r); err != nil {
63+
t.Fatal(err)
64+
}
65+
66+
b := protocol.AssertionResponse{}
67+
if err := json.Unmarshal([]byte(assertionResponses[i]), &b); err != nil {
68+
t.Fatal(err)
69+
}
70+
71+
p, err := protocol.ParseAssertionResponse(b)
72+
if err != nil {
73+
t.Fatal(err)
74+
}
75+
76+
d, err := protocol.IsValidAssertion(p, r.PublicKey.Challenge, "", "", cert)
77+
if err != nil {
78+
t.Fatal(err)
79+
}
80+
81+
if !d {
82+
t.Fatal("is not valid")
83+
}
84+
})
6685
}
86+
}
6787

68-
d, err := protocol.IsValidAssertion(p, r.PublicKey.Challenge, "", "", cert)
69-
if err != nil {
70-
t.Fatal(err)
71-
}
88+
var attestationRequests = []string{
89+
`{"publicKey":{"rp":{"name":"accountsvc"},"user":{"id":"MTAwNjg1ODU4NDE3ODI5NDc4NA==","name":"Koen Vlaswinkel","displayName":"Koen Vlaswinkel"},"pubKeyCredParams":[{"type":"public-key","alg":-7}],"timeout":10000,"attestation":"direct","challenge":"+1jQysnwaIjNU+GrwRp4PWNBMlX0i9/caRkcKd7LPj8="}}`,
90+
`{"publicKey":{"rp":{"name":"webauthn-demo"},"user":{"name":"koen","id":"a29lbg==","displayName":"koen"},"challenge":"JUtlYcgpkSiFNzsThDYuOrtSVY1VeLofM+mWTRCCXqU=","pubKeyCredParams":[{"type":"public-key","alg":-7}],"timeout":30000,"authenticatorSelection":{"requireResidentKey":false},"attestation":"direct"}}`,
91+
}
7292

73-
if !d {
74-
t.Fatal("is not valid")
75-
}
93+
var attestationResponses = []string{
94+
`{"id":"LOXI3xfiLvIP04MD_S2ZmJYwn3cvMX1FUXxiQO7xlfUvrfcj99UVO2aMrMAwsGvsujY7NHWiM6G3B6ryKJDBBdab-cl4tVZeOwOMhgvHLXk","rawId":"LOXI3xfiLvIP04MD/S2ZmJYwn3cvMX1FUXxiQO7xlfUvrfcj99UVO2aMrMAwsGvsujY7NHWiM6G3B6ryKJDBBdab+cl4tVZeOwOMhgvHLXk=","response":{"attestationObject":"o2dhdHRTdG10omNzaWdYRjBEAiAJ8Q7i8DQzKlb00g4Wby4PoEjlI+s3bS+kVKI3PKoyXQIgDzcP2c5vpplZdmftN+zUDNfXtG1TniWbJv2+6kGZ8bljeDVjgVkBKzCCAScwgc6gAwIBAgIBADAKBggqhkjOPQQDAjAWMRQwEgYDVQQDDAtLcnlwdG9uIEtleTAeFw0xODA5MTcxODQ3NDJaFw0yODA5MTcxODQ3NDJaMBYxFDASBgNVBAMMC0tyeXB0b24gS2V5MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwzIpvM5A6mZQXYxRIhfp0sb/21yTcr/sp5Y5DU0IWODQf5ldS2rlDCl62yEaQDM9Akxbsay/vA/S5ut4VSsvoKMNMAswCQYDVR0TBAIwADAKBggqhkjOPQQDAgNIADBFAiA4Yx+5MtKVnjme6V3qXKQ2qcgaHfO6DMgXM9kwOCZcNAIhAJdNk5PPSA04ITfrX9HQy5azo8sH9yhkW7c6gLdb/Kz+aGF1dGhEYXRhWNRJlg3liA6MaHQ0Fw9kdmBbj+SuuaKGMseZXPO6gx2XY0EAAAAALOXI3xfiLvIP04MD/S2ZmABQLOXI3xfiLvIP04MD/S2ZmJYwn3cvMX1FUXxiQO7xlfUvrfcj99UVO2aMrMAwsGvsujY7NHWiM6G3B6ryKJDBBdab+cl4tVZeOwOMhgvHLXmlAQIDJiABIVggwzIpvM5A6mZQXYxRIhfp0sb/21yTcr/sp5Y5DU0IWOAiWCDQf5ldS2rlDCl62yEaQDM9Akxbsay/vA/S5ut4VSsvoGNmbXRoZmlkby11MmY=","clientDataJSON":"eyJjaGFsbGVuZ2UiOiItMWpReXNud2FJak5VLUdyd1JwNFBXTkJNbFgwaTlfY2FSa2NLZDdMUGo4IiwiY2xpZW50RXh0ZW5zaW9ucyI6e30sImhhc2hBbGdvcml0aG0iOiJTSEEtMjU2Iiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDo1Mzg3OSIsInRva2VuQmluZGluZyI6eyJzdGF0dXMiOiJub3Qtc3VwcG9ydGVkIn0sInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ=="},"type":"public-key"}`,
95+
`{"id":"SNBSJTt1DHEuG9XBd6lfc4XXqxkppWfFbt4P5sRVQEPIPANIHHCmPo1AwY5pkUGcpVL3W-uHyWEn4vbgzp34Qw","rawId":"SNBSJTt1DHEuG9XBd6lfc4XXqxkppWfFbt4P5sRVQEPIPANIHHCmPo1AwY5pkUGcpVL3W+uHyWEn4vbgzp34Qw==","response":{"attestationObject":"o2NmbXRmcGFja2VkZ2F0dFN0bXSjY2FsZyZjc2lnWEcwRQIgFls/elhmdZmqEBEKafdcyvQPDrTdBRMW92v6RKJj1bACIQCZ+46sXn65dMEpPuGxvMUruV5i7XN25ctFV/iAi3wSomN4NWOBWQLCMIICvjCCAaagAwIBAgIEdIb9wjANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNZdWJpY28gVTJGIFJvb3QgQ0EgU2VyaWFsIDQ1NzIwMDYzMTAgFw0xNDA4MDEwMDAwMDBaGA8yMDUwMDkwNDAwMDAwMFowbzELMAkGA1UEBhMCU0UxEjAQBgNVBAoMCVl1YmljbyBBQjEiMCAGA1UECwwZQXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjEoMCYGA1UEAwwfWXViaWNvIFUyRiBFRSBTZXJpYWwgMTk1NTAwMzg0MjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJVd8633JH0xde/9nMTzGk6HjrrhgQlWYVD7OIsuX2Unv1dAmqWBpQ0KxS8YRFwKE1SKE1PIpOWacE5SO8BN6+2jbDBqMCIGCSsGAQQBgsQKAgQVMS4zLjYuMS40LjEuNDE0ODIuMS4xMBMGCysGAQQBguUcAgEBBAQDAgUgMCEGCysGAQQBguUcAQEEBBIEEPigEfOMCk0VgAYXER+e3H0wDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAMVxIgOaaUn44Zom9af0KqG9J655OhUVBVW+q0As6AIod3AH5bHb2aDYakeIyyBCnnGMHTJtuekbrHbXYXERIn4aKdkPSKlyGLsA/A+WEi+OAfXrNVfjhrh7iE6xzq0sg4/vVJoywe4eAJx0fS+Dl3axzTTpYl71Nc7p/NX6iCMmdik0pAuYJegBcTckE3AoYEg4K99AM/JaaKIblsbFh8+3LxnemeNf7UwOczaGGvjS6UzGVI0Odf9lKcPIwYhuTxM5CaNMXTZQ7xq4/yTfC3kPWtE4hFT34UJJflZBiLrxG4OsYxkHw/n5vKgmpspB3GfYuYTWhkDKiE8CYtyg87mhhdXRoRGF0YVjESZYN5YgOjGh0NBcPZHZgW4/krrmihjLHmVzzuoMdl2NBAAAAA/igEfOMCk0VgAYXER+e3H0AQEjQUiU7dQxxLhvVwXepX3OF16sZKaVnxW7eD+bEVUBDyDwDSBxwpj6NQMGOaZFBnKVS91vrh8lhJ+L24M6d+EOlAQIDJiABIVggLxxTguKmjCV4N5OMqd2Sl9AIxSltaPevmQxSqnyNlAciWCDEHOaQDaZ6pC2gC+Z0KS4Ln/XQiJp0X1BmTd+K+FdqSg==","clientDataJSON":"eyJjaGFsbGVuZ2UiOiJKVXRsWWNncGtTaUZOenNUaERZdU9ydFNWWTFWZUxvZk0tbVdUUkNDWHFVIiwibmV3X2tleXNfbWF5X2JlX2FkZGVkX2hlcmUiOiJkbyBub3QgY29tcGFyZSBjbGllbnREYXRhSlNPTiBhZ2FpbnN0IGEgdGVtcGxhdGUuIFNlZSBodHRwczovL2dvby5nbC95YWJQZXgiLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjkwMDAiLCJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIn0="},"type":"public-key"}`,
7696
}
7797

78-
const attestationRequest = `{"publicKey":{"rp":{"name":"accountsvc"},"user":{"id":"MTAwNjg1ODU4NDE3ODI5NDc4NA==","name":"Koen Vlaswinkel","displayName":"Koen Vlaswinkel"},"pubKeyCredParams":[{"type":"public-key","alg":-7}],"timeout":10000,"attestation":"direct","challenge":"+1jQysnwaIjNU+GrwRp4PWNBMlX0i9/caRkcKd7LPj8="}}`
79-
const attestationResponse = `{"id":"LOXI3xfiLvIP04MD_S2ZmJYwn3cvMX1FUXxiQO7xlfUvrfcj99UVO2aMrMAwsGvsujY7NHWiM6G3B6ryKJDBBdab-cl4tVZeOwOMhgvHLXk","rawId":"LOXI3xfiLvIP04MD/S2ZmJYwn3cvMX1FUXxiQO7xlfUvrfcj99UVO2aMrMAwsGvsujY7NHWiM6G3B6ryKJDBBdab+cl4tVZeOwOMhgvHLXk=","response":{"attestationObject":"o2dhdHRTdG10omNzaWdYRjBEAiAJ8Q7i8DQzKlb00g4Wby4PoEjlI+s3bS+kVKI3PKoyXQIgDzcP2c5vpplZdmftN+zUDNfXtG1TniWbJv2+6kGZ8bljeDVjgVkBKzCCAScwgc6gAwIBAgIBADAKBggqhkjOPQQDAjAWMRQwEgYDVQQDDAtLcnlwdG9uIEtleTAeFw0xODA5MTcxODQ3NDJaFw0yODA5MTcxODQ3NDJaMBYxFDASBgNVBAMMC0tyeXB0b24gS2V5MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwzIpvM5A6mZQXYxRIhfp0sb/21yTcr/sp5Y5DU0IWODQf5ldS2rlDCl62yEaQDM9Akxbsay/vA/S5ut4VSsvoKMNMAswCQYDVR0TBAIwADAKBggqhkjOPQQDAgNIADBFAiA4Yx+5MtKVnjme6V3qXKQ2qcgaHfO6DMgXM9kwOCZcNAIhAJdNk5PPSA04ITfrX9HQy5azo8sH9yhkW7c6gLdb/Kz+aGF1dGhEYXRhWNRJlg3liA6MaHQ0Fw9kdmBbj+SuuaKGMseZXPO6gx2XY0EAAAAALOXI3xfiLvIP04MD/S2ZmABQLOXI3xfiLvIP04MD/S2ZmJYwn3cvMX1FUXxiQO7xlfUvrfcj99UVO2aMrMAwsGvsujY7NHWiM6G3B6ryKJDBBdab+cl4tVZeOwOMhgvHLXmlAQIDJiABIVggwzIpvM5A6mZQXYxRIhfp0sb/21yTcr/sp5Y5DU0IWOAiWCDQf5ldS2rlDCl62yEaQDM9Akxbsay/vA/S5ut4VSsvoGNmbXRoZmlkby11MmY=","clientDataJSON":"eyJjaGFsbGVuZ2UiOiItMWpReXNud2FJak5VLUdyd1JwNFBXTkJNbFgwaTlfY2FSa2NLZDdMUGo4IiwiY2xpZW50RXh0ZW5zaW9ucyI6e30sImhhc2hBbGdvcml0aG0iOiJTSEEtMjU2Iiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDo1Mzg3OSIsInRva2VuQmluZGluZyI6eyJzdGF0dXMiOiJub3Qtc3VwcG9ydGVkIn0sInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ=="},"type":"public-key"}`
98+
var assertionRequests = []string{
99+
`{"publicKey":{"allowCredentials":[{"id":"LOXI3xfiLvIP04MD/S2ZmJYwn3cvMX1FUXxiQO7xlfUvrfcj99UVO2aMrMAwsGvsujY7NHWiM6G3B6ryKJDBBdab+cl4tVZeOwOMhgvHLXk=","type":"public-key"}],"challenge":"+c0hMsULvTWp6ASl45YyOQRA/yVVK60XccCQ+Vui9j8=","timeout":10000}}`,
100+
`{"publicKey":{"challenge":"mcPXIDRHSPBF2gJWU58GPrR3TodLDXR1kHJhgVanYnU=","timeout":30000,"allowCredentials":[{"type":"public-key","id":"SNBSJTt1DHEuG9XBd6lfc4XXqxkppWfFbt4P5sRVQEPIPANIHHCmPo1AwY5pkUGcpVL3W+uHyWEn4vbgzp34Qw=="}]}}`,
101+
}
80102

81-
const assertionRequest = `{"publicKey":{"allowCredentials":[{"id":"LOXI3xfiLvIP04MD/S2ZmJYwn3cvMX1FUXxiQO7xlfUvrfcj99UVO2aMrMAwsGvsujY7NHWiM6G3B6ryKJDBBdab+cl4tVZeOwOMhgvHLXk=","type":"public-key"}],"challenge":"+c0hMsULvTWp6ASl45YyOQRA/yVVK60XccCQ+Vui9j8=","timeout":10000}}`
82-
const assertionResponse = `{"id":"LOXI3xfiLvIP04MD_S2ZmJYwn3cvMX1FUXxiQO7xlfUvrfcj99UVO2aMrMAwsGvsujY7NHWiM6G3B6ryKJDBBdab-cl4tVZeOwOMhgvHLXk","rawId":"LOXI3xfiLvIP04MD/S2ZmJYwn3cvMX1FUXxiQO7xlfUvrfcj99UVO2aMrMAwsGvsujY7NHWiM6G3B6ryKJDBBdab+cl4tVZeOwOMhgvHLXk=","response":{"clientDataJSON":"eyJjaGFsbGVuZ2UiOiItYzBoTXNVTHZUV3A2QVNsNDVZeU9RUkFfeVZWSzYwWGNjQ1EtVnVpOWo4IiwiaGFzaEFsZ29yaXRobSI6IlNIQS0yNTYiLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjUzODc5IiwidHlwZSI6IndlYmF1dGhuLmdldCJ9","authenticatorData":"SZYN5YgOjGh0NBcPZHZgW4/krrmihjLHmVzzuoMdl2MBAAAAAQ==","signature":"MEYCIQD7W6TPIviP+BztYxEMsan/esy/O0S4pJO+9QxDaA0ehAIhANo5D+5UxwbtJGFcvSryl0+RdJd3j4lIKVhEe7WpvZeV","userHandle":""},"type":"public-key"}`
103+
var assertionResponses = []string{
104+
`{"id":"LOXI3xfiLvIP04MD_S2ZmJYwn3cvMX1FUXxiQO7xlfUvrfcj99UVO2aMrMAwsGvsujY7NHWiM6G3B6ryKJDBBdab-cl4tVZeOwOMhgvHLXk","rawId":"LOXI3xfiLvIP04MD/S2ZmJYwn3cvMX1FUXxiQO7xlfUvrfcj99UVO2aMrMAwsGvsujY7NHWiM6G3B6ryKJDBBdab+cl4tVZeOwOMhgvHLXk=","response":{"clientDataJSON":"eyJjaGFsbGVuZ2UiOiItYzBoTXNVTHZUV3A2QVNsNDVZeU9RUkFfeVZWSzYwWGNjQ1EtVnVpOWo4IiwiaGFzaEFsZ29yaXRobSI6IlNIQS0yNTYiLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjUzODc5IiwidHlwZSI6IndlYmF1dGhuLmdldCJ9","authenticatorData":"SZYN5YgOjGh0NBcPZHZgW4/krrmihjLHmVzzuoMdl2MBAAAAAQ==","signature":"MEYCIQD7W6TPIviP+BztYxEMsan/esy/O0S4pJO+9QxDaA0ehAIhANo5D+5UxwbtJGFcvSryl0+RdJd3j4lIKVhEe7WpvZeV","userHandle":""},"type":"public-key"}`,
105+
`{"id":"SNBSJTt1DHEuG9XBd6lfc4XXqxkppWfFbt4P5sRVQEPIPANIHHCmPo1AwY5pkUGcpVL3W-uHyWEn4vbgzp34Qw","rawId":"SNBSJTt1DHEuG9XBd6lfc4XXqxkppWfFbt4P5sRVQEPIPANIHHCmPo1AwY5pkUGcpVL3W+uHyWEn4vbgzp34Qw==","response":{"clientDataJSON":"eyJjaGFsbGVuZ2UiOiJtY1BYSURSSFNQQkYyZ0pXVTU4R1ByUjNUb2RMRFhSMWtISmhnVmFuWW5VIiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDo5MDAwIiwidHlwZSI6IndlYmF1dGhuLmdldCJ9","authenticatorData":"SZYN5YgOjGh0NBcPZHZgW4/krrmihjLHmVzzuoMdl2MBAAAABA==","signature":"MEUCIQCWGnyWIV4s13/9TRcLtDesxa0UJs+pwNaF3YDP/5RHDwIgIWlEiH74R7sPiyNffp8Tof3qo1s8jVvFDxCGejlICFI=","userHandle":""},"type":"public-key"}`,
106+
}
83107

84-
const attestationPublicKey = `-----BEGIN CERTIFICATE-----
108+
var attestationPublicKeys = []string{
109+
`-----BEGIN CERTIFICATE-----
85110
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwzIpvM5A6mZQXYxRIhfp0sb/21yT
86111
cr/sp5Y5DU0IWODQf5ldS2rlDCl62yEaQDM9Akxbsay/vA/S5ut4VSsvoA==
87-
-----END CERTIFICATE-----`
112+
-----END CERTIFICATE-----`,
113+
`-----BEGIN PUBLIC KEY-----
114+
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELxxTguKmjCV4N5OMqd2Sl9AIxSlt
115+
aPevmQxSqnyNlAfEHOaQDaZ6pC2gC+Z0KS4Ln/XQiJp0X1BmTd+K+FdqSg==
116+
-----END PUBLIC KEY-----`,
117+
}

0 commit comments

Comments
 (0)