diff --git a/metadata/metadata.go b/metadata/metadata.go index 043f205..46a2e66 100644 --- a/metadata/metadata.go +++ b/metadata/metadata.go @@ -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 } @@ -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 } @@ -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 } @@ -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 } diff --git a/protocol/assertion.go b/protocol/assertion.go index a34e7dc..f3093ea 100644 --- a/protocol/assertion.go +++ b/protocol/assertion.go @@ -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") } diff --git a/protocol/assertion_test.go b/protocol/assertion_test.go index 4fc015d..0620a0a 100644 --- a/protocol/assertion_test.go +++ b/protocol/assertion_test.go @@ -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 diff --git a/protocol/attestation_safetynet.go b/protocol/attestation_safetynet.go index e63ba3e..ff949e6 100644 --- a/protocol/attestation_safetynet.go +++ b/protocol/attestation_safetynet.go @@ -17,6 +17,8 @@ import ( var safetyNetAttestationKey = "android-safetynet" func init() { + jwt.DecodeStrict = true + RegisterAttestationFormat(safetyNetAttestationKey, verifySafetyNetFormat) } @@ -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 } @@ -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)) } diff --git a/protocol/authenticator_test.go b/protocol/authenticator_test.go index af03c04..9dd3d84 100644 --- a/protocol/authenticator_test.go +++ b/protocol/authenticator_test.go @@ -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 diff --git a/protocol/base64.go b/protocol/base64.go index 8e29109..4a486c5 100644 --- a/protocol/base64.go +++ b/protocol/base64.go @@ -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 @@ -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 } @@ -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 } diff --git a/protocol/base64_test.go b/protocol/base64_test.go index 8b91897..0ff0452 100644 --- a/protocol/base64_test.go +++ b/protocol/base64_test.go @@ -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"), diff --git a/protocol/challenge_test.go b/protocol/challenge_test.go index f2e5d8d..3ee93a9 100644 --- a/protocol/challenge_test.go +++ b/protocol/challenge_test.go @@ -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 diff --git a/protocol/credential.go b/protocol/credential.go index befb653..99d41cf 100644 --- a/protocol/credential.go +++ b/protocol/credential.go @@ -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") } diff --git a/protocol/credential_test.go b/protocol/credential_test.go index 89aca29..e386fdd 100644 --- a/protocol/credential_test.go +++ b/protocol/credential_test.go @@ -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 @@ -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