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

fix(protocol): use strict base64 encoding #129

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions metadata/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -565,12 +565,14 @@ func unmarshalMDSBLOB(body []byte, c http.Client) (MetadataBLOBPayload, error) {
return nil, err
}

encoding := base64.StdEncoding.Strict()

// Chain validated, extract the TOC signing certificate from the chain. Create a buffer large enough to hold the
// certificate bytes.
o := make([]byte, base64.StdEncoding.DecodedLen(len(chain[0].(string))))
o := make([]byte, encoding.DecodedLen(len(chain[0].(string))))

// base64 decode the certificate into the buffer.
n, err := base64.StdEncoding.Decode(o, []byte(chain[0].(string)))
n, err := encoding.Decode(o, []byte(chain[0].(string)))
if err != nil {
return nil, err
}
Expand All @@ -596,9 +598,11 @@ func unmarshalMDSBLOB(body []byte, c http.Client) (MetadataBLOBPayload, error) {
}

func validateChain(chain []interface{}, c http.Client) (bool, error) {
oRoot := make([]byte, base64.StdEncoding.DecodedLen(len(MDSRoot)))
encoding := base64.StdEncoding.Strict()

oRoot := make([]byte, encoding.DecodedLen(len(MDSRoot)))

nRoot, err := base64.StdEncoding.Decode(oRoot, []byte(MDSRoot))
nRoot, err := encoding.Decode(oRoot, []byte(MDSRoot))
if err != nil {
return false, err
}
Expand All @@ -612,9 +616,9 @@ func validateChain(chain []interface{}, c http.Client) (bool, error) {

roots.AddCert(rootcert)

o := make([]byte, base64.StdEncoding.DecodedLen(len(chain[1].(string))))
o := make([]byte, encoding.DecodedLen(len(chain[1].(string))))

n, err := base64.StdEncoding.Decode(o, []byte(chain[1].(string)))
n, err := encoding.Decode(o, []byte(chain[1].(string)))
if err != nil {
return false, err
}
Expand All @@ -637,9 +641,9 @@ func validateChain(chain []interface{}, c http.Client) (bool, error) {
ints := x509.NewCertPool()
ints.AddCert(intcert)

l := make([]byte, base64.StdEncoding.DecodedLen(len(chain[0].(string))))
l := make([]byte, encoding.DecodedLen(len(chain[0].(string))))

n, err = base64.StdEncoding.Decode(l, []byte(chain[0].(string)))
n, err = encoding.Decode(l, []byte(chain[0].(string)))
if err != nil {
return false, err
}
Expand Down
2 changes: 1 addition & 1 deletion protocol/assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func (car CredentialAssertionResponse) Parse() (par *ParsedCredentialAssertionDa
return nil, ErrBadRequest.WithDetails("CredentialAssertionResponse with ID missing")
}

if _, err = base64.RawURLEncoding.DecodeString(car.ID); err != nil {
if _, err = base64.RawURLEncoding.Strict().DecodeString(car.ID); err != nil {
return nil, ErrBadRequest.WithDetails("CredentialAssertionResponse with ID not base64url encoded")
}

Expand Down
18 changes: 10 additions & 8 deletions protocol/assertion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ import (
)

func TestParseCredentialRequestResponse(t *testing.T) {
byteID, _ := base64.RawURLEncoding.DecodeString("AI7D5q2P0LS-Fal9ZT7CHM2N5BLbUunF92T8b6iYC199bO2kagSuU05-5dZGqb1SP0A0lyTWng")
byteAAGUID, _ := base64.RawURLEncoding.DecodeString("rc4AAjW8xgpkiwsl8fBVAw")
byteRPIDHash, _ := base64.RawURLEncoding.DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvA")
byteAuthData, _ := base64.RawURLEncoding.DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBFXJJiGa3OAAI1vMYKZIsLJfHwVQMANwCOw-atj9C0vhWpfWU-whzNjeQS21Lpxfdk_G-omAtffWztpGoErlNOfuXWRqm9Uj9ANJck1p6lAQIDJiABIVggKAhfsdHcBIc0KPgAcRyAIK_-Vi-nCXHkRHPNaCMBZ-4iWCBxB8fGYQSBONi9uvq0gv95dGWlhJrBwCsj_a4LJQKVHQ")
byteSignature, _ := base64.RawURLEncoding.DecodeString("MEUCIBtIVOQxzFYdyWQyxaLR0tik1TnuPhGVhXVSNgFwLmN5AiEAnxXdCq0UeAVGWxOaFcjBZ_mEZoXqNboY5IkQDdlWZYc")
byteUserHandle, _ := base64.RawURLEncoding.DecodeString("0ToAAAAAAAAAAA")
byteCredentialPubKey, _ := base64.RawURLEncoding.DecodeString("pQMmIAEhWCAoCF-x0dwEhzQo-ABxHIAgr_5WL6cJceREc81oIwFn7iJYIHEHx8ZhBIE42L26-rSC_3l0ZaWEmsHAKyP9rgslApUdAQI")
byteClientDataJSON, _ := base64.RawURLEncoding.DecodeString("eyJjaGFsbGVuZ2UiOiJFNFBUY0lIX0hmWDFwQzZTaWdrMVNDOU5BbGdlenROMDQzOXZpOHpfYzlrIiwibmV3X2tleXNfbWF5X2JlX2FkZGVkX2hlcmUiOiJkbyBub3QgY29tcGFyZSBjbGllbnREYXRhSlNPTiBhZ2FpbnN0IGEgdGVtcGxhdGUuIFNlZSBodHRwczovL2dvby5nbC95YWJQZXgiLCJvcmlnaW4iOiJodHRwczovL3dlYmF1dGhuLmlvIiwidHlwZSI6IndlYmF1dGhuLmdldCJ9")
encoding := base64.RawURLEncoding.Strict()

byteID, _ := encoding.DecodeString("AI7D5q2P0LS-Fal9ZT7CHM2N5BLbUunF92T8b6iYC199bO2kagSuU05-5dZGqb1SP0A0lyTWng")
byteAAGUID, _ := encoding.DecodeString("rc4AAjW8xgpkiwsl8fBVAw")
byteRPIDHash, _ := encoding.DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvA")
byteAuthData, _ := encoding.DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBFXJJiGa3OAAI1vMYKZIsLJfHwVQMANwCOw-atj9C0vhWpfWU-whzNjeQS21Lpxfdk_G-omAtffWztpGoErlNOfuXWRqm9Uj9ANJck1p6lAQIDJiABIVggKAhfsdHcBIc0KPgAcRyAIK_-Vi-nCXHkRHPNaCMBZ-4iWCBxB8fGYQSBONi9uvq0gv95dGWlhJrBwCsj_a4LJQKVHQ")
byteSignature, _ := encoding.DecodeString("MEUCIBtIVOQxzFYdyWQyxaLR0tik1TnuPhGVhXVSNgFwLmN5AiEAnxXdCq0UeAVGWxOaFcjBZ_mEZoXqNboY5IkQDdlWZYc")
byteUserHandle, _ := encoding.DecodeString("0ToAAAAAAAAAAA")
byteCredentialPubKey, _ := encoding.DecodeString("pQMmIAEhWCAoCF-x0dwEhzQo-ABxHIAgr_5WL6cJceREc81oIwFn7iJYIHEHx8ZhBIE42L26-rSC_3l0ZaWEmsHAKyP9rgslApUdAQI")
byteClientDataJSON, _ := encoding.DecodeString("eyJjaGFsbGVuZ2UiOiJFNFBUY0lIX0hmWDFwQzZTaWdrMVNDOU5BbGdlenROMDQzOXZpOHpfYzlrIiwibmV3X2tleXNfbWF5X2JlX2FkZGVkX2hlcmUiOiJkbyBub3QgY29tcGFyZSBjbGllbnREYXRhSlNPTiBhZ2FpbnN0IGEgdGVtcGxhdGUuIFNlZSBodHRwczovL2dvby5nbC95YWJQZXgiLCJvcmlnaW4iOiJodHRwczovL3dlYmF1dGhuLmlvIiwidHlwZSI6IndlYmF1dGhuLmdldCJ9")

type args struct {
responseName string
Expand Down
14 changes: 9 additions & 5 deletions protocol/attestation_safetynet.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
var safetyNetAttestationKey = "android-safetynet"

func init() {
jwt.DecodeStrict = true

RegisterAttestationFormat(safetyNetAttestationKey, verifySafetyNetFormat)
}

Expand Down Expand Up @@ -75,12 +77,14 @@ func verifySafetyNetFormat(att AttestationObject, clientDataHash []byte) (string
return "", nil, ErrAttestationFormat.WithDetails("Unable to find the SafetyNet response")
}

encoding := base64.StdEncoding.Strict()

token, err := jwt.Parse(string(response), func(token *jwt.Token) (interface{}, error) {
chain := token.Header["x5c"].([]interface{})

o := make([]byte, base64.StdEncoding.DecodedLen(len(chain[0].(string))))
o := make([]byte, encoding.DecodedLen(len(chain[0].(string))))

n, err := base64.StdEncoding.Decode(o, []byte(chain[0].(string)))
n, err := encoding.Decode(o, []byte(chain[0].(string)))
if err != nil {
return nil, err
}
Expand All @@ -104,16 +108,16 @@ func verifySafetyNetFormat(att AttestationObject, clientDataHash []byte) (string
// of authenticatorData and clientDataHash.
nonceBuffer := sha256.Sum256(append(att.RawAuthData, clientDataHash...))

nonceBytes, err := base64.StdEncoding.DecodeString(safetyNetResponse.Nonce)
nonceBytes, err := encoding.DecodeString(safetyNetResponse.Nonce)
if !bytes.Equal(nonceBuffer[:], nonceBytes) || err != nil {
return "", nil, ErrInvalidAttestation.WithDetails("Invalid nonce for in SafetyNet response")
}

// §8.5.4 Let attestationCert be the attestation certificate (https://www.w3.org/TR/webauthn/#attestation-certificate)
certChain := token.Header["x5c"].([]interface{})
l := make([]byte, base64.StdEncoding.DecodedLen(len(certChain[0].(string))))
l := make([]byte, encoding.DecodedLen(len(certChain[0].(string))))

n, err := base64.StdEncoding.Decode(l, []byte(certChain[0].(string)))
n, err := encoding.Decode(l, []byte(certChain[0].(string)))
if err != nil {
return "", nil, ErrInvalidAttestation.WithDetails(fmt.Sprintf("Error finding cert issued to correct hostname: %+v", err))
}
Expand Down
4 changes: 2 additions & 2 deletions protocol/authenticator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ func TestAuthenticatorData_Unmarshal(t *testing.T) {
rawAuthData []byte
}

noneAuthData, _ := base64.StdEncoding.DecodeString("pkLSG3xtVeHOI8U5mCjSx0m/am7y/gPMnhDN9O1TCItBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQMAxl6G32ykWaLrv/ouCs5HoGsvONqBtOb7ZmyMs8K8PccnwyyqPzWn/yZuyQmQBguvjYSvH6gDBlFG65quUDCSlAQIDJiABIVggyJGP+ra/u/eVjqN4OeYXUShRWxrEeC6Sb5/bZmJ9q8MiWCCHIkRdg5oRb1RHoFVYUpogcjlObCKFsV1ls1T+uUc6rA==")
attAuthData, _ := base64.StdEncoding.DecodeString("lWkIjx7O4yMpVANdvRDXyuORMFonUbVZu4/Xy7IpvdRBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQIniszxcGnhupdPFOHJIm6dscrWCC2h8xHicBMu91THD0kdOdB0QQtkaEn+6KfsfT1o3NmmFT8YfXrG734WfVSmlAQIDJiABIVggyoHHeiUw5aSbt8/GsL9zaqZGRzV26A4y3CnCGUhVXu4iWCBMnc8za5xgPzIygngAv9W+vZTMGJwwZcM4sjiqkcb/1g==")
noneAuthData, _ := base64.StdEncoding.Strict().DecodeString("pkLSG3xtVeHOI8U5mCjSx0m/am7y/gPMnhDN9O1TCItBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQMAxl6G32ykWaLrv/ouCs5HoGsvONqBtOb7ZmyMs8K8PccnwyyqPzWn/yZuyQmQBguvjYSvH6gDBlFG65quUDCSlAQIDJiABIVggyJGP+ra/u/eVjqN4OeYXUShRWxrEeC6Sb5/bZmJ9q8MiWCCHIkRdg5oRb1RHoFVYUpogcjlObCKFsV1ls1T+uUc6rA==")
attAuthData, _ := base64.StdEncoding.Strict().DecodeString("lWkIjx7O4yMpVANdvRDXyuORMFonUbVZu4/Xy7IpvdRBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQIniszxcGnhupdPFOHJIm6dscrWCC2h8xHicBMu91THD0kdOdB0QQtkaEn+6KfsfT1o3NmmFT8YfXrG734WfVSmlAQIDJiABIVggyoHHeiUw5aSbt8/GsL9zaqZGRzV26A4y3CnCGUhVXu4iWCBMnc8za5xgPzIygngAv9W+vZTMGJwwZcM4sjiqkcb/1g==")

tests := []struct {
name string
Expand Down
17 changes: 9 additions & 8 deletions protocol/base64.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
type URLEncodedBase64 []byte

func (e URLEncodedBase64) String() string {
return base64.RawURLEncoding.EncodeToString(e)
return base64.RawURLEncoding.Strict().EncodeToString(e)
}

// UnmarshalJSON base64 decodes a URL-encoded value, storing the result in the
Expand All @@ -22,16 +22,17 @@ func (e *URLEncodedBase64) UnmarshalJSON(data []byte) error {
return nil
}

// TODO: Investigate this line. It is commented as trimming the leading spaces but appears to trim the leading and trailing double quotes instead.
// Trim the leading spaces.
data = bytes.Trim(data, "\"")
// Trim the leading and trailing JSON encoding characters.
data = bytes.Trim(data, `"`)

// Trim the trailing equal characters.
// Trim the trailing padding characters.
data = bytes.TrimRight(data, "=")

out := make([]byte, base64.RawURLEncoding.DecodedLen(len(data)))
encoding := base64.RawURLEncoding.Strict()

n, err := base64.RawURLEncoding.Decode(out, data)
out := make([]byte, encoding.DecodedLen(len(data)))

n, err := encoding.Decode(out, data)
if err != nil {
return err
}
Expand All @@ -49,5 +50,5 @@ func (e URLEncodedBase64) MarshalJSON() ([]byte, error) {
return []byte("null"), nil
}

return []byte(`"` + base64.RawURLEncoding.EncodeToString(e) + `"`), nil
return []byte(`"` + e.String() + `"`), nil
}
2 changes: 1 addition & 1 deletion protocol/base64_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestBase64UnmarshalJSON(t *testing.T) {
expectedTestData testData
}{
{
encodedMessage: "\"" + base64.RawURLEncoding.EncodeToString([]byte("test base64 data")) + "\"",
encodedMessage: "\"" + base64.RawURLEncoding.Strict().EncodeToString([]byte("test base64 data")) + "\"",
expectedTestData: testData{
StringData: "test string",
EncodedData: URLEncodedBase64("test base64 data"),
Expand Down
2 changes: 1 addition & 1 deletion protocol/challenge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func TestChallenge_String(t *testing.T) {
return
}

wantChallenge := base64.RawURLEncoding.EncodeToString(newChallenge)
wantChallenge := base64.RawURLEncoding.Strict().EncodeToString(newChallenge)

tests := []struct {
name string
Expand Down
2 changes: 1 addition & 1 deletion protocol/credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func (ccr CredentialCreationResponse) Parse() (pcc *ParsedCredentialCreationData
return nil, ErrBadRequest.WithDetails("Parse error for Registration").WithInfo("Missing ID")
}

testB64, err := base64.RawURLEncoding.DecodeString(ccr.ID)
testB64, err := base64.RawURLEncoding.Strict().DecodeString(ccr.ID)
if err != nil || !(len(testB64) > 0) {
return nil, ErrBadRequest.WithDetails("Parse error for Registration").WithInfo("ID not base64.RawURLEncoded")
}
Expand Down
30 changes: 17 additions & 13 deletions protocol/credential_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ func TestParseCredentialCreationResponse(t *testing.T) {
responseName string
}

byteID, _ := base64.RawURLEncoding.DecodeString("6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g")
byteAuthData, _ := base64.RawURLEncoding.DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw")
byteRPIDHash, _ := base64.RawURLEncoding.DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvA")
byteCredentialPubKey, _ := base64.RawURLEncoding.DecodeString("pSJYIMfCKfxl2SvnqJIiHQysHmpmITNgtCkQ5ESExSRjqrhXAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNc")
byteAttObject, _ := base64.RawURLEncoding.DecodeString("o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw")
byteClientDataJSON, _ := base64.RawURLEncoding.DecodeString("eyJjaGFsbGVuZ2UiOiJXOEd6RlU4cEdqaG9SYldyTERsYW1BZnFfeTRTMUNaRzFWdW9lUkxBUnJFIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ")
encoding := base64.RawURLEncoding.Strict()

byteID, _ := encoding.DecodeString("6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g")
byteAuthData, _ := encoding.DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw")
byteRPIDHash, _ := encoding.DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvA")
byteCredentialPubKey, _ := encoding.DecodeString("pSJYIMfCKfxl2SvnqJIiHQysHmpmITNgtCkQ5ESExSRjqrhXAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNc")
byteAttObject, _ := encoding.DecodeString("o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw")
byteClientDataJSON, _ := encoding.DecodeString("eyJjaGFsbGVuZ2UiOiJXOEd6RlU4cEdqaG9SYldyTERsYW1BZnFfeTRTMUNaRzFWdW9lUkxBUnJFIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ")

testCases := []struct {
name string
Expand Down Expand Up @@ -257,13 +259,15 @@ func TestParseCredentialCreationResponse(t *testing.T) {
}

func TestParsedCredentialCreationData_Verify(t *testing.T) {
byteID, _ := base64.RawURLEncoding.DecodeString("6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g")
byteChallenge, _ := base64.RawURLEncoding.DecodeString("W8GzFU8pGjhoRbWrLDlamAfq_y4S1CZG1VuoeRLARrE")
byteAuthData, _ := base64.RawURLEncoding.DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw")
byteRPIDHash, _ := base64.RawURLEncoding.DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvA")
byteCredentialPubKey, _ := base64.RawURLEncoding.DecodeString("pSJYIMfCKfxl2SvnqJIiHQysHmpmITNgtCkQ5ESExSRjqrhXAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNc")
byteAttObject, _ := base64.RawURLEncoding.DecodeString("o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw")
byteClientDataJSON, _ := base64.RawURLEncoding.DecodeString("eyJjaGFsbGVuZ2UiOiJXOEd6RlU4cEdqaG9SYldyTERsYW1BZnFfeTRTMUNaRzFWdW9lUkxBUnJFIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ")
encoding := base64.RawURLEncoding.Strict()

byteID, _ := encoding.DecodeString("6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g")
byteChallenge, _ := encoding.DecodeString("W8GzFU8pGjhoRbWrLDlamAfq_y4S1CZG1VuoeRLARrE")
byteAuthData, _ := encoding.DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw")
byteRPIDHash, _ := encoding.DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvA")
byteCredentialPubKey, _ := encoding.DecodeString("pSJYIMfCKfxl2SvnqJIiHQysHmpmITNgtCkQ5ESExSRjqrhXAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNc")
byteAttObject, _ := encoding.DecodeString("o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw")
byteClientDataJSON, _ := encoding.DecodeString("eyJjaGFsbGVuZ2UiOiJXOEd6RlU4cEdqaG9SYldyTERsYW1BZnFfeTRTMUNaRzFWdW9lUkxBUnJFIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ")

type fields struct {
ParsedPublicKeyCredential ParsedPublicKeyCredential
Expand Down