From 464523041afb1c681297d782edc14c18f2ab195a Mon Sep 17 00:00:00 2001 From: James Elliott Date: Wed, 22 Feb 2023 11:48:52 +1100 Subject: [PATCH 1/3] fix(protocol): use strict base64 encoding This ensures the strict version of base64 is used for all encoding/decoding. --- metadata/metadata.go | 18 ++++++++++-------- protocol/assertion.go | 2 +- protocol/assertion_test.go | 16 ++++++++-------- protocol/attestation_safetynet.go | 14 +++++++++----- protocol/authenticator_test.go | 4 ++-- protocol/base64.go | 10 ++++++---- protocol/base64_test.go | 2 +- protocol/challenge_test.go | 2 +- protocol/credential.go | 2 +- protocol/credential_test.go | 26 +++++++++++++------------- 10 files changed, 52 insertions(+), 44 deletions(-) diff --git a/metadata/metadata.go b/metadata/metadata.go index 043f205..922ed25 100644 --- a/metadata/metadata.go +++ b/metadata/metadata.go @@ -567,10 +567,10 @@ func unmarshalMDSBLOB(body []byte, c http.Client) (MetadataBLOBPayload, error) { // 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, base64.StdEncoding.Strict().DecodedLen(len(chain[0].(string)))) // base64 decode the certificate into the buffer. - n, err := base64.StdEncoding.Decode(o, []byte(chain[0].(string))) + n, err := base64.StdEncoding.Strict().Decode(o, []byte(chain[0].(string))) if err != nil { return nil, err } @@ -596,9 +596,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))) + decoder := base64.StdEncoding.Strict() - nRoot, err := base64.StdEncoding.Decode(oRoot, []byte(MDSRoot)) + oRoot := make([]byte, decoder.DecodedLen(len(MDSRoot))) + + nRoot, err := decoder.Decode(oRoot, []byte(MDSRoot)) if err != nil { return false, err } @@ -612,9 +614,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, decoder.DecodedLen(len(chain[1].(string)))) - n, err := base64.StdEncoding.Decode(o, []byte(chain[1].(string))) + n, err := decoder.Decode(o, []byte(chain[1].(string))) if err != nil { return false, err } @@ -637,9 +639,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, decoder.DecodedLen(len(chain[0].(string)))) - n, err = base64.StdEncoding.Decode(l, []byte(chain[0].(string))) + n, err = decoder.Decode(l, []byte(chain[0].(string))) if err != nil { return false, err } diff --git a/protocol/assertion.go b/protocol/assertion.go index defb8bf..17c2a68 100644 --- a/protocol/assertion.go +++ b/protocol/assertion.go @@ -68,7 +68,7 @@ func ParseCredentialRequestResponseBody(body io.Reader) (par *ParsedCredentialAs 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..624f7d2 100644 --- a/protocol/assertion_test.go +++ b/protocol/assertion_test.go @@ -13,14 +13,14 @@ 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") + byteID, _ := base64.RawURLEncoding.Strict().DecodeString("AI7D5q2P0LS-Fal9ZT7CHM2N5BLbUunF92T8b6iYC199bO2kagSuU05-5dZGqb1SP0A0lyTWng") + byteAAGUID, _ := base64.RawURLEncoding.Strict().DecodeString("rc4AAjW8xgpkiwsl8fBVAw") + byteRPIDHash, _ := base64.RawURLEncoding.Strict().DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvA") + byteAuthData, _ := base64.RawURLEncoding.Strict().DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBFXJJiGa3OAAI1vMYKZIsLJfHwVQMANwCOw-atj9C0vhWpfWU-whzNjeQS21Lpxfdk_G-omAtffWztpGoErlNOfuXWRqm9Uj9ANJck1p6lAQIDJiABIVggKAhfsdHcBIc0KPgAcRyAIK_-Vi-nCXHkRHPNaCMBZ-4iWCBxB8fGYQSBONi9uvq0gv95dGWlhJrBwCsj_a4LJQKVHQ") + byteSignature, _ := base64.RawURLEncoding.Strict().DecodeString("MEUCIBtIVOQxzFYdyWQyxaLR0tik1TnuPhGVhXVSNgFwLmN5AiEAnxXdCq0UeAVGWxOaFcjBZ_mEZoXqNboY5IkQDdlWZYc") + byteUserHandle, _ := base64.RawURLEncoding.Strict().DecodeString("0ToAAAAAAAAAAA") + byteCredentialPubKey, _ := base64.RawURLEncoding.Strict().DecodeString("pQMmIAEhWCAoCF-x0dwEhzQo-ABxHIAgr_5WL6cJceREc81oIwFn7iJYIHEHx8ZhBIE42L26-rSC_3l0ZaWEmsHAKyP9rgslApUdAQI") + byteClientDataJSON, _ := base64.RawURLEncoding.Strict().DecodeString("eyJjaGFsbGVuZ2UiOiJFNFBUY0lIX0hmWDFwQzZTaWdrMVNDOU5BbGdlenROMDQzOXZpOHpfYzlrIiwibmV3X2tleXNfbWF5X2JlX2FkZGVkX2hlcmUiOiJkbyBub3QgY29tcGFyZSBjbGllbnREYXRhSlNPTiBhZ2FpbnN0IGEgdGVtcGxhdGUuIFNlZSBodHRwczovL2dvby5nbC95YWJQZXgiLCJvcmlnaW4iOiJodHRwczovL3dlYmF1dGhuLmlvIiwidHlwZSI6IndlYmF1dGhuLmdldCJ9") type args struct { responseName string diff --git a/protocol/attestation_safetynet.go b/protocol/attestation_safetynet.go index e63ba3e..f690ca1 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") } + decoder := 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, decoder.DecodedLen(len(chain[0].(string)))) - n, err := base64.StdEncoding.Decode(o, []byte(chain[0].(string))) + n, err := decoder.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 := decoder.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, decoder.DecodedLen(len(certChain[0].(string)))) - n, err := base64.StdEncoding.Decode(l, []byte(certChain[0].(string))) + n, err := decoder.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..e0a9a89 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 @@ -29,9 +29,11 @@ func (e *URLEncodedBase64) UnmarshalJSON(data []byte) error { // Trim the trailing equal characters. data = bytes.TrimRight(data, "=") - out := make([]byte, base64.RawURLEncoding.DecodedLen(len(data))) + decoder := base64.RawURLEncoding.Strict() - n, err := base64.RawURLEncoding.Decode(out, data) + out := make([]byte, decoder.DecodedLen(len(data))) + + n, err := decoder.Decode(out, data) if err != nil { return err } @@ -49,5 +51,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 a416472..79d6db8 100644 --- a/protocol/credential.go +++ b/protocol/credential.go @@ -75,7 +75,7 @@ func ParseCredentialCreationResponseBody(body io.Reader) (pcc *ParsedCredentialC 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..75674f7 100644 --- a/protocol/credential_test.go +++ b/protocol/credential_test.go @@ -16,12 +16,12 @@ 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") + byteID, _ := base64.RawURLEncoding.Strict().DecodeString("6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g") + byteAuthData, _ := base64.RawURLEncoding.Strict().DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw") + byteRPIDHash, _ := base64.RawURLEncoding.Strict().DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvA") + byteCredentialPubKey, _ := base64.RawURLEncoding.Strict().DecodeString("pSJYIMfCKfxl2SvnqJIiHQysHmpmITNgtCkQ5ESExSRjqrhXAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNc") + byteAttObject, _ := base64.RawURLEncoding.Strict().DecodeString("o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw") + byteClientDataJSON, _ := base64.RawURLEncoding.Strict().DecodeString("eyJjaGFsbGVuZ2UiOiJXOEd6RlU4cEdqaG9SYldyTERsYW1BZnFfeTRTMUNaRzFWdW9lUkxBUnJFIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ") testCases := []struct { name string @@ -257,13 +257,13 @@ 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") + byteID, _ := base64.RawURLEncoding.Strict().DecodeString("6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g") + byteChallenge, _ := base64.RawURLEncoding.Strict().DecodeString("W8GzFU8pGjhoRbWrLDlamAfq_y4S1CZG1VuoeRLARrE") + byteAuthData, _ := base64.RawURLEncoding.Strict().DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw") + byteRPIDHash, _ := base64.RawURLEncoding.Strict().DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvA") + byteCredentialPubKey, _ := base64.RawURLEncoding.Strict().DecodeString("pSJYIMfCKfxl2SvnqJIiHQysHmpmITNgtCkQ5ESExSRjqrhXAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNc") + byteAttObject, _ := base64.RawURLEncoding.Strict().DecodeString("o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw") + byteClientDataJSON, _ := base64.RawURLEncoding.Strict().DecodeString("eyJjaGFsbGVuZ2UiOiJXOEd6RlU4cEdqaG9SYldyTERsYW1BZnFfeTRTMUNaRzFWdW9lUkxBUnJFIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ") type fields struct { ParsedPublicKeyCredential ParsedPublicKeyCredential From 79e0cecb6a2c284da2df7526db86e040883d4673 Mon Sep 17 00:00:00 2001 From: James Elliott Date: Wed, 22 Feb 2023 19:34:41 +1100 Subject: [PATCH 2/3] fix: comments --- protocol/base64.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/protocol/base64.go b/protocol/base64.go index e0a9a89..165b654 100644 --- a/protocol/base64.go +++ b/protocol/base64.go @@ -22,11 +22,10 @@ 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, "=") decoder := base64.RawURLEncoding.Strict() From 655747df5f50fc4dba72219f8adab5f061960fae Mon Sep 17 00:00:00 2001 From: James Elliott Date: Thu, 23 Feb 2023 13:46:53 +1100 Subject: [PATCH 3/3] refactor: decoder to encoding --- metadata/metadata.go | 20 +++++++++++--------- protocol/assertion_test.go | 18 ++++++++++-------- protocol/attestation_safetynet.go | 12 ++++++------ protocol/base64.go | 6 +++--- protocol/credential_test.go | 30 +++++++++++++++++------------- 5 files changed, 47 insertions(+), 39 deletions(-) diff --git a/metadata/metadata.go b/metadata/metadata.go index 922ed25..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.Strict().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.Strict().Decode(o, []byte(chain[0].(string))) + n, err := encoding.Decode(o, []byte(chain[0].(string))) if err != nil { return nil, err } @@ -596,11 +598,11 @@ func unmarshalMDSBLOB(body []byte, c http.Client) (MetadataBLOBPayload, error) { } func validateChain(chain []interface{}, c http.Client) (bool, error) { - decoder := base64.StdEncoding.Strict() + encoding := base64.StdEncoding.Strict() - oRoot := make([]byte, decoder.DecodedLen(len(MDSRoot))) + oRoot := make([]byte, encoding.DecodedLen(len(MDSRoot))) - nRoot, err := decoder.Decode(oRoot, []byte(MDSRoot)) + nRoot, err := encoding.Decode(oRoot, []byte(MDSRoot)) if err != nil { return false, err } @@ -614,9 +616,9 @@ func validateChain(chain []interface{}, c http.Client) (bool, error) { roots.AddCert(rootcert) - o := make([]byte, decoder.DecodedLen(len(chain[1].(string)))) + o := make([]byte, encoding.DecodedLen(len(chain[1].(string)))) - n, err := decoder.Decode(o, []byte(chain[1].(string))) + n, err := encoding.Decode(o, []byte(chain[1].(string))) if err != nil { return false, err } @@ -639,9 +641,9 @@ func validateChain(chain []interface{}, c http.Client) (bool, error) { ints := x509.NewCertPool() ints.AddCert(intcert) - l := make([]byte, decoder.DecodedLen(len(chain[0].(string)))) + l := make([]byte, encoding.DecodedLen(len(chain[0].(string)))) - n, err = decoder.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_test.go b/protocol/assertion_test.go index 624f7d2..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.Strict().DecodeString("AI7D5q2P0LS-Fal9ZT7CHM2N5BLbUunF92T8b6iYC199bO2kagSuU05-5dZGqb1SP0A0lyTWng") - byteAAGUID, _ := base64.RawURLEncoding.Strict().DecodeString("rc4AAjW8xgpkiwsl8fBVAw") - byteRPIDHash, _ := base64.RawURLEncoding.Strict().DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvA") - byteAuthData, _ := base64.RawURLEncoding.Strict().DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBFXJJiGa3OAAI1vMYKZIsLJfHwVQMANwCOw-atj9C0vhWpfWU-whzNjeQS21Lpxfdk_G-omAtffWztpGoErlNOfuXWRqm9Uj9ANJck1p6lAQIDJiABIVggKAhfsdHcBIc0KPgAcRyAIK_-Vi-nCXHkRHPNaCMBZ-4iWCBxB8fGYQSBONi9uvq0gv95dGWlhJrBwCsj_a4LJQKVHQ") - byteSignature, _ := base64.RawURLEncoding.Strict().DecodeString("MEUCIBtIVOQxzFYdyWQyxaLR0tik1TnuPhGVhXVSNgFwLmN5AiEAnxXdCq0UeAVGWxOaFcjBZ_mEZoXqNboY5IkQDdlWZYc") - byteUserHandle, _ := base64.RawURLEncoding.Strict().DecodeString("0ToAAAAAAAAAAA") - byteCredentialPubKey, _ := base64.RawURLEncoding.Strict().DecodeString("pQMmIAEhWCAoCF-x0dwEhzQo-ABxHIAgr_5WL6cJceREc81oIwFn7iJYIHEHx8ZhBIE42L26-rSC_3l0ZaWEmsHAKyP9rgslApUdAQI") - byteClientDataJSON, _ := base64.RawURLEncoding.Strict().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 f690ca1..ff949e6 100644 --- a/protocol/attestation_safetynet.go +++ b/protocol/attestation_safetynet.go @@ -77,14 +77,14 @@ func verifySafetyNetFormat(att AttestationObject, clientDataHash []byte) (string return "", nil, ErrAttestationFormat.WithDetails("Unable to find the SafetyNet response") } - decoder := base64.StdEncoding.Strict() + encoding := base64.StdEncoding.Strict() token, err := jwt.Parse(string(response), func(token *jwt.Token) (interface{}, error) { chain := token.Header["x5c"].([]interface{}) - o := make([]byte, decoder.DecodedLen(len(chain[0].(string)))) + o := make([]byte, encoding.DecodedLen(len(chain[0].(string)))) - n, err := decoder.Decode(o, []byte(chain[0].(string))) + n, err := encoding.Decode(o, []byte(chain[0].(string))) if err != nil { return nil, err } @@ -108,16 +108,16 @@ func verifySafetyNetFormat(att AttestationObject, clientDataHash []byte) (string // of authenticatorData and clientDataHash. nonceBuffer := sha256.Sum256(append(att.RawAuthData, clientDataHash...)) - nonceBytes, err := decoder.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, decoder.DecodedLen(len(certChain[0].(string)))) + l := make([]byte, encoding.DecodedLen(len(certChain[0].(string)))) - n, err := decoder.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/base64.go b/protocol/base64.go index 165b654..4a486c5 100644 --- a/protocol/base64.go +++ b/protocol/base64.go @@ -28,11 +28,11 @@ func (e *URLEncodedBase64) UnmarshalJSON(data []byte) error { // Trim the trailing padding characters. data = bytes.TrimRight(data, "=") - decoder := base64.RawURLEncoding.Strict() + encoding := base64.RawURLEncoding.Strict() - out := make([]byte, decoder.DecodedLen(len(data))) + out := make([]byte, encoding.DecodedLen(len(data))) - n, err := decoder.Decode(out, data) + n, err := encoding.Decode(out, data) if err != nil { return err } diff --git a/protocol/credential_test.go b/protocol/credential_test.go index 75674f7..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.Strict().DecodeString("6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g") - byteAuthData, _ := base64.RawURLEncoding.Strict().DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw") - byteRPIDHash, _ := base64.RawURLEncoding.Strict().DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvA") - byteCredentialPubKey, _ := base64.RawURLEncoding.Strict().DecodeString("pSJYIMfCKfxl2SvnqJIiHQysHmpmITNgtCkQ5ESExSRjqrhXAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNc") - byteAttObject, _ := base64.RawURLEncoding.Strict().DecodeString("o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw") - byteClientDataJSON, _ := base64.RawURLEncoding.Strict().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.Strict().DecodeString("6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g") - byteChallenge, _ := base64.RawURLEncoding.Strict().DecodeString("W8GzFU8pGjhoRbWrLDlamAfq_y4S1CZG1VuoeRLARrE") - byteAuthData, _ := base64.RawURLEncoding.Strict().DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw") - byteRPIDHash, _ := base64.RawURLEncoding.Strict().DecodeString("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvA") - byteCredentialPubKey, _ := base64.RawURLEncoding.Strict().DecodeString("pSJYIMfCKfxl2SvnqJIiHQysHmpmITNgtCkQ5ESExSRjqrhXAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNc") - byteAttObject, _ := base64.RawURLEncoding.Strict().DecodeString("o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw") - byteClientDataJSON, _ := base64.RawURLEncoding.Strict().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