pax_global_header00006660000000000000000000000064141420152510014505gustar00rootroot0000000000000052 comment=a19301eb3272d771eb4a93bda2c28b3384224f28 golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/000077500000000000000000000000001414201525100222265ustar00rootroot00000000000000golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/.DS_Store000066400000000000000000000200041414201525100237050ustar00rootroot00000000000000Bud1 !lg1Scomp  @€ @€ @€ @!.gitlg1ScompWi.gitmoDDblobhõîêRÃA.gitmodDblobhõîêRÃA.gitph1Scomp .githublg1Scomp\.githubmoDDblob9£-êRÃA.githubmodDblob9£-êRÃA.githubph1Scomp badge.svgIlocblobA.ÿÿÿÿÿÿgo.modIlocblob¯.ÿÿÿÿÿÿgo.sumIlocblob.ÿÿÿÿÿÿ LICENSE.txtIlocblob‹.ÿÿÿÿÿÿmetadataIlocblobAžÿÿÿÿÿÿmetadatalg1ScompŠmetadatamoDDblobŸè-êRÃAmetadatamodDblobŸè-êRÃAmetadataph1Scomp protocolIlocblob¯žÿÿÿÿÿÿprotocollg1Scompä½protocolmoDDblobظýëRÃAprotocolmodDblobظýëRÃAprotocolph1Scomp README.mdIlocblobžÿÿÿÿÿÿtestdataIlocblob‹žÿÿÿÿÿÿtestdatalg1Scomp¸àtestdatamoDDblob^%/êRÃAtestdatamodDblob^%/êRÃAtestdataph1ScompàwebauthnIlocblobAÿÿÿÿÿÿwebauthnlg1Scomp_ñwebauthnmoDDblob•d/êRÃAwebauthnmodDblob•d/êRÃAwebauthnph1Scompà E DSDB `€ @€ @€ @êRÃAwebauthnph1Scompàgolang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/.github/000077500000000000000000000000001414201525100235665ustar00rootroot00000000000000golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/.github/workflows/000077500000000000000000000000001414201525100256235ustar00rootroot00000000000000golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/.github/workflows/go.yml000066400000000000000000000011341414201525100267520ustar00rootroot00000000000000name: Go on: [push] jobs: build: name: Build runs-on: ubuntu-latest steps: - name: Set up Go 1.13 uses: actions/setup-go@v1 with: go-version: 1.13 id: go - name: Check out code into the Go module directory uses: actions/checkout@v2 - name: Get dependencies run: | go get -v -t -d ./... if [ -f Gopkg.toml ]; then curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh dep ensure fi - name: Build run: go build -v ./... - name: Test run: go test -v ./... golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/.gitignore000066400000000000000000000011651414201525100242210ustar00rootroot00000000000000 # Created by https://www.gitignore.io/api/go,visualstudiocode # Edit at https://www.gitignore.io/?templates=go,visualstudiocode ### Go ### # Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, build with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out ### Go Patch ### /vendor/ /Godeps/ ### VisualStudioCode ### .vscode/* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json ### VisualStudioCode Patch ### # Ignore all local history of files .history # End of https://www.gitignore.io/api/go,visualstudiocodegolang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/LICENSE.txt000066400000000000000000000027351414201525100240600ustar00rootroot00000000000000Copyright (c) 2017 Duo Security, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/README.md000066400000000000000000000161071414201525100235120ustar00rootroot00000000000000WebAuthn Library ============= [![GoDoc](https://godoc.org/github.com/duo-labs/webauthn?status.svg)](https://godoc.org/github.com/duo-labs/webauthn) ![Build Status](https://github.com/duo-labs/webauthn/workflows/Go/badge.svg) [![Go Report Card](https://goreportcard.com/badge/github.com/duo-labs/webauthn)](https://goreportcard.com/report/github.com/duo-labs/webauthn) This library is meant to handle [Web Authentication](https://w3c.github.io/webauthn) for Go apps that wish to implement a passwordless solution for users. While the specification is currently in Candidate Recommendation, this library conforms as much as possible to the guidelines and implementation procedures outlined by the document. ### Demo at webauthn.io An implementation of this library can be used at [webauthn.io](https://webauthn.io) and the code for this website can be found in the Duo Labs repository [`webauthn-io`](https://github.com/duo-labs/webauthn.io). ### Simplified demo A simplified demonstration of this library can be found [here](https://github.com/hbolimovsky/webauthn-example). It includes a minimal interface and is great for quickly testing out the code. The associated blog post can be found [here](). Quickstart ---------- `go get github.com/duo-labs/webauthn` and initialize it in your application with basic configuration values. Make sure your `user` model is able to handle the interface functions laid out in `webauthn/user.go`. This means also supporting the storage and retrieval of the credential and authenticator structs in `webauthn/credential.go` and `webauthn/authenticator.go`, respectively. ### Initialize the request handler ```golang import "github.com/duo-labs/webauthn/webauthn" var ( web *webauthn.WebAuthn err error ) // Your initialization function func main() { web, err = webauthn.New(&webauthn.Config{ RPDisplayName: "Duo Labs", // Display Name for your site RPID: "duo.com", // Generally the FQDN for your site RPOrigin: "https://login.duo.com", // The origin URL for WebAuthn requests RPIcon: "https://duo.com/logo.png", // Optional icon URL for your site }) if err != nil { fmt.Println(err) } } ``` ### Registering an account ```golang func BeginRegistration(w http.ResponseWriter, r *http.Request) { user := datastore.GetUser() // Find or create the new user options, sessionData, err := web.BeginRegistration(&user) // handle errors if present // store the sessionData values JSONResponse(w, options, http.StatusOK) // return the options generated // options.publicKey contain our registration options } func FinishRegistration(w http.ResponseWriter, r *http.Request) { user := datastore.GetUser() // Get the user // Get the session data stored from the function above // using gorilla/sessions it could look like this sessionData := store.Get(r, "registration-session") parsedResponse, err := protocol.ParseCredentialCreationResponseBody(r.Body) credential, err := web.CreateCredential(&user, sessionData, parsedResponse) // Handle validation or input errors // If creation was successful, store the credential object JSONResponse(w, "Registration Success", http.StatusOK) // Handle next steps } ``` ### Logging into an account ```golang func BeginLogin(w http.ResponseWriter, r *http.Request) { user := datastore.GetUser() // Find the user options, sessionData, err := webauthn.BeginLogin(&user) // handle errors if present // store the sessionData values JSONResponse(w, options, http.StatusOK) // return the options generated // options.publicKey contain our registration options } func FinishLogin(w http.ResponseWriter, r *http.Request) { user := datastore.GetUser() // Get the user // Get the session data stored from the function above // using gorilla/sessions it could look like this sessionData := store.Get(r, "login-session") parsedResponse, err := protocol.ParseCredentialRequestResponseBody(r.Body) credential, err := webauthn.ValidateLogin(&user, sessionData, parsedResponse) // Handle validation or input errors // If login was successful, handle next steps JSONResponse(w, "Login Success", http.StatusOK) } ``` Modifying Credential Options ---------------------------- You can modify the default credential creation options for registration and login by providing optional structs to the `BeginRegistration` and `BeginLogin` functions. ### Registration modifiers You can modify the registration options in the following ways: ```golang // Wherever you handle your WebAuthn requests import "github.com/duo-labs/webauthn/protocol" import "github.com/duo-labs/webauthn/webauthn" var webAuthnHandler webauthn.WebAuthn // init this in your init function func beginRegistration() { // Updating the AuthenticatorSelection options. // See the struct declarations for values authSelect := protocol.AuthenticatorSelection{ AuthenticatorAttachment: protocol.AuthenticatorAttachment("platform"), RequireResidentKey: protocol.ResidentKeyUnrequired(), UserVerification: protocol.VerificationRequired } // Updating the ConveyencePreference options. // See the struct declarations for values conveyencePref := protocol.ConveyancePreference(protocol.PreferNoAttestation) user := datastore.GetUser() // Get the user opts, sessionData, err webAuthnHandler.BeginRegistration(&user, webauthn.WithAuthenticatorSelection(authSelect), webauthn.WithConveyancePreference(conveyancePref)) // Handle next steps } ``` ### Login modifiers You can modify the login options to allow only certain credentials: ```golang // Wherever you handle your WebAuthn requests import "github.com/duo-labs/webauthn/protocol" import "github.com/duo-labs/webauthn/webauthn" var webAuthnHandler webauthn.WebAuthn // init this in your init function func beginLogin() { // Updating the AuthenticatorSelection options. // See the struct declarations for values allowList := make([]protocol.CredentialDescriptor, 1) allowList[0] = protocol.CredentialDescriptor{ CredentialID: credentialToAllowID, Type: protocol.CredentialType("public-key"), } user := datastore.GetUser() // Get the user opts, sessionData, err := webAuthnHandler.BeginLogin(&user, webauthn.wat.WithAllowedCredentials(allowList)) // Handle next steps } ``` Acknowledgements ---------------- I could not have made this library without the work of [Jordan Wright](https://twitter.com/jw_sec) and the designs done for our demo site by [Emily Rosen](http://www.emiroze.design/). When I began refactoring this library in December 2018, [Koen Vlaswinkel's](https://github.com/koesie10) Golang WebAuthn library really helped set me in the right direction. A huge thanks to [Alex Seigler](https://github.com/aseigler) for his continuing work on this WebAuthn library and many others. Thanks to everyone who submitted issues and pull requests to help make this library what it is today! golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/badge.svg000066400000000000000000000664141414201525100240240ustar00rootroot00000000000000 shield Created with Sketch. golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/go.mod000066400000000000000000000010021414201525100233250ustar00rootroot00000000000000module github.com/duo-labs/webauthn require ( github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/fxamacker/cbor/v2 v2.2.0 github.com/google/certificate-transparency-go v1.0.21 // indirect github.com/kr/pretty v0.1.0 // indirect github.com/mitchellh/mapstructure v1.1.2 github.com/satori/go.uuid v1.2.0 golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect ) go 1.13 golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/go.sum000066400000000000000000000046721414201525100233720ustar00rootroot00000000000000github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7 h1:Puu1hUwfps3+1CUzYdAZXijuvLuRMirgiXdf3zsM2Ig= github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/fxamacker/cbor v1.5.1 h1:XjQWBgdmQyqimslUh5r4tUGmoqzHmBFQOImkWGi2awg= github.com/fxamacker/cbor/v2 v2.2.0 h1:6eXqdDDe588rSYAi1HfZKbx6YYQO4mxQ9eC6xYpU/JQ= github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/metadata/000077500000000000000000000000001414201525100240065ustar00rootroot00000000000000golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/metadata/metadata.go000066400000000000000000001012141414201525100261140ustar00rootroot00000000000000package metadata import ( "bytes" "crypto" "crypto/x509" "encoding/base64" "encoding/json" "errors" "io/ioutil" "net/http" "github.com/cloudflare/cfssl/revoke" "github.com/mitchellh/mapstructure" uuid "github.com/satori/go.uuid" jwt "github.com/dgrijalva/jwt-go" ) // Metadata is a map of authenticator AAGUIDs to corresponding metadata statements var Metadata = make(map[uuid.UUID]MetadataTOCPayloadEntry) // Conformance indicates if test metadata is currently being used var Conformance = false // AuthenticatorAttestationType - The ATTESTATION constants are 16 bit long integers indicating the specific attestation that authenticator supports. type AuthenticatorAttestationType uint16 const ( // BasicFull - Indicates full basic attestation, based on an attestation private key shared among a class of authenticators (e.g. same model). Authenticators must provide its attestation signature during the registration process for the same reason. The attestation trust anchor is shared with FIDO Servers out of band (as part of the Metadata). This sharing process shouldt be done according to [UAFMetadataService]. BasicFull AuthenticatorAttestationType = 0x3E07 // BasicSurrogate - Just syntactically a Basic Attestation. The attestation object self-signed, i.e. it is signed using the UAuth.priv key, i.e. the key corresponding to the UAuth.pub key included in the attestation object. As a consequence it does not provide a cryptographic proof of the security characteristics. But it is the best thing we can do if the authenticator is not able to have an attestation private key. BasicSurrogate // Ecdaa - Indicates use of elliptic curve based direct anonymous attestation as defined in [FIDOEcdaaAlgorithm]. Support for this attestation type is optional at this time. It might be required by FIDO Certification. Ecdaa // AttCA - Indicates PrivacyCA attestation as defined in [TCG-CMCProfile-AIKCertEnroll]. Support for this attestation type is optional at this time. It might be required by FIDO Certification. AttCA ) // AuthenticatorStatus - This enumeration describes the status of an authenticator model as identified by its AAID and potentially some additional information (such as a specific attestation key). type AuthenticatorStatus string const ( // NotFidoCertified - This authenticator is not FIDO certified. NotFidoCertified = "NOT_FIDO_CERTIFIED" // FidoCertified - This authenticator has passed FIDO functional certification. This certification scheme is phased out and will be replaced by FIDO_CERTIFIED_L1. FidoCertified = "FIDO_CERTIFIED" // UserVerificationBypass - Indicates that malware is able to bypass the user verification. This means that the authenticator could be used without the user's consent and potentially even without the user's knowledge. UserVerificationBypass = "USER_VERIFICATION_BYPASS" // AttestationKeyCompromise - Indicates that an attestation key for this authenticator is known to be compromised. Additional data should be supplied, including the key identifier and the date of compromise, if known. AttestationKeyCompromise = "ATTESTATION_KEY_COMPROMISE" // UserKeyRemoteCompromise - This authenticator has identified weaknesses that allow registered keys to be compromised and should not be trusted. This would include both, e.g. weak entropy that causes predictable keys to be generated or side channels that allow keys or signatures to be forged, guessed or extracted. UserKeyRemoteCompromise = "USER_KEY_REMOTE_COMPROMISE" // UserKeyPhysicalCompromise - This authenticator has known weaknesses in its key protection mechanism(s) that allow user keys to be extracted by an adversary in physical possession of the device. UserKeyPhysicalCompromise = "USER_KEY_PHYSICAL_COMPROMISE" // UpdateAvailable - A software or firmware update is available for the device. Additional data should be supplied including a URL where users can obtain an update and the date the update was published. UpdateAvailable = "UPDATE_AVAILABLE" // Revoked - The FIDO Alliance has determined that this authenticator should not be trusted for any reason, for example if it is known to be a fraudulent product or contain a deliberate backdoor. Revoked = "REVOKED" // SelfAssertionSubmitted - The authenticator vendor has completed and submitted the self-certification checklist to the FIDO Alliance. If this completed checklist is publicly available, the URL will be specified in StatusReport.url. SelfAssertionSubmitted = "SELF_ASSERTION_SUBMITTED" // FidoCertifiedL1 - The authenticator has passed FIDO Authenticator certification at level 1. This level is the more strict successor of FIDO_CERTIFIED. FidoCertifiedL1 = "FIDO_CERTIFIED_L1" // FidoCertifiedL1plus - The authenticator has passed FIDO Authenticator certification at level 1+. This level is the more than level 1. FidoCertifiedL1plus = "FIDO_CERTIFIED_L1plus" // FidoCertifiedL2 - The authenticator has passed FIDO Authenticator certification at level 2. This level is more strict than level 1+. FidoCertifiedL2 = "FIDO_CERTIFIED_L2" // FidoCertifiedL2plus - The authenticator has passed FIDO Authenticator certification at level 2+. This level is more strict than level 2. FidoCertifiedL2plus = "FIDO_CERTIFIED_L2plus" // FidoCertifiedL3 - The authenticator has passed FIDO Authenticator certification at level 3. This level is more strict than level 2+. FidoCertifiedL3 = "FIDO_CERTIFIED_L3" // FidoCertifiedL3plus - The authenticator has passed FIDO Authenticator certification at level 3+. This level is more strict than level 3. FidoCertifiedL3plus = "FIDO_CERTIFIED_L3plus" ) // UndesiredAuthenticatorStatus is an array of undesirable authenticator statuses var UndesiredAuthenticatorStatus = [...]AuthenticatorStatus{ AttestationKeyCompromise, UserVerificationBypass, UserKeyRemoteCompromise, UserKeyPhysicalCompromise, Revoked, } // IsUndesiredAuthenticatorStatus returns whether the supplied authenticator status is desirable or not func IsUndesiredAuthenticatorStatus(status AuthenticatorStatus) bool { for _, s := range UndesiredAuthenticatorStatus { if s == status { return true } } return false } // StatusReport - Contains the current BiometricStatusReport of one of the authenticator's biometric component. type StatusReport struct { // Status of the authenticator. Additional fields MAY be set depending on this value. Status string `json:"status"` // ISO-8601 formatted date since when the status code was set, if applicable. If no date is given, the status is assumed to be effective while present. EffectiveDate string `json:"effectiveDate"` // Base64-encoded [RFC4648] (not base64url!) DER [ITU-X690-2008] PKIX certificate value related to the current status, if applicable. Certificate string `json:"certificate"` // HTTPS URL where additional information may be found related to the current status, if applicable. URL string `json:"url"` // Describes the externally visible aspects of the Authenticator Certification evaluation. CertificationDescriptor string `json:"certificationDescriptor"` // The unique identifier for the issued Certification. CertificateNumber string `json:"certificateNumber"` // The version of the Authenticator Certification Policy the implementation is Certified to, e.g. "1.0.0". CertificationPolicyVersion string `json:"certificationPolicyVersion"` // The Document Version of the Authenticator Security Requirements (DV) [FIDOAuthenticatorSecurityRequirements] the implementation is certified to, e.g. "1.2.0". CertificationRequirementsVersion string `json:"certificationRequirementsVersion"` } // BiometricStatusReport - Contains the current BiometricStatusReport of one of the authenticator's biometric component. type BiometricStatusReport struct { // Achieved level of the biometric certification of this biometric component of the authenticator CertLevel uint16 `json:"certLevel"` // A single USER_VERIFY constant indicating the modality of the biometric component Modality uint32 `json:"modality"` // ISO-8601 formatted date since when the certLevel achieved, if applicable. If no date is given, the status is assumed to be effective while present. EffectiveDate string `json:"effectiveDate"` // Describes the externally visible aspects of the Biometric Certification evaluation. CertificationDescriptor string `json:"certificationDescriptor"` // The unique identifier for the issued Biometric Certification. CertificateNumber string `json:"certificateNumber"` // The version of the Biometric Certification Policy the implementation is Certified to, e.g. "1.0.0". CertificationPolicyVersion string `json:"certificationPolicyVersion"` // The version of the Biometric Requirements [FIDOBiometricsRequirements] the implementation is certified to, e.g. "1.0.0". CertificationRequirementsVersion string `json:"certificationRequirementsVersion"` } // MetadataTOCPayloadEntry - Represents the MetadataTOCPayloadEntry type MetadataTOCPayloadEntry struct { // The AAID of the authenticator this metadata TOC payload entry relates to. Aaid string `json:"aaid"` // The Authenticator Attestation GUID. AaGUID string `json:"aaguid"` // A list of the attestation certificate public key identifiers encoded as hex string. AttestationCertificateKeyIdentifiers []string `json:"attestationCertificateKeyIdentifiers"` // The hash value computed over the base64url encoding of the UTF-8 representation of the JSON encoded metadata statement available at url and as defined in [FIDOMetadataStatement]. Hash string `json:"hash"` // Uniform resource locator (URL) of the encoded metadata statement for this authenticator model (identified by its AAID, AAGUID or attestationCertificateKeyIdentifier). URL string `json:"url"` // Status of the FIDO Biometric Certification of one or more biometric components of the Authenticator BiometricStatusReports []BiometricStatusReport `json:"biometricStatusReports"` // An array of status reports applicable to this authenticator. StatusReports []StatusReport `json:"statusReports"` // ISO-8601 formatted date since when the status report array was set to the current value. TimeOfLastStatusChange string `json:"timeOfLastStatusChange"` // URL of a list of rogue (i.e. untrusted) individual authenticators. RogueListURL string `json:"rogueListURL"` // The hash value computed over the Base64url encoding of the UTF-8 representation of the JSON encoded rogueList available at rogueListURL (with type rogueListEntry[]). RogueListHash string `json:"rogueListHash"` MetadataStatement MetadataStatement } // RogueListEntry - Contains a list of individual authenticators known to be rogue type RogueListEntry struct { // Base64url encoding of the rogue authenticator's secret key Sk string `json:"sk"` // ISO-8601 formatted date since when this entry is effective. Date string `json:"date"` } // MetadataTOCPayload - Represents the MetadataTOCPayload type MetadataTOCPayload struct { // The legalHeader, if present, contains a legal guide for accessing and using metadata, which itself MAY contain URL(s) pointing to further information, such as a full Terms and Conditions statement. LegalHeader string `json:"legalHeader"` // The serial number of this UAF Metadata TOC Payload. Serial numbers MUST be consecutive and strictly monotonic, i.e. the successor TOC will have a no value exactly incremented by one. Number int `json:"no"` // ISO-8601 formatted date when the next update will be provided at latest. NextUpdate string `json:"nextUpdate"` // List of zero or more MetadataTOCPayloadEntry objects. Entries []MetadataTOCPayloadEntry `json:"entries"` } // Version - Represents a generic version with major and minor fields. type Version struct { // Major version. Major uint16 `json:"major"` // Minor version. Minor uint16 `json:"minor"` } // CodeAccuracyDescriptor describes the relevant accuracy/complexity aspects of passcode user verification methods. type CodeAccuracyDescriptor struct { // The numeric system base (radix) of the code, e.g. 10 in the case of decimal digits. Base uint16 `json:"base"` // The minimum number of digits of the given base required for that code, e.g. 4 in the case of 4 digits. MinLength uint16 `json:"minLength"` // Maximum number of false attempts before the authenticator will block this method (at least for some time). 0 means it will never block. MaxRetries uint16 `json:"maxRetries"` // Enforced minimum number of seconds wait time after blocking (e.g. due to forced reboot or similar). // 0 means this user verification method will be blocked, either permanently or until an alternative user verification method method succeeded. // All alternative user verification methods MUST be specified appropriately in the Metadata in userVerificationDetails. BlockSlowdown uint16 `json:"blockSlowdown"` } // The BiometricAccuracyDescriptor describes relevant accuracy/complexity aspects in the case of a biometric user verification method. type BiometricAccuracyDescriptor struct { // The false rejection rate [ISO19795-1] for a single template, i.e. the percentage of verification transactions with truthful claims of identity that are incorrectly denied. SelfAttestedFRR int64 `json:"selfAttestedFRR "` // The false acceptance rate [ISO19795-1] for a single template, i.e. the percentage of verification transactions with wrongful claims of identity that are incorrectly confirmed. SelfAttestedFAR int64 `json:"selfAttestedFAR "` // Maximum number of alternative templates from different fingers allowed. MaxTemplates uint16 `json:"maxTemplates"` // Maximum number of false attempts before the authenticator will block this method (at least for some time). 0 means it will never block. MaxRetries uint16 `json:"maxRetries"` // Enforced minimum number of seconds wait time after blocking (e.g. due to forced reboot or similar). // 0 means that this user verification method will be blocked either permanently or until an alternative user verification method succeeded. // All alternative user verification methods MUST be specified appropriately in the metadata in userVerificationDetails. BlockSlowdown uint16 `json:"blockSlowdown"` } // The PatternAccuracyDescriptor describes relevant accuracy/complexity aspects in the case that a pattern is used as the user verification method. type PatternAccuracyDescriptor struct { // Number of possible patterns (having the minimum length) out of which exactly one would be the right one, i.e. 1/probability in the case of equal distribution. MinComplexity uint32 `json:"minComplexity"` // Maximum number of false attempts before the authenticator will block authentication using this method (at least temporarily). 0 means it will never block. MaxRetries uint16 `json:"maxRetries"` // Enforced minimum number of seconds wait time after blocking (due to forced reboot or similar mechanism). // 0 means this user verification method will be blocked, either permanently or until an alternative user verification method method succeeded. // All alternative user verification methods MUST be specified appropriately in the metadata under userVerificationDetails. BlockSlowdown uint16 `json:"blockSlowdown"` } // VerificationMethodDescriptor - A descriptor for a specific base user verification method as implemented by the authenticator. type VerificationMethodDescriptor struct { // a single USER_VERIFY constant (see [FIDORegistry]), not a bit flag combination. This value MUST be non-zero. UserVerification uint32 `json:"userVerification"` // May optionally be used in the case of method USER_VERIFY_PASSCODE. CaDesc CodeAccuracyDescriptor `json:"caDesc"` // May optionally be used in the case of method USER_VERIFY_FINGERPRINT, USER_VERIFY_VOICEPRINT, USER_VERIFY_FACEPRINT, USER_VERIFY_EYEPRINT, or USER_VERIFY_HANDPRINT. BaDesc BiometricAccuracyDescriptor `json:"baDesc"` // May optionally be used in case of method USER_VERIFY_PATTERN. PaDesc PatternAccuracyDescriptor `json:"paDesc"` } // VerificationMethodANDCombinations MUST be non-empty. It is a list containing the base user verification methods which must be passed as part of a successful user verification. type VerificationMethodANDCombinations struct { //This list will contain only a single entry if using a single user verification method is sufficient. // If this list contains multiple entries, then all of the listed user verification methods MUST be passed as part of the user verification process. VerificationMethodAndCombinations []VerificationMethodDescriptor `json:"verificationMethodANDCombinations"` } // The rgbPaletteEntry is an RGB three-sample tuple palette entry type rgbPaletteEntry struct { // Red channel sample value R uint16 `json:"r"` // Green channel sample value G uint16 `json:"g"` // Blue channel sample value B uint16 `json:"b"` } // The DisplayPNGCharacteristicsDescriptor describes a PNG image characteristics as defined in the PNG [PNG] spec for IHDR (image header) and PLTE (palette table) type DisplayPNGCharacteristicsDescriptor struct { // image width Width uint32 `json:"width"` // image height Height uint32 `json:"height"` // Bit depth - bits per sample or per palette index. BitDepth byte `json:"bitDepth"` // Color type defines the PNG image type. ColorType byte `json:"colorType"` // Compression method used to compress the image data. Compression byte `json:"compression"` // Filter method is the preprocessing method applied to the image data before compression. Filter byte `json:"filter"` // Interlace method is the transmission order of the image data. Interlace byte `json:"interlace"` // 1 to 256 palette entries Plte []rgbPaletteEntry `json:"plte"` } // EcdaaTrustAnchor - In the case of ECDAA attestation, the ECDAA-Issuer's trust anchor MUST be specified in this field. type EcdaaTrustAnchor struct { // base64url encoding of the result of ECPoint2ToB of the ECPoint2 X X string `json:"x"` // base64url encoding of the result of ECPoint2ToB of the ECPoint2 Y Y string `json:"y"` // base64url encoding of the result of BigNumberToB(c) C string `json:"c"` // base64url encoding of the result of BigNumberToB(sx) SX string `json:"sx"` // base64url encoding of the result of BigNumberToB(sy) SY string `json:"sy"` // Name of the Barreto-Naehrig elliptic curve for G1. "BN_P256", "BN_P638", "BN_ISOP256", and "BN_ISOP512" are supported. G1Curve string `json:"G1Curve"` } // ExtensionDescriptor - This descriptor contains an extension supported by the authenticator. type ExtensionDescriptor struct { // Identifies the extension. ID string `json:"id"` // The TAG of the extension if this was assigned. TAGs are assigned to extensions if they could appear in an assertion. Tag uint16 `json:"tag"` // Contains arbitrary data further describing the extension and/or data needed to correctly process the extension. Data string `json:"data"` // Indicates whether unknown extensions must be ignored (false) or must lead to an error (true) when the extension is to be processed by the FIDO Server, FIDO Client, ASM, or FIDO Authenticator. FailIfUnknown bool `json:"fail_if_unknown"` } // MetadataStatement - Authenticator metadata statements are used directly by the FIDO server at a relying party, but the information contained in the authoritative statement is used in several other places. type MetadataStatement struct { // The legalHeader, if present, contains a legal guide for accessing and using metadata, which itself MAY contain URL(s) pointing to further information, such as a full Terms and Conditions statement. LegalHeader string `json:"legalHeader"` // The Authenticator Attestation ID. Aaid string `json:"aaid"` // The Authenticator Attestation GUID. AaGUID string `json:"aaguid"` // A list of the attestation certificate public key identifiers encoded as hex string. AttestationCertificateKeyIdentifiers []string `json:"attestationCertificateKeyIdentifiers"` // A human-readable, short description of the authenticator, in English. Description string `json:"description"` // A list of human-readable short descriptions of the authenticator in different languages. AlternativeDescriptions map[string]string `json:"alternativeDescriptions"` // Earliest (i.e. lowest) trustworthy authenticatorVersion meeting the requirements specified in this metadata statement. AuthenticatorVersion uint16 `json:"authenticatorVersion"` // The FIDO protocol family. The values "uaf", "u2f", and "fido2" are supported. ProtocolFamily string `json:"protocolFamily"` // The FIDO unified protocol version(s) (related to the specific protocol family) supported by this authenticator. Upv []Version `json:"upv"` // The assertion scheme supported by the authenticator. AssertionScheme string `json:"assertionScheme"` // The preferred authentication algorithm supported by the authenticator. AuthenticationAlgorithm uint16 `json:"authenticationAlgorithm"` // The list of authentication algorithms supported by the authenticator. AuthenticationAlgorithms []uint16 `json:"authenticationAlgorithms"` // The preferred public key format used by the authenticator during registration operations. PublicKeyAlgAndEncoding uint16 `json:"publicKeyAlgAndEncoding"` // The list of public key formats supported by the authenticator during registration operations. PublicKeyAlgAndEncodings []uint16 `json:"publicKeyAlgAndEncodings"` // The supported attestation type(s). AttestationTypes []uint16 `json:"attestationTypes"` // A list of alternative VerificationMethodANDCombinations. UserVerificationDetails [][]VerificationMethodDescriptor `json:"userVerificationDetails"` // A 16-bit number representing the bit fields defined by the KEY_PROTECTION constants in the FIDO Registry of Predefined Values KeyProtection uint16 `json:"keyProtection"` // This entry is set to true or it is ommitted, if the Uauth private key is restricted by the authenticator to only sign valid FIDO signature assertions. // This entry is set to false, if the authenticator doesn't restrict the Uauth key to only sign valid FIDO signature assertions. IsKeyRestricted bool `json:"isKeyRestricted"` // This entry is set to true or it is ommitted, if Uauth key usage always requires a fresh user verification // This entry is set to false, if the Uauth key can be used without requiring a fresh user verification, e.g. without any additional user interaction, if the user was verified a (potentially configurable) caching time ago. IsFreshUserVerificationRequired bool `json:"isFreshUserVerificationRequired"` // A 16-bit number representing the bit fields defined by the MATCHER_PROTECTION constants in the FIDO Registry of Predefined Values MatcherProtection uint16 `json:"matcherProtection"` // The authenticator's overall claimed cryptographic strength in bits (sometimes also called security strength or security level). CryptoStrength uint16 `json:"cryptoStrength"` // Description of the particular operating environment that is used for the Authenticator. OperatingEnv string `json:"operatingEnv"` // A 32-bit number representing the bit fields defined by the ATTACHMENT_HINT constants in the FIDO Registry of Predefined Values AttachmentHint uint32 `json:"attachmentHint"` // Indicates if the authenticator is designed to be used only as a second factor, i.e. requiring some other authentication method as a first factor (e.g. username+password). IsSecondFactorOnly bool `json:"isSecondFactorOnly"` // A 16-bit number representing a combination of the bit flags defined by the TRANSACTION_CONFIRMATION_DISPLAY constants in the FIDO Registry of Predefined Values TcDisplay uint16 `json:"tcDisplay"` // Supported MIME content type [RFC2049] for the transaction confirmation display, such as text/plain or image/png. TcDisplayContentType string `json:"tcDisplayContentType"` // A list of alternative DisplayPNGCharacteristicsDescriptor. Each of these entries is one alternative of supported image characteristics for displaying a PNG image. TcDisplayPNGCharacteristics []DisplayPNGCharacteristicsDescriptor `json:"tcDisplayPNGCharacteristics"` // Each element of this array represents a PKIX [RFC5280] X.509 certificate that is a valid trust anchor for this authenticator model. // Multiple certificates might be used for different batches of the same model. // The array does not represent a certificate chain, but only the trust anchor of that chain. // A trust anchor can be a root certificate, an intermediate CA certificate or even the attestation certificate itself. AttestationRootCertificates []string `json:"attestationRootCertificates"` // A list of trust anchors used for ECDAA attestation. This entry MUST be present if and only if attestationType includes ATTESTATION_ECDAA. EcdaaTrustAnchors []EcdaaTrustAnchor `json:"ecdaaTrustAnchors"` // A data: url [RFC2397] encoded PNG [PNG] icon for the Authenticator. Icon string `json:"icon"` // List of extensions supported by the authenticator. SupportedExtensions []ExtensionDescriptor `json:"supportedExtensions"` } // MDSGetEndpointsRequest is the request sent to the conformance metadata getEndpoints endpoint type MDSGetEndpointsRequest struct { // The URL of the local server endpoint, e.g. https://webauthn.io/ Endpoint string `json:"endpoint"` } // MDSGetEndpointsResponse is the response received from a conformance metadata getEndpoints request type MDSGetEndpointsResponse struct { // The status of the response Status string `json:"status"` // An array of urls, each pointing to a MetadataTOCPayload Result []string `json:"result"` } // ProcessMDSTOC processes a FIDO metadata table of contents object per §3.1.8, steps 1 through 5 // FIDO Authenticator Metadata Service // https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-metadata-service-v2.0-rd-20180702.html#metadata-toc-object-processing-rules func ProcessMDSTOC(url string, suffix string, c http.Client) (MetadataTOCPayload, string, error) { var tocAlg string var payload MetadataTOCPayload // 1. The FIDO Server MUST be able to download the latest metadata TOC object from the well-known URL, when appropriate. body, err := downloadBytes(url+suffix, c) if err != nil { return payload, tocAlg, err } // Steps 2 - 4 done in unmarshalMDSTOC. Caller is responsible for step 5. return unmarshalMDSTOC(body, c) } func unmarshalMDSTOC(body []byte, c http.Client) (MetadataTOCPayload, string, error) { var tocAlg string var payload MetadataTOCPayload token, err := jwt.Parse(string(body), func(token *jwt.Token) (interface{}, error) { // 2. If the x5u attribute is present in the JWT Header, then if _, ok := token.Header["x5u"].([]interface{}); ok { // never seen an x5u here, although it is in the spec return nil, errors.New("x5u encountered in header of metadata TOC payload") } var chain []interface{} // 3. If the x5u attribute is missing, the chain should be retrieved from the x5c attribute. if x5c, ok := token.Header["x5c"].([]interface{}); !ok { // If that attribute is missing as well, Metadata TOC signing trust anchor is considered the TOC signing certificate chain. root, err := getMetdataTOCSigningTrustAnchor(c) if nil != err { return nil, err } chain[0] = root } else { chain = x5c } // The certificate chain MUST be verified to properly chain to the metadata TOC signing trust anchor valid, err := validateChain(chain, c) if !valid || err != nil { return nil, err } // 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)))) // base64 decode the certificate into the buffer n, err := base64.StdEncoding.Decode(o, []byte(chain[0].(string))) // parse the certificate from the buffer cert, err := x509.ParseCertificate(o[:n]) if err != nil { return nil, err } // 4. Verify the signature of the Metadata TOC object using the TOC signing certificate chain // jwt.Parse() uses the TOC signing certificate public key internally to verify the signature return cert.PublicKey, err }) if err != nil { return payload, tocAlg, err } tocAlg = token.Header["alg"].(string) err = mapstructure.Decode(token.Claims, &payload) return payload, tocAlg, err } func getMetdataTOCSigningTrustAnchor(c http.Client) ([]byte, error) { rooturl := "" if Conformance { rooturl = "https://fidoalliance.co.nz/mds/pki/MDSROOT.crt" } else { rooturl = "https://mds.fidoalliance.org/Root.cer" } return downloadBytes(rooturl, c) } func validateChain(chain []interface{}, c http.Client) (bool, error) { root, err := getMetdataTOCSigningTrustAnchor(c) if err != nil { return false, err } roots := x509.NewCertPool() ok := roots.AppendCertsFromPEM(root) if !ok { return false, err } o := make([]byte, base64.StdEncoding.DecodedLen(len(chain[1].(string)))) n, err := base64.StdEncoding.Decode(o, []byte(chain[1].(string))) if err != nil { return false, err } intcert, err := x509.ParseCertificate(o[:n]) if err != nil { return false, err } if revoked, ok := revoke.VerifyCertificate(intcert); !ok { return false, errCRLUnavailable } else if revoked { return false, errIntermediateCertRevoked } ints := x509.NewCertPool() ints.AddCert(intcert) l := make([]byte, base64.StdEncoding.DecodedLen(len(chain[0].(string)))) n, err = base64.StdEncoding.Decode(l, []byte(chain[0].(string))) if err != nil { return false, err } leafcert, err := x509.ParseCertificate(l[:n]) if err != nil { return false, err } if revoked, ok := revoke.VerifyCertificate(leafcert); !ok { return false, errCRLUnavailable } else if revoked { return false, errLeafCertRevoked } opts := x509.VerifyOptions{ Roots: roots, Intermediates: ints, } _, err = leafcert.Verify(opts) return err == nil, err } // GetMetadataStatement iterates through a list of payload entries within a FIDO metadata table of contents object per §3.1.8, step 6 // FIDO Authenticator Metadata Service // https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-metadata-service-v2.0-rd-20180702.html#metadata-toc-object-processing-rules func GetMetadataStatement(entry MetadataTOCPayloadEntry, suffix string, alg string, c http.Client) (MetadataStatement, error) { var statement MetadataStatement // 1. Ignore the entry if the AAID, AAGUID or attestationCertificateKeyIdentifiers is not relevant to the relying party (e.g. not acceptable by any policy) // Caller is responsible for determining if entry is relevant. // 2. Download the metadata statement from the URL specified by the field url. body, err := downloadBytes(entry.URL+suffix, c) if err != nil { return statement, err } // 3. Check whether the status report of the authenticator model has changed compared to the cached entry by looking at the fields timeOfLastStatusChange and statusReport. // Caller is responsible for cache // step 4 done in unmarshalMetadataStatement, caller is responsible for step 5 return unmarshalMetadataStatement(body, entry.Hash) } func unmarshalMetadataStatement(body []byte, hash string) (MetadataStatement, error) { // 4. Compute the hash value of the metadata statement downloaded from the URL and verify the hash value to the hash specified in the field hash of the metadata TOC object. var statement MetadataStatement entryHash, err := base64.URLEncoding.DecodeString(hash) if err != nil { entryHash, err = base64.RawURLEncoding.DecodeString(hash) } if err != nil { return statement, err } // TODO: Get hasher based on MDS TOC alg instead of assuming SHA256 hasher := crypto.SHA256.New() _, _ = hasher.Write(body) hashed := hasher.Sum(nil) // Ignore the downloaded metadata statement if the hash value doesn't match. if !bytes.Equal(hashed, entryHash) { return statement, errHashValueMismatch } // Extract the metadata statement from base64 encoded form n := base64.URLEncoding.DecodedLen(len(body)) out := make([]byte, n) m, err := base64.URLEncoding.Decode(out, body) if err != nil { return statement, err } // Unmarshal the metadata statement into a MetadataStatement structure and return it to caller err = json.Unmarshal(out[:m], &statement) return statement, err } func downloadBytes(url string, c http.Client) ([]byte, error) { res, err := c.Get(url) if err != nil { return nil, err } defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) return body, err } type MetadataError struct { // Short name for the type of error that has occurred Type string `json:"type"` // Additional details about the error Details string `json:"error"` // Information to help debug the error DevInfo string `json:"debug"` } var ( errHashValueMismatch = &MetadataError{ Type: "hash_mismatch", Details: "Hash value mismatch between entry.Hash and downloaded bytes", } errIntermediateCertRevoked = &MetadataError{ Type: "intermediate_revoked", Details: "Intermediate certificate is on issuers revocation list", } errLeafCertRevoked = &MetadataError{ Type: "leaf_revoked", Details: "Leaf certificate is on issuers revocation list", } errCRLUnavailable = &MetadataError{ Type: "crl_unavailable", Details: "Certificate revocation list is unavailable", } ) func (err *MetadataError) Error() string { return err.Details } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/metadata/metadata_test.go000066400000000000000000000035701414201525100271610ustar00rootroot00000000000000package metadata import ( "io/ioutil" "net/http" "testing" "time" jwt "github.com/dgrijalva/jwt-go" ) func TestMetadataTOCParsing(t *testing.T) { Conformance = true httpClient := &http.Client{ Timeout: time.Second * 30, } tests := []struct { name string file string wantErr error }{ { "success", "../testdata/MetadataTOCParsing-P1.jwt", nil, }, { "verification_failure", "../testdata/MetadataTOCParsing-F1.jwt", errIntermediateCertRevoked, }, { "intermediate_revoked", "../testdata/MetadataTOCParsing-F2.jwt", jwt.ErrECDSAVerification, }, { "leaf_revoked", "../testdata/MetadataTOCParsing-F3.jwt", errLeafCertRevoked, }, { "asn1_parse_error", "../testdata/MetadataTOCParsing-F4.jwt", errCRLUnavailable, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { b, _ := ioutil.ReadFile(tt.file) _, _, err := unmarshalMDSTOC(b, *httpClient) failed := true if err != nil { failed = (err.Error() != tt.wantErr.Error()) } else { failed = tt.wantErr != nil } if failed { t.Errorf("unmarshalMDSTOC() got %v, wanted %v", err, tt.wantErr) } }) } } func TestMetadataStatementParsing(t *testing.T) { tests := []struct { name string file string hash string wantErr error }{ { "success", "../testdata/TestMetadataStatementParsing-P1.json", "bEtEyoVkc-X-ypuFoAIj8s4xKKTZw3wzD7IuDnoBUE8", nil, }, { "hash_value_mismatch", "../testdata/TestMetadataStatementParsing-F1.json", "eq28frELluGyBesOw_xE_10Tj25NG0pDS7Oa0DP2kVk", errHashValueMismatch, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { b, _ := ioutil.ReadFile(tt.file) _, err := unmarshalMetadataStatement(b, tt.hash) if err != tt.wantErr { t.Errorf("unmarshalMetadataStatement() error %v, wantErr %v", err, tt.wantErr) } }) } } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/000077500000000000000000000000001414201525100240675ustar00rootroot00000000000000golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/.DS_Store000066400000000000000000000140041414201525100255510ustar00rootroot00000000000000Bud1 letpmlg googletpmlg1ScompG googletpmmoDDblob¢«.êRÃA googletpmmodDblob¢«.êRÃA googletpmph1ScompP webauthncoselg1Scomp8; webauthncosemoDDblobÜ.êRÃA webauthncosemodDblobÜ.êRÃA webauthncoseph1Scomp`  @€ @€ @€ @ E DSDB `€ @€ @€ @golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/assertion.go000066400000000000000000000131211414201525100264230ustar00rootroot00000000000000package protocol import ( "crypto/sha256" "encoding/base64" "encoding/json" "fmt" "io" "net/http" "github.com/duo-labs/webauthn/protocol/webauthncose" ) // The raw response returned to us from an authenticator when we request a // credential for login/assertion. type CredentialAssertionResponse struct { PublicKeyCredential AssertionResponse AuthenticatorAssertionResponse `json:"response"` } // The parsed CredentialAssertionResponse that has been marshalled into a format // that allows us to verify the client and authenticator data inside the response type ParsedCredentialAssertionData struct { ParsedPublicKeyCredential Response ParsedAssertionResponse Raw CredentialAssertionResponse } // The AuthenticatorAssertionResponse contains the raw authenticator assertion data and is parsed into // ParsedAssertionResponse type AuthenticatorAssertionResponse struct { AuthenticatorResponse AuthenticatorData URLEncodedBase64 `json:"authenticatorData"` Signature URLEncodedBase64 `json:"signature"` UserHandle URLEncodedBase64 `json:"userHandle,omitempty"` } // Parsed form of AuthenticatorAssertionResponse type ParsedAssertionResponse struct { CollectedClientData CollectedClientData AuthenticatorData AuthenticatorData Signature []byte UserHandle []byte } // Parse the credential request response into a format that is either required by the specification // or makes the assertion verification steps easier to complete. This takes an http.Request that contains // the attestation response data in a raw, mostly base64 encoded format, and parses the data into // manageable structures func ParseCredentialRequestResponse(response *http.Request) (*ParsedCredentialAssertionData, error) { if response == nil || response.Body == nil { return nil, ErrBadRequest.WithDetails("No response given") } return ParseCredentialRequestResponseBody(response.Body) } // Parse the credential request response into a format that is either required by the specification // or makes the assertion verification steps easier to complete. This takes an io.Reader that contains // the attestation response data in a raw, mostly base64 encoded format, and parses the data into // manageable structures func ParseCredentialRequestResponseBody(body io.Reader) (*ParsedCredentialAssertionData, error) { var car CredentialAssertionResponse err := json.NewDecoder(body).Decode(&car) if err != nil { return nil, ErrBadRequest.WithDetails("Parse error for Assertion") } if car.ID == "" { return nil, ErrBadRequest.WithDetails("CredentialAssertionResponse with ID missing") } _, err = base64.RawURLEncoding.DecodeString(car.ID) if err != nil { return nil, ErrBadRequest.WithDetails("CredentialAssertionResponse with ID not base64url encoded") } if car.Type != "public-key" { return nil, ErrBadRequest.WithDetails("CredentialAssertionResponse with bad type") } var par ParsedCredentialAssertionData par.ID, par.RawID, par.Type = car.ID, car.RawID, car.Type par.Raw = car par.Response.Signature = car.AssertionResponse.Signature par.Response.UserHandle = car.AssertionResponse.UserHandle // Step 5. Let JSONtext be the result of running UTF-8 decode on the value of cData. // We don't call it cData but this is Step 5 in the spec. err = json.Unmarshal(car.AssertionResponse.ClientDataJSON, &par.Response.CollectedClientData) if err != nil { return nil, err } err = par.Response.AuthenticatorData.Unmarshal(car.AssertionResponse.AuthenticatorData) if err != nil { return nil, ErrParsingData.WithDetails("Error unmarshalling auth data") } return &par, nil } // Follow the remaining steps outlined in §7.2 Verifying an authentication assertion // (https://www.w3.org/TR/webauthn/#verifying-assertion) and return an error if there // is a failure during each step. func (p *ParsedCredentialAssertionData) Verify(storedChallenge string, relyingPartyID, relyingPartyOrigin string, verifyUser bool, credentialBytes []byte) error { // Steps 4 through 6 in verifying the assertion data (https://www.w3.org/TR/webauthn/#verifying-assertion) are // "assertive" steps, i.e "Let JSONtext be the result of running UTF-8 decode on the value of cData." // We handle these steps in part as we verify but also beforehand // Handle steps 7 through 10 of assertion by verifying stored data against the Collected Client Data // returned by the authenticator validError := p.Response.CollectedClientData.Verify(storedChallenge, AssertCeremony, relyingPartyOrigin) if validError != nil { return validError } // Begin Step 11. Verify that the rpIdHash in authData is the SHA-256 hash of the RP ID expected by the RP. rpIDHash := sha256.Sum256([]byte(relyingPartyID)) // Handle steps 11 through 14, verifying the authenticator data. validError = p.Response.AuthenticatorData.Verify(rpIDHash[:], verifyUser) if validError != nil { return ErrAuthData.WithInfo(validError.Error()) } // allowedUserCredentialIDs := session.AllowedCredentialIDs // Step 15. Let hash be the result of computing a hash over the cData using SHA-256. clientDataHash := sha256.Sum256(p.Raw.AssertionResponse.ClientDataJSON) // Step 16. Using the credential public key looked up in step 3, verify that sig is // a valid signature over the binary concatenation of authData and hash. sigData := append(p.Raw.AssertionResponse.AuthenticatorData, clientDataHash[:]...) key, err := webauthncose.ParsePublicKey(credentialBytes) valid, err := webauthncose.VerifySignature(key, sigData, p.Response.Signature) if !valid { return ErrAssertionSignature.WithDetails(fmt.Sprintf("Error validating the assertion signature: %+v\n", err)) } return nil } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/assertion_test.go000066400000000000000000000214211414201525100274640ustar00rootroot00000000000000package protocol import ( "bytes" "encoding/base64" "io/ioutil" "net/http" "reflect" "testing" "github.com/fxamacker/cbor/v2" ) func TestParseCredentialRequestResponse(t *testing.T) { reqBody := ioutil.NopCloser(bytes.NewReader([]byte(testAssertionResponses["success"]))) httpReq := &http.Request{Body: reqBody} 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") type args struct { response *http.Request } tests := []struct { name string args args want *ParsedCredentialAssertionData wantErr bool }{ { name: "Successfully Parse Credential Assertion", args: args{ httpReq, }, want: &ParsedCredentialAssertionData{ ParsedPublicKeyCredential: ParsedPublicKeyCredential{ ParsedCredential: ParsedCredential{ ID: "AI7D5q2P0LS-Fal9ZT7CHM2N5BLbUunF92T8b6iYC199bO2kagSuU05-5dZGqb1SP0A0lyTWng", Type: "public-key", }, RawID: byteID, }, Response: ParsedAssertionResponse{ CollectedClientData: CollectedClientData{ Type: CeremonyType("webauthn.get"), Challenge: "E4PTcIH_HfX1pC6Sigk1SC9NAlgeztN0439vi8z_c9k", Origin: "https://webauthn.io", Hint: "do not compare clientDataJSON against a template. See https://goo.gl/yabPex", }, AuthenticatorData: AuthenticatorData{ RPIDHash: byteRPIDHash, Counter: 1553097241, Flags: 0x045, AttData: AttestedCredentialData{ AAGUID: byteAAGUID, CredentialID: byteID, CredentialPublicKey: byteCredentialPubKey, }, }, Signature: byteSignature, UserHandle: byteUserHandle, }, Raw: CredentialAssertionResponse{ PublicKeyCredential: PublicKeyCredential{ Credential: Credential{ Type: "public-key", ID: "AI7D5q2P0LS-Fal9ZT7CHM2N5BLbUunF92T8b6iYC199bO2kagSuU05-5dZGqb1SP0A0lyTWng", }, RawID: byteID, }, AssertionResponse: AuthenticatorAssertionResponse{ AuthenticatorResponse: AuthenticatorResponse{ ClientDataJSON: byteClientDataJSON, }, AuthenticatorData: byteAuthData, Signature: byteSignature, UserHandle: byteUserHandle, }, }, }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := ParseCredentialRequestResponse(tt.args.response) if (err != nil) != tt.wantErr { t.Errorf("ParseCredentialRequestResponse() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got.Extensions, tt.want.Extensions) { t.Errorf("Extensions = %v \n want: %v", got, tt.want) } if !reflect.DeepEqual(got.ID, tt.want.ID) { t.Errorf("ID = %v \n want: %v", got.ID, tt.want.ID) } if !reflect.DeepEqual(got.ParsedCredential, tt.want.ParsedCredential) { t.Errorf("ParsedCredential = %v \n want: %v", got, tt.want) } if !reflect.DeepEqual(got.ParsedPublicKeyCredential, tt.want.ParsedPublicKeyCredential) { t.Errorf("ParsedPublicKeyCredential = %v \n want: %v", got.ParsedPublicKeyCredential.Extensions, tt.want.ParsedPublicKeyCredential.Extensions) } if !reflect.DeepEqual(got.Raw, tt.want.Raw) { t.Errorf("Raw = %+v \n want: %+v", got.Raw, tt.want.Raw) } if !reflect.DeepEqual(got.RawID, tt.want.RawID) { t.Errorf("RawID = %v \n want: %v", got, tt.want) } if !reflect.DeepEqual(got.Response, tt.want.Response) { var pkInterfaceMismatch bool if !reflect.DeepEqual(got.Response.CollectedClientData, tt.want.Response.CollectedClientData) { t.Errorf("Collected Client Data = %v \n want: %v", got.Response.CollectedClientData, tt.want.Response.CollectedClientData) } if !reflect.DeepEqual(got.Response.Signature, tt.want.Response.Signature) { t.Errorf("Signature = %v \n want: %v", got.Response.Signature, tt.want.Response.Signature) } if !reflect.DeepEqual(got.Response.AuthenticatorData.AttData.CredentialPublicKey, tt.want.Response.AuthenticatorData.AttData.CredentialPublicKey) { // Unmarshall CredentialPublicKey var pkWant interface{} keyBytesWant := tt.want.Response.AuthenticatorData.AttData.CredentialPublicKey cbor.Unmarshal(keyBytesWant, &pkWant) var pkGot interface{} keyBytesGot := got.Response.AuthenticatorData.AttData.CredentialPublicKey cbor.Unmarshal(keyBytesGot, &pkGot) if !reflect.DeepEqual(pkGot, pkWant) { t.Errorf("Response = %+v \n want: %+v", pkGot, pkWant) } else { pkInterfaceMismatch = true } } if pkInterfaceMismatch { return } else { t.Errorf("Response = %+v \n want: %+v", got.Response, tt.want.Response) } } }) } } func TestParsedCredentialAssertionData_Verify(t *testing.T) { type fields struct { ParsedPublicKeyCredential ParsedPublicKeyCredential Response ParsedAssertionResponse Raw CredentialAssertionResponse } type args struct { storedChallenge Challenge relyingPartyID string relyingPartyOrigin string verifyUser bool credentialBytes []byte } tests := []struct { name string fields fields args args wantErr bool }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { p := &ParsedCredentialAssertionData{ ParsedPublicKeyCredential: tt.fields.ParsedPublicKeyCredential, Response: tt.fields.Response, Raw: tt.fields.Raw, } if err := p.Verify(tt.args.storedChallenge.String(), tt.args.relyingPartyID, tt.args.relyingPartyOrigin, tt.args.verifyUser, tt.args.credentialBytes); (err != nil) != tt.wantErr { t.Errorf("ParsedCredentialAssertionData.Verify() error = %v, wantErr %v", err, tt.wantErr) } }) } } var testAssertionOptions = map[string]string{ // None Attestation - MacOS TouchID `success`: `{ "id":"AI7D5q2P0LS-Fal9ZT7CHM2N5BLbUunF92T8b6iYC199bO2kagSuU05-5dZGqb1SP0A0lyTWng", "rawId":"AI7D5q2P0LS-Fal9ZT7CHM2N5BLbUunF92T8b6iYC199bO2kagSuU05-5dZGqb1SP0A0lyTWng", "type":"public-key", "response":{ "attestationObject":"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVi7dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBFXJJiFa3OAAI1vMYKZIsLJfHwVQMANwCOw-atj9C0vhWpfWU-whzNjeQS21Lpxfdk_G-omAtffWztpGoErlNOfuXWRqm9Uj9ANJck1p6lAQIDJiABIVggKAhfsdHcBIc0KPgAcRyAIK_-Vi-nCXHkRHPNaCMBZ-4iWCBxB8fGYQSBONi9uvq0gv95dGWlhJrBwCsj_a4LJQKVHQ", "clientDataJSON":"eyJjaGFsbGVuZ2UiOiJmeWV1dUdQOXp1ZWoyRkdqZXZpNzlienFNS1d4aTRQWUlhXzV3ajI2MVcwIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ"} } `, } var testAssertionResponses = map[string]string{ // None Attestation - MacOS TouchID `success`: `{ "id":"AI7D5q2P0LS-Fal9ZT7CHM2N5BLbUunF92T8b6iYC199bO2kagSuU05-5dZGqb1SP0A0lyTWng", "rawId":"AI7D5q2P0LS-Fal9ZT7CHM2N5BLbUunF92T8b6iYC199bO2kagSuU05-5dZGqb1SP0A0lyTWng", "type":"public-key", "response":{ "authenticatorData":"dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBFXJJiGa3OAAI1vMYKZIsLJfHwVQMANwCOw-atj9C0vhWpfWU-whzNjeQS21Lpxfdk_G-omAtffWztpGoErlNOfuXWRqm9Uj9ANJck1p6lAQIDJiABIVggKAhfsdHcBIc0KPgAcRyAIK_-Vi-nCXHkRHPNaCMBZ-4iWCBxB8fGYQSBONi9uvq0gv95dGWlhJrBwCsj_a4LJQKVHQ", "clientDataJSON":"eyJjaGFsbGVuZ2UiOiJFNFBUY0lIX0hmWDFwQzZTaWdrMVNDOU5BbGdlenROMDQzOXZpOHpfYzlrIiwibmV3X2tleXNfbWF5X2JlX2FkZGVkX2hlcmUiOiJkbyBub3QgY29tcGFyZSBjbGllbnREYXRhSlNPTiBhZ2FpbnN0IGEgdGVtcGxhdGUuIFNlZSBodHRwczovL2dvby5nbC95YWJQZXgiLCJvcmlnaW4iOiJodHRwczovL3dlYmF1dGhuLmlvIiwidHlwZSI6IndlYmF1dGhuLmdldCJ9", "signature":"MEUCIBtIVOQxzFYdyWQyxaLR0tik1TnuPhGVhXVSNgFwLmN5AiEAnxXdCq0UeAVGWxOaFcjBZ_mEZoXqNboY5IkQDdlWZYc", "userHandle":"0ToAAAAAAAAAAA"} } `, } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/attestation.go000066400000000000000000000165261414201525100267670ustar00rootroot00000000000000package protocol import ( "crypto/sha256" "encoding/json" "fmt" "github.com/fxamacker/cbor/v2" ) // From §5.2.1 (https://www.w3.org/TR/webauthn/#authenticatorattestationresponse) // "The authenticator's response to a client’s request for the creation // of a new public key credential. It contains information about the new credential // that can be used to identify it for later use, and metadata that can be used by // the WebAuthn Relying Party to assess the characteristics of the credential // during registration." // The initial unpacked 'response' object received by the relying party. This // contains the clientDataJSON object, which will be marshalled into // CollectedClientData, and the 'attestationObject', which contains // information about the authenticator, and the newly minted // public key credential. The information in both objects are used // to verify the authenticity of the ceremony and new credential type AuthenticatorAttestationResponse struct { // The byte slice of clientDataJSON, which becomes CollectedClientData AuthenticatorResponse // The byte slice version of AttestationObject // This attribute contains an attestation object, which is opaque to, and // cryptographically protected against tampering by, the client. The // attestation object contains both authenticator data and an attestation // statement. The former contains the AAGUID, a unique credential ID, and // the credential public key. The contents of the attestation statement are // determined by the attestation statement format used by the authenticator. // It also contains any additional information that the Relying Party's server // requires to validate the attestation statement, as well as to decode and // validate the authenticator data along with the JSON-serialized client data. AttestationObject URLEncodedBase64 `json:"attestationObject"` } // The parsed out version of AuthenticatorAttestationResponse. type ParsedAttestationResponse struct { CollectedClientData CollectedClientData AttestationObject AttestationObject } // From §6.4. Authenticators MUST also provide some form of attestation. The basic requirement is that the // authenticator can produce, for each credential public key, an attestation statement verifiable by the // WebAuthn Relying Party. Typically, this attestation statement contains a signature by an attestation // private key over the attested credential public key and a challenge, as well as a certificate or similar // data providing provenance information for the attestation public key, enabling the Relying Party to make // a trust decision. However, if an attestation key pair is not available, then the authenticator MUST // perform self attestation of the credential public key with the corresponding credential private key. // All this information is returned by authenticators any time a new public key credential is generated, in // the overall form of an attestation object. (https://www.w3.org/TR/webauthn/#attestation-object) // type AttestationObject struct { // The authenticator data, including the newly created public key. See AuthenticatorData for more info AuthData AuthenticatorData // The byteform version of the authenticator data, used in part for signature validation RawAuthData []byte `json:"authData"` // The format of the Attestation data. Format string `json:"fmt"` // The attestation statement data sent back if attestation is requested. AttStatement map[string]interface{} `json:"attStmt,omitempty"` } type attestationFormatValidationHandler func(AttestationObject, []byte) (string, []interface{}, error) var attestationRegistry = make(map[string]attestationFormatValidationHandler) // Using one of the locally registered attestation formats, handle validating the attestation // data provided by the authenticator (and in some cases its manufacturer) func RegisterAttestationFormat(format string, handler attestationFormatValidationHandler) { attestationRegistry[format] = handler } // Parse the values returned in the authenticator response and perform attestation verification // Step 8. This returns a fully decoded struct with the data put into a format that can be // used to verify the user and credential that was created func (ccr *AuthenticatorAttestationResponse) Parse() (*ParsedAttestationResponse, error) { var p ParsedAttestationResponse err := json.Unmarshal(ccr.ClientDataJSON, &p.CollectedClientData) if err != nil { return nil, ErrParsingData.WithInfo(err.Error()) } err = cbor.Unmarshal(ccr.AttestationObject, &p.AttestationObject) if err != nil { return nil, ErrParsingData.WithInfo(err.Error()) } // Step 8. Perform CBOR decoding on the attestationObject field of the AuthenticatorAttestationResponse // structure to obtain the attestation statement format fmt, the authenticator data authData, and // the attestation statement attStmt. err = p.AttestationObject.AuthData.Unmarshal(p.AttestationObject.RawAuthData) if err != nil { return nil, fmt.Errorf("error decoding auth data: %v", err) } if !p.AttestationObject.AuthData.Flags.HasAttestedCredentialData() { return nil, ErrAttestationFormat.WithInfo("Attestation missing attested credential data flag") } return &p, nil } // Verify - Perform Steps 9 through 14 of registration verification, delegating Steps func (attestationObject *AttestationObject) Verify(relyingPartyID string, clientDataHash []byte, verificationRequired bool) error { // Steps 9 through 12 are verified against the auth data. // These steps are identical to 11 through 14 for assertion // so we handle them with AuthData // Begin Step 9. Verify that the rpIdHash in authData is // the SHA-256 hash of the RP ID expected by the RP. rpIDHash := sha256.Sum256([]byte(relyingPartyID)) // Handle Steps 9 through 12 authDataVerificationError := attestationObject.AuthData.Verify(rpIDHash[:], verificationRequired) if authDataVerificationError != nil { return authDataVerificationError } // Step 13. Determine the attestation statement format by performing a // USASCII case-sensitive match on fmt against the set of supported // WebAuthn Attestation Statement Format Identifier values. The up-to-date // list of registered WebAuthn Attestation Statement Format Identifier // values is maintained in the IANA registry of the same name // [WebAuthn-Registries] (https://www.w3.org/TR/webauthn/#biblio-webauthn-registries). // Since there is not an active registry yet, we'll check it against our internal // Supported types. // But first let's make sure attestation is present. If it isn't, we don't need to handle // any of the following steps if attestationObject.Format == "none" { if len(attestationObject.AttStatement) != 0 { return ErrAttestationFormat.WithInfo("Attestation format none with attestation present") } return nil } formatHandler, valid := attestationRegistry[attestationObject.Format] if !valid { return ErrAttestationFormat.WithInfo(fmt.Sprintf("Attestation format %s is unsupported", attestationObject.Format)) } // Step 14. Verify that attStmt is a correct attestation statement, conveying a valid attestation signature, by using // the attestation statement format fmt’s verification procedure given attStmt, authData and the hash of the serialized // client data computed in step 7. attestationType, _, err := formatHandler(*attestationObject, clientDataHash) if err != nil { return err.(*Error).WithInfo(attestationType) } return nil } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/attestation_androidkey.go000066400000000000000000000256211414201525100311740ustar00rootroot00000000000000package protocol import ( "bytes" "crypto/x509" "encoding/asn1" "fmt" "github.com/duo-labs/webauthn/protocol/webauthncose" ) var androidAttestationKey = "android-key" func init() { RegisterAttestationFormat(androidAttestationKey, verifyAndroidKeyFormat) } // From §8.4. https://www.w3.org/TR/webauthn/#android-key-attestation // The android-key attestation statement looks like: // $$attStmtType //= ( // fmt: "android-key", // attStmt: androidStmtFormat // ) // androidStmtFormat = { // alg: COSEAlgorithmIdentifier, // sig: bytes, // x5c: [ credCert: bytes, * (caCert: bytes) ] // } func verifyAndroidKeyFormat(att AttestationObject, clientDataHash []byte) (string, []interface{}, error) { // Given the verification procedure inputs attStmt, authenticatorData and clientDataHash, the verification procedure is as follows: // §8.4.1. Verify that attStmt is valid CBOR conforming to the syntax defined above and perform CBOR decoding on it to extract // the contained fields. // Get the alg value - A COSEAlgorithmIdentifier containing the identifier of the algorithm // used to generate the attestation signature. alg, present := att.AttStatement["alg"].(int64) if !present { return androidAttestationKey, nil, ErrAttestationFormat.WithDetails("Error retreiving alg value") } // Get the sig value - A byte string containing the attestation signature. sig, present := att.AttStatement["sig"].([]byte) if !present { return androidAttestationKey, nil, ErrAttestationFormat.WithDetails("Error retreiving sig value") } // If x5c is not present, return an error x5c, x509present := att.AttStatement["x5c"].([]interface{}) if !x509present { // Handle Basic Attestation steps for the x509 Certificate return androidAttestationKey, nil, ErrAttestationFormat.WithDetails("Error retreiving x5c value") } // §8.4.2. Verify that sig is a valid signature over the concatenation of authenticatorData and clientDataHash // using the public key in the first certificate in x5c with the algorithm specified in alg. attCertBytes, valid := x5c[0].([]byte) if !valid { return androidAttestationKey, nil, ErrAttestation.WithDetails("Error getting certificate from x5c cert chain") } signatureData := append(att.RawAuthData, clientDataHash...) attCert, err := x509.ParseCertificate(attCertBytes) if err != nil { return androidAttestationKey, nil, ErrAttestationFormat.WithDetails(fmt.Sprintf("Error parsing certificate from ASN.1 data: %+v", err)) } coseAlg := webauthncose.COSEAlgorithmIdentifier(alg) sigAlg := webauthncose.SigAlgFromCOSEAlg(coseAlg) err = attCert.CheckSignature(x509.SignatureAlgorithm(sigAlg), signatureData, sig) if err != nil { return androidAttestationKey, nil, ErrInvalidAttestation.WithDetails(fmt.Sprintf("Signature validation error: %+v\n", err)) } // Verify that the public key in the first certificate in x5c matches the credentialPublicKey in the attestedCredentialData in authenticatorData. pubKey, err := webauthncose.ParsePublicKey(att.AuthData.AttData.CredentialPublicKey) if err != nil { return androidAttestationKey, nil, ErrInvalidAttestation.WithDetails(fmt.Sprintf("Error parsing public key: %+v\n", err)) } e := pubKey.(webauthncose.EC2PublicKeyData) valid, err = e.Verify(signatureData, sig) if err != nil || valid != true { return androidAttestationKey, nil, ErrInvalidAttestation.WithDetails(fmt.Sprintf("Error parsing public key: %+v\n", err)) } // §8.4.3. Verify that the attestationChallenge field in the attestation certificate extension data is identical to clientDataHash. // attCert.Extensions var attExtBytes []byte for _, ext := range attCert.Extensions { if ext.Id.Equal([]int{1, 3, 6, 1, 4, 1, 11129, 2, 1, 17}) { attExtBytes = ext.Value } } if len(attExtBytes) == 0 { return androidAttestationKey, nil, ErrAttestationFormat.WithDetails("Attestation certificate extensions missing 1.3.6.1.4.1.11129.2.1.17") } // As noted in §8.4.1 (https://w3c.github.io/webauthn/#key-attstn-cert-requirements) the Android Key Attestation attestation certificate's // android key attestation certificate extension data is identified by the OID "1.3.6.1.4.1.11129.2.1.17". decoded := keyDescription{} _, err = asn1.Unmarshal([]byte(attExtBytes), &decoded) if err != nil { return androidAttestationKey, nil, ErrAttestationFormat.WithDetails("Unable to parse Android key attestation certificate extensions") } // Verify that the attestationChallenge field in the attestation certificate extension data is identical to clientDataHash. if 0 != bytes.Compare(decoded.AttestationChallenge, clientDataHash) { return androidAttestationKey, nil, ErrAttestationFormat.WithDetails("Attestation challenge not equal to clientDataHash") } // The AuthorizationList.allApplications field is not present on either authorization list (softwareEnforced nor teeEnforced), since PublicKeyCredential MUST be scoped to the RP ID. if nil != decoded.SoftwareEnforced.AllApplications || nil != decoded.TeeEnforced.AllApplications { return androidAttestationKey, nil, ErrAttestationFormat.WithDetails("Attestation certificate extensions contains all applications field") } // For the following, use only the teeEnforced authorization list if the RP wants to accept only keys from a trusted execution environment, otherwise use the union of teeEnforced and softwareEnforced. // The value in the AuthorizationList.origin field is equal to KM_ORIGIN_GENERATED. (which == 0) if KM_ORIGIN_GENERATED != decoded.SoftwareEnforced.Origin || KM_ORIGIN_GENERATED != decoded.TeeEnforced.Origin { return androidAttestationKey, nil, ErrAttestationFormat.WithDetails("Attestation certificate extensions contains authorization list with origin not equal KM_ORIGIN_GENERATED") } // The value in the AuthorizationList.purpose field is equal to KM_PURPOSE_SIGN. (which == 2) if !contains(decoded.SoftwareEnforced.Purpose, KM_PURPOSE_SIGN) && !contains(decoded.TeeEnforced.Purpose, KM_PURPOSE_SIGN) { return androidAttestationKey, nil, ErrAttestationFormat.WithDetails("Attestation certificate extensions contains authorization list with purpose not equal KM_PURPOSE_SIGN") } return androidAttestationKey, x5c, err } func contains(s []int, e int) bool { for _, a := range s { if a == e { return true } } return false } type keyDescription struct { AttestationVersion int AttestationSecurityLevel asn1.Enumerated KeymasterVersion int KeymasterSecurityLevel asn1.Enumerated AttestationChallenge []byte UniqueID []byte SoftwareEnforced authorizationList TeeEnforced authorizationList } type authorizationList struct { Purpose []int `asn1:"tag:1,explicit,set,optional"` Algorithm int `asn1:"tag:2,explicit,optional"` KeySize int `asn1:"tag:3,explicit,optional"` Digest []int `asn1:"tag:5,explicit,set,optional"` Padding []int `asn1:"tag:6,explicit,set,optional"` EcCurve int `asn1:"tag:10,explicit,optional"` RsaPublicExponent int `asn1:"tag:200,explicit,optional"` RollbackResistance interface{} `asn1:"tag:303,explicit,optional"` ActiveDateTime int `asn1:"tag:400,explicit,optional"` OriginationExpireDateTime int `asn1:"tag:401,explicit,optional"` UsageExpireDateTime int `asn1:"tag:402,explicit,optional"` NoAuthRequired interface{} `asn1:"tag:503,explicit,optional"` UserAuthType int `asn1:"tag:504,explicit,optional"` AuthTimeout int `asn1:"tag:505,explicit,optional"` AllowWhileOnBody interface{} `asn1:"tag:506,explicit,optional"` TrustedUserPresenceRequired interface{} `asn1:"tag:507,explicit,optional"` TrustedConfirmationRequired interface{} `asn1:"tag:508,explicit,optional"` UnlockedDeviceRequired interface{} `asn1:"tag:509,explicit,optional"` AllApplications interface{} `asn1:"tag:600,explicit,optional"` ApplicationID interface{} `asn1:"tag:601,explicit,optional"` CreationDateTime int `asn1:"tag:701,explicit,optional"` Origin int `asn1:"tag:702,explicit,optional"` RootOfTrust rootOfTrust `asn1:"tag:704,explicit,optional"` OsVersion int `asn1:"tag:705,explicit,optional"` OsPatchLevel int `asn1:"tag:706,explicit,optional"` AttestationApplicationID []byte `asn1:"tag:709,explicit,optional"` AttestationIDBrand []byte `asn1:"tag:710,explicit,optional"` AttestationIDDevice []byte `asn1:"tag:711,explicit,optional"` AttestationIDProduct []byte `asn1:"tag:712,explicit,optional"` AttestationIDSerial []byte `asn1:"tag:713,explicit,optional"` AttestationIDImei []byte `asn1:"tag:714,explicit,optional"` AttestationIDMeid []byte `asn1:"tag:715,explicit,optional"` AttestationIDManufacturer []byte `asn1:"tag:716,explicit,optional"` AttestationIDModel []byte `asn1:"tag:717,explicit,optional"` VendorPatchLevel int `asn1:"tag:718,explicit,optional"` BootPatchLevel int `asn1:"tag:719,explicit,optional"` } type rootOfTrust struct { verifiedBootKey []byte deviceLocked bool verifiedBootState verifiedBootState verifiedBootHash []byte } type verifiedBootState int const ( Verified verifiedBootState = iota SelfSigned Unverified Failed ) /** * The origin of a key (or pair), i.e. where it was generated. Note that KM_TAG_ORIGIN can be found * in either the hardware-enforced or software-enforced list for a key, indicating whether the key * is hardware or software-based. Specifically, a key with KM_ORIGIN_GENERATED in the * hardware-enforced list is guaranteed never to have existed outide the secure hardware. */ type KM_KEY_ORIGIN int const ( KM_ORIGIN_GENERATED = iota /* Generated in keymaster. Should not exist outside the TEE. */ KM_ORIGIN_DERIVED /* Derived inside keymaster. Likely exists off-device. */ KM_ORIGIN_IMPORTED /* Imported into keymaster. Existed as cleartext in Android. */ KM_ORIGIN_UNKNOWN /* Keymaster did not record origin. This value can only be seen on * keys in a keymaster0 implementation. The keymaster0 adapter uses * this value to document the fact that it is unkown whether the key * was generated inside or imported into keymaster. */ ) /** * Possible purposes of a key (or pair). */ type KM_PURPOSE int const ( KM_PURPOSE_ENCRYPT = iota /* Usable with RSA, EC and AES keys. */ KM_PURPOSE_DECRYPT /* Usable with RSA, EC and AES keys. */ KM_PURPOSE_SIGN /* Usable with RSA, EC and HMAC keys. */ KM_PURPOSE_VERIFY /* Usable with RSA, EC and HMAC keys. */ KM_PURPOSE_DERIVE_KEY /* Usable with EC keys. */ KM_PURPOSE_WRAP /* Usable with wrapped keys. */ ) golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/attestation_apple.go000066400000000000000000000073161414201525100301450ustar00rootroot00000000000000package protocol import ( "bytes" "crypto/ecdsa" "crypto/elliptic" "crypto/sha256" "crypto/x509" "encoding/asn1" "fmt" "math/big" "github.com/duo-labs/webauthn/protocol/webauthncose" ) var appleAttestationKey = "apple" func init() { RegisterAttestationFormat(appleAttestationKey, verifyAppleKeyFormat) } // From §8.8. https://www.w3.org/TR/webauthn-2/#sctn-apple-anonymous-attestation // The apple attestation statement looks like: // $$attStmtType //= ( // fmt: "apple", // attStmt: appleStmtFormat // ) // appleStmtFormat = { // x5c: [ credCert: bytes, * (caCert: bytes) ] // } func verifyAppleKeyFormat(att AttestationObject, clientDataHash []byte) (string, []interface{}, error) { // Step 1. Verify that attStmt is valid CBOR conforming to the syntax defined // above and perform CBOR decoding on it to extract the contained fields. // If x5c is not present, return an error x5c, x509present := att.AttStatement["x5c"].([]interface{}) if !x509present { // Handle Basic Attestation steps for the x509 Certificate return appleAttestationKey, nil, ErrAttestationFormat.WithDetails("Error retreiving x5c value") } credCertBytes, valid := x5c[0].([]byte) if !valid { return appleAttestationKey, nil, ErrAttestation.WithDetails("Error getting certificate from x5c cert chain") } credCert, err := x509.ParseCertificate(credCertBytes) if err != nil { return appleAttestationKey, nil, ErrAttestationFormat.WithDetails(fmt.Sprintf("Error parsing certificate from ASN.1 data: %+v", err)) } // Step 2. Concatenate authenticatorData and clientDataHash to form nonceToHash. nonceToHash := append(att.RawAuthData, clientDataHash...) // Step 3. Perform SHA-256 hash of nonceToHash to produce nonce. nonce := sha256.Sum256(nonceToHash) // Step 4. Verify that nonce equals the value of the extension with OID 1.2.840.113635.100.8.2 in credCert. var attExtBytes []byte for _, ext := range credCert.Extensions { if ext.Id.Equal([]int{1, 2, 840, 113635, 100, 8, 2}) { attExtBytes = ext.Value } } if len(attExtBytes) == 0 { return appleAttestationKey, nil, ErrAttestationFormat.WithDetails("Attestation certificate extensions missing 1.2.840.113635.100.8.2") } decoded := AppleAnonymousAttestation{} _, err = asn1.Unmarshal([]byte(attExtBytes), &decoded) if err != nil { return appleAttestationKey, nil, ErrAttestationFormat.WithDetails("Unable to parse apple attestation certificate extensions") } if !bytes.Equal(decoded.Nonce, nonce[:]) || err != nil { return appleAttestationKey, nil, ErrInvalidAttestation.WithDetails("Attestation certificate does not contain expected nonce") } // Step 5. Verify that the credential public key equals the Subject Public Key of credCert. // TODO: Probably move this part to webauthncose.go pubKey, err := webauthncose.ParsePublicKey(att.AuthData.AttData.CredentialPublicKey) if err != nil { return appleAttestationKey, nil, ErrInvalidAttestation.WithDetails(fmt.Sprintf("Error parsing public key: %+v\n", err)) } credPK := pubKey.(webauthncose.EC2PublicKeyData) subjectPK := credCert.PublicKey.(*ecdsa.PublicKey) credPKInfo := &ecdsa.PublicKey{ Curve: elliptic.P256(), X: big.NewInt(0).SetBytes(credPK.XCoord), Y: big.NewInt(0).SetBytes(credPK.YCoord), } if !credPKInfo.Equal(subjectPK) { return appleAttestationKey, nil, ErrInvalidAttestation.WithDetails("Certificate public key does not match public key in authData") } // Step 6. If successful, return implementation-specific values representing attestation type Anonymization CA and attestation trust path x5c. return appleAttestationKey, x5c, nil } // Apple has not yet publish schema for the extension(as of JULY 2021.) type AppleAnonymousAttestation struct { Nonce []byte `asn1:"tag:1,explicit"` } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/attestation_packed.go000066400000000000000000000257771414201525100303060ustar00rootroot00000000000000package protocol import ( "bytes" "crypto/x509" "encoding/asn1" "fmt" "strings" "time" "github.com/duo-labs/webauthn/metadata" uuid "github.com/satori/go.uuid" "github.com/duo-labs/webauthn/protocol/webauthncose" ) var packedAttestationKey = "packed" func init() { RegisterAttestationFormat(packedAttestationKey, verifyPackedFormat) } // From §8.2. https://www.w3.org/TR/webauthn/#packed-attestation // The packed attestation statement looks like: // packedStmtFormat = { // alg: COSEAlgorithmIdentifier, // sig: bytes, // x5c: [ attestnCert: bytes, * (caCert: bytes) ] // } OR // { // alg: COSEAlgorithmIdentifier, (-260 for ED256 / -261 for ED512) // sig: bytes, // ecdaaKeyId: bytes // } OR // { // alg: COSEAlgorithmIdentifier // sig: bytes, // } func verifyPackedFormat(att AttestationObject, clientDataHash []byte) (string, []interface{}, error) { // Step 1. Verify that attStmt is valid CBOR conforming to the syntax defined // above and perform CBOR decoding on it to extract the contained fields. // Get the alg value - A COSEAlgorithmIdentifier containing the identifier of the algorithm // used to generate the attestation signature. alg, present := att.AttStatement["alg"].(int64) if !present { return packedAttestationKey, nil, ErrAttestationFormat.WithDetails("Error retreiving alg value") } // Get the sig value - A byte string containing the attestation signature. sig, present := att.AttStatement["sig"].([]byte) if !present { return packedAttestationKey, nil, ErrAttestationFormat.WithDetails("Error retreiving sig value") } // Step 2. If x5c is present, this indicates that the attestation type is not ECDAA. x5c, x509present := att.AttStatement["x5c"].([]interface{}) if x509present { // Handle Basic Attestation steps for the x509 Certificate return handleBasicAttestation(sig, clientDataHash, att.RawAuthData, att.AuthData.AttData.AAGUID, alg, x5c) } // Step 3. If ecdaaKeyId is present, then the attestation type is ECDAA. // Also make sure the we did not have an x509 then ecdaaKeyID, ecdaaKeyPresent := att.AttStatement["ecdaaKeyId"].([]byte) if ecdaaKeyPresent { // Handle ECDAA Attestation steps for the x509 Certificate return handleECDAAAttesation(sig, clientDataHash, ecdaaKeyID) } // Step 4. If neither x5c nor ecdaaKeyId is present, self attestation is in use. return handleSelfAttestation(alg, att.AuthData.AttData.CredentialPublicKey, att.RawAuthData, clientDataHash, sig) } // Handle the attestation steps laid out in func handleBasicAttestation(signature, clientDataHash, authData, aaguid []byte, alg int64, x5c []interface{}) (string, []interface{}, error) { // Step 2.1. Verify that sig is a valid signature over the concatenation of authenticatorData // and clientDataHash using the attestation public key in attestnCert with the algorithm specified in alg. attestationType := "Packed (Basic)" for _, c := range x5c { cb, cv := c.([]byte) if !cv { return attestationType, x5c, ErrAttestation.WithDetails("Error getting certificate from x5c cert chain") } ct, err := x509.ParseCertificate(cb) if err != nil { return attestationType, x5c, ErrAttestationFormat.WithDetails(fmt.Sprintf("Error parsing certificate from ASN.1 data: %+v", err)) } if ct.NotBefore.After(time.Now()) || ct.NotAfter.Before(time.Now()) { return attestationType, x5c, ErrAttestationFormat.WithDetails("Cert in chain not time valid") } } attCertBytes, valid := x5c[0].([]byte) if !valid { return attestationType, x5c, ErrAttestation.WithDetails("Error getting certificate from x5c cert chain") } signatureData := append(authData, clientDataHash...) attCert, err := x509.ParseCertificate(attCertBytes) if err != nil { return attestationType, x5c, ErrAttestationFormat.WithDetails(fmt.Sprintf("Error parsing certificate from ASN.1 data: %+v", err)) } coseAlg := webauthncose.COSEAlgorithmIdentifier(alg) sigAlg := webauthncose.SigAlgFromCOSEAlg(coseAlg) err = attCert.CheckSignature(x509.SignatureAlgorithm(sigAlg), signatureData, signature) if err != nil { return attestationType, x5c, ErrInvalidAttestation.WithDetails(fmt.Sprintf("Signature validation error: %+v\n", err)) } // Step 2.2 Verify that attestnCert meets the requirements in §8.2.1 Packed attestation statement certificate requirements. // §8.2.1 can be found here https://www.w3.org/TR/webauthn/#packed-attestation-cert-requirements // Step 2.2.1 (from §8.2.1) Version MUST be set to 3 (which is indicated by an ASN.1 INTEGER with value 2). if attCert.Version != 3 { return attestationType, x5c, ErrAttestationCertificate.WithDetails("Attestation Certificate is incorrect version") } // Step 2.2.2 (from §8.2.1) Subject field MUST be set to: // Subject-C // ISO 3166 code specifying the country where the Authenticator vendor is incorporated (PrintableString) // TODO: Find a good, useable, country code library. For now, check stringy-ness subjectString := strings.Join(attCert.Subject.Country, "") if subjectString == "" { return attestationType, x5c, ErrAttestationCertificate.WithDetails("Attestation Certificate Country Code is invalid") } // Subject-O // Legal name of the Authenticator vendor (UTF8String) subjectString = strings.Join(attCert.Subject.Organization, "") if subjectString == "" { return attestationType, x5c, ErrAttestationCertificate.WithDetails("Attestation Certificate Organization is invalid") } // Subject-OU // Literal string “Authenticator Attestation†(UTF8String) subjectString = strings.Join(attCert.Subject.OrganizationalUnit, " ") if subjectString != "Authenticator Attestation" { // TODO: Implement a return error when I'm more certain this is general practice } // Subject-CN // A UTF8String of the vendor’s choosing subjectString = attCert.Subject.CommonName if subjectString == "" { return attestationType, x5c, ErrAttestationCertificate.WithDetails("Attestation Certificate Common Name not set") } // TODO: And then what // Step 2.2.3 (from §8.2.1) If the related attestation root certificate is used for multiple authenticator models, // the Extension 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 OCTET STRING. The extension MUST NOT be marked as critical. idFido := asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 45724, 1, 1, 4} var foundAAGUID []byte for _, extension := range attCert.Extensions { if extension.Id.Equal(idFido) { if extension.Critical { return attestationType, x5c, ErrInvalidAttestation.WithDetails("Attestation certificate FIDO extension marked as critical") } foundAAGUID = extension.Value } } // We validate the AAGUID as mentioned above // This is not well defined in§8.2.1 but mentioned in step 2.3: we validate the AAGUID if it is present within the certificate // and make sure it matches the auth data AAGUID // Note that an X.509 Extension encodes the DER-encoding of the value in an OCTET STRING. Thus, the // AAGUID MUST be wrapped in two OCTET STRINGS to be valid. if len(foundAAGUID) > 0 { unMarshalledAAGUID := []byte{} asn1.Unmarshal(foundAAGUID, &unMarshalledAAGUID) if !bytes.Equal(aaguid, unMarshalledAAGUID) { return attestationType, x5c, ErrInvalidAttestation.WithDetails("Certificate AAGUID does not match Auth Data certificate") } } uuid, err := uuid.FromBytes(aaguid) if meta, ok := metadata.Metadata[uuid]; ok { for _, s := range meta.StatusReports { if metadata.IsUndesiredAuthenticatorStatus(metadata.AuthenticatorStatus(s.Status)) { return attestationType, x5c, ErrInvalidAttestation.WithDetails("Authenticator with undesirable status encountered") } } if attCert.Subject.CommonName != attCert.Issuer.CommonName { var hasBasicFull = false for _, a := range meta.MetadataStatement.AttestationTypes { if metadata.AuthenticatorAttestationType(a) == metadata.AuthenticatorAttestationType(metadata.BasicFull) { hasBasicFull = true } } if !hasBasicFull { return attestationType, x5c, ErrInvalidAttestation.WithDetails("Attestation with full attestation from authentictor that does not support full attestation") } } } else { if metadata.Conformance { return attestationType, x5c, ErrInvalidAttestation.WithDetails("AAGUID not found in metadata during conformance testing") } } // Step 2.2.4 The Basic Constraints extension MUST have the CA component set to false. if attCert.IsCA { return attestationType, x5c, ErrInvalidAttestation.WithDetails("Attestation certificate's Basic Constraints marked as CA") } // Note for 2.2.5 An Authority Information Access (AIA) extension with entry id-ad-ocsp and a CRL // Distribution Point extension [RFC5280](https://www.w3.org/TR/webauthn/#biblio-rfc5280) are // both OPTIONAL as the status of many attestation certificates is available through authenticator // metadata services. See, for example, the FIDO Metadata Service // [FIDOMetadataService] (https://www.w3.org/TR/webauthn/#biblio-fidometadataservice) // Step 2.4 If successful, return attestation type Basic and attestation trust path x5c. // We don't handle trust paths yet but we're done return attestationType, x5c, nil } func handleECDAAAttesation(signature, clientDataHash, ecdaaKeyID []byte) (string, []interface{}, error) { return "Packed (ECDAA)", nil, ErrNotSpecImplemented } func handleSelfAttestation(alg int64, pubKey, authData, clientDataHash, signature []byte) (string, []interface{}, error) { attestationType := "Packed (Self)" // §4.1 Validate that alg matches the algorithm of the credentialPublicKey in authenticatorData. // §4.2 Verify that sig is a valid signature over the concatenation of authenticatorData and // clientDataHash using the credential public key with alg. verificationData := append(authData, clientDataHash...) key, err := webauthncose.ParsePublicKey(pubKey) if err != nil { return attestationType, nil, ErrAttestationFormat.WithDetails(fmt.Sprintf("Error parsing the public key: %+v\n", err)) } switch key.(type) { case webauthncose.OKPPublicKeyData: k := key.(webauthncose.OKPPublicKeyData) err := verifyKeyAlgorithm(k.Algorithm, alg) if err != nil { return attestationType, nil, err } case webauthncose.EC2PublicKeyData: k := key.(webauthncose.EC2PublicKeyData) err := verifyKeyAlgorithm(k.Algorithm, alg) if err != nil { return attestationType, nil, err } case webauthncose.RSAPublicKeyData: k := key.(webauthncose.RSAPublicKeyData) err := verifyKeyAlgorithm(k.Algorithm, alg) if err != nil { return attestationType, nil, err } default: return attestationType, nil, ErrInvalidAttestation.WithDetails("Error verifying the public key data") } valid, err := webauthncose.VerifySignature(key, verificationData, signature) if !valid && err == nil { return attestationType, nil, ErrInvalidAttestation.WithDetails("Unabled to verify signature") } return attestationType, nil, err } func verifyKeyAlgorithm(keyAlgorithm, attestedAlgorithm int64) error { if keyAlgorithm != attestedAlgorithm { return ErrInvalidAttestation.WithDetails("Public key algorithm does not equal att statement algorithm") } return nil } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/attestation_packed_test.go000066400000000000000000000017521414201525100313300ustar00rootroot00000000000000package protocol import ( "reflect" "testing" ) func Test_verifyPackedFormat(t *testing.T) { type args struct { att AttestationObject clientDataHash []byte } tests := []struct { name string args args want string want1 []interface{} wantErr bool }{ // { // name: "Successful Self Attestation", // args: args{ // att: AttestationObject // } // } } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, got1, err := verifyPackedFormat(tt.args.att, tt.args.clientDataHash) if (err != nil) != tt.wantErr { t.Errorf("verifyPackedFormat() error = %v, wantErr %v", err, tt.wantErr) return } if got != tt.want { t.Errorf("verifyPackedFormat() got = %v, want %v", got, tt.want) } if !reflect.DeepEqual(got1, tt.want1) { t.Errorf("verifyPackedFormat() got1 = %v, want %v", got1, tt.want1) } }) } } var testPackedAttestationOptions = []string{} var testPackedAttestationResponses = []string{} golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/attestation_safetynet.go000066400000000000000000000150201414201525100310350ustar00rootroot00000000000000package protocol import ( "bytes" "crypto/sha256" "crypto/x509" "encoding/base64" "fmt" "time" "github.com/duo-labs/webauthn/metadata" jwt "github.com/dgrijalva/jwt-go" "github.com/mitchellh/mapstructure" ) var safetyNetAttestationKey = "android-safetynet" func init() { RegisterAttestationFormat(safetyNetAttestationKey, verifySafetyNetFormat) } type SafetyNetResponse struct { Nonce string `json:"nonce"` TimestampMs int64 `json:"timestampMs"` ApkPackageName string `json:"apkPackageName"` ApkDigestSha256 string `json:"apkDigestSha256"` CtsProfileMatch bool `json:"ctsProfileMatch"` ApkCertificateDigestSha256 []interface{} `json:"apkCertificateDigestSha256"` BasicIntegrity bool `json:"basicIntegrity"` } // Thanks to @koesie10 and @herrjemand for outlining how to support this type really well // §8.5. Android SafetyNet Attestation Statement Format https://w3c.github.io/webauthn/#android-safetynet-attestation // When the authenticator in question is a platform-provided Authenticator on certain Android platforms, the attestation // statement is based on the SafetyNet API. In this case the authenticator data is completely controlled by the caller of // the SafetyNet API (typically an application running on the Android platform) and the attestation statement only provides // some statements about the health of the platform and the identity of the calling application. This attestation does not // provide information regarding provenance of the authenticator and its associated data. Therefore platform-provided // authenticators SHOULD make use of the Android Key Attestation when available, even if the SafetyNet API is also present. func verifySafetyNetFormat(att AttestationObject, clientDataHash []byte) (string, []interface{}, error) { // The syntax of an Android Attestation statement is defined as follows: // $$attStmtType //= ( // fmt: "android-safetynet", // attStmt: safetynetStmtFormat // ) // safetynetStmtFormat = { // ver: text, // response: bytes // } // §8.5.1 Verify that attStmt is valid CBOR conforming to the syntax defined above and perform CBOR decoding on it to extract // the contained fields. // We have done this // §8.5.2 Verify that response is a valid SafetyNet response of version ver. version, present := att.AttStatement["ver"].(string) if !present { return safetyNetAttestationKey, nil, ErrAttestationFormat.WithDetails("Unable to find the version of SafetyNet") } if version == "" { return safetyNetAttestationKey, nil, ErrAttestationFormat.WithDetails("Not a proper version for SafetyNet") } // TODO: provide user the ability to designate their supported versions response, present := att.AttStatement["response"].([]byte) if !present { return safetyNetAttestationKey, nil, ErrAttestationFormat.WithDetails("Unable to find the SafetyNet response") } 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)))) n, err := base64.StdEncoding.Decode(o, []byte(chain[0].(string))) cert, err := x509.ParseCertificate(o[:n]) return cert.PublicKey, err }) if err != nil { return safetyNetAttestationKey, nil, ErrInvalidAttestation.WithDetails(fmt.Sprintf("Error finding cert issued to correct hostname: %+v", err)) } // marshall the JWT payload into the safetynet response json var safetyNetResponse SafetyNetResponse err = mapstructure.Decode(token.Claims, &safetyNetResponse) if err != nil { return safetyNetAttestationKey, nil, ErrAttestationFormat.WithDetails(fmt.Sprintf("Error parsing the SafetyNet response: %+v", err)) } // §8.5.3 Verify that the nonce in the response is identical to the Base64 encoding of the SHA-256 hash of the concatenation // of authenticatorData and clientDataHash. nonceBuffer := sha256.Sum256(append(att.RawAuthData, clientDataHash...)) nonceBytes, err := base64.StdEncoding.DecodeString(safetyNetResponse.Nonce) if !bytes.Equal(nonceBuffer[:], nonceBytes) || err != nil { return safetyNetAttestationKey, 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)))) n, err := base64.StdEncoding.Decode(l, []byte(certChain[0].(string))) if err != nil { return safetyNetAttestationKey, nil, ErrInvalidAttestation.WithDetails(fmt.Sprintf("Error finding cert issued to correct hostname: %+v", err)) } attestationCert, err := x509.ParseCertificate(l[:n]) if err != nil { return safetyNetAttestationKey, nil, ErrInvalidAttestation.WithDetails(fmt.Sprintf("Error finding cert issued to correct hostname: %+v", err)) } // §8.5.5 Verify that attestationCert is issued to the hostname "attest.android.com" err = attestationCert.VerifyHostname("attest.android.com") if err != nil { return safetyNetAttestationKey, nil, ErrInvalidAttestation.WithDetails(fmt.Sprintf("Error finding cert issued to correct hostname: %+v", err)) } // §8.5.6 Verify that the ctsProfileMatch attribute in the payload of response is true. if !safetyNetResponse.CtsProfileMatch { return safetyNetAttestationKey, nil, ErrInvalidAttestation.WithDetails("ctsProfileMatch attribute of the JWT payload is false") } // Verify sanity of timestamp in the payload now := time.Now() oneMinuteAgo := now.Add(-time.Minute) t := time.Unix(safetyNetResponse.TimestampMs/1000, 0) if t.After(now) { // zero tolerance for post-dated timestamps return "Basic attestation with SafetyNet", nil, ErrInvalidAttestation.WithDetails("SafetyNet response with timestamp after current time") } else if t.Before(oneMinuteAgo) { // allow old timestamp for testing purposes // TODO: Make this user configurable msg := "SafetyNet response with timestamp before one minute ago" if metadata.Conformance { return "Basic attestation with SafetyNet", nil, ErrInvalidAttestation.WithDetails(msg) } } // §8.5.7 If successful, return implementation-specific values representing attestation type Basic and attestation // trust path attestationCert. return "Basic attestation with SafetyNet", nil, nil } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/attestation_safetynet_test.go000066400000000000000000000242041414201525100321000ustar00rootroot00000000000000package protocol import ( "crypto/sha256" "reflect" "testing" ) func Test_verifySafetyNetFormat(t *testing.T) { type args struct { att AttestationObject clientDataHash []byte } successAttResponse := attestationTestUnpackResponse(t, safetyNetTestResponse["success"]).Response.AttestationObject successClienDataHash := sha256.Sum256(attestationTestUnpackResponse(t, safetyNetTestResponse["success"]).Raw.AttestationResponse.ClientDataJSON) tests := []struct { name string args args want string want1 []interface{} wantErr bool }{ { "success", args{ successAttResponse, successClienDataHash[:], }, "Basic attestation with SafetyNet", nil, false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, got1, err := verifySafetyNetFormat(tt.args.att, tt.args.clientDataHash) if (err != nil) != tt.wantErr { t.Errorf("verifySafetyNetFormat() error = %v, wantErr %v", err, tt.wantErr) return } if got != tt.want { t.Errorf("verifySafetyNetFormat() got = %v, want %v", got, tt.want) } if !reflect.DeepEqual(got1, tt.want1) { t.Errorf("verifySafetyNetFormat() got1 = %v, want %v", got1, tt.want1) } }) } } var safetyNetTestRequest = map[string]string{ `success`: `{ "publicKey": { "challenge": "dfo+HlqJp3MLK+J5TLxxmvXJieS3zGwdk9G9H9bPezg=", "rp": { "name": "webauthn.io", "id": "webauthn.io" }, "user": { "name": "safetynetter", "displayName": "safetynetter", "id": "wDkAAAAAAAAAAA==" }, "pubKeyCredParams": [ { "type": "public-key", "alg": -7 }, { "type": "public-key", "alg": -35 }, { "type": "public-key", "alg": -36 }, { "type": "public-key", "alg": -65535 }, { "type": "public-key", "alg": -257 }, { "type": "public-key", "alg": -258 }, { "type": "public-key", "alg": -259 }, { "type": "public-key", "alg": -37 }, { "type": "public-key", "alg": -38 }, { "type": "public-key", "alg": -39 }, { "type": "public-key", "alg": -8 } ], "authenticatorSelection": { "authenticatorAttachment": "platform", "userVerification": "preferred" }, "timeout": 60000, "attestation": "direct" } }`, } var safetyNetTestResponse = map[string]string{ `success`: `{ "id":"AUiVU3Mk3uJomfHcJcu6ScwUHRysE2e6IgaTNAzQ34TP0OPifi2LgGD_5hzxRhOfQTB1fW6k63C8tk-MwywpNVI", "rawId":"AUiVU3Mk3uJomfHcJcu6ScwUHRysE2e6IgaTNAzQ34TP0OPifi2LgGD_5hzxRhOfQTB1fW6k63C8tk-MwywpNVI", "type":"public-key", "response":{ "attestationObject":"o2NmbXRxYW5kcm9pZC1zYWZldHluZXRnYXR0U3RtdKJjdmVyaDE1MTgwMDM3aHJlc3BvbnNlWRS9ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbmcxWXlJNld5Sk5TVWxHYTJwRFEwSkljV2RCZDBsQ1FXZEpVVkpZY205T01GcFBaRkpyUWtGQlFVRkJRVkIxYm5wQlRrSm5hM0ZvYTJsSE9YY3dRa0ZSYzBaQlJFSkRUVkZ6ZDBOUldVUldVVkZIUlhkS1ZsVjZSV1ZOUW5kSFFURlZSVU5vVFZaU01qbDJXako0YkVsR1VubGtXRTR3U1VaT2JHTnVXbkJaTWxaNlRWSk5kMFZSV1VSV1VWRkVSWGR3U0ZaR1RXZFJNRVZuVFZVNGVFMUNORmhFVkVVMFRWUkJlRTFFUVROTlZHc3dUbFp2V0VSVVJUVk5WRUYzVDFSQk0wMVVhekJPVm05M1lrUkZURTFCYTBkQk1WVkZRbWhOUTFaV1RYaEZla0ZTUW1kT1ZrSkJaMVJEYTA1b1lrZHNiV0l6U25WaFYwVjRSbXBCVlVKblRsWkNRV05VUkZVeGRtUlhOVEJaVjJ4MVNVWmFjRnBZWTNoRmVrRlNRbWRPVmtKQmIxUkRhMlIyWWpKa2MxcFRRazFVUlUxNFIzcEJXa0puVGxaQ1FVMVVSVzFHTUdSSFZucGtRelZvWW0xU2VXSXliR3RNYlU1MllsUkRRMEZUU1hkRVVWbEtTMjlhU1doMlkwNUJVVVZDUWxGQlJHZG5SVkJCUkVORFFWRnZRMmRuUlVKQlRtcFlhM293WlVzeFUwVTBiU3N2UnpWM1QyOHJXRWRUUlVOeWNXUnVPRGh6UTNCU04yWnpNVFJtU3pCU2FETmFRMWxhVEVaSWNVSnJOa0Z0V2xaM01rczVSa2N3VHpseVVsQmxVVVJKVmxKNVJUTXdVWFZ1VXpsMVowaEROR1ZuT1c5MmRrOXRLMUZrV2pKd09UTllhSHAxYmxGRmFGVlhXRU40UVVSSlJVZEtTek5UTW1GQlpucGxPVGxRVEZNeU9XaE1ZMUYxV1ZoSVJHRkROMDlhY1U1dWIzTnBUMGRwWm5NNGRqRnFhVFpJTDNob2JIUkRXbVV5YkVvck4wZDFkSHBsZUV0d2VIWndSUzkwV2xObVlsazVNRFZ4VTJ4Q2FEbG1jR293TVRWamFtNVJSbXRWYzBGVmQyMUxWa0ZWZFdWVmVqUjBTMk5HU3pSd1pYWk9UR0Y0UlVGc0swOXJhV3hOZEVsWlJHRmpSRFZ1Wld3MGVFcHBlWE0wTVROb1lXZHhWekJYYUdnMVJsQXpPV2hIYXpsRkwwSjNVVlJxWVhwVGVFZGtkbGd3YlRaNFJsbG9hQzh5VmsxNVdtcFVORXQ2VUVwRlEwRjNSVUZCWVU5RFFXeG5kMmRuU2xWTlFUUkhRVEZWWkVSM1JVSXZkMUZGUVhkSlJtOUVRVlJDWjA1V1NGTlZSVVJFUVV0Q1oyZHlRbWRGUmtKUlkwUkJWRUZOUW1kT1ZraFNUVUpCWmpoRlFXcEJRVTFDTUVkQk1WVmtSR2RSVjBKQ1VYRkNVWGRIVjI5S1FtRXhiMVJMY1hWd2J6UlhObmhVTm1veVJFRm1RbWRPVmtoVFRVVkhSRUZYWjBKVFdUQm1hSFZGVDNaUWJTdDRaMjU0YVZGSE5rUnlabEZ1T1V0NlFtdENaMmR5UW1kRlJrSlJZMEpCVVZKWlRVWlpkMHAzV1VsTGQxbENRbEZWU0UxQlIwZEhNbWd3WkVoQk5reDVPWFpaTTA1M1RHNUNjbUZUTlc1aU1qbHVUREprTUdONlJuWk5WRUZ5UW1kbmNrSm5SVVpDVVdOM1FXOVpabUZJVWpCalJHOTJURE5DY21GVE5XNWlNamx1VERKa2VtTnFTWFpTTVZKVVRWVTRlRXh0VG5sa1JFRmtRbWRPVmtoU1JVVkdha0ZWWjJoS2FHUklVbXhqTTFGMVdWYzFhMk50T1hCYVF6VnFZakl3ZDBsUldVUldVakJuUWtKdmQwZEVRVWxDWjFwdVoxRjNRa0ZuU1hkRVFWbExTM2RaUWtKQlNGZGxVVWxHUVhwQmRrSm5UbFpJVWpoRlMwUkJiVTFEVTJkSmNVRm5hR2cxYjJSSVVuZFBhVGgyV1ROS2MweHVRbkpoVXpWdVlqSTVia3d3WkZWVmVrWlFUVk0xYW1OdGQzZG5aMFZGUW1kdmNrSm5SVVZCWkZvMVFXZFJRMEpKU0RGQ1NVaDVRVkJCUVdSM1EydDFVVzFSZEVKb1dVWkpaVGRGTmt4TldqTkJTMUJFVjFsQ1VHdGlNemRxYW1RNE1FOTVRVE5qUlVGQlFVRlhXbVJFTTFCTVFVRkJSVUYzUWtsTlJWbERTVkZEVTFwRFYyVk1Tblp6YVZaWE5rTm5LMmRxTHpsM1dWUktVbnAxTkVocGNXVTBaVmswWXk5dGVYcHFaMGxvUVV4VFlta3ZWR2g2WTNweGRHbHFNMlJyTTNaaVRHTkpWek5NYkRKQ01HODNOVWRSWkdoTmFXZGlRbWRCU0ZWQlZtaFJSMjFwTDFoM2RYcFVPV1ZIT1ZKTVNTdDRNRm95ZFdKNVdrVldla0UzTlZOWlZtUmhTakJPTUVGQlFVWnRXRkU1ZWpWQlFVRkNRVTFCVW1wQ1JVRnBRbU5EZDBFNWFqZE9WRWRZVURJM09IbzBhSEl2ZFVOSWFVRkdUSGx2UTNFeVN6QXJlVXhTZDBwVlltZEpaMlk0WjBocWRuQjNNbTFDTVVWVGFuRXlUMll6UVRCQlJVRjNRMnR1UTJGRlMwWlZlVm8zWmk5UmRFbDNSRkZaU2t0dldrbG9kbU5PUVZGRlRFSlJRVVJuWjBWQ1FVazVibFJtVWt0SlYyZDBiRmRzTTNkQ1REVTFSVlJXTm10aGVuTndhRmN4ZVVGak5VUjFiVFpZVHpReGExcDZkMG8yTVhkS2JXUlNVbFF2VlhORFNYa3hTMFYwTW1Nd1JXcG5iRzVLUTBZeVpXRjNZMFZYYkV4UldUSllVRXg1Um1wclYxRk9ZbE5vUWpGcE5GY3lUbEpIZWxCb2RETnRNV0kwT1doaWMzUjFXRTAyZEZnMVEzbEZTRzVVYURoQ2IyMDBMMWRzUm1sb2VtaG5iamd4Ukd4a2IyZDZMMHN5VlhkTk5sTTJRMEl2VTBWNGEybFdabllyZW1KS01ISnFkbWM1TkVGc1pHcFZabFYzYTBrNVZrNU5ha1ZRTldVNGVXUkNNMjlNYkRabmJIQkRaVVkxWkdkbVUxZzBWVGw0TXpWdmFpOUpTV1F6VlVVdlpGQndZaTl4WjBkMmMydG1aR1Y2ZEcxVmRHVXZTMU50Y21sM1kyZFZWMWRsV0daVVlra3plbk5wYTNkYVltdHdiVkpaUzIxcVVHMW9kalJ5YkdsNlIwTkhkRGhRYmpod2NUaE5Na3RFWmk5UU0ydFdiM1F6WlRFNFVUMGlMQ0pOU1VsRlUycERRMEY2UzJkQmQwbENRV2RKVGtGbFR6QnRjVWRPYVhGdFFrcFhiRkYxUkVGT1FtZHJjV2hyYVVjNWR6QkNRVkZ6UmtGRVFrMU5VMEYzU0dkWlJGWlJVVXhGZUdSSVlrYzVhVmxYZUZSaFYyUjFTVVpLZG1JelVXZFJNRVZuVEZOQ1UwMXFSVlJOUWtWSFFURlZSVU5vVFV0U01uaDJXVzFHYzFVeWJHNWlha1ZVVFVKRlIwRXhWVVZCZUUxTFVqSjRkbGx0Um5OVk1teHVZbXBCWlVaM01IaE9la0V5VFZSVmQwMUVRWGRPUkVwaFJuY3dlVTFVUlhsTlZGVjNUVVJCZDA1RVNtRk5SVWw0UTNwQlNrSm5UbFpDUVZsVVFXeFdWRTFTTkhkSVFWbEVWbEZSUzBWNFZraGlNamx1WWtkVloxWklTakZqTTFGblZUSldlV1J0YkdwYVdFMTRSWHBCVWtKblRsWkNRVTFVUTJ0a1ZWVjVRa1JSVTBGNFZIcEZkMmRuUldsTlFUQkhRMU54UjFOSllqTkVVVVZDUVZGVlFVRTBTVUpFZDBGM1oyZEZTMEZ2U1VKQlVVUlJSMDA1UmpGSmRrNHdOWHByVVU4NUszUk9NWEJKVW5aS2VucDVUMVJJVnpWRWVrVmFhRVF5WlZCRGJuWlZRVEJSYXpJNFJtZEpRMlpMY1VNNVJXdHpRelJVTW1aWFFsbHJMMnBEWmtNelVqTldXazFrVXk5a1RqUmFTME5GVUZwU2NrRjZSSE5wUzFWRWVsSnliVUpDU2pWM2RXUm5lbTVrU1UxWlkweGxMMUpIUjBac05YbFBSRWxMWjJwRmRpOVRTa2d2VlV3clpFVmhiSFJPTVRGQ2JYTkxLMlZSYlUxR0t5dEJZM2hIVG1oeU5UbHhUUzg1YVd3M01Va3laRTQ0UmtkbVkyUmtkM1ZoWldvMFlsaG9jREJNWTFGQ1ltcDRUV05KTjBwUU1HRk5NMVEwU1N0RWMyRjRiVXRHYzJKcWVtRlVUa001ZFhwd1JteG5UMGxuTjNKU01qVjRiM2x1VlhoMk9IWk9iV3R4TjNwa1VFZElXR3Q0VjFrM2IwYzVhaXRLYTFKNVFrRkNhemRZY2twbWIzVmpRbHBGY1VaS1NsTlFhemRZUVRCTVMxY3dXVE42Tlc5Nk1rUXdZekYwU2t0M1NFRm5UVUpCUVVkcVoyZEZlazFKU1VKTWVrRlBRbWRPVmtoUk9FSkJaamhGUWtGTlEwRlpXWGRJVVZsRVZsSXdiRUpDV1hkR1FWbEpTM2RaUWtKUlZVaEJkMFZIUTBOelIwRlJWVVpDZDAxRFRVSkpSMEV4VldSRmQwVkNMM2RSU1UxQldVSkJaamhEUVZGQmQwaFJXVVJXVWpCUFFrSlpSVVpLYWxJclJ6UlJOamdyWWpkSFEyWkhTa0ZpYjA5ME9VTm1NSEpOUWpoSFFURlZaRWwzVVZsTlFtRkJSa3AyYVVJeFpHNUlRamRCWVdkaVpWZGlVMkZNWkM5alIxbFpkVTFFVlVkRFEzTkhRVkZWUmtKM1JVSkNRMnQzU25wQmJFSm5aM0pDWjBWR1FsRmpkMEZaV1ZwaFNGSXdZMFJ2ZGt3eU9XcGpNMEYxWTBkMGNFeHRaSFppTW1OMldqTk9lVTFxUVhsQ1owNVdTRkk0UlV0NlFYQk5RMlZuU21GQmFtaHBSbTlrU0ZKM1QyazRkbGt6U25OTWJrSnlZVk0xYm1JeU9XNU1NbVI2WTJwSmRsb3pUbmxOYVRWcVkyMTNkMUIzV1VSV1VqQm5Ra1JuZDA1cVFUQkNaMXB1WjFGM1FrRm5TWGRMYWtGdlFtZG5ja0puUlVaQ1VXTkRRVkpaWTJGSVVqQmpTRTAyVEhrNWQyRXlhM1ZhTWpsMlduazVlVnBZUW5aak1td3dZak5LTlV4NlFVNUNaMnR4YUd0cFJ6bDNNRUpCVVhOR1FVRlBRMEZSUlVGSGIwRXJUbTV1TnpoNU5uQlNhbVE1V0d4UlYwNWhOMGhVWjJsYUwzSXpVazVIYTIxVmJWbElVRkZ4TmxOamRHazVVRVZoYW5aM1VsUXlhVmRVU0ZGeU1ESm1aWE54VDNGQ1dUSkZWRlYzWjFwUksyeHNkRzlPUm5ab2MwODVkSFpDUTA5SllYcHdjM2RYUXpsaFNqbDRhblUwZEZkRVVVZzRUbFpWTmxsYVdpOVlkR1ZFVTBkVk9WbDZTbkZRYWxrNGNUTk5SSGh5ZW0xeFpYQkNRMlkxYnpodGR5OTNTalJoTWtjMmVIcFZjalpHWWpaVU9FMWpSRTh5TWxCTVVrdzJkVE5OTkZSNmN6TkJNazB4YWpaaWVXdEtXV2s0ZDFkSlVtUkJka3RNVjFwMUwyRjRRbFppZWxsdGNXMTNhMjAxZWt4VFJGYzFia2xCU21KRlRFTlJRMXAzVFVnMU5uUXlSSFp4YjJaNGN6WkNRbU5EUmtsYVZWTndlSFUyZURaMFpEQldOMU4yU2tORGIzTnBjbE50U1dGMGFpODVaRk5UVmtSUmFXSmxkRGh4THpkVlN6UjJORnBWVGpnd1lYUnVXbm94ZVdjOVBTSmRmUS5leUp1YjI1alpTSTZJazlGTDJkV09FYzRXazFKTW1ORUsyRk1lRzB2VGt4a1dVMHdjemxsVDB0V1NYUlhOblZTVDI5d1prRTlJaXdpZEdsdFpYTjBZVzF3VFhNaU9qRTFOVE13TWpnd05ETTFNamtzSW1Gd2ExQmhZMnRoWjJWT1lXMWxJam9pWTI5dExtZHZiMmRzWlM1aGJtUnliMmxrTG1kdGN5SXNJbUZ3YTBScFoyVnpkRk5vWVRJMU5pSTZJbGRVYkd4aVVuVXhZbFEyYlZoeWRXRmlXVWQ1WmtvMFJGUTVVR1I0YnpGUFMwb3ZWRTQzTVZWU1lXODlJaXdpWTNSelVISnZabWxzWlUxaGRHTm9JanAwY25WbExDSmhjR3REWlhKMGFXWnBZMkYwWlVScFoyVnpkRk5vWVRJMU5pSTZXeUk0VURGelZ6QkZVRXBqYzJ4M04xVjZVbk5wV0V3Mk5IY3JUelV3UldRclVrSkpRM1JoZVRGbk1qUk5QU0pkTENKaVlYTnBZMGx1ZEdWbmNtbDBlU0k2ZEhKMVpYMC56V3ViaWlraGt5alhETUJpV080ajZEdnVBZWdpSUh1WGhaNWQtTEh3Z1VBZFVSMWxNTU0tZ0Y4VklmSEdYcFZNZ1hhN3plR0l5NEROU19uNTdBZ2c0eE5lTVhQMHRpMVJ4QktVVlJKeUc1OXVoejJJbDBtZkl1UVZNckRpSHBiWjdYb2tKcG1jZlUyWU9QbmppcjlWUjlsVlRZUHVHV1phT01ua1kyRnlvbTRGZzhrNFA3dEtWWllzTXNERWR3ZVdOdTM5MS1mcXdKWUxQUWNjQ0ZiNURCRWc0SlMwa05pWG8zLWc3MTFWVGd2Z284WDMyMS03NWw5MnN6UWpDeDQ3aDFzY243ZmE1TkJhTkdfanVPZjV0QnhFbl9uY3N1TjR3RVRnT0JJVHFVN0xZWmxTVEtUX2lYODFncUJOOWtuWGMtQ0NVZUh1LThvLUdmekh1Y1BsSEFoYXV0aERhdGFYxXSm6pITyZwvdLIkkrMgz0AmKpTBqVCgOX8pJQtghB7wRQAAAAC5P9lh8uZGL7EiggAiR954AEEBSJVTcyTe4miZ8dwly7pJzBQdHKwTZ7oiBpM0DNDfhM_Q4-J-LYuAYP_mHPFGE59BMHV9bqTrcLy2T4zDLCk1UqUBAgMmIAEhWCC0eleNTLgwWxaVBqV139T6hONseRz7HgXRIVS9bPxIjSJYIJ1MfwUhvkSEjeiNJ6y5-w8PuuwMAvfgpN7F4Q2EW79v", "clientDataJSON":"eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiZGZvLUhscUpwM01MSy1KNVRMeHhtdlhKaWVTM3pHd2RrOUc5SDliUGV6ZyIsIm9yaWdpbiI6Imh0dHBzOlwvXC93ZWJhdXRobi5pbyIsImFuZHJvaWRQYWNrYWdlTmFtZSI6ImNvbS5hbmRyb2lkLmNocm9tZSJ9" } }`, } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/attestation_test.go000066400000000000000000000162271414201525100300240ustar00rootroot00000000000000package protocol import ( "crypto/sha256" "encoding/json" "fmt" "testing" ) func TestAttestationVerify(t *testing.T) { for i := range testAttestationOptions { t.Run(fmt.Sprintf("Running test %d", i), func(t *testing.T) { options := CredentialCreation{} if err := json.Unmarshal([]byte(testAttestationOptions[i]), &options); err != nil { t.Fatal(err) } ccr := CredentialCreationResponse{} if err := json.Unmarshal([]byte(testAttestationResponses[i]), &ccr); err != nil { t.Fatal(err) } var pcc ParsedCredentialCreationData pcc.ID, pcc.RawID, pcc.Type = ccr.ID, ccr.RawID, ccr.Type pcc.Raw = ccr parsedAttestationResponse, err := ccr.AttestationResponse.Parse() if err != nil { t.Fatal(err) } pcc.Response = *parsedAttestationResponse // Test Base Verification err = pcc.Verify(options.Response.Challenge.String(), false, options.Response.RelyingParty.ID, options.Response.RelyingParty.Name) if err != nil { t.Fatalf("Not valid: %+v (%+s)", err, err.(*Error).DevInfo) } }) } } func attestationTestUnpackRequest(t *testing.T, request string) CredentialCreation { options := CredentialCreation{} if err := json.Unmarshal([]byte(request), &options); err != nil { t.Fatal(err) } return options } func attestationTestUnpackResponse(t *testing.T, response string) ParsedCredentialCreationData { ccr := CredentialCreationResponse{} if err := json.Unmarshal([]byte(response), &ccr); err != nil { t.Fatal(err) } var pcc ParsedCredentialCreationData pcc.ID, pcc.RawID, pcc.Type = ccr.ID, ccr.RawID, ccr.Type pcc.Raw = ccr parsedAttestationResponse, err := ccr.AttestationResponse.Parse() if err != nil { t.Fatal(err) } pcc.Response = *parsedAttestationResponse return pcc } func TestPackedAttestationVerification(t *testing.T) { t.Run(fmt.Sprintf("Testing Self Packed"), func(t *testing.T) { pcc := attestationTestUnpackResponse(t, testAttestationResponses[0]) // Test Packed Verification // Unpack args clientDataHash := sha256.Sum256(pcc.Raw.AttestationResponse.ClientDataJSON) _, _, err := verifyPackedFormat(pcc.Response.AttestationObject, clientDataHash[:]) if err != nil { t.Fatalf("Not valid: %+v", err) } }) } var testAttestationOptions = []string{ // Direct Self Attestation with EC256 - MacOS `{"publicKey": { "challenge": "rWiex8xDOPfiCgyFu4BLW6vVOmXKgPwHrlMCgEs9SBA=", "rp": { "name": "http://localhost:9005", "id": "localhost" }, "user": { "name": "self", "displayName": "self", "id": "2iEAAAAAAAAAAA==" }, "pubKeyCredParams": [ { "type": "public-key", "alg": -7 } ], "authenticatorSelection": { "authenticatorAttachment": "cross-platform", "userVerification": "preferred" }, "timeout": 60000, "attestation": "direct" }}`, // Direct Attestation with EC256 `{"publicKey": { "challenge": "+Ri5NZTzJ8b6mvW3TVScLotEoALfgBa2Bn4YSaIObHc=", "rp": { "name": "https://webauthn.io", "id": "webauthn.io" }, "user": { "name": "flort", "displayName": "flort", "id": "1DMAAAAAAAAAAA==" }, "pubKeyCredParams": [ { "type": "public-key", "alg": -7 } ], "authenticatorSelection": { "authenticatorAttachment": "cross-platform", "userVerification": "preferred" }, "timeout": 60000, "attestation": "direct" }}`, // None Attestation with EC256 `{ "publicKey": { "challenge": "sVt4ScceMzqFSnfAq8hgLzblvo3fa4/aFVEcIESHIJ0=", "rp": { "name": "https://webauthn.io", "id": "webauthn.io" }, "user": { "name": "testuser1", "displayName": "testuser1", "id": "1zMAAAAAAAAAAA==" }, "pubKeyCredParams": [ { "type": "public-key", "alg": -7 } ], "authenticatorSelection": { "authenticatorAttachment": "cross-platform", "userVerification": "preferred" }, "timeout": 60000, "attestation": "none" } }`, } var testAttestationResponses = []string{ // Self Attestation with EC256 - MacOS `{ "id": "AOx6vFGGITtlwjhqFFvAkJmBzSzfwE1dBa1fVR_Ltq5L35FJRNdgkXe84v3-0TEVNCSp", "rawId": "AOx6vFGGITtlwjhqFFvAkJmBzSzfwE1dBa1fVR_Ltq5L35FJRNdgkXe84v3-0TEVNCSp", "response": { "attestationObject": "o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEcwRQIhAJgdgw5x8JzE4JfR6x1RBO8eCHNE8eW_L1VTV03zpyL5AiBv8eUzua3XSS3bPYC7m8eXzJhcaRyeGe7UcuqIrDSvC2hhdXRoRGF0YVi3SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFXJE5zK3OAAI1vMYKZIsLJfHwVQMAMwDserxRhiE7ZcI4ahRbwJCZgc0s38BNXQWtX1Ufy7auS9-RSUTXYJF3vOL9_tExFTQkqaUBAgMmIAEhWCCm9OYidwiIoH9SwVQqUAnH8Gj5ZJ2_qr8gjbg41q4M1SJYIA07XKpHSgS1mE7R1MjotVIQqyHi9WAxGwHQsCteVK2V", "clientDataJSON": "eyJjaGFsbGVuZ2UiOiJyV2lleDh4RE9QZmlDZ3lGdTRCTFc2dlZPbVhLZ1B3SHJsTUNnRXM5U0JBIiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDo5MDA1IiwidHlwZSI6IndlYmF1dGhuLmNyZWF0ZSJ9" }, "type": "public-key" }`, // Direct Attestation with EC256 - Titan `{ "id": "FOxcmsqPLNCHtyILvbNkrtHMdKAeqSJXYZDbeFd0kc5Enm8Kl6a0Jp0szgLilDw1S4CjZhe9Z2611EUGbjyEmg", "rawId": "FOxcmsqPLNCHtyILvbNkrtHMdKAeqSJXYZDbeFd0kc5Enm8Kl6a0Jp0szgLilDw1S4CjZhe9Z2611EUGbjyEmg", "response": { "attestationObject": "o2NmbXRoZmlkby11MmZnYXR0U3RtdKJjc2lnWEYwRAIgfyIhwZj-fkEVyT1GOK8chDHJR2chXBLSRg6bTCjODmwCIHH6GXI_BQrcR-GHg5JfazKVQdezp6_QWIFfT4ltTCO2Y3g1Y4FZAlMwggJPMIIBN6ADAgECAgQSNtF_MA0GCSqGSIb3DQEBCwUAMC4xLDAqBgNVBAMTI1l1YmljbyBVMkYgUm9vdCBDQSBTZXJpYWwgNDU3MjAwNjMxMCAXDTE0MDgwMTAwMDAwMFoYDzIwNTAwOTA0MDAwMDAwWjAxMS8wLQYDVQQDDCZZdWJpY28gVTJGIEVFIFNlcmlhbCAyMzkyNTczNDEwMzI0MTA4NzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABNNlqR5emeDVtDnA2a-7h_QFjkfdErFE7bFNKzP401wVE-QNefD5maviNnGVk4HJ3CsHhYuCrGNHYgTM9zTWriGjOzA5MCIGCSsGAQQBgsQKAgQVMS4zLjYuMS40LjEuNDE0ODIuMS41MBMGCysGAQQBguUcAgEBBAQDAgUgMA0GCSqGSIb3DQEBCwUAA4IBAQAiG5uzsnIk8T6-oyLwNR6vRklmo29yaYV8jiP55QW1UnXdTkEiPn8mEQkUac-Sn6UmPmzHdoGySG2q9B-xz6voVQjxP2dQ9sgbKd5gG15yCLv6ZHblZKkdfWSrUkrQTrtaziGLFSbxcfh83vUjmOhDLFC5vxV4GXq2674yq9F2kzg4nCS4yXrO4_G8YWR2yvQvE2ffKSjQJlXGO5080Ktptplv5XN4i5lS-AKrT5QRVbEJ3B4g7G0lQhdYV-6r4ZtHil8mF4YNMZ0-RaYPxAaYNWkFYdzOZCaIdQbXRZefgGfbMUiAC2gwWN7fiPHV9eu82NYypGU32OijG9BjhGt_aGF1dGhEYXRhWMR0puqSE8mcL3SyJJKzIM9AJiqUwalQoDl_KSULYIQe8EEAAAAAAAAAAAAAAAAAAAAAAAAAAABAFOxcmsqPLNCHtyILvbNkrtHMdKAeqSJXYZDbeFd0kc5Enm8Kl6a0Jp0szgLilDw1S4CjZhe9Z2611EUGbjyEmqUBAgMmIAEhWCD_ap3Q9zU8OsGe967t48vyRxqn8NfFTk307mC1WsH2ISJYIIcqAuW3MxhU0uDtaSX8-Ftf_zeNJLdCOEjZJGHsrLxH", "clientDataJSON": "eyJjaGFsbGVuZ2UiOiItUmk1TlpUeko4YjZtdlczVFZTY0xvdEVvQUxmZ0JhMkJuNFlTYUlPYkhjIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ" }, "type": "public-key" }`, // None Attestation with EC256 - Titan `{ "id": "6Jry73M_WVWDoXLsGxRsBVVHpPWDpNy1ETGXUEvJLdTAn5Ew6nDGU6W8iO3ZkcLEqr-CBwvx0p2WAxzt8RiwQQ", "rawId": "6Jry73M_WVWDoXLsGxRsBVVHpPWDpNy1ETGXUEvJLdTAn5Ew6nDGU6W8iO3ZkcLEqr-CBwvx0p2WAxzt8RiwQQ", "response": { "attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOia8u9zP1lVg6Fy7BsUbAVVR6T1g6TctRExl1BLyS3UwJ-RMOpwxlOlvIjt2ZHCxKq_ggcL8dKdlgMc7fEYsEGlAQIDJiABIVgg--n_QvZithDycYmnifk6vMHiwBP6kugn2PlsnvkrcSgiWCBAlBYm2B-rMtQlp5MxGTLoGDHoktxb0p364Hy2BH9U2Q", "clientDataJSON": "eyJjaGFsbGVuZ2UiOiJzVnQ0U2NjZU16cUZTbmZBcThoZ0x6Ymx2bzNmYTRfYUZWRWNJRVNISUowIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ" }, "type": "public-key" }`, } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/attestation_tpm.go000066400000000000000000000306641414201525100276460ustar00rootroot00000000000000package protocol import ( "bytes" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "errors" "fmt" "math/big" "strings" "github.com/duo-labs/webauthn/protocol/webauthncose" "github.com/duo-labs/webauthn/protocol/googletpm" ) var tpmAttestationKey = "tpm" func init() { RegisterAttestationFormat(tpmAttestationKey, verifyTPMFormat) googletpm.UseTPM20LengthPrefixSize() } func verifyTPMFormat(att AttestationObject, clientDataHash []byte) (string, []interface{}, error) { // Given the verification procedure inputs attStmt, authenticatorData // and clientDataHash, the verification procedure is as follows // Verify that attStmt is valid CBOR conforming to the syntax defined // above and perform CBOR decoding on it to extract the contained fields ver, present := att.AttStatement["ver"].(string) if !present { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Error retreiving ver value") } if ver != "2.0" { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("WebAuthn only supports TPM 2.0 currently") } alg, present := att.AttStatement["alg"].(int64) if !present { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Error retreiving alg value") } coseAlg := webauthncose.COSEAlgorithmIdentifier(alg) x5c, x509present := att.AttStatement["x5c"].([]interface{}) if !x509present { // Handle Basic Attestation steps for the x509 Certificate return tpmAttestationKey, nil, ErrNotImplemented } _, ecdaaKeyPresent := att.AttStatement["ecdaaKeyId"].([]byte) if ecdaaKeyPresent { return tpmAttestationKey, nil, ErrNotImplemented } sigBytes, present := att.AttStatement["sig"].([]byte) if !present { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Error retreiving sig value") } certInfoBytes, present := att.AttStatement["certInfo"].([]byte) if !present { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Error retreiving certInfo value") } pubAreaBytes, present := att.AttStatement["pubArea"].([]byte) if !present { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Error retreiving pubArea value") } // Verify that the public key specified by the parameters and unique fields of pubArea // is identical to the credentialPublicKey in the attestedCredentialData in authenticatorData. pubArea, err := googletpm.DecodePublic(pubAreaBytes) if err != nil { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Unable to decode TPMT_PUBLIC in attestation statement") } key, err := webauthncose.ParsePublicKey(att.AuthData.AttData.CredentialPublicKey) switch key.(type) { case webauthncose.EC2PublicKeyData: e := key.(webauthncose.EC2PublicKeyData) if pubArea.ECCParameters.CurveID != googletpm.EllipticCurve(e.Curve) || 0 != pubArea.ECCParameters.Point.X.Cmp(new(big.Int).SetBytes(e.XCoord)) || 0 != pubArea.ECCParameters.Point.Y.Cmp(new(big.Int).SetBytes(e.YCoord)) { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Mismatch between ECCParameters in pubArea and credentialPublicKey") } case webauthncose.RSAPublicKeyData: r := key.(webauthncose.RSAPublicKeyData) mod := new(big.Int).SetBytes(r.Modulus) exp := uint32(r.Exponent[0]) + uint32(r.Exponent[1])<<8 + uint32(r.Exponent[2])<<16 if 0 != pubArea.RSAParameters.Modulus.Cmp(mod) || pubArea.RSAParameters.Exponent != exp { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Mismatch between RSAParameters in pubArea and credentialPublicKey") } default: return "", nil, ErrUnsupportedKey } // Concatenate authenticatorData and clientDataHash to form attToBeSigned attToBeSigned := append(att.RawAuthData, clientDataHash...) // Validate that certInfo is valid: certInfo, err := googletpm.DecodeAttestationData(certInfoBytes) // 1/4 Verify that magic is set to TPM_GENERATED_VALUE. if certInfo.Magic != 0xff544347 { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Magic is not set to TPM_GENERATED_VALUE") } // 2/4 Verify that type is set to TPM_ST_ATTEST_CERTIFY. if certInfo.Type != googletpm.TagAttestCertify { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Type is not set to TPM_ST_ATTEST_CERTIFY") } // 3/4 Verify that extraData is set to the hash of attToBeSigned using the hash algorithm employed in "alg". f := webauthncose.HasherFromCOSEAlg(coseAlg) h := f() h.Write(attToBeSigned) if 0 != bytes.Compare(certInfo.ExtraData, h.Sum(nil)) { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("ExtraData is not set to hash of attToBeSigned") } // 4/4 Verify that attested contains a TPMS_CERTIFY_INFO structure as specified in // [TPMv2-Part2] section 10.12.3, whose name field contains a valid Name for pubArea, // as computed using the algorithm in the nameAlg field of pubArea // using the procedure specified in [TPMv2-Part1] section 16. f, err = certInfo.AttestedCertifyInfo.Name.Digest.Alg.HashConstructor() h = f() h.Write(pubAreaBytes) if 0 != bytes.Compare(h.Sum(nil), certInfo.AttestedCertifyInfo.Name.Digest.Value) { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Hash value mismatch attested and pubArea") } // Note that the remaining fields in the "Standard Attestation Structure" // [TPMv2-Part1] section 31.2, i.e., qualifiedSigner, clockInfo and firmwareVersion // are ignored. These fields MAY be used as an input to risk engines. // If x5c is present, this indicates that the attestation type is not ECDAA. if x509present { // In this case: // Verify the sig is a valid signature over certInfo using the attestation public key in aikCert with the algorithm specified in alg. aikCertBytes, valid := x5c[0].([]byte) if !valid { return tpmAttestationKey, nil, ErrAttestation.WithDetails("Error getting certificate from x5c cert chain") } aikCert, err := x509.ParseCertificate(aikCertBytes) if err != nil { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Error parsing certificate from ASN.1") } sigAlg := webauthncose.SigAlgFromCOSEAlg(coseAlg) err = aikCert.CheckSignature(x509.SignatureAlgorithm(sigAlg), certInfoBytes, sigBytes) if err != nil { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails(fmt.Sprintf("Signature validation error: %+v\n", err)) } // Verify that aikCert meets the requirements in §8.3.1 TPM Attestation Statement Certificate Requirements // 1/6 Version MUST be set to 3. if aikCert.Version != 3 { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("AIK certificate version must be 3") } // 2/6 Subject field MUST be set to empty. if aikCert.Subject.String() != "" { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("AIK certificate subject must be empty") } // 3/6 The Subject Alternative Name extension MUST be set as defined in [TPMv2-EK-Profile] section 3.2.9{} var manufacturer, model, version string for _, ext := range aikCert.Extensions { if ext.Id.Equal([]int{2, 5, 29, 17}) { manufacturer, model, version, err = parseSANExtension(ext.Value) } } if manufacturer == "" || model == "" || version == "" { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Invalid SAN data in AIK certificate") } if false == isValidTPMManufacturer(manufacturer) { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("Invalid TPM manufacturer") } // 4/6 The Extended Key Usage extension MUST contain the "joint-iso-itu-t(2) internationalorganizations(23) 133 tcg-kp(8) tcg-kp-AIKCertificate(3)" OID. var ekuValid = false var eku []asn1.ObjectIdentifier for _, ext := range aikCert.Extensions { if ext.Id.Equal([]int{2, 5, 29, 37}) { rest, err := asn1.Unmarshal(ext.Value, &eku) if len(rest) != 0 || err != nil || !eku[0].Equal(tcgKpAIKCertificate) { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("AIK certificate EKU missing 2.23.133.8.3") } ekuValid = true } } if false == ekuValid { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("AIK certificate missing EKU") } // 5/6 The Basic Constraints extension MUST have the CA component set to false. type basicConstraints struct { IsCA bool `asn1:"optional"` MaxPathLen int `asn1:"optional,default:-1"` } var constraints basicConstraints for _, ext := range aikCert.Extensions { if ext.Id.Equal([]int{2, 5, 29, 19}) { if rest, err := asn1.Unmarshal(ext.Value, &constraints); err != nil { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("AIK certificate basic constraints malformed") } else if len(rest) != 0 { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("AIK certificate basic constraints contains extra data") } } } if constraints.IsCA != false { return tpmAttestationKey, nil, ErrAttestationFormat.WithDetails("AIK certificate basic constraints missing or CA is true") } // 6/6 An Authority Information Access (AIA) extension with entry id-ad-ocsp and a CRL Distribution Point // extension [RFC5280] are both OPTIONAL as the status of many attestation certificates is available // through metadata services. See, for example, the FIDO Metadata Service. } return tpmAttestationKey, x5c, err } func forEachSAN(extension []byte, callback func(tag int, data []byte) error) error { // RFC 5280, 4.2.1.6 // SubjectAltName ::= GeneralNames // // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName // // GeneralName ::= CHOICE { // otherName [0] OtherName, // rfc822Name [1] IA5String, // dNSName [2] IA5String, // x400Address [3] ORAddress, // directoryName [4] Name, // ediPartyName [5] EDIPartyName, // uniformResourceIdentifier [6] IA5String, // iPAddress [7] OCTET STRING, // registeredID [8] OBJECT IDENTIFIER } var seq asn1.RawValue rest, err := asn1.Unmarshal(extension, &seq) if err != nil { return err } else if len(rest) != 0 { return errors.New("x509: trailing data after X.509 extension") } if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 { return asn1.StructuralError{Msg: "bad SAN sequence"} } rest = seq.Bytes for len(rest) > 0 { var v asn1.RawValue rest, err = asn1.Unmarshal(rest, &v) if err != nil { return err } if err := callback(v.Tag, v.Bytes); err != nil { return err } } return nil } const ( nameTypeDN = 4 ) var ( tcgKpAIKCertificate = asn1.ObjectIdentifier{2, 23, 133, 8, 3} tcgAtTpmManufacturer = asn1.ObjectIdentifier{2, 23, 133, 2, 1} tcgAtTpmModel = asn1.ObjectIdentifier{2, 23, 133, 2, 2} tcgAtTpmVersion = asn1.ObjectIdentifier{2, 23, 133, 2, 3} ) func parseSANExtension(value []byte) (manufacturer string, model string, version string, err error) { err = forEachSAN(value, func(tag int, data []byte) error { switch tag { case nameTypeDN: tpmDeviceAttributes := pkix.RDNSequence{} _, err := asn1.Unmarshal(data, &tpmDeviceAttributes) if err != nil { return err } for _, rdn := range tpmDeviceAttributes { if len(rdn) == 0 { continue } for _, atv := range rdn { value, ok := atv.Value.(string) if !ok { continue } if atv.Type.Equal(tcgAtTpmManufacturer) { manufacturer = strings.TrimPrefix(value, "id:") } if atv.Type.Equal(tcgAtTpmModel) { model = value } if atv.Type.Equal(tcgAtTpmVersion) { version = strings.TrimPrefix(value, "id:") } } } } return nil }) return } var tpmManufacturers = []struct { id string name string code string }{ {"414D4400", "AMD", "AMD"}, {"41544D4C", "Atmel", "ATML"}, {"4252434D", "Broadcom", "BRCM"}, {"49424d00", "IBM", "IBM"}, {"49465800", "Infineon", "IFX"}, {"494E5443", "Intel", "INTC"}, {"4C454E00", "Lenovo", "LEN"}, {"4E534D20", "National Semiconductor", "NSM"}, {"4E545A00", "Nationz", "NTZ"}, {"4E544300", "Nuvoton Technology", "NTC"}, {"51434F4D", "Qualcomm", "QCOM"}, {"534D5343", "SMSC", "SMSC"}, {"53544D20", "ST Microelectronics", "STM"}, {"534D534E", "Samsung", "SMSN"}, {"534E5300", "Sinosun", "SNS"}, {"54584E00", "Texas Instruments", "TXN"}, {"57454300", "Winbond", "WEC"}, {"524F4343", "Fuzhouk Rockchip", "ROCC"}, {"FFFFF1D0", "FIDO Alliance Conformance Testing", "FIDO"}, } func isValidTPMManufacturer(id string) bool { for _, m := range tpmManufacturers { if m.id == id { return true } } return false } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/attestation_u2f.go000066400000000000000000000137051414201525100275370ustar00rootroot00000000000000package protocol import ( "bytes" "crypto/ecdsa" "crypto/elliptic" "crypto/x509" "github.com/duo-labs/webauthn/protocol/webauthncose" "github.com/fxamacker/cbor/v2" ) var u2fAttestationKey = "fido-u2f" func init() { RegisterAttestationFormat(u2fAttestationKey, verifyU2FFormat) } // verifyU2FFormat - Follows verification steps set out by https://www.w3.org/TR/webauthn/#fido-u2f-attestation func verifyU2FFormat(att AttestationObject, clientDataHash []byte) (string, []interface{}, error) { if !bytes.Equal(att.AuthData.AttData.AAGUID, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) { return u2fAttestationKey, nil, ErrUnsupportedAlgorithm.WithDetails("U2F attestation format AAGUID not set to 0x00") } // Signing procedure step - If the credential public key of the given credential is not of // algorithm -7 ("ES256"), stop and return an error. key := webauthncose.EC2PublicKeyData{} cbor.Unmarshal(att.AuthData.AttData.CredentialPublicKey, &key) if webauthncose.COSEAlgorithmIdentifier(key.PublicKeyData.Algorithm) != webauthncose.AlgES256 { return u2fAttestationKey, nil, ErrUnsupportedAlgorithm.WithDetails("Non-ES256 Public Key algorithm used") } // U2F Step 1. Verify that attStmt is valid CBOR conforming to the syntax defined above // and perform CBOR decoding on it to extract the contained fields. // The Format/syntax is // u2fStmtFormat = { // x5c: [ attestnCert: bytes ], // sig: bytes // } // Check for "x5c" which is a single element array containing the attestation certificate in X.509 format. x5c, present := att.AttStatement["x5c"].([]interface{}) if !present { return u2fAttestationKey, nil, ErrAttestationFormat.WithDetails("Missing properly formatted x5c data") } // Check for "sig" which is The attestation signature. The signature was calculated over the (raw) U2F // registration response message https://www.w3.org/TR/webauthn/#biblio-fido-u2f-message-formats] // received by the client from the authenticator. signature, present := att.AttStatement["sig"].([]byte) if !present { return u2fAttestationKey, nil, ErrAttestationFormat.WithDetails("Missing sig data") } // U2F Step 2. (1) Check that x5c has exactly one element and let attCert be that element. (2) Let certificate public // key be the public key conveyed by attCert. (3) If certificate public key is not an Elliptic Curve (EC) public // key over the P-256 curve, terminate this algorithm and return an appropriate error. // Step 2.1 if len(x5c) > 1 { return u2fAttestationKey, nil, ErrAttestationFormat.WithDetails("Received more than one element in x5c values") } // Note: Packed Attestation, FIDO U2F Attestation, and Assertion Signatures support ASN.1,but it is recommended // that any new attestation formats defined not use ASN.1 encodings, but instead represent signatures as equivalent // fixed-length byte arrays without internal structure, using the same representations as used by COSE signatures // as defined in RFC8152 (https://www.w3.org/TR/webauthn/#biblio-rfc8152) // and RFC8230 (https://www.w3.org/TR/webauthn/#biblio-rfc8230). // Step 2.2 asn1Bytes, decoded := x5c[0].([]byte) if !decoded { return u2fAttestationKey, nil, ErrAttestationFormat.WithDetails("Error decoding ASN.1 data from x5c") } attCert, err := x509.ParseCertificate(asn1Bytes) if err != nil { return u2fAttestationKey, nil, ErrAttestationFormat.WithDetails("Error parsing certificate from ASN.1 data into certificate") } // Step 2.3 if attCert.PublicKeyAlgorithm != x509.ECDSA && attCert.PublicKey.(*ecdsa.PublicKey).Curve != elliptic.P256() { return u2fAttestationKey, nil, ErrAttestationFormat.WithDetails("Attestation certificate is in invalid format") } // Step 3. Extract the claimed rpIdHash from authenticatorData, and the claimed credentialId and credentialPublicKey // from authenticatorData.attestedCredentialData. rpIdHash := att.AuthData.RPIDHash credentialID := att.AuthData.AttData.CredentialID // credentialPublicKey handled earlier // Step 4. Convert the COSE_KEY formatted credentialPublicKey (see Section 7 of RFC8152 [https://www.w3.org/TR/webauthn/#biblio-rfc8152]) // to Raw ANSI X9.62 public key format (see ALG_KEY_ECC_X962_RAW in Section 3.6.2 Public Key // Representation Formats of FIDO-Registry [https://www.w3.org/TR/webauthn/#biblio-fido-registry]). // Let x be the value corresponding to the "-2" key (representing x coordinate) in credentialPublicKey, and confirm // its size to be of 32 bytes. If size differs or "-2" key is not found, terminate this algorithm and // return an appropriate error. // Let y be the value corresponding to the "-3" key (representing y coordinate) in credentialPublicKey, and confirm // its size to be of 32 bytes. If size differs or "-3" key is not found, terminate this algorithm and // return an appropriate error. if len(key.XCoord) > 32 || len(key.YCoord) > 32 { return u2fAttestationKey, nil, ErrAttestation.WithDetails("X or Y Coordinate for key is invalid length") } // Let publicKeyU2F be the concatenation 0x04 || x || y. publicKeyU2F := bytes.NewBuffer([]byte{0x04}) publicKeyU2F.Write(key.XCoord) publicKeyU2F.Write(key.YCoord) // Step 5. Let verificationData be the concatenation of (0x00 || rpIdHash || clientDataHash || credentialId || publicKeyU2F) // (see §4.3 of FIDO-U2F-Message-Formats [https://www.w3.org/TR/webauthn/#biblio-fido-u2f-message-formats]). verificationData := bytes.NewBuffer([]byte{0x00}) verificationData.Write(rpIdHash) verificationData.Write(clientDataHash) verificationData.Write(credentialID) verificationData.Write(publicKeyU2F.Bytes()) // Step 6. Verify the sig using verificationData and certificate public key per SEC1[https://www.w3.org/TR/webauthn/#biblio-sec1]. sigErr := attCert.CheckSignature(x509.ECDSAWithSHA256, verificationData.Bytes(), signature) if sigErr != nil { return u2fAttestationKey, nil, sigErr } // Step 7. If successful, return attestation type Basic with the attestation trust path set to x5c. return "Fido U2F Basic", x5c, sigErr } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/authenticator.go000066400000000000000000000266361414201525100273050ustar00rootroot00000000000000package protocol import ( "bytes" "encoding/binary" "fmt" "github.com/fxamacker/cbor/v2" ) var minAuthDataLength = 37 // Authenticators respond to Relying Party requests by returning an object derived from the // AuthenticatorResponse interface. See §5.2. Authenticator Responses // https://www.w3.org/TR/webauthn/#iface-authenticatorresponse type AuthenticatorResponse struct { // From the spec https://www.w3.org/TR/webauthn/#dom-authenticatorresponse-clientdatajson // This attribute contains a JSON serialization of the client data passed to the authenticator // by the client in its call to either create() or get(). ClientDataJSON URLEncodedBase64 `json:"clientDataJSON"` } // AuthenticatorData From §6.1 of the spec. // The authenticator data structure encodes contextual bindings made by the authenticator. These bindings // are controlled by the authenticator itself, and derive their trust from the WebAuthn Relying Party's // assessment of the security properties of the authenticator. In one extreme case, the authenticator // may be embedded in the client, and its bindings may be no more trustworthy than the client data. // At the other extreme, the authenticator may be a discrete entity with high-security hardware and // software, connected to the client over a secure channel. In both cases, the Relying Party receives // the authenticator data in the same format, and uses its knowledge of the authenticator to make // trust decisions. // // The authenticator data, at least during attestation, contains the Public Key that the RP stores // and will associate with the user attempting to register. type AuthenticatorData struct { RPIDHash []byte `json:"rpid"` Flags AuthenticatorFlags `json:"flags"` Counter uint32 `json:"sign_count"` AttData AttestedCredentialData `json:"att_data"` ExtData []byte `json:"ext_data"` } type AttestedCredentialData struct { AAGUID []byte `json:"aaguid"` CredentialID []byte `json:"credential_id"` // The raw credential public key bytes received from the attestation data CredentialPublicKey []byte `json:"public_key"` } // AuthenticatorAttachment https://www.w3.org/TR/webauthn/#platform-attachment type AuthenticatorAttachment string const ( // Platform - A platform authenticator is attached using a client device-specific transport, called // platform attachment, and is usually not removable from the client device. A public key credential // bound to a platform authenticator is called a platform credential. Platform AuthenticatorAttachment = "platform" // CrossPlatform A roaming authenticator is attached using cross-platform transports, called // cross-platform attachment. Authenticators of this class are removable from, and can "roam" // among, client devices. A public key credential bound to a roaming authenticator is called a // roaming credential. CrossPlatform AuthenticatorAttachment = "cross-platform" ) // Authenticators may implement various transports for communicating with clients. This enumeration defines // hints as to how clients might communicate with a particular authenticator in order to obtain an assertion // for a specific credential. Note that these hints represent the WebAuthn Relying Party's best belief as to // how an authenticator may be reached. A Relying Party may obtain a list of transports hints from some // attestation statement formats or via some out-of-band mechanism; it is outside the scope of this // specification to define that mechanism. // See §5.10.4. Authenticator Transport https://www.w3.org/TR/webauthn/#transport type AuthenticatorTransport string const ( // USB The authenticator should transport information over USB USB AuthenticatorTransport = "usb" // NFC The authenticator should transport information over Near Field Communication Protocol NFC AuthenticatorTransport = "nfc" // BLE The authenticator should transport information over Bluetooth BLE AuthenticatorTransport = "ble" // Internal the client should use an internal source like a TPM or SE Internal AuthenticatorTransport = "internal" ) // A WebAuthn Relying Party may require user verification for some of its operations but not for others, // and may use this type to express its needs. // See §5.10.6. User Verification Requirement Enumeration https://www.w3.org/TR/webauthn/#userVerificationRequirement type UserVerificationRequirement string const ( // VerificationRequired User verification is required to create/release a credential VerificationRequired UserVerificationRequirement = "required" // VerificationPreferred User verification is preferred to create/release a credential VerificationPreferred UserVerificationRequirement = "preferred" // This is the default // VerificationDiscouraged The authenticator should not verify the user for the credential VerificationDiscouraged UserVerificationRequirement = "discouraged" ) // AuthenticatorFlags A byte of information returned during during ceremonies in the // authenticatorData that contains bits that give us information about the // whether the user was present and/or verified during authentication, and whether // there is attestation or extension data present. Bit 0 is the least significant bit. type AuthenticatorFlags byte // The bits that do not have flags are reserved for future use. const ( // FlagUserPresent Bit 00000001 in the byte sequence. Tells us if user is present FlagUserPresent AuthenticatorFlags = 1 << iota // Referred to as UP _ // Reserved // FlagUserVerified Bit 00000100 in the byte sequence. Tells us if user is verified // by the authenticator using a biometric or PIN FlagUserVerified // Referred to as UV _ // Reserved _ // Reserved _ // Reserved // FlagAttestedCredentialData Bit 01000000 in the byte sequence. Indicates whether // the authenticator added attested credential data. FlagAttestedCredentialData // Referred to as AT // FlagHasExtension Bit 10000000 in the byte sequence. Indicates if the authenticator data has extensions. FlagHasExtensions // Referred to as ED ) // UserPresent returns if the UP flag was set func (flag AuthenticatorFlags) UserPresent() bool { return (flag & FlagUserPresent) == FlagUserPresent } // UserVerified returns if the UV flag was set func (flag AuthenticatorFlags) UserVerified() bool { return (flag & FlagUserVerified) == FlagUserVerified } // HasAttestedCredentialData returns if the AT flag was set func (flag AuthenticatorFlags) HasAttestedCredentialData() bool { return (flag & FlagAttestedCredentialData) == FlagAttestedCredentialData } // HasExtensions returns if the ED flag was set func (flag AuthenticatorFlags) HasExtensions() bool { return (flag & FlagHasExtensions) == FlagHasExtensions } // Unmarshal will take the raw Authenticator Data and marshalls it into AuthenticatorData for further validation. // The authenticator data has a compact but extensible encoding. This is desired since authenticators can be // devices with limited capabilities and low power requirements, with much simpler software stacks than the client platform. // The authenticator data structure is a byte array of 37 bytes or more, and is laid out in this table: // https://www.w3.org/TR/webauthn/#table-authData func (a *AuthenticatorData) Unmarshal(rawAuthData []byte) error { if minAuthDataLength > len(rawAuthData) { err := ErrBadRequest.WithDetails("Authenticator data length too short") info := fmt.Sprintf("Expected data greater than %d bytes. Got %d bytes\n", minAuthDataLength, len(rawAuthData)) return err.WithInfo(info) } a.RPIDHash = rawAuthData[:32] a.Flags = AuthenticatorFlags(rawAuthData[32]) a.Counter = binary.BigEndian.Uint32(rawAuthData[33:37]) remaining := len(rawAuthData) - minAuthDataLength if a.Flags.HasAttestedCredentialData() { if len(rawAuthData) > minAuthDataLength { a.unmarshalAttestedData(rawAuthData) attDataLen := len(a.AttData.AAGUID) + 2 + len(a.AttData.CredentialID) + len(a.AttData.CredentialPublicKey) remaining = remaining - attDataLen } else { return ErrBadRequest.WithDetails("Attested credential flag set but data is missing") } } else { if !a.Flags.HasExtensions() && len(rawAuthData) != 37 { return ErrBadRequest.WithDetails("Attested credential flag not set") } } if a.Flags.HasExtensions() { if remaining != 0 { a.ExtData = rawAuthData[len(rawAuthData)-remaining:] remaining -= len(a.ExtData) } else { return ErrBadRequest.WithDetails("Extensions flag set but extensions data is missing") } } if remaining != 0 { return ErrBadRequest.WithDetails("Leftover bytes decoding AuthenticatorData") } return nil } // If Attestation Data is present, unmarshall that into the appropriate public key structure func (a *AuthenticatorData) unmarshalAttestedData(rawAuthData []byte) { a.AttData.AAGUID = rawAuthData[37:53] idLength := binary.BigEndian.Uint16(rawAuthData[53:55]) a.AttData.CredentialID = rawAuthData[55 : 55+idLength] a.AttData.CredentialPublicKey = unmarshalCredentialPublicKey(rawAuthData[55+idLength:]) } // Unmarshall the credential's Public Key into CBOR encoding func unmarshalCredentialPublicKey(keyBytes []byte) []byte { var m interface{} cbor.Unmarshal(keyBytes, &m) rawBytes, _ := cbor.Marshal(m) return rawBytes } // ResidentKeyRequired - Require that the key be private key resident to the client device func ResidentKeyRequired() *bool { required := true return &required } // ResidentKeyUnrequired - Do not require that the private key be resident to the client device. func ResidentKeyUnrequired() *bool { required := false return &required } // Verify on AuthenticatorData handles Steps 9 through 12 for Registration // and Steps 11 through 14 for Assertion. func (a *AuthenticatorData) Verify(rpIdHash []byte, userVerificationRequired bool) error { // Registration Step 9 & Assertion Step 11 // Verify that the RP ID hash in authData is indeed the SHA-256 // hash of the RP ID expected by the RP. if !bytes.Equal(a.RPIDHash[:], rpIdHash) { return ErrVerification.WithInfo(fmt.Sprintf("RP Hash mismatch. Expected %+s and Received %+s\n", a.RPIDHash, rpIdHash)) } // Registration Step 10 & Assertion Step 12 // Verify that the User Present bit of the flags in authData is set. if !a.Flags.UserPresent() { return ErrVerification.WithInfo(fmt.Sprintln("User presence flag not set by authenticator")) } // Registration Step 11 & Assertion Step 13 // If user verification is required for this assertion, verify that // the User Verified bit of the flags in authData is set. if userVerificationRequired && !a.Flags.UserVerified() { return ErrVerification.WithInfo(fmt.Sprintln("User verification required but flag not set by authenticator")) } // Registration Step 12 & Assertion Step 14 // Verify that the values of the client extension outputs in clientExtensionResults // and the authenticator extension outputs in the extensions in authData are as // expected, considering the client extension input values that were given as the // extensions option in the create() call. In particular, any extension identifier // values in the clientExtensionResults and the extensions in authData MUST be also be // present as extension identifier values in the extensions member of options, i.e., no // extensions are present that were not requested. In the general case, the meaning // of "are as expected" is specific to the Relying Party and which extensions are in use. // This is not yet fully implemented by the spec or by browsers return nil } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/authenticator_test.go000066400000000000000000000133141414201525100303310ustar00rootroot00000000000000package protocol import ( "encoding/base64" "reflect" "testing" ) func TestAuthenticatorFlags_UserPresent(t *testing.T) { var goodByte byte = 0x01 var badByte byte = 0x10 tests := []struct { name string flag AuthenticatorFlags want bool }{ { "Present", AuthenticatorFlags(goodByte), true, }, { "Missing", AuthenticatorFlags(badByte), false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.flag.UserPresent(); got != tt.want { t.Errorf("AuthenticatorFlags.UserPresent() = %v, want %v", got, tt.want) } }) } } func TestAuthenticatorFlags_UserVerified(t *testing.T) { var goodByte byte = 0x04 var badByte byte = 0x02 tests := []struct { name string flag AuthenticatorFlags want bool }{ { "Present", AuthenticatorFlags(goodByte), true, }, { "Missing", AuthenticatorFlags(badByte), false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.flag.UserVerified(); got != tt.want { t.Errorf("AuthenticatorFlags.UserVerified() = %v, want %v", got, tt.want) } }) } } func TestAuthenticatorFlags_HasAttestedCredentialData(t *testing.T) { var goodByte byte = 0x40 var badByte byte = 0x01 tests := []struct { name string flag AuthenticatorFlags want bool }{ { "Present", AuthenticatorFlags(goodByte), true, }, { "Missing", AuthenticatorFlags(badByte), false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.flag.HasAttestedCredentialData(); got != tt.want { t.Errorf("AuthenticatorFlags.HasAttestedCredentialData() = %v, want %v", got, tt.want) } }) } } func TestAuthenticatorFlags_HasExtensions(t *testing.T) { var goodByte byte = 0x80 var badByte byte = 0x01 tests := []struct { name string flag AuthenticatorFlags want bool }{ { "Present", AuthenticatorFlags(goodByte), true, }, { "Missing", AuthenticatorFlags(badByte), false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.flag.HasExtensions(); got != tt.want { t.Errorf("AuthenticatorFlags.HasExtensions() = %v, want %v", got, tt.want) } }) } } func TestAuthenticatorData_Unmarshal(t *testing.T) { type fields struct { RPIDHash []byte Flags AuthenticatorFlags Counter uint32 AttData AttestedCredentialData ExtData []byte } type args struct { 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==") tests := []struct { name string fields fields args args wantErr bool }{ { "None Marshall Successfully", fields{}, args{ noneAuthData, }, false, }, { "Att Data Marshall Successfully", fields{}, args{ attAuthData, }, false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { a := &AuthenticatorData{ RPIDHash: tt.fields.RPIDHash, Flags: tt.fields.Flags, Counter: tt.fields.Counter, AttData: tt.fields.AttData, ExtData: tt.fields.ExtData, } if err := a.Unmarshal(tt.args.rawAuthData); (err != nil) != tt.wantErr { t.Errorf("AuthenticatorData.Unmarshal() error = %v, wantErr %v", err, tt.wantErr) } }) } } func TestAuthenticatorData_unmarshalAttestedData(t *testing.T) { type fields struct { RPIDHash []byte Flags AuthenticatorFlags Counter uint32 AttData AttestedCredentialData ExtData []byte } type args struct { rawAuthData []byte } tests := []struct { name string fields fields args args }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { a := &AuthenticatorData{ RPIDHash: tt.fields.RPIDHash, Flags: tt.fields.Flags, Counter: tt.fields.Counter, AttData: tt.fields.AttData, ExtData: tt.fields.ExtData, } a.unmarshalAttestedData(tt.args.rawAuthData) }) } } func Test_unmarshalCredentialPublicKey(t *testing.T) { type args struct { keyBytes []byte } tests := []struct { name string args args want []byte }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := unmarshalCredentialPublicKey(tt.args.keyBytes); !reflect.DeepEqual(got, tt.want) { t.Errorf("unmarshalCredentialPublicKey() = %v, want %v", got, tt.want) } }) } } func TestAuthenticatorData_Verify(t *testing.T) { type fields struct { RPIDHash []byte Flags AuthenticatorFlags Counter uint32 AttData AttestedCredentialData ExtData []byte } type args struct { rpIdHash []byte userVerificationRequired bool } tests := []struct { name string fields fields args args wantErr bool }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { a := &AuthenticatorData{ RPIDHash: tt.fields.RPIDHash, Flags: tt.fields.Flags, Counter: tt.fields.Counter, AttData: tt.fields.AttData, ExtData: tt.fields.ExtData, } if err := a.Verify(tt.args.rpIdHash, tt.args.userVerificationRequired); (err != nil) != tt.wantErr { t.Errorf("AuthenticatorData.Verify() error = %v, wantErr %v", err, tt.wantErr) } }) } } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/base64.go000066400000000000000000000020701414201525100255010ustar00rootroot00000000000000package protocol import ( "bytes" "encoding/base64" "reflect" ) // URLEncodedBase64 represents a byte slice holding URL-encoded base64 data. // When fields of this type are unmarshaled from JSON, the data is base64 // decoded into a byte slice. type URLEncodedBase64 []byte // UnmarshalJSON base64 decodes a URL-encoded value, storing the result in the // provided byte slice. func (dest *URLEncodedBase64) UnmarshalJSON(data []byte) error { if bytes.Equal(data, []byte("null")) { return nil } // Trim the leading spaces data = bytes.Trim(data, "\"") out := make([]byte, base64.RawURLEncoding.DecodedLen(len(data))) n, err := base64.RawURLEncoding.Decode(out, data) if err != nil { return err } v := reflect.ValueOf(dest).Elem() v.SetBytes(out[:n]) return nil } // MarshalJSON base64 encodes a non URL-encoded value, storing the result in the // provided byte slice. func (data URLEncodedBase64) MarshalJSON() ([]byte, error) { if data == nil { return []byte("null"), nil } return []byte(`"` + base64.RawURLEncoding.EncodeToString(data) + `"`), nil } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/base64_test.go000066400000000000000000000025741414201525100265510ustar00rootroot00000000000000package protocol import ( "bytes" "encoding/base64" "encoding/json" "fmt" "strings" "testing" ) func TestBase64UnmarshalJSON(t *testing.T) { type testData struct { StringData string `json:"string_data"` EncodedData URLEncodedBase64 `json:"encoded_data"` } tests := []struct { encodedMessage string expectedTestData testData }{ { encodedMessage: "\"" + base64.RawURLEncoding.EncodeToString([]byte("test base64 data")) + "\"", expectedTestData: testData{ StringData: "test string", EncodedData: URLEncodedBase64("test base64 data"), }, }, { encodedMessage: "null", expectedTestData: testData{ StringData: "test string", EncodedData: nil, }, }, } for _, test := range tests { raw := fmt.Sprintf(`{"string_data": "test string", "encoded_data": %s}`, test.encodedMessage) t.Logf("%s\n", raw) got := testData{} err := json.NewDecoder(strings.NewReader(raw)).Decode(&got) if err != nil { t.Fatalf("error decoding JSON: %v", err) } if !bytes.Equal(test.expectedTestData.EncodedData, got.EncodedData) { t.Fatalf("invalid URLEncodedBase64 data received: expected %s got %s", test.expectedTestData.EncodedData, got.EncodedData) } if test.expectedTestData.StringData != got.StringData { t.Fatalf("invalid string data received: expected %s got %s", test.expectedTestData.StringData, got.StringData) } } } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/challenge.go000066400000000000000000000012471414201525100263440ustar00rootroot00000000000000package protocol import ( "crypto/rand" "encoding/base64" ) // ChallengeLength - Length of bytes to generate for a challenge const ChallengeLength = 32 // Challenge that should be signed and returned by the authenticator type Challenge URLEncodedBase64 // Create a new challenge to be sent to the authenticator. The spec recommends using // at least 16 bytes with 100 bits of entropy. We use 32 bytes. func CreateChallenge() (Challenge, error) { challenge := make([]byte, ChallengeLength) _, err := rand.Read(challenge) if err != nil { return nil, err } return challenge, nil } func (c Challenge) String() string { return base64.RawURLEncoding.EncodeToString(c) } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/challenge_test.go000066400000000000000000000022341414201525100274000ustar00rootroot00000000000000package protocol import ( "encoding/base64" "reflect" "testing" ) func TestCreateChallenge(t *testing.T) { tests := []struct { name string want Challenge wantErr bool }{ { "Successfull Challenge Create", Challenge{}, false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := CreateChallenge() if (err != nil) != tt.wantErr { t.Errorf("CreateChallenge() error = %v, wantErr %v", err, tt.wantErr) return } tt.want = got if !reflect.DeepEqual(got, tt.want) { t.Errorf("CreateChallenge() = %v, want %v", got, tt.want) } }) } } func TestChallenge_String(t *testing.T) { newChallenge, err := CreateChallenge() if err != nil { t.Errorf("CreateChallenge() error = %v", err) return } wantChallenge := base64.RawURLEncoding.EncodeToString(newChallenge) tests := []struct { name string c Challenge want string }{ { "Successful String", newChallenge, wantChallenge, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.c.String(); got != tt.want { t.Errorf("Challenge.String() = %v, want %v", got, tt.want) } }) } } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/client.go000066400000000000000000000113421414201525100256750ustar00rootroot00000000000000package protocol import ( "fmt" "net/url" "strings" ) // CollectedClientData represents the contextual bindings of both the WebAuthn Relying Party // and the client. It is a key-value mapping whose keys are strings. Values can be any type // that has a valid encoding in JSON. Its structure is defined by the following Web IDL. // https://www.w3.org/TR/webauthn/#sec-client-data type CollectedClientData struct { // Type the string "webauthn.create" when creating new credentials, // and "webauthn.get" when getting an assertion from an existing credential. The // purpose of this member is to prevent certain types of signature confusion attacks //(where an attacker substitutes one legitimate signature for another). Type CeremonyType `json:"type"` Challenge string `json:"challenge"` Origin string `json:"origin"` TokenBinding *TokenBinding `json:"tokenBinding,omitempty"` // Chromium (Chrome) returns a hint sometimes about how to handle clientDataJSON in a safe manner Hint string `json:"new_keys_may_be_added_here,omitempty"` } type CeremonyType string const ( CreateCeremony CeremonyType = "webauthn.create" AssertCeremony CeremonyType = "webauthn.get" ) type TokenBinding struct { Status TokenBindingStatus `json:"status"` ID string `json:"id,omitempty"` } type TokenBindingStatus string const ( // Indicates token binding was used when communicating with the // Relying Party. In this case, the id member MUST be present. Present TokenBindingStatus = "present" // Indicates token binding was used when communicating with the // negotiated when communicating with the Relying Party. Supported TokenBindingStatus = "supported" // Indicates token binding not supported // when communicating with the Relying Party. NotSupported TokenBindingStatus = "not-supported" ) // Returns the origin per the HTML spec: (scheme)://(host)[:(port)] func FullyQualifiedOrigin(u *url.URL) string { return fmt.Sprintf("%s://%s", u.Scheme, u.Host) } // Handles steps 3 through 6 of verfying the registering client data of a // new credential and steps 7 through 10 of verifying an authentication assertion // See https://www.w3.org/TR/webauthn/#registering-a-new-credential // and https://www.w3.org/TR/webauthn/#verifying-assertion func (c *CollectedClientData) Verify(storedChallenge string, ceremony CeremonyType, relyingPartyOrigin string) error { // Registration Step 3. Verify that the value of C.type is webauthn.create. // Assertion Step 7. Verify that the value of C.type is the string webauthn.get. if c.Type != ceremony { err := ErrVerification.WithDetails("Error validating ceremony type") err.WithInfo(fmt.Sprintf("Expected Value: %s\n Received: %s\n", ceremony, c.Type)) return err } // Registration Step 4. Verify that the value of C.challenge matches the challenge // that was sent to the authenticator in the create() call. // Assertion Step 8. Verify that the value of C.challenge matches the challenge // that was sent to the authenticator in the PublicKeyCredentialRequestOptions // passed to the get() call. challenge := c.Challenge if 0 != strings.Compare(storedChallenge, challenge) { err := ErrVerification.WithDetails("Error validating challenge") return err.WithInfo(fmt.Sprintf("Expected b Value: %#v\nReceived b: %#v\n", storedChallenge, challenge)) } // Registration Step 5 & Assertion Step 9. Verify that the value of C.origin matches // the Relying Party's origin. clientDataOrigin, err := url.Parse(c.Origin) if err != nil { return ErrParsingData.WithDetails("Error decoding clientData origin as URL") } if !strings.EqualFold(FullyQualifiedOrigin(clientDataOrigin), relyingPartyOrigin) { err := ErrVerification.WithDetails("Error validating origin") return err.WithInfo(fmt.Sprintf("Expected Value: %s\n Received: %s\n", relyingPartyOrigin, FullyQualifiedOrigin(clientDataOrigin))) } // Registration Step 6 and Assertion Step 10. Verify that the value of C.tokenBinding.status // matches the state of Token Binding for the TLS connection over which the assertion was // obtained. If Token Binding was used on that TLS connection, also verify that C.tokenBinding.id // matches the base64url encoding of the Token Binding ID for the connection. if c.TokenBinding != nil { if c.TokenBinding.Status == "" { return ErrParsingData.WithDetails("Error decoding clientData, token binding present without status") } if c.TokenBinding.Status != Present && c.TokenBinding.Status != Supported && c.TokenBinding.Status != NotSupported { return ErrParsingData.WithDetails("Error decoding clientData, token binding present with invalid status").WithInfo(fmt.Sprintf("Got: %s\n", c.TokenBinding.Status)) } } // Not yet fully implemented by the spec, browsers, and me. return nil } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/client_test.go000066400000000000000000000025501414201525100267350ustar00rootroot00000000000000package protocol import ( "encoding/base64" "net/url" "testing" ) func setupCollectedClientData(challenge []byte) *CollectedClientData { ccd := &CollectedClientData{ Type: CreateCeremony, Origin: "example.com", } ccd.Challenge = base64.RawURLEncoding.EncodeToString(challenge) return ccd } func TestVerifyCollectedClientData(t *testing.T) { newChallenge, err := CreateChallenge() if err != nil { t.Fatalf("error creating challenge: %s", err) } ccd := setupCollectedClientData(newChallenge) var storedChallenge = newChallenge originURL, _ := url.Parse(ccd.Origin) err = ccd.Verify(storedChallenge.String(), ccd.Type, FullyQualifiedOrigin(originURL)) if err != nil { t.Fatalf("error verifying challenge: expected %#v got %#v", Challenge(ccd.Challenge), storedChallenge) } } func TestVerifyCollectedClientDataIncorrectChallenge(t *testing.T) { newChallenge, err := CreateChallenge() if err != nil { t.Fatalf("error creating challenge: %s", err) } ccd := setupCollectedClientData(newChallenge) bogusChallenge, err := CreateChallenge() if err != nil { t.Fatalf("error creating challenge: %s", err) } storedChallenge := Challenge(bogusChallenge) err = ccd.Verify(storedChallenge.String(), ccd.Type, ccd.Origin) if err == nil { t.Fatalf("error expected but not received. expected %#v got %#v", Challenge(ccd.Challenge), storedChallenge) } } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/credential.go000066400000000000000000000154741414201525100265430ustar00rootroot00000000000000package protocol import ( "crypto/sha256" "encoding/base64" "encoding/json" "io" "net/http" ) // The basic credential type that is inherited by WebAuthn's // PublicKeyCredential type // https://w3c.github.io/webappsec-credential-management/#credential type Credential struct { // ID is The credential’s identifier. The requirements for the // identifier are distinct for each type of credential. It might // represent a username for username/password tuples, for example. ID string `json:"id"` // Type is the value of the object’s interface object's [[type]] slot, // which specifies the credential type represented by this object. // This should be type "public-key" for Webauthn credentials. Type string `json:"type"` } // The PublicKeyCredential interface inherits from Credential, and contains // the attributes that are returned to the caller when a new credential // is created, or a new assertion is requested. type ParsedCredential struct { ID string `cbor:"id"` Type string `cbor:"type"` } type PublicKeyCredential struct { Credential RawID URLEncodedBase64 `json:"rawId"` Extensions AuthenticationExtensionsClientOutputs `json:"extensions,omitempty"` } type ParsedPublicKeyCredential struct { ParsedCredential RawID []byte `json:"rawId"` Extensions AuthenticationExtensionsClientOutputs `json:"extensions,omitempty"` } type CredentialCreationResponse struct { PublicKeyCredential AttestationResponse AuthenticatorAttestationResponse `json:"response"` } type ParsedCredentialCreationData struct { ParsedPublicKeyCredential Response ParsedAttestationResponse Raw CredentialCreationResponse } func ParseCredentialCreationResponse(response *http.Request) (*ParsedCredentialCreationData, error) { if response == nil || response.Body == nil { return nil, ErrBadRequest.WithDetails("No response given") } return ParseCredentialCreationResponseBody(response.Body) } func ParseCredentialCreationResponseBody(body io.Reader) (*ParsedCredentialCreationData, error) { var ccr CredentialCreationResponse err := json.NewDecoder(body).Decode(&ccr) if err != nil { return nil, ErrBadRequest.WithDetails("Parse error for Registration").WithInfo(err.Error()) } if ccr.ID == "" { return nil, ErrBadRequest.WithDetails("Parse error for Registration").WithInfo("Missing ID") } testB64, err := base64.RawURLEncoding.DecodeString(ccr.ID) if err != nil || !(len(testB64) > 0) { return nil, ErrBadRequest.WithDetails("Parse error for Registration").WithInfo("ID not base64.RawURLEncoded") } if ccr.PublicKeyCredential.Credential.Type == "" { return nil, ErrBadRequest.WithDetails("Parse error for Registration").WithInfo("Missing type") } if ccr.PublicKeyCredential.Credential.Type != "public-key" { return nil, ErrBadRequest.WithDetails("Parse error for Registration").WithInfo("Type not public-key") } var pcc ParsedCredentialCreationData pcc.ID, pcc.RawID, pcc.Type = ccr.ID, ccr.RawID, ccr.Type pcc.Raw = ccr parsedAttestationResponse, err := ccr.AttestationResponse.Parse() if err != nil { return nil, ErrParsingData.WithDetails("Error parsing attestation response") } pcc.Response = *parsedAttestationResponse return &pcc, nil } // Verifies the Client and Attestation data as laid out by §7.1. Registering a new credential // https://www.w3.org/TR/webauthn/#registering-a-new-credential func (pcc *ParsedCredentialCreationData) Verify(storedChallenge string, verifyUser bool, relyingPartyID, relyingPartyOrigin string) error { // Handles steps 3 through 6 - Verifying the Client Data against the Relying Party's stored data verifyError := pcc.Response.CollectedClientData.Verify(storedChallenge, CreateCeremony, relyingPartyOrigin) if verifyError != nil { return verifyError } // Step 7. Compute the hash of response.clientDataJSON using SHA-256. clientDataHash := sha256.Sum256(pcc.Raw.AttestationResponse.ClientDataJSON) // Step 8. Perform CBOR decoding on the attestationObject field of the AuthenticatorAttestationResponse // structure to obtain the attestation statement format fmt, the authenticator data authData, and the // attestation statement attStmt. is handled while // We do the above step while parsing and decoding the CredentialCreationResponse // Handle steps 9 through 14 - This verifies the attestaion object and verifyError = pcc.Response.AttestationObject.Verify(relyingPartyID, clientDataHash[:], verifyUser) if verifyError != nil { return verifyError } // Step 15. If validation is successful, obtain a list of acceptable trust anchors (attestation root // certificates or ECDAA-Issuer public keys) for that attestation type and attestation statement // format fmt, from a trusted source or from policy. For example, the FIDO Metadata Service provides // one way to obtain such information, using the aaguid in the attestedCredentialData in authData. // [https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-metadata-service-v2.0-id-20180227.html] // TODO: There are no valid AAGUIDs yet or trust sources supported. We could implement policy for the RP in // the future, however. // Step 16. Assess the attestation trustworthiness using outputs of the verification procedure in step 14, as follows: // - If self attestation was used, check if self attestation is acceptable under Relying Party policy. // - If ECDAA was used, verify that the identifier of the ECDAA-Issuer public key used is included in // the set of acceptable trust anchors obtained in step 15. // - Otherwise, use the X.509 certificates returned by the verification procedure to verify that the // attestation public key correctly chains up to an acceptable root certificate. // TODO: We're not supporting trust anchors, self-attestation policy, or acceptable root certs yet // Step 17. Check that the credentialId is not yet registered to any other user. If registration is // requested for a credential that is already registered to a different user, the Relying Party SHOULD // fail this registration ceremony, or it MAY decide to accept the registration, e.g. while deleting // the older registration. // TODO: We can't support this in the code's current form, the Relying Party would need to check for this // against their database // Step 18 If the attestation statement attStmt verified successfully and is found to be trustworthy, then // register the new credential with the account that was denoted in the options.user passed to create(), by // associating it with the credentialId and credentialPublicKey in the attestedCredentialData in authData, as // appropriate for the Relying Party's system. // Step 19. If the attestation statement attStmt successfully verified but is not trustworthy per step 16 above, // the Relying Party SHOULD fail the registration ceremony. // TODO: Not implemented for the reasons mentioned under Step 16 return nil } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/credential_test.go000066400000000000000000000243651414201525100276010ustar00rootroot00000000000000package protocol import ( "bytes" "encoding/base64" "io/ioutil" "net/http" "reflect" "testing" "github.com/fxamacker/cbor/v2" ) func TestParseCredentialCreationResponse(t *testing.T) { reqBody := ioutil.NopCloser(bytes.NewReader([]byte(testCredentialRequestBody))) httpReq := &http.Request{Body: reqBody} type args struct { response *http.Request } 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") tests := []struct { name string args args want *ParsedCredentialCreationData wantErr bool }{ { name: "Successful Credential Request Parsing", args: args{ response: httpReq, }, want: &ParsedCredentialCreationData{ ParsedPublicKeyCredential: ParsedPublicKeyCredential{ ParsedCredential: ParsedCredential{ ID: "6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g", Type: "public-key", }, RawID: byteID, }, Response: ParsedAttestationResponse{ CollectedClientData: CollectedClientData{ Type: CeremonyType("webauthn.create"), Challenge: "W8GzFU8pGjhoRbWrLDlamAfq_y4S1CZG1VuoeRLARrE", Origin: "https://webauthn.io", }, AttestationObject: AttestationObject{ Format: "none", RawAuthData: byteAuthData, AuthData: AuthenticatorData{ RPIDHash: byteRPIDHash, Counter: 0, Flags: 0x041, AttData: AttestedCredentialData{ AAGUID: make([]byte, 16), CredentialID: byteID, CredentialPublicKey: byteCredentialPubKey, }, }, }, }, Raw: CredentialCreationResponse{ PublicKeyCredential: PublicKeyCredential{ Credential: Credential{ Type: "public-key", ID: "6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g", }, RawID: byteID, }, AttestationResponse: AuthenticatorAttestationResponse{ AuthenticatorResponse: AuthenticatorResponse{ ClientDataJSON: byteClientDataJSON, }, AttestationObject: byteAttObject, }, }, }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := ParseCredentialCreationResponse(tt.args.response) if (err != nil) != tt.wantErr { t.Errorf("ParseCredentialCreationResponse() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got.Extensions, tt.want.Extensions) { t.Errorf("Extensions = %v \n want: %v", got, tt.want) } if !reflect.DeepEqual(got.ID, tt.want.ID) { t.Errorf("ID = %v \n want: %v", got, tt.want) } if !reflect.DeepEqual(got.ParsedCredential, tt.want.ParsedCredential) { t.Errorf("ParsedCredential = %v \n want: %v", got, tt.want) } if !reflect.DeepEqual(got.ParsedPublicKeyCredential, tt.want.ParsedPublicKeyCredential) { t.Errorf("ParsedPublicKeyCredential = %v \n want: %v", got, tt.want) } if !reflect.DeepEqual(got.Raw, tt.want.Raw) { t.Errorf("Raw = %v \n want: %v", got, tt.want) } if !reflect.DeepEqual(got.RawID, tt.want.RawID) { t.Errorf("RawID = %v \n want: %v", got, tt.want) } // Unmarshall CredentialPublicKey var pkWant interface{} keyBytesWant := tt.want.Response.AttestationObject.AuthData.AttData.CredentialPublicKey cbor.Unmarshal(keyBytesWant, &pkWant) var pkGot interface{} keyBytesGot := got.Response.AttestationObject.AuthData.AttData.CredentialPublicKey cbor.Unmarshal(keyBytesGot, &pkGot) if !reflect.DeepEqual(pkGot, pkWant) { t.Errorf("Response = %+v \n want: %+v", pkGot, pkWant) } if !reflect.DeepEqual(got.Type, tt.want.Type) { t.Errorf("Type = %v \n want: %v", got, tt.want) } if !reflect.DeepEqual(got.Response.CollectedClientData, tt.want.Response.CollectedClientData) { t.Errorf("CollectedClientData = %v \n want: %v", got, tt.want) } if !reflect.DeepEqual(got.Response.AttestationObject.Format, tt.want.Response.AttestationObject.Format) { t.Errorf("Format = %v \n want: %v", got, tt.want) } if !reflect.DeepEqual(got.Response.AttestationObject.AuthData.AttData.CredentialID, tt.want.Response.AttestationObject.AuthData.AttData.CredentialID) { t.Errorf("CredentialID = %v \n want: %v", got, tt.want) } }) } } 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") type fields struct { ParsedPublicKeyCredential ParsedPublicKeyCredential Response ParsedAttestationResponse Raw CredentialCreationResponse } type args struct { storedChallenge Challenge verifyUser bool relyingPartyID string relyingPartyOrigin string } tests := []struct { name string fields fields args args wantErr bool }{ { name: "Successful Verification Test", fields: fields{ ParsedPublicKeyCredential: ParsedPublicKeyCredential{ ParsedCredential: ParsedCredential{ ID: "6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g", Type: "public-key", }, RawID: byteID, }, Response: ParsedAttestationResponse{ CollectedClientData: CollectedClientData{ Type: CeremonyType("webauthn.create"), Challenge: "W8GzFU8pGjhoRbWrLDlamAfq_y4S1CZG1VuoeRLARrE", Origin: "https://webauthn.io", }, AttestationObject: AttestationObject{ Format: "none", RawAuthData: byteAuthData, AuthData: AuthenticatorData{ RPIDHash: byteRPIDHash, Counter: 0, Flags: 0x041, AttData: AttestedCredentialData{ AAGUID: make([]byte, 16), CredentialID: byteID, CredentialPublicKey: byteCredentialPubKey, }, }, }, }, Raw: CredentialCreationResponse{ PublicKeyCredential: PublicKeyCredential{ Credential: Credential{ Type: "public-key", ID: "6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g", }, RawID: byteID, }, AttestationResponse: AuthenticatorAttestationResponse{ AuthenticatorResponse: AuthenticatorResponse{ ClientDataJSON: byteClientDataJSON, }, AttestationObject: byteAttObject, }, }, }, args: args{ storedChallenge: byteChallenge, verifyUser: false, relyingPartyID: `webauthn.io`, relyingPartyOrigin: `https://webauthn.io`, }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { pcc := &ParsedCredentialCreationData{ ParsedPublicKeyCredential: tt.fields.ParsedPublicKeyCredential, Response: tt.fields.Response, Raw: tt.fields.Raw, } if err := pcc.Verify(tt.args.storedChallenge.String(), tt.args.verifyUser, tt.args.relyingPartyID, tt.args.relyingPartyOrigin); (err != nil) != tt.wantErr { t.Errorf("ParsedCredentialCreationData.Verify() error = %+v, wantErr %v", err, tt.wantErr) } }) } } var testCredentialRequestBody = `{ "id":"6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g", "rawId":"6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g", "type":"public-key", "response":{ "attestationObject":"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEdKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOsa7QYSUFukFOLTmgeK6x2ktirNMgwy_6vIwwtegxI2flS1X-JAkZL5dsadg-9bEz2J7PnsbB0B08txvsyUSvKlAQIDJiABIVggLKF5xS0_BntttUIrm2Z2tgZ4uQDwllbdIfrrBMABCNciWCDHwin8Zdkr56iSIh0MrB5qZiEzYLQpEOREhMUkY6q4Vw", "clientDataJSON":"eyJjaGFsbGVuZ2UiOiJXOEd6RlU4cEdqaG9SYldyTERsYW1BZnFfeTRTMUNaRzFWdW9lUkxBUnJFIiwib3JpZ2luIjoiaHR0cHM6Ly93ZWJhdXRobi5pbyIsInR5cGUiOiJ3ZWJhdXRobi5jcmVhdGUifQ" } }` golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/doc.go000066400000000000000000000010501414201525100251570ustar00rootroot00000000000000// The protocol package contains data structures and validation functionality // outlined in the Web Authnentication specification (https://www.w3.org/TR/webauthn). // The data structures here attempt to conform as much as possible to their definitions, // but some structs (like those that are used as part of validation steps) contain // additional fields that help us unpack and validate the data we unmarshall. // When implementing this library, most developers will primarily be using the API // outlined in the webauthn package. package protocol golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/entities.go000066400000000000000000000052401414201525100262430ustar00rootroot00000000000000package protocol // From §5.4.1 (https://www.w3.org/TR/webauthn/#dictionary-pkcredentialentity). // PublicKeyCredentialEntity describes a user account, or a WebAuthn Relying Party, // with which a public key credential is associated. type CredentialEntity struct { // A human-palatable name for the entity. Its function depends on what the PublicKeyCredentialEntity represents: // // When inherited by PublicKeyCredentialRpEntity it is a human-palatable identifier for the Relying Party, // intended only for display. For example, "ACME Corporation", "Wonderful Widgets, Inc." or "ОÐО Примертех". // // When inherited by PublicKeyCredentialUserEntity, it is a human-palatable identifier for a user account. It is // intended only for display, i.e., aiding the user in determining the difference between user accounts with similar // displayNames. For example, "alexm", "alex.p.mueller@example.com" or "+14255551234". Name string `json:"name"` // A serialized URL which resolves to an image associated with the entity. For example, // this could be a user’s avatar or a Relying Party's logo. This URL MUST be an a priori // authenticated URL. Authenticators MUST accept and store a 128-byte minimum length for // an icon member’s value. Authenticators MAY ignore an icon member’s value if its length // is greater than 128 bytes. The URL’s scheme MAY be "data" to avoid fetches of the URL, // at the cost of needing more storage. Icon string `json:"icon,omitempty"` } // From §5.4.2 (https://www.w3.org/TR/webauthn/#sctn-rp-credential-params). // The PublicKeyCredentialRpEntity is used to supply additional // Relying Party attributes when creating a new credential. type RelyingPartyEntity struct { CredentialEntity // A unique identifier for the Relying Party entity, which sets the RP ID. ID string `json:"id"` } // From §5.4.3 (https://www.w3.org/TR/webauthn/#sctn-user-credential-params). // The PublicKeyCredentialUserEntity is used to supply additional // user account attributes when creating a new credential. type UserEntity struct { CredentialEntity // A human-palatable name for the user account, intended only for display. // For example, "Alex P. Müller" or "田中 倫". The Relying Party SHOULD let // the user choose this, and SHOULD NOT restrict the choice more than necessary. DisplayName string `json:"displayName,omitempty"` // ID is the user handle of the user account entity. To ensure secure operation, // authentication and authorization decisions MUST be made on the basis of this id // member, not the displayName nor name members. See Section 6.1 of // [RFC8266](https://www.w3.org/TR/webauthn/#biblio-rfc8266). ID []byte `json:"id"` } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/errors.go000066400000000000000000000042751414201525100257420ustar00rootroot00000000000000package protocol type Error struct { // Short name for the type of error that has occurred Type string `json:"type"` // Additional details about the error Details string `json:"error"` // Information to help debug the error DevInfo string `json:"debug"` } var ( ErrBadRequest = &Error{ Type: "invalid_request", Details: "Error reading the requst data", } ErrChallengeMismatch = &Error{ Type: "challenge_mismatch", Details: "Stored challenge and received challenge do not match", } ErrParsingData = &Error{ Type: "parse_error", Details: "Error parsing the authenticator response", } ErrAuthData = &Error{ Type: "auth_data", Details: "Error verifying the authenticator data", } ErrVerification = &Error{ Type: "verification_error", Details: "Error validating the authenticator response", } ErrAttestation = &Error{ Type: "attesation_error", Details: "Error validating the attestation data provided", } ErrInvalidAttestation = &Error{ Type: "invalid_attestation", Details: "Invalid attestation data", } ErrAttestationFormat = &Error{ Type: "invalid_attestation", Details: "Invalid attestation format", } ErrAttestationCertificate = &Error{ Type: "invalid_certificate", Details: "Invalid attestation certificate", } ErrAssertionSignature = &Error{ Type: "invalid_signature", Details: "Assertion Signature against auth data and client hash is not valid", } ErrUnsupportedKey = &Error{ Type: "invalid_key_type", Details: "Unsupported Public Key Type", } ErrUnsupportedAlgorithm = &Error{ Type: "unsupported_key_algorithm", Details: "Unsupported public key algorithm", } ErrNotSpecImplemented = &Error{ Type: "spec_unimplemented", Details: "This field is not yet supported by the WebAuthn spec", } ErrNotImplemented = &Error{ Type: "not_implemented", Details: "This field is not yet supported by this library", } ) func (err *Error) Error() string { return err.Details } func (passedError *Error) WithDetails(details string) *Error { err := *passedError err.Details = details return &err } func (passedError *Error) WithInfo(info string) *Error { err := *passedError err.DevInfo = info return &err } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/extensions.go000066400000000000000000000005161414201525100266170ustar00rootroot00000000000000package protocol // Extensions are discussed in §9. WebAuthn Extensions (https://www.w3.org/TR/webauthn/#extensions). // For a list of commonly supported extenstions, see §10. Defined Extensions // (https://www.w3.org/TR/webauthn/#sctn-defined-extensions). type AuthenticationExtensionsClientOutputs map[interface{}]interface{} golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/googletpm/000077500000000000000000000000001414201525100260645ustar00rootroot00000000000000golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/googletpm/certinfo.go000066400000000000000000000161771414201525100302400ustar00rootroot00000000000000package googletpm import ( "bytes" "crypto/sha1" "crypto/sha256" "crypto/sha512" "fmt" "hash" ) // DecodeAttestationData decode a TPMS_ATTEST message. No error is returned if // the input has extra trailing data. func DecodeAttestationData(in []byte) (*AttestationData, error) { buf := bytes.NewBuffer(in) var ad AttestationData if err := UnpackBuf(buf, &ad.Magic, &ad.Type); err != nil { return nil, fmt.Errorf("decoding Magic/Type: %v", err) } n, err := decodeName(buf) if err != nil { return nil, fmt.Errorf("decoding QualifiedSigner: %v", err) } ad.QualifiedSigner = *n if err := UnpackBuf(buf, &ad.ExtraData, &ad.ClockInfo, &ad.FirmwareVersion); err != nil { return nil, fmt.Errorf("decoding ExtraData/ClockInfo/FirmwareVersion: %v", err) } // The spec specifies several other types of attestation data. We only need // parsing of Certify & Creation attestation data for now. If you need // support for other attestation types, add them here. switch ad.Type { case TagAttestCertify: if ad.AttestedCertifyInfo, err = decodeCertifyInfo(buf); err != nil { return nil, fmt.Errorf("decoding AttestedCertifyInfo: %v", err) } case TagAttestCreation: if ad.AttestedCreationInfo, err = decodeCreationInfo(buf); err != nil { return nil, fmt.Errorf("decoding AttestedCreationInfo: %v", err) } case TagAttestQuote: if ad.AttestedQuoteInfo, err = decodeQuoteInfo(buf); err != nil { return nil, fmt.Errorf("decoding AttestedQuoteInfo: %v", err) } default: return nil, fmt.Errorf("only Certify & Creation attestation structures are supported, got type 0x%x", ad.Type) } return &ad, nil } // AttestationData contains data attested by TPM commands (like Certify). type AttestationData struct { Magic uint32 Type Tag QualifiedSigner Name ExtraData []byte ClockInfo ClockInfo FirmwareVersion uint64 AttestedCertifyInfo *CertifyInfo AttestedQuoteInfo *QuoteInfo AttestedCreationInfo *CreationInfo } // Tag is a command tag. type Tag uint16 type Name struct { Handle *Handle Digest *HashValue } // A Handle is a reference to a TPM object. type Handle uint32 type HashValue struct { Alg Algorithm Value []byte } // ClockInfo contains TPM state info included in AttestationData. type ClockInfo struct { Clock uint64 ResetCount uint32 RestartCount uint32 Safe byte } // CertifyInfo contains Certify-specific data for TPMS_ATTEST. type CertifyInfo struct { Name Name QualifiedName Name } // QuoteInfo represents a TPMS_QUOTE_INFO structure. type QuoteInfo struct { PCRSelection PCRSelection PCRDigest []byte } // PCRSelection contains a slice of PCR indexes and a hash algorithm used in // them. type PCRSelection struct { Hash Algorithm PCRs []int } // CreationInfo contains Creation-specific data for TPMS_ATTEST. type CreationInfo struct { Name Name // Most TPM2B_Digest structures contain a TPMU_HA structure // and get parsed to HashValue. This is never the case for the // digest in TPMS_CREATION_INFO. OpaqueDigest []byte } func decodeName(in *bytes.Buffer) (*Name, error) { var nameBuf []byte if err := UnpackBuf(in, &nameBuf); err != nil { return nil, err } name := new(Name) switch len(nameBuf) { case 0: // No name is present. case 4: name.Handle = new(Handle) if err := UnpackBuf(bytes.NewBuffer(nameBuf), name.Handle); err != nil { return nil, fmt.Errorf("decoding Handle: %v", err) } default: var err error name.Digest, err = decodeHashValue(bytes.NewBuffer(nameBuf)) if err != nil { return nil, fmt.Errorf("decoding Digest: %v", err) } } return name, nil } func decodeHashValue(in *bytes.Buffer) (*HashValue, error) { var hv HashValue if err := UnpackBuf(in, &hv.Alg); err != nil { return nil, fmt.Errorf("decoding Alg: %v", err) } hfn, ok := hashConstructors[hv.Alg] if !ok { return nil, fmt.Errorf("unsupported hash algorithm type 0x%x", hv.Alg) } hv.Value = make([]byte, hfn().Size()) if _, err := in.Read(hv.Value); err != nil { return nil, fmt.Errorf("decoding Value: %v", err) } return &hv, nil } // HashConstructor returns a function that can be used to make a // hash.Hash using the specified algorithm. An error is returned // if the algorithm is not a hash algorithm. func (a Algorithm) HashConstructor() (func() hash.Hash, error) { c, ok := hashConstructors[a] if !ok { return nil, fmt.Errorf("algorithm not supported: 0x%x", a) } return c, nil } var hashConstructors = map[Algorithm]func() hash.Hash{ AlgSHA1: sha1.New, AlgSHA256: sha256.New, AlgSHA384: sha512.New384, AlgSHA512: sha512.New, } // TPM Structure Tags. Tags are used to disambiguate structures, similar to Alg // values: tag value defines what kind of data lives in a nested field. const ( TagNull Tag = 0x8000 TagNoSessions Tag = 0x8001 TagSessions Tag = 0x8002 TagAttestCertify Tag = 0x8017 TagAttestQuote Tag = 0x8018 TagAttestCreation Tag = 0x801a TagHashCheck Tag = 0x8024 ) func decodeCertifyInfo(in *bytes.Buffer) (*CertifyInfo, error) { var ci CertifyInfo n, err := decodeName(in) if err != nil { return nil, fmt.Errorf("decoding Name: %v", err) } ci.Name = *n n, err = decodeName(in) if err != nil { return nil, fmt.Errorf("decoding QualifiedName: %v", err) } ci.QualifiedName = *n return &ci, nil } func decodeCreationInfo(in *bytes.Buffer) (*CreationInfo, error) { var ci CreationInfo n, err := decodeName(in) if err != nil { return nil, fmt.Errorf("decoding Name: %v", err) } ci.Name = *n if err := UnpackBuf(in, &ci.OpaqueDigest); err != nil { return nil, fmt.Errorf("decoding Digest: %v", err) } return &ci, nil } func decodeQuoteInfo(in *bytes.Buffer) (*QuoteInfo, error) { var out QuoteInfo sel, err := decodeTPMLPCRSelection(in) if err != nil { return nil, fmt.Errorf("decoding PCRSelection: %v", err) } out.PCRSelection = sel if err := UnpackBuf(in, &out.PCRDigest); err != nil { return nil, fmt.Errorf("decoding PCRDigest: %v", err) } return &out, nil } func decodeTPMLPCRSelection(buf *bytes.Buffer) (PCRSelection, error) { var count uint32 var sel PCRSelection if err := UnpackBuf(buf, &count); err != nil { return sel, err } switch count { case 0: sel.Hash = AlgUnknown return sel, nil case 1: // We only support decoding of a single PCRSelection. default: return sel, fmt.Errorf("decoding TPML_PCR_SELECTION list longer than 1 is not supported (got length %d)", count) } // See comment in encodeTPMLPCRSelection for details on this format. var ts tpmsPCRSelection if err := UnpackBuf(buf, &ts.Hash, &ts.Size); err != nil { return sel, err } ts.PCRs = make([]byte, ts.Size) if _, err := buf.Read(ts.PCRs); err != nil { return sel, err } sel.Hash = ts.Hash for i := 0; i < int(ts.Size); i++ { for j := 0; j < 8; j++ { set := ts.PCRs[i] & byte(1<= size { *b = (*b)[:size] } else { *b = append(*b, make([]byte, size-len(*b))...) } case *[]Handle: if len(*b) >= size { *b = (*b)[:size] } else { *b = append(*b, make([]Handle, size-len(*b))...) } default: return fmt.Errorf("can't fill pointer to %T, only []byte or []Handle slices", e) } if err := binary.Read(buf, binary.BigEndian, e); err != nil { return err } default: if err := binary.Read(buf, binary.BigEndian, e); err != nil { return err } } } return nil } // lengthPrefixSize is the size in bytes of length prefix for byte slices. // // In TPM 1.2 this is 4 bytes. // In TPM 2.0 this is 2 bytes. var lengthPrefixSize int const ( tpm12PrefixSize = 4 tpm20PrefixSize = 2 ) // UseTPM20LengthPrefixSize makes Pack/Unpack use TPM 2.0 encoding for byte // arrays. func UseTPM20LengthPrefixSize() { lengthPrefixSize = tpm20PrefixSize } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/googletpm/pubarea.go000066400000000000000000000153321414201525100300360ustar00rootroot00000000000000package googletpm import ( "bytes" "fmt" "math/big" ) // DecodePublic decodes a TPMT_PUBLIC message. No error is returned if // the input has extra trailing data. func DecodePublic(buf []byte) (Public, error) { in := bytes.NewBuffer(buf) var pub Public var err error if err = UnpackBuf(in, &pub.Type, &pub.NameAlg, &pub.Attributes, &pub.AuthPolicy); err != nil { return pub, fmt.Errorf("decoding TPMT_PUBLIC: %v", err) } switch pub.Type { case AlgRSA: pub.RSAParameters, err = decodeRSAParams(in) case AlgECC: pub.ECCParameters, err = decodeECCParams(in) default: err = fmt.Errorf("unsupported type in TPMT_PUBLIC: %v", pub.Type) } return pub, err } // Public contains the public area of an object. type Public struct { Type Algorithm NameAlg Algorithm Attributes KeyProp AuthPolicy []byte // If Type is AlgKeyedHash, then do not set these. // Otherwise, only one of the Parameters fields should be set. When encoding/decoding, // one will be picked based on Type. RSAParameters *RSAParams ECCParameters *ECCParams } // Algorithm represents a TPM_ALG_ID value. type Algorithm uint16 // KeyProp is a bitmask used in Attributes field of key templates. Individual // flags should be OR-ed to form a full mask. type KeyProp uint32 // Key properties. const ( FlagFixedTPM KeyProp = 0x00000002 FlagFixedParent KeyProp = 0x00000010 FlagSensitiveDataOrigin KeyProp = 0x00000020 FlagUserWithAuth KeyProp = 0x00000040 FlagAdminWithPolicy KeyProp = 0x00000080 FlagNoDA KeyProp = 0x00000400 FlagRestricted KeyProp = 0x00010000 FlagDecrypt KeyProp = 0x00020000 FlagSign KeyProp = 0x00040000 FlagSealDefault = FlagFixedTPM | FlagFixedParent FlagSignerDefault = FlagSign | FlagRestricted | FlagFixedTPM | FlagFixedParent | FlagSensitiveDataOrigin | FlagUserWithAuth FlagStorageDefault = FlagDecrypt | FlagRestricted | FlagFixedTPM | FlagFixedParent | FlagSensitiveDataOrigin | FlagUserWithAuth ) func decodeRSAParams(in *bytes.Buffer) (*RSAParams, error) { var params RSAParams var err error if params.Symmetric, err = decodeSymScheme(in); err != nil { return nil, fmt.Errorf("decoding Symmetric: %v", err) } if params.Sign, err = decodeSigScheme(in); err != nil { return nil, fmt.Errorf("decoding Sign: %v", err) } var modBytes []byte if err := UnpackBuf(in, ¶ms.KeyBits, ¶ms.Exponent, &modBytes); err != nil { return nil, fmt.Errorf("decoding KeyBits, Exponent, Modulus: %v", err) } if params.Exponent == 0 { params.encodeDefaultExponentAsZero = true params.Exponent = defaultRSAExponent } params.Modulus = new(big.Int).SetBytes(modBytes) return ¶ms, nil } const defaultRSAExponent = 1<<16 + 1 // RSAParams represents parameters of an RSA key pair. // // Symmetric and Sign may be nil, depending on key Attributes in Public. // // One of Modulus and ModulusRaw must always be non-nil. Modulus takes // precedence. ModulusRaw is used for key templates where the field named // "unique" must be a byte array of all zeroes. type RSAParams struct { Symmetric *SymScheme Sign *SigScheme KeyBits uint16 // The default Exponent (65537) has two representations; the // 0 value, and the value 65537. // If encodeDefaultExponentAsZero is set, an exponent of 65537 // will be encoded as zero. This is necessary to produce an identical // encoded bitstream, so Name digest calculations will be correct. encodeDefaultExponentAsZero bool Exponent uint32 ModulusRaw []byte Modulus *big.Int } // SymScheme represents a symmetric encryption scheme. type SymScheme struct { Alg Algorithm KeyBits uint16 Mode Algorithm } // SigScheme represents a signing scheme. type SigScheme struct { Alg Algorithm Hash Algorithm Count uint32 } func decodeSigScheme(in *bytes.Buffer) (*SigScheme, error) { var scheme SigScheme if err := UnpackBuf(in, &scheme.Alg); err != nil { return nil, fmt.Errorf("decoding Alg: %v", err) } if scheme.Alg == AlgNull { return nil, nil } if err := UnpackBuf(in, &scheme.Hash); err != nil { return nil, fmt.Errorf("decoding Hash: %v", err) } if scheme.Alg.UsesCount() { if err := UnpackBuf(in, &scheme.Count); err != nil { return nil, fmt.Errorf("decoding Count: %v", err) } } return &scheme, nil } // UsesCount returns true if a signature algorithm uses count value. func (a Algorithm) UsesCount() bool { return a == AlgECDAA } func decodeKDFScheme(in *bytes.Buffer) (*KDFScheme, error) { var scheme KDFScheme if err := UnpackBuf(in, &scheme.Alg); err != nil { return nil, fmt.Errorf("decoding Alg: %v", err) } if scheme.Alg == AlgNull { return nil, nil } if err := UnpackBuf(in, &scheme.Hash); err != nil { return nil, fmt.Errorf("decoding Hash: %v", err) } return &scheme, nil } func decodeSymScheme(in *bytes.Buffer) (*SymScheme, error) { var scheme SymScheme if err := UnpackBuf(in, &scheme.Alg); err != nil { return nil, fmt.Errorf("decoding Alg: %v", err) } if scheme.Alg == AlgNull { return nil, nil } if err := UnpackBuf(in, &scheme.KeyBits, &scheme.Mode); err != nil { return nil, fmt.Errorf("decoding KeyBits, Mode: %v", err) } return &scheme, nil } func decodeECCParams(in *bytes.Buffer) (*ECCParams, error) { var params ECCParams var err error if params.Symmetric, err = decodeSymScheme(in); err != nil { return nil, fmt.Errorf("decoding Symmetric: %v", err) } if params.Sign, err = decodeSigScheme(in); err != nil { return nil, fmt.Errorf("decoding Sign: %v", err) } if err := UnpackBuf(in, ¶ms.CurveID); err != nil { return nil, fmt.Errorf("decoding CurveID: %v", err) } if params.KDF, err = decodeKDFScheme(in); err != nil { return nil, fmt.Errorf("decoding KDF: %v", err) } var x, y []byte if err := UnpackBuf(in, &x, &y); err != nil { return nil, fmt.Errorf("decoding Point: %v", err) } params.Point.X = new(big.Int).SetBytes(x) params.Point.Y = new(big.Int).SetBytes(y) return ¶ms, nil } // ECCParams represents parameters of an ECC key pair. // // Symmetric, Sign and KDF may be nil, depending on key Attributes in Public. type ECCParams struct { Symmetric *SymScheme Sign *SigScheme CurveID EllipticCurve KDF *KDFScheme Point ECPoint } // EllipticCurve identifies specific EC curves. type EllipticCurve uint16 // ECC curves supported by TPM 2.0 spec. const ( CurveNISTP192 = EllipticCurve(iota + 1) CurveNISTP224 CurveNISTP256 CurveNISTP384 CurveNISTP521 CurveBNP256 = EllipticCurve(iota + 10) CurveBNP638 CurveSM2P256 = EllipticCurve(0x0020) ) // ECPoint represents a ECC coordinates for a point. type ECPoint struct { X, Y *big.Int } // KDFScheme represents a KDF (Key Derivation Function) scheme. type KDFScheme struct { Alg Algorithm Hash Algorithm } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/options.go000066400000000000000000000156661414201525100261270ustar00rootroot00000000000000package protocol import ( "github.com/duo-labs/webauthn/protocol/webauthncose" ) type CredentialCreation struct { Response PublicKeyCredentialCreationOptions `json:"publicKey"` } type CredentialAssertion struct { Response PublicKeyCredentialRequestOptions `json:"publicKey"` } // In order to create a Credential via create(), the caller specifies a few parameters in a CredentialCreationOptions object. // See §5.4. Options for Credential Creation https://www.w3.org/TR/webauthn/#dictionary-makecredentialoptions type PublicKeyCredentialCreationOptions struct { Challenge Challenge `json:"challenge"` RelyingParty RelyingPartyEntity `json:"rp"` User UserEntity `json:"user"` Parameters []CredentialParameter `json:"pubKeyCredParams,omitempty"` AuthenticatorSelection AuthenticatorSelection `json:"authenticatorSelection,omitempty"` Timeout int `json:"timeout,omitempty"` CredentialExcludeList []CredentialDescriptor `json:"excludeCredentials,omitempty"` Extensions AuthenticationExtensions `json:"extensions,omitempty"` Attestation ConveyancePreference `json:"attestation,omitempty"` } // The PublicKeyCredentialRequestOptions dictionary supplies get() with the data it needs to generate an assertion. // Its challenge member MUST be present, while its other members are OPTIONAL. // See §5.5. Options for Assertion Generation https://www.w3.org/TR/webauthn/#assertion-options type PublicKeyCredentialRequestOptions struct { Challenge Challenge `json:"challenge"` Timeout int `json:"timeout,omitempty"` RelyingPartyID string `json:"rpId,omitempty"` AllowedCredentials []CredentialDescriptor `json:"allowCredentials,omitempty"` UserVerification UserVerificationRequirement `json:"userVerification,omitempty"` // Default is "preferred" Extensions AuthenticationExtensions `json:"extensions,omitempty"` } // This dictionary contains the attributes that are specified by a caller when referring to a public // key credential as an input parameter to the create() or get() methods. It mirrors the fields of // the PublicKeyCredential object returned by the latter methods. // See §5.10.3. Credential Descriptor https://www.w3.org/TR/webauthn/#credential-dictionary type CredentialDescriptor struct { // The valid credential types. Type CredentialType `json:"type"` // CredentialID The ID of a credential to allow/disallow CredentialID []byte `json:"id"` // The authenticator transports that can be used Transport []AuthenticatorTransport `json:"transports,omitempty"` } // CredentialParameter is the credential type and algorithm // that the relying party wants the authenticator to create type CredentialParameter struct { Type CredentialType `json:"type"` Algorithm webauthncose.COSEAlgorithmIdentifier `json:"alg"` } // This enumeration defines the valid credential types. // It is an extension point; values can be added to it in the future, as // more credential types are defined. The values of this enumeration are used // for versioning the Authentication Assertion and attestation structures according // to the type of the authenticator. // See §5.10.3. Credential Descriptor https://www.w3.org/TR/webauthn/#credentialType type CredentialType string const ( // PublicKeyCredentialType - Currently one credential type is defined, namely "public-key". PublicKeyCredentialType CredentialType = "public-key" ) // AuthenticationExtensions - referred to as AuthenticationExtensionsClientInputs in the // spec document, this member contains additional parameters requesting additional processing // by the client and authenticator. // This is currently under development type AuthenticationExtensions map[string]interface{} // WebAuthn Relying Parties may use the AuthenticatorSelectionCriteria dictionary to specify their requirements // regarding authenticator attributes. See §5.4.4. Authenticator Selection Criteria // https://www.w3.org/TR/webauthn/#authenticatorSelection type AuthenticatorSelection struct { // AuthenticatorAttachment If this member is present, eligible authenticators are filtered to only // authenticators attached with the specified AuthenticatorAttachment enum AuthenticatorAttachment AuthenticatorAttachment `json:"authenticatorAttachment,omitempty"` // RequireResidentKey this member describes the Relying Party's requirements regarding resident // credentials. If the parameter is set to true, the authenticator MUST create a client-side-resident // public key credential source when creating a public key credential. RequireResidentKey *bool `json:"requireResidentKey,omitempty"` // UserVerification This member describes the Relying Party's requirements regarding user verification for // the create() operation. Eligible authenticators are filtered to only those capable of satisfying this // requirement. UserVerification UserVerificationRequirement `json:"userVerification,omitempty"` } // WebAuthn Relying Parties may use AttestationConveyancePreference to specify their preference regarding // attestation conveyance during credential generation. See §5.4.6. https://www.w3.org/TR/webauthn/#attestation-convey type ConveyancePreference string const ( // The default value. This value indicates that the Relying Party is not interested in authenticator attestation. For example, // in order to potentially avoid having to obtain user consent to relay identifying information to the Relying Party, or to // save a roundtrip to an Attestation CA. PreferNoAttestation ConveyancePreference = "none" // This value indicates that the Relying Party prefers an attestation conveyance yielding verifiable attestation // statements, but allows the client to decide how to obtain such attestation statements. The client MAY replace // the authenticator-generated attestation statements with attestation statements generated by an Anonymization // CA, in order to protect the user’s privacy, or to assist Relying Parties with attestation verification in a // heterogeneous ecosystem. PreferIndirectAttestation ConveyancePreference = "indirect" // This value indicates that the Relying Party wants to receive the attestation statement as generated by the authenticator. PreferDirectAttestation ConveyancePreference = "direct" ) func (a *PublicKeyCredentialRequestOptions) GetAllowedCredentialIDs() [][]byte { var allowedCredentialIDs = make([][]byte, len(a.AllowedCredentials)) for i, credential := range a.AllowedCredentials { allowedCredentialIDs[i] = credential.CredentialID } return allowedCredentialIDs } type Extensions interface{} type ServerResponse struct { Status ServerResponseStatus `json:"status"` Message string `json:"errorMessage"` } type ServerResponseStatus string const ( StatusOk ServerResponseStatus = "ok" StatusFailed ServerResponseStatus = "failed" ) golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/options_test.go000066400000000000000000000030151414201525100271470ustar00rootroot00000000000000package protocol import ( "reflect" "testing" ) func TestPublicKeyCredentialRequestOptions_GetAllowedCredentialIDs(t *testing.T) { type fields struct { Challenge Challenge Timeout int RelyingPartyID string AllowedCredentials []CredentialDescriptor UserVerification UserVerificationRequirement Extensions AuthenticationExtensions } tests := []struct { name string fields fields want [][]byte }{ { "Correct Credential IDs", fields{ Challenge: Challenge([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), Timeout: 60, AllowedCredentials: []CredentialDescriptor{ { "public-key", []byte("1234"), []AuthenticatorTransport{"usb"}, }, }, RelyingPartyID: "test.org", UserVerification: VerificationPreferred, Extensions: AuthenticationExtensions{}, }, [][]byte{ []byte("1234"), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { a := &PublicKeyCredentialRequestOptions{ Challenge: tt.fields.Challenge, Timeout: tt.fields.Timeout, RelyingPartyID: tt.fields.RelyingPartyID, AllowedCredentials: tt.fields.AllowedCredentials, UserVerification: tt.fields.UserVerification, Extensions: tt.fields.Extensions, } if got := a.GetAllowedCredentialIDs(); !reflect.DeepEqual(got, tt.want) { t.Errorf("PublicKeyCredentialRequestOptions.GetAllowedCredentialIDs() = %v, want %v", got, tt.want) } }) } } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/signature_algorithms.go000066400000000000000000000000211414201525100306410ustar00rootroot00000000000000package protocol golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/webauthncose/000077500000000000000000000000001414201525100265565ustar00rootroot00000000000000golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/webauthncose/ed25519.go000066400000000000000000000003041414201525100301000ustar00rootroot00000000000000// +build go1.13 package webauthncose import ( "crypto/ed25519" "crypto/x509" ) func marshalEd25519PublicKey(pub ed25519.PublicKey) ([]byte, error) { return x509.MarshalPKIXPublicKey(pub) } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/webauthncose/ed25519_go112.go000066400000000000000000000015531414201525100310200ustar00rootroot00000000000000// +build !go1.13 package webauthncose import ( "crypto/x509/pkix" "encoding/asn1" "golang.org/x/crypto/ed25519" ) var oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112} type pkixPublicKey struct { Algo pkix.AlgorithmIdentifier BitString asn1.BitString } // marshalEd25519PublicKey is a backport of the functionality introduced in // Go v1.13. // Ref: https://golang.org/doc/go1.13#crypto/ed25519 // Ref: https://golang.org/doc/go1.13#crypto/x509 func marshalEd25519PublicKey(pub ed25519.PublicKey) ([]byte, error) { publicKeyBytes := pub var publicKeyAlgorithm pkix.AlgorithmIdentifier publicKeyAlgorithm.Algorithm = oidSignatureEd25519 pkix := pkixPublicKey{ Algo: publicKeyAlgorithm, BitString: asn1.BitString{ Bytes: publicKeyBytes, BitLength: 8 * len(publicKeyBytes), }, } ret, _ := asn1.Marshal(pkix) return ret, nil } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/webauthncose/webauthncose.go000066400000000000000000000257301414201525100316030ustar00rootroot00000000000000package webauthncose import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rsa" "crypto/x509" "encoding/asn1" "encoding/pem" "fmt" "hash" "math/big" "golang.org/x/crypto/ed25519" "github.com/fxamacker/cbor/v2" ) // PublicKeyData The public key portion of a Relying Party-specific credential key pair, generated // by an authenticator and returned to a Relying Party at registration time. We unpack this object // using fxamacker's cbor library ("github.com/fxamacker/cbor/v2") which is why there are cbor tags // included. The tag field values correspond to the IANA COSE keys that give their respective // values. // See §6.4.1.1 https://www.w3.org/TR/webauthn/#sctn-encoded-credPubKey-examples for examples of this // COSE data. type PublicKeyData struct { // Decode the results to int by default. _struct bool `cbor:",keyasint" json:"public_key"` // The type of key created. Should be OKP, EC2, or RSA. KeyType int64 `cbor:"1,keyasint" json:"kty"` // A COSEAlgorithmIdentifier for the algorithm used to derive the key signature. Algorithm int64 `cbor:"3,keyasint" json:"alg"` } type EC2PublicKeyData struct { PublicKeyData // If the key type is EC2, the curve on which we derive the signature from. Curve int64 `cbor:"-1,keyasint,omitempty" json:"crv"` // A byte string 32 bytes in length that holds the x coordinate of the key. XCoord []byte `cbor:"-2,keyasint,omitempty" json:"x"` // A byte string 32 bytes in length that holds the y coordinate of the key. YCoord []byte `cbor:"-3,keyasint,omitempty" json:"y"` } type RSAPublicKeyData struct { PublicKeyData // Represents the modulus parameter for the RSA algorithm Modulus []byte `cbor:"-1,keyasint,omitempty" json:"n"` // Represents the exponent parameter for the RSA algorithm Exponent []byte `cbor:"-2,keyasint,omitempty" json:"e"` } type OKPPublicKeyData struct { PublicKeyData Curve int64 // A byte string that holds the x coordinate of the key. XCoord []byte `cbor:"-2,keyasint,omitempty" json:"x"` } // Verify Octet Key Pair (OKP) Public Key Signature func (k *OKPPublicKeyData) Verify(data []byte, sig []byte) (bool, error) { var key ed25519.PublicKey = make([]byte, ed25519.PublicKeySize) copy(key, k.XCoord) return ed25519.Verify(key, data, sig), nil } // Verify Elliptic Curce Public Key Signature func (k *EC2PublicKeyData) Verify(data []byte, sig []byte) (bool, error) { var curve elliptic.Curve switch COSEAlgorithmIdentifier(k.Algorithm) { case AlgES512: // IANA COSE code for ECDSA w/ SHA-512 curve = elliptic.P521() case AlgES384: // IANA COSE code for ECDSA w/ SHA-384 curve = elliptic.P384() case AlgES256: // IANA COSE code for ECDSA w/ SHA-256 curve = elliptic.P256() default: return false, ErrUnsupportedAlgorithm } pubkey := &ecdsa.PublicKey{ Curve: curve, X: big.NewInt(0).SetBytes(k.XCoord), Y: big.NewInt(0).SetBytes(k.YCoord), } type ECDSASignature struct { R, S *big.Int } e := &ECDSASignature{} f := HasherFromCOSEAlg(COSEAlgorithmIdentifier(k.PublicKeyData.Algorithm)) h := f() h.Write(data) _, err := asn1.Unmarshal(sig, e) if err != nil { return false, ErrSigNotProvidedOrInvalid } return ecdsa.Verify(pubkey, h.Sum(nil), e.R, e.S), nil } // Verify RSA Public Key Signature func (k *RSAPublicKeyData) Verify(data []byte, sig []byte) (bool, error) { pubkey := &rsa.PublicKey{ N: big.NewInt(0).SetBytes(k.Modulus), E: int(uint(k.Exponent[2]) | uint(k.Exponent[1])<<8 | uint(k.Exponent[0])<<16), } f := HasherFromCOSEAlg(COSEAlgorithmIdentifier(k.PublicKeyData.Algorithm)) h := f() h.Write(data) var hash crypto.Hash switch COSEAlgorithmIdentifier(k.PublicKeyData.Algorithm) { case AlgRS1: hash = crypto.SHA1 case AlgPS256, AlgRS256: hash = crypto.SHA256 case AlgPS384, AlgRS384: hash = crypto.SHA384 case AlgPS512, AlgRS512: hash = crypto.SHA512 default: return false, ErrUnsupportedAlgorithm } switch COSEAlgorithmIdentifier(k.PublicKeyData.Algorithm) { case AlgPS256, AlgPS384, AlgPS512: err := rsa.VerifyPSS(pubkey, hash, h.Sum(nil), sig, nil) return err == nil, err case AlgRS1, AlgRS256, AlgRS384, AlgRS512: err := rsa.VerifyPKCS1v15(pubkey, hash, h.Sum(nil), sig) return err == nil, err default: return false, ErrUnsupportedAlgorithm } } // Return which signature algorithm is being used from the COSE Key func SigAlgFromCOSEAlg(coseAlg COSEAlgorithmIdentifier) SignatureAlgorithm { for _, details := range SignatureAlgorithmDetails { if details.coseAlg == coseAlg { return details.algo } } return UnknownSignatureAlgorithm } // Return the Hashing interface to be used for a given COSE Algorithm func HasherFromCOSEAlg(coseAlg COSEAlgorithmIdentifier) func() hash.Hash { for _, details := range SignatureAlgorithmDetails { if details.coseAlg == coseAlg { return details.hasher } } // default to SHA256? Why not. return crypto.SHA256.New } // Figure out what kind of COSE material was provided and create the data for the new key func ParsePublicKey(keyBytes []byte) (interface{}, error) { pk := PublicKeyData{} cbor.Unmarshal(keyBytes, &pk) switch COSEKeyType(pk.KeyType) { case OctetKey: var o OKPPublicKeyData cbor.Unmarshal(keyBytes, &o) o.PublicKeyData = pk return o, nil case EllipticKey: var e EC2PublicKeyData cbor.Unmarshal(keyBytes, &e) e.PublicKeyData = pk return e, nil case RSAKey: var r RSAPublicKeyData cbor.Unmarshal(keyBytes, &r) r.PublicKeyData = pk return r, nil default: return nil, ErrUnsupportedKey } } // COSEAlgorithmIdentifier From §5.10.5. A number identifying a cryptographic algorithm. The algorithm // identifiers SHOULD be values registered in the IANA COSE Algorithms registry // [https://www.w3.org/TR/webauthn/#biblio-iana-cose-algs-reg], for instance, -7 for "ES256" // and -257 for "RS256". type COSEAlgorithmIdentifier int const ( // AlgES256 ECDSA with SHA-256 AlgES256 COSEAlgorithmIdentifier = -7 // AlgES384 ECDSA with SHA-384 AlgES384 COSEAlgorithmIdentifier = -35 // AlgES512 ECDSA with SHA-512 AlgES512 COSEAlgorithmIdentifier = -36 // AlgRS1 RSASSA-PKCS1-v1_5 with SHA-1 AlgRS1 COSEAlgorithmIdentifier = -65535 // AlgRS256 RSASSA-PKCS1-v1_5 with SHA-256 AlgRS256 COSEAlgorithmIdentifier = -257 // AlgRS384 RSASSA-PKCS1-v1_5 with SHA-384 AlgRS384 COSEAlgorithmIdentifier = -258 // AlgRS512 RSASSA-PKCS1-v1_5 with SHA-512 AlgRS512 COSEAlgorithmIdentifier = -259 // AlgPS256 RSASSA-PSS with SHA-256 AlgPS256 COSEAlgorithmIdentifier = -37 // AlgPS384 RSASSA-PSS with SHA-384 AlgPS384 COSEAlgorithmIdentifier = -38 // AlgPS512 RSASSA-PSS with SHA-512 AlgPS512 COSEAlgorithmIdentifier = -39 // AlgEdDSA EdDSA AlgEdDSA COSEAlgorithmIdentifier = -8 ) // The Key Type derived from the IANA COSE AuthData type COSEKeyType int const ( // OctetKey is an Octet Key OctetKey COSEKeyType = 1 // EllipticKey is an Elliptic Curve Public Key EllipticKey COSEKeyType = 2 // RSAKey is an RSA Public Key RSAKey COSEKeyType = 3 ) func VerifySignature(key interface{}, data []byte, sig []byte) (bool, error) { switch key.(type) { case OKPPublicKeyData: o := key.(OKPPublicKeyData) return o.Verify(data, sig) case EC2PublicKeyData: e := key.(EC2PublicKeyData) return e.Verify(data, sig) case RSAPublicKeyData: r := key.(RSAPublicKeyData) return r.Verify(data, sig) default: return false, ErrUnsupportedKey } } func DisplayPublicKey(cpk []byte) string { parsedKey, err := ParsePublicKey(cpk) if err != nil { return "Cannot display key" } switch parsedKey.(type) { case RSAPublicKeyData: pKey := parsedKey.(RSAPublicKeyData) rKey := &rsa.PublicKey{ N: big.NewInt(0).SetBytes(pKey.Modulus), E: int(uint(pKey.Exponent[2]) | uint(pKey.Exponent[1])<<8 | uint(pKey.Exponent[0])<<16), } data, err := x509.MarshalPKIXPublicKey(rKey) if err != nil { return "Cannot display key" } pemBytes := pem.EncodeToMemory(&pem.Block{ Type: "RSA PUBLIC KEY", Bytes: data, }) return fmt.Sprintf("%s", pemBytes) case EC2PublicKeyData: pKey := parsedKey.(EC2PublicKeyData) var curve elliptic.Curve switch COSEAlgorithmIdentifier(pKey.Algorithm) { case AlgES256: curve = elliptic.P256() case AlgES384: curve = elliptic.P384() case AlgES512: curve = elliptic.P521() default: return "Cannot display key" } eKey := &ecdsa.PublicKey{ Curve: curve, X: big.NewInt(0).SetBytes(pKey.XCoord), Y: big.NewInt(0).SetBytes(pKey.YCoord), } data, err := x509.MarshalPKIXPublicKey(eKey) if err != nil { return "Cannot display key" } pemBytes := pem.EncodeToMemory(&pem.Block{ Type: "PUBLIC KEY", Bytes: data, }) return fmt.Sprintf("%s", pemBytes) case OKPPublicKeyData: pKey := parsedKey.(OKPPublicKeyData) if len(pKey.XCoord) != ed25519.PublicKeySize { return "Cannot display key" } var oKey ed25519.PublicKey = make([]byte, ed25519.PublicKeySize) copy(oKey, pKey.XCoord) data, err := marshalEd25519PublicKey(oKey) if err != nil { return "Cannot display key" } pemBytes := pem.EncodeToMemory(&pem.Block{ Type: "PUBLIC KEY", Bytes: data, }) return fmt.Sprintf("%s", pemBytes) default: return "Cannot display key of this type" } } // Algorithm enumerations used for type SignatureAlgorithm int const ( UnknownSignatureAlgorithm SignatureAlgorithm = iota MD2WithRSA MD5WithRSA SHA1WithRSA SHA256WithRSA SHA384WithRSA SHA512WithRSA DSAWithSHA1 DSAWithSHA256 ECDSAWithSHA1 ECDSAWithSHA256 ECDSAWithSHA384 ECDSAWithSHA512 SHA256WithRSAPSS SHA384WithRSAPSS SHA512WithRSAPSS ) var SignatureAlgorithmDetails = []struct { algo SignatureAlgorithm coseAlg COSEAlgorithmIdentifier name string hasher func() hash.Hash }{ {SHA1WithRSA, AlgRS1, "SHA1-RSA", crypto.SHA1.New}, {SHA256WithRSA, AlgRS256, "SHA256-RSA", crypto.SHA256.New}, {SHA384WithRSA, AlgRS384, "SHA384-RSA", crypto.SHA384.New}, {SHA512WithRSA, AlgRS512, "SHA512-RSA", crypto.SHA512.New}, {SHA256WithRSAPSS, AlgPS256, "SHA256-RSAPSS", crypto.SHA256.New}, {SHA384WithRSAPSS, AlgPS384, "SHA384-RSAPSS", crypto.SHA384.New}, {SHA512WithRSAPSS, AlgPS512, "SHA512-RSAPSS", crypto.SHA512.New}, {ECDSAWithSHA256, AlgES256, "ECDSA-SHA256", crypto.SHA256.New}, {ECDSAWithSHA384, AlgES384, "ECDSA-SHA384", crypto.SHA384.New}, {ECDSAWithSHA512, AlgES512, "ECDSA-SHA512", crypto.SHA512.New}, {UnknownSignatureAlgorithm, AlgEdDSA, "EdDSA", crypto.SHA512.New}, } type Error struct { // Short name for the type of error that has occurred Type string `json:"type"` // Additional details about the error Details string `json:"error"` // Information to help debug the error DevInfo string `json:"debug"` } var ( ErrUnsupportedKey = &Error{ Type: "invalid_key_type", Details: "Unsupported Public Key Type", } ErrUnsupportedAlgorithm = &Error{ Type: "unsupported_key_algorithm", Details: "Unsupported public key algorithm", } ErrSigNotProvidedOrInvalid = &Error{ Type: "signature_not_provided_or_invalid", Details: "Signature invalid or not provided", } ) func (err *Error) Error() string { return err.Details } func (passedError *Error) WithDetails(details string) *Error { err := *passedError err.Details = details return &err } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/protocol/webauthncose/webauthncose_test.go000066400000000000000000000040641414201525100326370ustar00rootroot00000000000000package webauthncose import ( "crypto/rand" "testing" "github.com/fxamacker/cbor/v2" "golang.org/x/crypto/ed25519" ) // TestOKPSignatureVerification is a compatibility test to ensure that removing // a previously used dependency doesn't introduce new issues. // // Since OKPs are used to represent Ed25519 keys, this test largely ensures // that the underlying Ed25519 signature verification passes. func TestOKPSignatureVerification(t *testing.T) { pub, priv, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatalf("error creating ed25519 key: %v", err) } data := []byte("Sample data to sign") validSig := ed25519.Sign(priv, data) invalidSig := []byte("invalid") key := OKPPublicKeyData{ XCoord: pub, } // Test that a valid signature passes ok, err := key.Verify(data, validSig) if err != nil { t.Fatalf("error verifying okp signature: %v", err) } if !ok { t.Fatalf("valid signature wasn't properly verified") } // And that an invalid signature fails ok, err = key.Verify(data, invalidSig) if err != nil { t.Fatalf("error verifying okp signature: %v", err) } if ok { t.Fatalf("invalid signature was incorrectly verified") } } func TestOKPDisplayPublicKey(t *testing.T) { // Sample public key generated from ed25519.GenerateKey(rand.Reader) var pub ed25519.PublicKey = []byte{0x7b, 0x88, 0x10, 0x24, 0xad, 0xc9, 0x82, 0xd3, 0x80, 0xb8, 0x77, 0x1e, 0x3b, 0x9b, 0xf8, 0xe4, 0xb3, 0x99, 0x8b, 0xc7, 0xd0, 0x58, 0x30, 0x66, 0x2, 0xce, 0x4d, 0xf, 0x2f, 0xe4, 0xb7, 0x81} // The PEM encoded representation of the public key in PKIX, ASN.1 DER format. expected := `-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEAe4gQJK3JgtOAuHceO5v45LOZi8fQWDBmAs5NDy/kt4E= -----END PUBLIC KEY----- ` key := OKPPublicKeyData{ XCoord: pub, PublicKeyData: PublicKeyData{ KeyType: int64(OctetKey), }, } // Get the CBOR-encoded representation of the OKPPublicKeyData buf, _ := cbor.Marshal(key) got := DisplayPublicKey(buf) if got != expected { t.Fatalf("incorrect PEM format received for ed25519 public key. expected\n%#v\n got \n%#v\n", expected, got) } } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/testdata/000077500000000000000000000000001414201525100240375ustar00rootroot00000000000000golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/testdata/MetadataTOCParsing-F1.jwt000077500000000000000000001265421414201525100304600ustar00rootroot00000000000000eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlDenpDQ0FuV2dBd0lCQWdJUEJLV3k0ZEhyQ1FQeHREcnc5MnRUTUFvR0NDcUdTTTQ5QkFNQ01HY3hDekFKQmdOVkJBWVRBbFZUTVJZd0ZBWURWUVFLREExR1NVUlBJRUZzYkdsaGJtTmxNU2N3SlFZRFZRUUxEQjVHUVV0RklFMWxkR0ZrWVhSaElGUlBReUJUYVdkdWFXNW5JRVpCUzBVeEZ6QVZCZ05WQkFNTURrWkJTMFVnUTBFdE1TQkdRVXRGTUI0WERURTNNREl3TVRBd01EQXdNRm9YRFRNd01ERXpNVEl6TlRrMU9Wb3dlREVMTUFrR0ExVUVCaE1DVlZNeEZqQVVCZ05WQkFvTURVWkpSRThnUVd4c2FXRnVZMlV4SnpBbEJnTlZCQXNNSGtaQlMwVWdUV1YwWVdSaGRHRWdWRTlESUZOcFoyNXBibWNnUmtGTFJURW9NQ1lHQTFVRUF3d2ZSa0ZMUlNCTlpYUmhaR0YwWVNCVVQwTWdVMmxuYm1WeUlEUWdSa0ZMUlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkhrUUV6NVBnbk1hM0xYb2ZCYWlPc1lsTWNabmNBNlh1TXBCRkNvVEU0eE0vYWJTRGpjUVREcW1DRVdTdms0eHJqL3BZajNUdzdkSXd2ZkpLUWlNVmFpamdmSXdnZTh3Q3dZRFZSMFBCQVFEQWdiQU1Bd0dBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRkx3QU10ZkhrVWdmbHc2bXlvUGt3WTB4U0g3bU1COEdBMVVkSXdRWU1CYUFGRkJhVWJ4bzloS1U5TVNQQVhPeUFkenVqRDh5TUQ4R0ExVWRId1E0TURZd05LQXlvRENHTG1oMGRIQnpPaTh2Wm1sa2IyRnNiR2xoYm1ObExtTnZMbTU2TDIxa2N5OWpjbXd2VFVSVFEwRXRNUzVqY213d1VRWURWUjBnQkVvd1NEQkdCZ3NyQmdFRUFZTGxIQUVEQVRBM01EVUdDQ3NHQVFVRkJ3SUJGaWxvZEhSd2N6b3ZMMlpwWkc5aGJHeHBZVzVqWlM1amJ5NXVlaTl0WkhNdmNtVndiM05wZEc5eWVUQUtCZ2dxaGtqT1BRUURBZ05JQURCRkFpQWg3QXlFZzZ3SmdrRTZzdGZDdUtyMGExVkJkL3NWd1JkZmI0V0FXT1pLc0FJaEFMYktYUVRFNEl1aTlET0kxV0c0c1ZVVXJFQSs0cFZ4VzVxL2RwQ2ttbEx0IiwiTUlJQzR6Q0NBbWlnQXdJQkFnSVFCQ1pZZldidkF0Q2lDaURremxWQk5qQUtCZ2dxaGtqT1BRUURBekJuTVFzd0NRWURWUVFHRXdKVlV6RVdNQlFHQTFVRUNnd05Sa2xFVHlCQmJHeHBZVzVqWlRFbk1DVUdBMVVFQ3d3ZVJrRkxSU0JOWlhSaFpHRjBZU0JVVDBNZ1UybG5ibWx1WnlCR1FVdEZNUmN3RlFZRFZRUUREQTVHUVV0RklGSnZiM1FnUmtGTFJUQWVGdzB4TnpBeU1ERXdNREF3TURCYUZ3MDBNREF4TXpFeU16VTVOVGxhTUdjeEN6QUpCZ05WQkFZVEFsVlRNUll3RkFZRFZRUUtEQTFHU1VSUElFRnNiR2xoYm1ObE1TY3dKUVlEVlFRTERCNUdRVXRGSUUxbGRHRmtZWFJoSUZSUFF5QlRhV2R1YVc1bklFWkJTMFV4RnpBVkJnTlZCQU1NRGtaQlMwVWdRMEV0TVNCR1FVdEZNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUV5MzMveXFLc3piRDlwMy9qdlFVR1dZNFoyUGVEMXVoV2VrQVN1NnVlTjlhMnFHQTBCRFB1V2E1azMycVZ6OVFzUEZPb0R3c1IwYWtnSWYxaTR4REUwYU9COVRDQjhqQUxCZ05WSFE4RUJBTUNBUVl3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVVUZwUnZHajJFcFQweEk4QmM3SUIzTzZNUHpJd0h3WURWUjBqQkJnd0ZvQVUzZmVheUJ6djRWL1RvZXZiTTE4dzlHb1ptVmt3UHdZRFZSMGZCRGd3TmpBMG9ES2dNSVl1YUhSMGNITTZMeTltYVdSdllXeHNhV0Z1WTJVdVkyOHVibm92YldSekwyTnliQzlOUkZOU1QwOVVMbU55YkRCUkJnTlZIU0FFU2pCSU1FWUdDeXNHQVFRQmd1VWNBUU1CTURjd05RWUlLd1lCQlFVSEFnRVdLV2gwZEhCek9pOHZabWxrYjJGc2JHbGhibU5sTG1OdkxtNTZMMjFrY3k5eVpYQnZjMmwwYjNKNU1Bb0dDQ3FHU000OUJBTURBMmtBTUdZQ01RREFaY3N5QzhScnBLOVBoVHdSNHNLcGkzcWh3SGthY01VNUN6WStDa2ZyTXA2VW9EY1A4RmVTcmw1L29PemYrbHNDTVFEUjBOZzF2bk9ZbUo2NUdvb2hMNWlDQXNkLzBQVUIraVk1RGJhNHZPdmgrWlR5SWtFQU1VdFJGc1MzMnR1dG00VT0iXX0.eyJsZWdhbEhlYWRlciI6IkJ5IHVzaW5nIHRoaXMgbWV0YWRhdGEgc2VydmljZSwgeW91IGFyZSBzb2xlbWx5IHN3ZWFyIG5vdCB0byBkbyBldmlsISIsIm5vIjo0MiwibmV4dFVwZGF0ZSI6IjIwMjAtMDQtMDgiLCJlbnRyaWVzIjpbeyJhYWd1aWQiOiJkYTYzZDNlNy1jZGU5LTQyZmQtOWI1ZS1kOThkOTQ4NGQ2NGEiLCJoYXNoIjoiMUVvZjA0eDg1YlRqNHp5b25lb1NNRTgzWmtNZmhRenNHb09nMU1SczczRSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9kYTYzZDNlNy1jZGU5LTQyZmQtOWI1ZS1kOThkOTQ4NGQ2NGEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDYtMDcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAyLTEwIn0seyJhYWd1aWQiOiI4NjBiOWNjNi1kYzQwLTRlYmMtOTJiOS1jMTRhNzhjZWU5MWYiLCJoYXNoIjoiV25URGV0WkNjMl9sRUY0Z2JfanJtclo2bjV1SGJZTjJPQnN3R0w5dFVFYyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84NjBiOWNjNi1kYzQwLTRlYmMtOTJiOS1jMTRhNzhjZWU5MWYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA5LTI1In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMi0xMCJ9LHsiYWFndWlkIjoiZDgxZjJlNmMtODgyNS00NjkxLTk0ZmYtZmM0OWUzY2VlZGY2IiwiaGFzaCI6IlNBdjdmMHRHUlNsLTRNUURTZS15bERsMTBTLVRYcURuUl9rY3B4eENZYTAiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZDgxZjJlNmMtODgyNS00NjkxLTk0ZmYtZmM0OWUzY2VlZGY2Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0xMC0xOSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDgtMDcifSx7ImFhZ3VpZCI6IjNjZmQzYTJjLTU0MmYtNGVlMC1iNWYzLWYwZWEyZTk0MjgyYSIsImhhc2giOiJXRGNubDRxVXZ1R1BXR0J4MXlYdWdNVFU1Y1E2aHBobzE3VzFvQUMxcmNrIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzNjZmQzYTJjLTU0MmYtNGVlMC1iNWYzLWYwZWEyZTk0MjgyYS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDJwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDItMTgifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTEyIn0seyJhYWd1aWQiOiI1ZDgzYzE4Ny03NWMzLTQyYmYtYTk2MC0zYWY4NWFiN2JlM2UiLCJoYXNoIjoiRTNaLVNNaFJGaWt2Yk5NckdTd05mbVJjNWtOcTQwRk9uaUNfUlp4eDVMNCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS81ZDgzYzE4Ny03NWMzLTQyYmYtYTk2MC0zYWY4NWFiN2JlM2UuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDgtMjYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTA3In0seyJhYWd1aWQiOiIzNDk2YTNjZS00M2QyLTQwZGYtYWVjNS05YjI4NGIyZDhiZGQiLCJoYXNoIjoiZDVRUVpNMWdVT3ZNcUliNmNldjEwUS1ua1M0QnVtUGVPWFQzZVFjd044ayIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8zNDk2YTNjZS00M2QyLTQwZGYtYWVjNS05YjI4NGIyZDhiZGQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDgtMTAifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTIwIn0seyJhYWd1aWQiOiJkYjU4OWEyOC0wYmY5LTQ3NjAtODM1NS0wMTk3YmExMDIzZDUiLCJoYXNoIjoiNFdwUVFTdkdBTE1GT25GV1RNMVVJQXA0TDFSa3oxb1R6NW1IaXNGZWdQZyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9kYjU4OWEyOC0wYmY5LTQ3NjAtODM1NS0wMTk3YmExMDIzZDUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDQtMjEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTIwIn0seyJhYWd1aWQiOiJkNWJhZTYxNC1iMDkyLTRiNzAtOTU1Yy01NzIyNDQ3ZTBiMjciLCJoYXNoIjoiejlxUk8yZGtyeFp5WFBjdGk2STFpV194R2x3TU9mak5jRFRSc3RVdGprYyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9kNWJhZTYxNC1iMDkyLTRiNzAtOTU1Yy01NzIyNDQ3ZTBiMjcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTEwLTAxIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNC0wOCJ9LHsiYWFndWlkIjoiNTcyNzI2MWItZDMzYy00ZDFhLTk3NzUtZDIzYWQ0NjAzMDg0IiwiaGFzaCI6IkJpbDVFTDBUYnRGdjRtUFpGX2VxUzlzM1RZaU9qNHJVNFpDSkhhdHk2WE0iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNTcyNzI2MWItZDMzYy00ZDFhLTk3NzUtZDIzYWQ0NjAzMDg0Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMiIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTEyLTE0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMi0xNSJ9LHsiYWFndWlkIjoiN2U2ZjY4ZmUtNDMxMy00MmEzLTlmYTgtNzk5MzI5ZjY1NDIxIiwiaGFzaCI6Ijk0cDd2U3Raa1JsZENQcmFFMkxITm91bkRfVnZVX2hrYmE5blMxTnh0dUEiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvN2U2ZjY4ZmUtNDMxMy00MmEzLTlmYTgtNzk5MzI5ZjY1NDIxLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wMi0xNyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDUtMjcifSx7ImFhZ3VpZCI6ImFiNDY5ZWQ2LTg2YWEtNDYzNy05OGVhLTViYmQ0ZGM4YTNjZiIsImhhc2giOiJ4cE5YaHV4N1NHMHpuSms2eEJuSE0tdlZpRk5sajJoTTdianJmUWwySEQ4IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2FiNDY5ZWQ2LTg2YWEtNDYzNy05OGVhLTViYmQ0ZGM4YTNjZi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDQtMDEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTAxIn0seyJhYWd1aWQiOiI3Njg0NWVkYy0wZGFlLTRjOWYtOTMzZC0yYjhjYmM3M2IxMjciLCJoYXNoIjoiSHZDcUdCVGZ4VElDcElYSko0Wlc4cHNQb2pYRkFvTnp6a2FkZ042c2pHayIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS83Njg0NWVkYy0wZGFlLTRjOWYtOTMzZC0yYjhjYmM3M2IxMjcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA2LTE0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNC0yMiJ9LHsiYWFndWlkIjoiOTczYTU0ZTgtNWU3Yy00ZGFhLTgzZGUtNGUzMGY5ODI4MWZiIiwiaGFzaCI6IkNjcVhNSC1DNENjSkhPcl9nOEQzUkdKV2lIMnhwM3dUWVJHZVVDb2hrZ0kiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvOTczYTU0ZTgtNWU3Yy00ZGFhLTgzZGUtNGUzMGY5ODI4MWZiLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wNS0xNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMDMifSx7ImFhZ3VpZCI6IjJkM2JkZTllLWFlOTMtNGY1OS1iZDI3LThjN2Q3MzQ0YmRkOSIsImhhc2giOiJ6Wk0ydDc0b1pPZDViQm9vRHViZjBKNFZpT2twNGZ3ZWtsS3pPbkdqVG80IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzJkM2JkZTllLWFlOTMtNGY1OS1iZDI3LThjN2Q3MzQ0YmRkOS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wNy0xOSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTItMTcifSx7ImFhZ3VpZCI6IjIyOTJiMjhiLTAxMDUtNDlhMi04MjZjLWIwM2RlODI4NGYxMSIsImhhc2giOiJNZ3pUSnJQQ25CSG5QZU1jX3I0T3NqUEhFU1IyN1dWRmVjZGJPcGVFZTlRIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzIyOTJiMjhiLTAxMDUtNDlhMi04MjZjLWIwM2RlODI4NGYxMS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wNC0yNyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDMtMDUifSx7ImFhZ3VpZCI6ImI3OWRjMzA2LTcxZTEtNDUwYi04NmE0LTFhM2I3ZTZjMzI2MyIsImhhc2giOiJyUG1DSU8xaXpVNWZqNzZYOGJwd0RGUTh3ZHAyYzFUdnExX0hUMEZ6UUpFIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2I3OWRjMzA2LTcxZTEtNDUwYi04NmE0LTFhM2I3ZTZjMzI2My5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMTAtMTcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAxLTIzIn0seyJhYWd1aWQiOiI5YjJmOTdmMy0zOGM3LTRiZWMtYTYwYy1iYzI3MzhjNGYyMTciLCJoYXNoIjoieGhNSDZjUkd2WXA4UzF1dFlOZXJXRUlmZWtGWW8xUEdNR2dpRUhyUm1VayIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS85YjJmOTdmMy0zOGM3LTRiZWMtYTYwYy1iYzI3MzhjNGYyMTcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDUtMDgifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA0LTI0In0seyJhYWd1aWQiOiI4NTE5YzRmZi0zMWFlLTRiYjctOWYwNC1kN2Q4ODkwOWU4YzgiLCJoYXNoIjoiUEloaEtMYkQzV2M2TGIwTFdXRzdGQ2xhSEVPY0ZMOFBiaVBiNDZKNkNmTSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84NTE5YzRmZi0zMWFlLTRiYjctOWYwNC1kN2Q4ODkwOWU4YzguanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDctMTcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTI2In0seyJhYWd1aWQiOiIzMzc1ZGI0Mi00NmUzLTQ4NmYtODhiYS1kZGM4YTA1YTk0YTYiLCJoYXNoIjoiN3ZLdDNWeTJsbUNhaFBPVnJGS2thaUhrNWtGdmdDV2VjWWtHZ0dfVHNGbyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8zMzc1ZGI0Mi00NmUzLTQ4NmYtODhiYS1kZGM4YTA1YTk0YTYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMTItMDcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEwLTI3In0seyJhYWd1aWQiOiIzOGM2M2UyZi1hODU1LTRhNGYtOGE1Ny0xNzNmYWUyZTY4NjUiLCJoYXNoIjoiX3BheHdBSkRBRVRnd3A0TThBSVRwS01WN205VHM2d095eEY0NWd1V0FkTSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8zOGM2M2UyZi1hODU1LTRhNGYtOGE1Ny0xNzNmYWUyZTY4NjUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlNFTEZfQVNTRVJUSU9OX1NVQk1JVFRFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTAyLTE5In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOC0wOSJ9LHsiYWFndWlkIjoiMDcxYmJkOWYtZWU4OC00ZmIwLTg0MTEtZjEyYzQ0MzM0OTcwIiwiaGFzaCI6InV3MUIxdkM3UW9XZkpBeE83V0RCaFdJZ00yd0ZEbHM2dkd1TklJRHlnRlkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMDcxYmJkOWYtZWU4OC00ZmIwLTg0MTEtZjEyYzQ0MzM0OTcwLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0xMS0xOCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDktMTQifSx7ImFhZ3VpZCI6IjliMDI5ZWFmLTcwNzktNDdjNS04ZDc3LTEzN2Y1MmI1NGQ5YSIsImhhc2giOiJKUk5LUmlhemNzblBkUUJldjE3cFMyeGVnUGlGS2tWdXpNbzFicWNXQ3Z3IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzliMDI5ZWFmLTcwNzktNDdjNS04ZDc3LTEzN2Y1MmI1NGQ5YS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0xMi0wNyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMTAifSx7ImFhZ3VpZCI6ImNiYmJhOGUyLTM5ZjYtNGU3My05ODIwLTRkZWY3MDdjMDVjMiIsImhhc2giOiJwaExnaUxnaFpuMWVHeFJiXzFLa1FJZjlwcHc4aXJkVS1ZdmQ5Zi1kRDQ4IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2NiYmJhOGUyLTM5ZjYtNGU3My05ODIwLTRkZWY3MDdjMDVjMi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wMy0wNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTAtMDYifSx7ImFhZ3VpZCI6ImRlOGI2OWNkLWJkNjctNDkxNy05MTVkLTljOTllMGYyMmY4NyIsImhhc2giOiJKTHM4Tzd6eHRpSlJDS0NwSWRIZGl1bXI4VDA5NVlDMGlLQmJZbWJCUnRnIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2RlOGI2OWNkLWJkNjctNDkxNy05MTVkLTljOTllMGYyMmY4Ny5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDEiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wNi0xNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDMtMTAifSx7ImFhZ3VpZCI6IjJhN2Q5OGQ1LTc5MWYtNDgyMi1iZjQwLTM1MTU2MzAwYjBhMyIsImhhc2giOiJ0aXNISUZ5dGhrRkRBX0ZHa1V3SGtTemFwcGpiQ3JhU2djYy1TSnYwb2xnIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzJhN2Q5OGQ1LTc5MWYtNDgyMi1iZjQwLTM1MTU2MzAwYjBhMy5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDEiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOS0yMCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDUtMDkifSx7ImFhZ3VpZCI6IjkzMDE3ODI1LWJmZmUtNDJlOS04MDRlLWJjNzgyY2Q0Y2UzMSIsImhhc2giOiJvd3FFeFRkbEJfaHhMQ193bm1Td3QzemJEQnQ5a3VZUVg2YkhRZTFia0U0IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzkzMDE3ODI1LWJmZmUtNDJlOS04MDRlLWJjNzgyY2Q0Y2UzMS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDgtMDMifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA5LTAyIn0seyJhYWd1aWQiOiI2ZjlhMjFkYy0xYjc1LTRmZTQtYjUyMC00MjJmYzRkNDYzOTMiLCJoYXNoIjoiX19DbENNQWM1ZlBZRE10VnVVaXJycU12ZGV3NWdOS2RvSWQ4cU9VanF5cyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS82ZjlhMjFkYy0xYjc1LTRmZTQtYjUyMC00MjJmYzRkNDYzOTMuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTAxLTI1In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMS0wNCJ9LHsiYWFndWlkIjoiYWM0ODhkYmUtYTA4MC00MDgzLWEwYmYtZDVhMTU4MTU5ZTYyIiwiaGFzaCI6IkQwQ24xYTZlTFQ3c3A3TTF3WXpyVjJ6LVlLOTg4QW5jLS1XbGlGWkFsTTgiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYWM0ODhkYmUtYTA4MC00MDgzLWEwYmYtZDVhMTU4MTU5ZTYyLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJTRUxGX0FTU0VSVElPTl9TVUJNSVRURUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wOC0wNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDUtMDIifSx7ImFhZ3VpZCI6IjY2OTJlYTc3LTVjMDQtNDRjNC05YWUxLTYwNzEwZjUyYWYxMCIsImhhc2giOiJ0RFlUQXl1M3FiV3hxVU1GNHBBbU5pLUZqQnYzVHNfUzZ0TGNzVzF5eTgwIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzY2OTJlYTc3LTVjMDQtNDRjNC05YWUxLTYwNzEwZjUyYWYxMC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wOS0xNSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDUtMDMifSx7ImFhZ3VpZCI6ImExZTM0YzdmLTc4MzctNDE2MS1iZWU5LTVhYTZhZTgzMzEyYiIsImhhc2giOiJuX3pyUTFmblNMOWJxY1lNa0ZHMmZVRXFWVldtOGt6SGlfZ1hVQVdGSjc0IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2ExZTM0YzdmLTc4MzctNDE2MS1iZWU5LTVhYTZhZTgzMzEyYi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0xMi0yMiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTEtMTgifSx7ImFhZ3VpZCI6IjRhN2ZlOGJmLTVjMWYtNDllMi1hN2VhLWVlZWM3NjU5OTMzOSIsImhhc2giOiJQc3M5ZWYzSjVzNURIMHNVTUdQOGdTX1NqV2hBeFVuRk5IRkVMN3NjbDNBIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzRhN2ZlOGJmLTVjMWYtNDllMi1hN2VhLWVlZWM3NjU5OTMzOS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDMtMDQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA0LTA1In0seyJhYWd1aWQiOiI4YjA1OGM1Ny02ZjU2LTQ3YzAtYmFhMC02MWQyMjMzZTY4NWIiLCJoYXNoIjoidWNNUUVLTkdVNnFYSW9remhYVWgyLVZSbEZ2OFVsdHplYU1XbjFLV1Z2OCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84YjA1OGM1Ny02ZjU2LTQ3YzAtYmFhMC02MWQyMjMzZTY4NWIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDMtMjEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEyLTA3In0seyJhYWd1aWQiOiJhODhjNGI2Ni05NmZiLTQ1OGItOTRlMS05YjdkYjkxZDU4NmIiLCJoYXNoIjoidXROU0NQNEM2bFBXM2JCdDRXVmlicm1Balc0Ukl3ZEM5OS1DT2xrZUhyWSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9hODhjNGI2Ni05NmZiLTQ1OGItOTRlMS05YjdkYjkxZDU4NmIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDctMTMifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTA2In0seyJhYWd1aWQiOiIxZDYzNTc4ZC0yYzRhLTRiZTQtYWIwZi00NzgxY2E2OWU4MzkiLCJoYXNoIjoiakRQZjZDVFVzUko1SXRzMmpOdE9yclZMT2JKWmwtLURrdFM3U0lrMUVDayIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8xZDYzNTc4ZC0yYzRhLTRiZTQtYWIwZi00NzgxY2E2OWU4MzkuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTExLTI2In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNC0xNSJ9LHsiYWFndWlkIjoiOGVhOTVkZjQtY2YyOS00OTgwLWIyMTctMzNiNGMzYTlmYzY5IiwiaGFzaCI6IjdxOVUzekg3c0dMNC03NnNVTVc0eFBnSXNKeklmaWdMajdSYTB2QzhkbTQiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvOGVhOTVkZjQtY2YyOS00OTgwLWIyMTctMzNiNGMzYTlmYzY5Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTEyLTIwIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOS0xMiJ9LHsiYWFndWlkIjoiNDdmOWQxMWMtOGE4Mi00MDNiLWFlZWMtYjU0N2ViNDQ5MmM2IiwiaGFzaCI6InRHMUZsU3ZTQS16MENJeldvSjZkZmdSYUVMdnBpWk16Y2FrSGcxR3JJa2siLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNDdmOWQxMWMtOGE4Mi00MDNiLWFlZWMtYjU0N2ViNDQ5MmM2Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMnBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wNS0yMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDUtMTAifSx7ImFhZ3VpZCI6IjNjMzIxYTM1LTIyMmYtNGJiMC1hNzNmLTBmNjM2NDYyZWIyNSIsImhhc2giOiJENnV2eWhIS0hzcG1laGU2T1g3NWFWczBIM19QUWd6czRYTG9lTGlnVlljIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzNjMzIxYTM1LTIyMmYtNGJiMC1hNzNmLTBmNjM2NDYyZWIyNS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wOS0yNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDItMTMifSx7ImFhZ3VpZCI6IjNjNGUwMmIzLTYyYmYtNGJiZC04MzI0LTEwNjJiM2ZiZjg2MiIsImhhc2giOiJvdUVSdWlMUm9XUHNfNmt1dm00M3hXeUpGanU4SjlaOWpVcUhDZmRuVVZ3IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzNjNGUwMmIzLTYyYmYtNGJiZC04MzI0LTEwNjJiM2ZiZjg2Mi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNy0xMSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDgtMjcifSx7ImFhZ3VpZCI6IjgzNGNmOWM0LWI3YzUtNDQwZS1iZDNmLWQyNzdkYWMxY2U0NCIsImhhc2giOiJSVmRWa0Fud3dkb0RTUmpjczFpazNQVkhwM1VGSzNoaWVOSXJWLU9JUXlRIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzgzNGNmOWM0LWI3YzUtNDQwZS1iZDNmLWQyNzdkYWMxY2U0NC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wMy0yOCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDUtMjcifSx7ImFhZ3VpZCI6IjQ0NGUzMjJkLWFiZTMtNDQzNS05YjQxLWY4MmE2NzYxZDI4ZCIsImhhc2giOiJFdGFNMXFhaGRxeW1XQlBya3Zob21XZmk2Q2ZlblI3SEJxaWFzUjhCV0VVIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzQ0NGUzMjJkLWFiZTMtNDQzNS05YjQxLWY4MmE2NzYxZDI4ZC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiTk9UX0ZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMTItMjcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA5LTE1In0seyJhYWd1aWQiOiIzMjljYjFlZC0zZTJhLTQ3ZWQtOGQ2Ny03ZjExMDY2MDkyZTMiLCJoYXNoIjoiV0NDa3huOE5iSkdJU3ptSXRELWdjbkIyVnV6QlJ0bWJpbTRaWU9YMVVwUSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8zMjljYjFlZC0zZTJhLTQ3ZWQtOGQ2Ny03ZjExMDY2MDkyZTMuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDUtMDMifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEyLTAzIn0seyJhYWd1aWQiOiIzZGI2NTk3Ni0yYzU3LTQ4N2ItYWJlMy00NGYyNGIwMWZlOWEiLCJoYXNoIjoia2VpdGxKY2JCYlhxOXFxdDJlWTQ0Q18wMmxydmJ6b3hIVEJ0eW5mTnlHWSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8zZGI2NTk3Ni0yYzU3LTQ4N2ItYWJlMy00NGYyNGIwMWZlOWEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlNFTEZfQVNTRVJUSU9OX1NVQk1JVFRFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA3LTE4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOS0xMSJ9LHsiYWFndWlkIjoiNThlMTcyMzctMjlhOC00MjViLWIwYTktNjA1ZTZkYzNjOWVlIiwiaGFzaCI6Ik15QkczbHptVGtNcWM2MzJQdTZkSGNqQzVUNjNNZUNQOVZqemxDLVptV00iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNThlMTcyMzctMjlhOC00MjViLWIwYTktNjA1ZTZkYzNjOWVlLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNC0xNyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDEtMjcifSx7ImFhZ3VpZCI6IjY5MWMwMDg4LTUzZDgtNDI4OS05NDExLTgyNGJmNzY4ZTA3OSIsImhhc2giOiI3SHBtRWZHNDl1a2Viak5GdVhrTGlGbzdRTU1MZWV5eEw1cXBTZmNYa1lZIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzY5MWMwMDg4LTUzZDgtNDI4OS05NDExLTgyNGJmNzY4ZTA3OS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiTk9UX0ZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDgtMTYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA0LTA1In0seyJhYWd1aWQiOiJkOTkxNGQ1Yi04NTk2LTQzODQtOWI0NC1lOTU5Y2FmZTYxMjgiLCJoYXNoIjoiMzF2WXdMN0M4aVpneXdJd0hWbE1JWm9IYjhaZzROblNxSU9adGtsOW5yUSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9kOTkxNGQ1Yi04NTk2LTQzODQtOWI0NC1lOTU5Y2FmZTYxMjguanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDQtMTkifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTE1In0seyJhYWd1aWQiOiJiOTk2ZjVkZi1hM2YxLTRiZWItOTQ4NS0yN2NiNWUwOGM2NzgiLCJoYXNoIjoiaE5OaXZiaTd0amJndkpxZXkxcDlyeTlIVm1XQXQ2V3p4ZFFFWmVrYVlqSSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9iOTk2ZjVkZi1hM2YxLTRiZWItOTQ4NS0yN2NiNWUwOGM2NzguanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTEwLTExIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMC0wNyJ9LHsiYWFndWlkIjoiYjk2NzdjZWEtNzVjZS00Nzk3LTgyOTQtNzkzNTA2YWJhZmUxIiwiaGFzaCI6IjVSZGpnTVp3VVZjM0VTMVhMVnZCc1I5VWdVRTcyTG9tVWVSNEFBcGdmQk0iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYjk2NzdjZWEtNzVjZS00Nzk3LTgyOTQtNzkzNTA2YWJhZmUxLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMiIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA2LTA4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0wNiJ9LHsiYWFndWlkIjoiMTViMDVjZDItNzg0Mi00NDRlLThiMDYtZTliNzg3Y2I4NzBkIiwiaGFzaCI6InZMa0NTc3hEWi03bXBCeEJUQ24tbGdVbGI2RVUwdFFUdWo3emFLSXc1VUEiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMTViMDVjZDItNzg0Mi00NDRlLThiMDYtZTliNzg3Y2I4NzBkLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJTRUxGX0FTU0VSVElPTl9TVUJNSVRURUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wMS0yNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDItMjQifSx7ImFhZ3VpZCI6IjIzNTA4ZjE5LTkyMTMtNDc1Mi05NGQ1LThkNzMwZjc3MTE4YSIsImhhc2giOiJ4eldsYno5cVdPcTAyckRKZmswbVZfOXNRUUVMUTdSRE9qR0xNUlpuVkFnIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzIzNTA4ZjE5LTkyMTMtNDc1Mi05NGQ1LThkNzMwZjc3MTE4YS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wMS0wNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTItMTgifSx7ImFhZ3VpZCI6IjQ5Y2Y0ZTUwLTc5NWQtNDJjOS04MjgzLTA1ODcyM2U1ZDhjMiIsImhhc2giOiJGX0VNbXd4R292Zy1pVmd5cThEVWc2dUppenNHX3JGenZGc2FuMWlmM2tzIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzQ5Y2Y0ZTUwLTc5NWQtNDJjOS04MjgzLTA1ODcyM2U1ZDhjMi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDUtMTkifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAxLTEzIn0seyJhYWd1aWQiOiIyZTY0MDY5OS1lMzc5LTQzYzctOGRhMi05MGQ3YmE3NGRhNTMiLCJoYXNoIjoiNG1EN3czWTEyMy1LS2NzV2FBWl9MMVZ6QkJBRTFGY190RWdTSEIxVHdMQSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8yZTY0MDY5OS1lMzc5LTQzYzctOGRhMi05MGQ3YmE3NGRhNTMuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMTItMjcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAxLTE4In0seyJhYWd1aWQiOiIzNWZlMmZlMi02MTMzLTQwZGMtODM4Zi0wZWVjOTZlMWY5NTMiLCJoYXNoIjoicHZQeE9rdkpCNWZQTzE5UWYzaDEzaHNBdUdiWjdWT2lTMWRvaXVtRXZvVSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8zNWZlMmZlMi02MTMzLTQwZGMtODM4Zi0wZWVjOTZlMWY5NTMuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wyIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDItMjUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAzLTEyIn0seyJhYWd1aWQiOiI4MjJlOTAzMi03N2MzLTQ3N2UtOTIyZi1hZGVmYzE1NDAxODciLCJoYXNoIjoiOF91VlpobzROTUlzcTl5LVdHMmo5QWt0UDFjQzRoQjZ6VjdaNWl0YjhwNCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84MjJlOTAzMi03N2MzLTQ3N2UtOTIyZi1hZGVmYzE1NDAxODcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDMtMjcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA2LTE1In0seyJhYWd1aWQiOiJiYjE5ZWI0Yy0wYzg5LTRkODEtOTJlMS0zM2Y0ZDBmM2Q3OTUiLCJoYXNoIjoiekNjSGJDVDRoMk9XZ1ZOcXBQSTZaVU1uQnptOHladGxZSXE2MVJkZEUxUSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9iYjE5ZWI0Yy0wYzg5LTRkODEtOTJlMS0zM2Y0ZDBmM2Q3OTUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMTEtMDIifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAxLTE0In0seyJhYWd1aWQiOiJiNmMxODg0ZS1jNjRkLTRmMWUtYjNkYi1iODA4OWFiNjgwYjAiLCJoYXNoIjoiYUNfc1BSUHppNHlHeVJJd3phWEp2ekxCV0tCNjdEYjlvdWhvRV9ObUN4YyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9iNmMxODg0ZS1jNjRkLTRmMWUtYjNkYi1iODA4OWFiNjgwYjAuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDMtMjgifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA5LTIzIn0seyJhYWd1aWQiOiIxYjY3ZGJjNy0wYWI3LTQzZTgtOGFkYS0wZDQ4OGRmZjFjYTkiLCJoYXNoIjoidGJBeUFQNkRHamdKenIteHlHdHVianh1eS1pX2NEOXo0RExJYS1ERmUzNCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8xYjY3ZGJjNy0wYWI3LTQzZTgtOGFkYS0wZDQ4OGRmZjFjYTkuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6Ik5PVF9GSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA1LTE0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0yMyJ9LHsiYWFndWlkIjoiYjM0OGU2ZjAtYTIxNy00OTllLTkwMDUtNzIwM2JmNTE0MWM5IiwiaGFzaCI6InhjTmtOUWtWbVhoMFNtQW1ZVHRreHVJY0w1ZHpqOTVYeUVOVHJSWS1SS2ciLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYjM0OGU2ZjAtYTIxNy00OTllLTkwMDUtNzIwM2JmNTE0MWM5Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMnBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wMi0yMiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMTgifSx7ImFhZ3VpZCI6ImZlNGZiODZlLWI1OGMtNGViMS04NjQxLTUxMmE1YzgzZGM5NyIsImhhc2giOiJYRVZoSEF3ajBqT2pKM2ZYUWZhcTRKSE9jeVZHT3dJY2czWHNnRHQ2MlFnIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2ZlNGZiODZlLWI1OGMtNGViMS04NjQxLTUxMmE1YzgzZGM5Ny5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDQtMDYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTE5In0seyJhYWd1aWQiOiIzZjIzNGMzOC0zMzM5LTRjMGUtYWZjNy1hNjcxMDExYzAzMWQiLCJoYXNoIjoiUG9VM2NHNzNxZk1POU8tRWRtQ0NOb0NnZ0pBa2ZfWnNKMnAxSElEQV9MOCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8zZjIzNGMzOC0zMzM5LTRjMGUtYWZjNy1hNjcxMDExYzAzMWQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA2LTAyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0wNCJ9LHsiYWFndWlkIjoiODkwNmRiZDAtMzRjZC00YTIxLWI2MzItYmNiYjgwNWY1NmFlIiwiaGFzaCI6IlotNmRBbVFPWGlraUt5R3RLYmNyWHJQb011MW5yOHdoU0pYblo2SGlVajgiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvODkwNmRiZDAtMzRjZC00YTIxLWI2MzItYmNiYjgwNWY1NmFlLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0xMS0xNSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTEtMDQifSx7ImFhZ3VpZCI6IjE1NDRjOGMxLTkyNjMtNGEzZi05NTJlLWJjYmMzNDAyMjc3MiIsImhhc2giOiJDV3RjdU9BbWlyTU42eW5XWjJ3Q0hKTFZ3STVyZUdDR3daX1FjZmNuWUJjIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzE1NDRjOGMxLTkyNjMtNGEzZi05NTJlLWJjYmMzNDAyMjc3Mi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDJwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDQtMjQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA3LTE4In0seyJhYWd1aWQiOiIzZjQzOTljOC0zOTljLTRlMmYtYmI5Ni1iNjk4OTI0NDVjNGUiLCJoYXNoIjoieTZReGs2Zm9UeWs5cVJ5THlVckpHaTNwaHQ2LWRkMFFPNFNraC1sWlBMNCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8zZjQzOTljOC0zOTljLTRlMmYtYmI5Ni1iNjk4OTI0NDVjNGUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDQtMDUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTE1In0seyJhYWd1aWQiOiIxYjA1MjJjNi02NDY2LTQyMWYtYTJmYS1jN2YwNzdhOTdmMzIiLCJoYXNoIjoiajVRY29RbXc2TzRacXFtUnA2M0hVaF93S3FmNjlSSm5lcEVLZ19Oci1JOCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8xYjA1MjJjNi02NDY2LTQyMWYtYTJmYS1jN2YwNzdhOTdmMzIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6Ik5PVF9GSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA4LTA3In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMC0xNSJ9LHsiYWFndWlkIjoiNjAyODEzMDMtZDFiYi00MGUxLWE2N2ItYzk2MjM0MmJjYmZhIiwiaGFzaCI6InVXY2Jwa2w4MmRaelVqUU5BdjBvR2ZlLUhzZU5BbS1oR3VLeVd5SWw2UFUiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNjAyODEzMDMtZDFiYi00MGUxLWE2N2ItYzk2MjM0MmJjYmZhLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTAxLTI2In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOC0yMiJ9LHsiYWFndWlkIjoiOGFlY2M2ZjUtNzE1Ni00ODRjLTkzMDAtMmJjMmJkMzkyN2M1IiwiaGFzaCI6Im9jemxiN0Q5UGtUMFpaUkwweTREdEJ3S2Nya0dEM3RzOE41b0Z5bER5LUkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvOGFlY2M2ZjUtNzE1Ni00ODRjLTkzMDAtMmJjMmJkMzkyN2M1Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJTRUxGX0FTU0VSVElPTl9TVUJNSVRURUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wOS0xOCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDMtMjUifSx7ImFhZ3VpZCI6ImExNjI3NjhlLWUzMDYtNDY0YS1iMDExLTViOGIwMzAxMmRiZSIsImhhc2giOiJ5akJFaEtzeTNWQzE0WHEzdWNtSVptNmZXR1Jma2lQOUpndnpuN0RXMmUwIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2ExNjI3NjhlLWUzMDYtNDY0YS1iMDExLTViOGIwMzAxMmRiZS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDktMjEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTI0In0seyJhYWd1aWQiOiIyZjQ0OWM4Ny1kMTBlLTRjZTctOWVjOS0yYzBkMzc5YjgyM2YiLCJoYXNoIjoiYWtOc0hSLXFINnJ6OVhtcl9RckNmamthM1JCTUIta05qakw1VW80MXV3QSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8yZjQ0OWM4Ny1kMTBlLTRjZTctOWVjOS0yYzBkMzc5YjgyM2YuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6Ik5PVF9GSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA2LTAxIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMS0xMSJ9LHsiYWFndWlkIjoiMmZlOTQwNzctZjllYy00NjhhLWI1ZWYtNjlkMGJiMDA4OTg1IiwiaGFzaCI6ImVwQkg2Y1pHUFA2RGhtVVp2cS16VHRfWGpiTk9uODlQZmpoU2JWTjhFOHciLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMmZlOTQwNzctZjllYy00NjhhLWI1ZWYtNjlkMGJiMDA4OTg1Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTAzLTIxIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNi0yMSJ9LHsiYWFndWlkIjoiOGFjZmM2OWMtZTIwNS00NzRhLWE4OTYtNzQ1ZGY5NzM4YjJlIiwiaGFzaCI6IjBXRU1NZjU5LVNfdXd5QWhIRmZXM2VNcTF0b1BYVnZRVVdKOXpjZ1gzZjgiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvOGFjZmM2OWMtZTIwNS00NzRhLWE4OTYtNzQ1ZGY5NzM4YjJlLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wMi0wOCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDMtMTQifSx7ImFhZ3VpZCI6IjgzZWI2ZjMyLTFiODUtNDdiZC04YTc5LWVhNmI4NmE1OWI4NiIsImhhc2giOiJybnBlaEYtdmllZkxXYlU0ZFl2TlB2TUpvd1oxRl9GQ05VaGI1MHNVeU9jIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzgzZWI2ZjMyLTFiODUtNDdiZC04YTc5LWVhNmI4NmE1OWI4Ni5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDEiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wNy0wNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDQtMDMifSx7ImFhZ3VpZCI6IjZiNjc0MTVkLTY2OGUtNDQwMS1hZGU3LTgzZGU5OWFlNGM5YSIsImhhc2giOiIwcG1iNUtnaTZNNmd5Z0VHN0gxOWZMM0xyRFUySUZ4cjQxX2pUdmg3X1pjIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzZiNjc0MTVkLTY2OGUtNDQwMS1hZGU3LTgzZGU5OWFlNGM5YS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiTk9UX0ZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDUtMDkifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA5LTI2In0seyJhYWd1aWQiOiJjOWE1OTQwOS1jMDFhLTRkZDYtODkzYS0zYTE2OTRiZjZlYjciLCJoYXNoIjoiMDlSWHgyalhTcnRVR1BGN2hFc09CLVRtczJyTFo2TkZDY2xPdFBtRVRKdyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9jOWE1OTQwOS1jMDFhLTRkZDYtODkzYS0zYTE2OTRiZjZlYjcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDgtMDUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEyLTA4In0seyJhYWd1aWQiOiI1MmY0YTA1MC05OWYyLTRiNTItODY0My1iOGI1OGFhNTliNmQiLCJoYXNoIjoiZ2tVZUVRcFU0dDdqNlpiVEJwQnBFRlZvbW9ybndQNjhkVVpSZVMtbC1ZUSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS81MmY0YTA1MC05OWYyLTRiNTItODY0My1iOGI1OGFhNTliNmQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTEyLTI1In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNS0yMSJ9LHsiYWFndWlkIjoiZTk3ZTU2OGEtNTNjZi00ODY2LWFkMWUtYzc3NWUwMjhmODllIiwiaGFzaCI6ImpBT1l3NWtXeTY1T0VrSWlkalZjWFVveExFMUcyU2dkdXdQZFduazFsODgiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZTk3ZTU2OGEtNTNjZi00ODY2LWFkMWUtYzc3NWUwMjhmODllLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMnBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wNy0wNSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDEtMTAifSx7ImFhZ3VpZCI6ImFjNmIzNzRiLTk3NjItNGY5OC1iOWViLTBkY2Q4NjFjMjNhMiIsImhhc2giOiJiMTNzSlFZeE1nT1dMUGVFMFVJNnY5WlQ2SmFyRDRld0JnWkxXd2Y2dEVvIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2FjNmIzNzRiLTk3NjItNGY5OC1iOWViLTBkY2Q4NjFjMjNhMi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDgtMjUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAxLTI0In0seyJhYWd1aWQiOiIyZjZhZTZiNy0wZmQ3LTQwZTMtYTg3YS1lOWJkODcyNjUwMDAiLCJoYXNoIjoiTVZobEZ2VEhYZGRjV3pBSmZRZkRyb2lHS1RDRzBJTkFnMm5qNUYxdnlJdyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8yZjZhZTZiNy0wZmQ3LTQwZTMtYTg3YS1lOWJkODcyNjUwMDAuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMTEtMDQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA3LTIwIn0seyJhYWd1aWQiOiIzMzE3NWY2OC04ZWM1LTRiYWUtOTEwZS1lNjBhNGIwNWU3ZmUiLCJoYXNoIjoieEhhX1h0T3diU2hJNmw2MHFmT015TjluZVdkbFBERDVSQU5NQ0xOdFBWbyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8zMzE3NWY2OC04ZWM1LTRiYWUtOTEwZS1lNjBhNGIwNWU3ZmUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6Ik5PVF9GSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA1LTI2In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMS0wMSJ9LHsiYWFndWlkIjoiMjRjZWNmNmItNjdlMy00ZjkwLTg4ZjAtMGI2MzE2NjVlODc5IiwiaGFzaCI6IjAwVVI0TUxNTWluWmZYR3VkenkyczZFQThYMW91OTh3NXJSS0ZtaUdTMEUiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMjRjZWNmNmItNjdlMy00ZjkwLTg4ZjAtMGI2MzE2NjVlODc5Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wNi0xNSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDktMTEifSx7ImFhZ3VpZCI6ImY2ODY0ZDc5LTFlNzUtNDlhZi04ZmQ2LWM3OTRlOWViMzhhMSIsImhhc2giOiIybmE2Y0puOWZocG85SGxqbV9IRG80TGR1NUFXcXlwaXk0OWZYbnZfQTNZIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2Y2ODY0ZDc5LTFlNzUtNDlhZi04ZmQ2LWM3OTRlOWViMzhhMS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDEtMDcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTE4In0seyJhYWd1aWQiOiJlNTk2NzBiMS1iYmZjLTQyMDgtOGY2Zi00NjM3ZmM5MzRjNzciLCJoYXNoIjoieFMzUWdnWktSTk9Fa2lKS2FmVGs3UmNmb0pPcTNaYlNJZ05tYnhOMlhBOCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9lNTk2NzBiMS1iYmZjLTQyMDgtOGY2Zi00NjM3ZmM5MzRjNzcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlNFTEZfQVNTRVJUSU9OX1NVQk1JVFRFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTExLTEzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMC0xNyJ9LHsiYWFndWlkIjoiYWUwMGE4MzItNDVhZi00OWFhLWFiMjctMjc3YTlhZmU2NTVjIiwiaGFzaCI6ImFjYTVYNW9Pa1B2bXBuMC12V3BxWWJKZmhzb1dkc0NXUkJMS2kwc0JOVzgiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYWUwMGE4MzItNDVhZi00OWFhLWFiMjctMjc3YTlhZmU2NTVjLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wOC0yMiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMTIifSx7ImFhZ3VpZCI6IjgyMGQ2NzI4LTk5YjUtNDA2ZS1iOTJmLWNlMTBhMGU0ZDEwYiIsImhhc2giOiJhTnJCdG5tQXdUVTdkUUZ4NVRVaTV3Z0pCMG80V3FmMlRlOW5mX05SS2o0IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzgyMGQ2NzI4LTk5YjUtNDA2ZS1iOTJmLWNlMTBhMGU0ZDEwYi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNy0xNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTAtMDIifSx7ImFhZ3VpZCI6ImEyZDhhNWRjLTZiOWItNGU1OC1iNzQ0LTA5Y2Q5NDFkZTkxOSIsImhhc2giOiI5SDZrUFhGWS1hNWE0OHRuVWNJaXpUaVU1dGs1RC1Sc21EODVEeldjSmRJIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2EyZDhhNWRjLTZiOWItNGU1OC1iNzQ0LTA5Y2Q5NDFkZTkxOS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDktMjcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTE5In0seyJhYWd1aWQiOiI5Y2E5Yjg5MS05MDgwLTQyMzMtOTc1YS1kNzVlYmU5MzI0ZTEiLCJoYXNoIjoiU1U4bVFoQmRMcG5HdEJOTnBfODE1Rkt5WmFLWGFEelJuSk55UC0xbDJ4TSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS85Y2E5Yjg5MS05MDgwLTQyMzMtOTc1YS1kNzVlYmU5MzI0ZTEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDUtMDgifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTA3In0seyJhYWd1aWQiOiJlZTI2ODU4ZC1kY2Y1LTRkZDktYTJmYS05MTk3Y2JjMDY0NzQiLCJoYXNoIjoia29SN1BEaW9udTJDcUoyRURhTVliR0k5dXFTU012ei1LRlp2VjNaX2FmVSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9lZTI2ODU4ZC1kY2Y1LTRkZDktYTJmYS05MTk3Y2JjMDY0NzQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDYtMDQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAxLTA2In0seyJhYWd1aWQiOiIzODgwY2QzYy0zYmNjLTQ0ZjEtYTgyOC05YjZkNDExM2QxZGMiLCJoYXNoIjoieG1ZRUpsQUk2OHd1aFRDemxLSXpIeHRCaGJ4RzZzaUdPeWtPRU9aMTJNUSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8zODgwY2QzYy0zYmNjLTQ0ZjEtYTgyOC05YjZkNDExM2QxZGMuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDItMDYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTExIn0seyJhYWd1aWQiOiJlNmQ2NWMzYi03NDI3LTQyNTktYWUyYS04OGQ3ZTg0N2YwZTMiLCJoYXNoIjoibjYtYmlzcXJfZl9ZOGtINXRuaFFOWGNjaU5aNGEwdnJGWGlHejRvN3BMcyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9lNmQ2NWMzYi03NDI3LTQyNTktYWUyYS04OGQ3ZTg0N2YwZTMuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6Ik5PVF9GSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA3LTExIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNC0yMSJ9LHsiYWFndWlkIjoiOTM4OGY4NjAtYmQ4MC00OWU4LWJjYWUtM2JhOGY2YTkyZWNlIiwiaGFzaCI6Im9lUC1fdF8xVmdObFgxVXFfbFVyMGhSa3JRNmhYVHVVb3VzbnAySjdTRjQiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvOTM4OGY4NjAtYmQ4MC00OWU4LWJjYWUtM2JhOGY2YTkyZWNlLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOS0yMSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMTEifSx7ImFhZ3VpZCI6IjhiYmU1YTQ4LTM5ZjItNGEzNS05MWZkLTEyNDI0YmI1MzVkMSIsImhhc2giOiJqdFNkaVNsOGNMeFJEbC14STRNUEtVdHVlLThhSzdrVGVTOUMxOWU5MlBvIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzhiYmU1YTQ4LTM5ZjItNGEzNS05MWZkLTEyNDI0YmI1MzVkMS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDMtMDQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEwLTExIn0seyJhYWd1aWQiOiIzNTZjNGY5ZS1jYzFjLTQ2YmUtYmFmMy1lMzE3NjNiNjQ1Y2MiLCJoYXNoIjoiWjNFNWF5dmZ6YkQ0N2NVam1RZTJOcGZ4ZTBlMFFpbF8xcHJKSUVXUGlTWSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8zNTZjNGY5ZS1jYzFjLTQ2YmUtYmFmMy1lMzE3NjNiNjQ1Y2MuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTAyLTAxIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMS0wMyJ9LHsiYWFndWlkIjoiNGU0MjEyMDktMDViMi00MDI5LWIyNDItNzI2MjBhN2ZlMzY2IiwiaGFzaCI6IllUUXNhOGc2NVBlaFp3SUxocjI0ZzB6U25kanpyTFV3d2lrX3BPNTBHY1UiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNGU0MjEyMDktMDViMi00MDI5LWIyNDItNzI2MjBhN2ZlMzY2Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wNS0xOSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDktMDgifSx7ImFhZ3VpZCI6IjliOTBlMDE0LTllNWQtNDE1OS1iOGZiLTZjZWQ3ZjZmMDNkYiIsImhhc2giOiJlTjhNRlBwWm01djhKdmNrSjlPODFndTl4dTdEUzNrU2xGUjlnUHltSVdZIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzliOTBlMDE0LTllNWQtNDE1OS1iOGZiLTZjZWQ3ZjZmMDNkYi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMTEtMTgifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA3LTI0In0seyJhYWd1aWQiOiI0NDViY2QzZS04ODUzLTRiMmMtODBiOS1jOTI2MWU1MDNmNTkiLCJoYXNoIjoiLUF5QlZVT3hibFFZY2hhbGVaOVFYc0hLdWc0WTR3QkZYZlc0dmV6d0xadyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS80NDViY2QzZS04ODUzLTRiMmMtODBiOS1jOTI2MWU1MDNmNTkuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDUtMDkifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEyLTA3In0seyJhYWd1aWQiOiIwYjliZGQzOC1iNGVhLTQ0MGQtYmM0Yy1hYjZjMTQ1MDQ1MTUiLCJoYXNoIjoibUNqdXV0ODI4Ymc0NDV6TlVHQjYwblhrOGtuRHFzSnpBbVBmRGljZk1JZyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8wYjliZGQzOC1iNGVhLTQ0MGQtYmM0Yy1hYjZjMTQ1MDQ1MTUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA0LTEyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMi0yMiJ9LHsiYWFndWlkIjoiYmY1N2QyYTMtZWZlNC00NGQ1LThiNjMtOGVmZDc4ZDkwNWQwIiwiaGFzaCI6IkhUZVhpVVBwQ3laUWxOelh2X0s1VldPQjVOU0UwM1M4VEh2VDdYN0hRdkkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYmY1N2QyYTMtZWZlNC00NGQ1LThiNjMtOGVmZDc4ZDkwNWQwLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJTRUxGX0FTU0VSVElPTl9TVUJNSVRURUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0xMi0yNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDktMDQifSx7ImFhZ3VpZCI6IjA4NTY5MjA1LThjYmMtNGQ1Yi05ZTllLTAzMGRmZDcxNjU0ZiIsImhhc2giOiI4QmlnY045TlBzMEFkZkMzUzdsOFdtS29TdVBrcEwtT2R2ejBEaXY4MDNNIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzA4NTY5MjA1LThjYmMtNGQ1Yi05ZTllLTAzMGRmZDcxNjU0Zi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wMi0yMiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTItMTgifSx7ImFhZ3VpZCI6IjljNGJmNWVhLWVmMjUtNDY3My04NzQwLTMwZTY1ZTY3NmMzNCIsImhhc2giOiI5dTgzQmxha2pqZ1dSVFZfZG9jZDFiUWMyVnFfbzZVVWw2WHB1d3JxUXhFIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzljNGJmNWVhLWVmMjUtNDY3My04NzQwLTMwZTY1ZTY3NmMzNC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDUtMDIifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAyLTEyIn0seyJhYWd1aWQiOiIzYjUwZDA0YS1jNDUxLTRkNzYtYjYyMy02ZGY5M2FiOWM4ODUiLCJoYXNoIjoiOGFnQjBJVW9TTS03ckJ6bk90UGpoTzkxaXAzakZuTlR5RGJEeExNSk9rYyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8zYjUwZDA0YS1jNDUxLTRkNzYtYjYyMy02ZGY5M2FiOWM4ODUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMTAtMDUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA0LTEyIn0seyJhYWd1aWQiOiJlY2RiYjIyMi1lMGQ4LTRmNjctYWFlMy04YzAwNDM5YTcwN2IiLCJoYXNoIjoiTGJ3VTFPcGY4Tjl0U3ZmQzhjQXROT3QxZm1YSkkwOTZkR0dBOWRfTlVqUSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9lY2RiYjIyMi1lMGQ4LTRmNjctYWFlMy04YzAwNDM5YTcwN2IuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTExLTIxIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMy0wMiJ9LHsiYWFndWlkIjoiNDdiYzMyN2QtMmQwNS00NjVhLThjNzAtNDViYmFlMzQ3MDlkIiwiaGFzaCI6InFrYlhJV0JXMF94a2dPVnoySS11akVaTFItSk15ZXhZbjlfT1dibkxsV00iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNDdiYzMyN2QtMmQwNS00NjVhLThjNzAtNDViYmFlMzQ3MDlkLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA0LTAzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0wNyJ9XX0.Y39V3S3YgMLbX1wq1sO823CRE1tL1bfUYHxYbVT6i8HDtzYATj7oatxFBIb3aKiZgYcSMTr_nfqEKxcS19lPBQgolang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/testdata/MetadataTOCParsing-F2.jwt000077500000000000000000001265521414201525100304620ustar00rootroot00000000000000eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlDenpDQ0FuV2dBd0lCQWdJUEJLV3k0ZEhyQ1FQeHREcnc5MnRUTUFvR0NDcUdTTTQ5QkFNQ01HY3hDekFKQmdOVkJBWVRBbFZUTVJZd0ZBWURWUVFLREExR1NVUlBJRUZzYkdsaGJtTmxNU2N3SlFZRFZRUUxEQjVHUVV0RklFMWxkR0ZrWVhSaElGUlBReUJUYVdkdWFXNW5JRVpCUzBVeEZ6QVZCZ05WQkFNTURrWkJTMFVnUTBFdE1TQkdRVXRGTUI0WERURTNNREl3TVRBd01EQXdNRm9YRFRNd01ERXpNVEl6TlRrMU9Wb3dlREVMTUFrR0ExVUVCaE1DVlZNeEZqQVVCZ05WQkFvTURVWkpSRThnUVd4c2FXRnVZMlV4SnpBbEJnTlZCQXNNSGtaQlMwVWdUV1YwWVdSaGRHRWdWRTlESUZOcFoyNXBibWNnUmtGTFJURW9NQ1lHQTFVRUF3d2ZSa0ZMUlNCTlpYUmhaR0YwWVNCVVQwTWdVMmxuYm1WeUlEUWdSa0ZMUlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkhrUUV6NVBnbk1hM0xYb2ZCYWlPc1lsTWNabmNBNlh1TXBCRkNvVEU0eE0vYWJTRGpjUVREcW1DRVdTdms0eHJqL3BZajNUdzdkSXd2ZkpLUWlNVmFpamdmSXdnZTh3Q3dZRFZSMFBCQVFEQWdiQU1Bd0dBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRkx3QU10ZkhrVWdmbHc2bXlvUGt3WTB4U0g3bU1COEdBMVVkSXdRWU1CYUFGRkJhVWJ4bzloS1U5TVNQQVhPeUFkenVqRDh5TUQ4R0ExVWRId1E0TURZd05LQXlvRENHTG1oMGRIQnpPaTh2Wm1sa2IyRnNiR2xoYm1ObExtTnZMbTU2TDIxa2N5OWpjbXd2VFVSVFEwRXRNUzVqY213d1VRWURWUjBnQkVvd1NEQkdCZ3NyQmdFRUFZTGxIQUVEQVRBM01EVUdDQ3NHQVFVRkJ3SUJGaWxvZEhSd2N6b3ZMMlpwWkc5aGJHeHBZVzVqWlM1amJ5NXVlaTl0WkhNdmNtVndiM05wZEc5eWVUQUtCZ2dxaGtqT1BRUURBZ05JQURCRkFpQWg3QXlFZzZ3SmdrRTZzdGZDdUtyMGExVkJkL3NWd1JkZmI0V0FXT1pLc0FJaEFMYktYUVRFNEl1aTlET0kxV0c0c1ZVVXJFQSs0cFZ4VzVxL2RwQ2ttbEx0IiwiTUlJQzRUQ0NBbWVnQXdJQkFnSVBCRS9kajhyak5xbGxWTHJDaGpTa01Bb0dDQ3FHU000OUJBTURNR2N4Q3pBSkJnTlZCQVlUQWxWVE1SWXdGQVlEVlFRS0RBMUdTVVJQSUVGc2JHbGhibU5sTVNjd0pRWURWUVFMREI1R1FVdEZJRTFsZEdGa1lYUmhJRlJQUXlCVGFXZHVhVzVuSUVaQlMwVXhGekFWQmdOVkJBTU1Ea1pCUzBVZ1VtOXZkQ0JHUVV0Rk1CNFhEVEUzTURJd01UQXdNREF3TUZvWERUUXdNREV6TVRJek5UazFPVm93WnpFTE1Ba0dBMVVFQmhNQ1ZWTXhGakFVQmdOVkJBb01EVVpKUkU4Z1FXeHNhV0Z1WTJVeEp6QWxCZ05WQkFzTUhrWkJTMFVnVFdWMFlXUmhkR0VnVkU5RElGTnBaMjVwYm1jZ1JrRkxSVEVYTUJVR0ExVUVBd3dPUmtGTFJTQkRRUzB4SUVaQlMwVXdXVEFUQmdjcWhrak9QUUlCQmdncWhrak9QUU1CQndOQ0FBVExmZi9Lb3F6TnNQMm5mK085QlFaWmpoblk5NFBXNkZaNlFCSzdxNTQzMXJhb1lEUUVNKzVacm1UZmFwWFAxQ3c4VTZnUEN4SFJxU0FoL1dMakVNVFJvNEgxTUlIeU1Bc0dBMVVkRHdRRUF3SUJCakFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQjBHQTFVZERnUVdCQlJRV2xHOGFQWVNsUFRFandGenNnSGM3b3cvTWpBZkJnTlZIU01FR0RBV2dCVGQ5NXJJSE8vaFg5T2g2OXN6WHpEMGFobVpXVEEvQmdOVkhSOEVPREEyTURTZ01xQXdoaTVvZEhSd2N6b3ZMMlpwWkc5aGJHeHBZVzVqWlM1amJ5NXVlaTl0WkhNdlkzSnNMMDFFVTFKUFQxUXVZM0pzTUZFR0ExVWRJQVJLTUVnd1JnWUxLd1lCQkFHQzVSd0JBd0V3TnpBMUJnZ3JCZ0VGQlFjQ0FSWXBhSFIwY0hNNkx5OW1hV1J2WVd4c2FXRnVZMlV1WTI4dWJub3ZiV1J6TDNKbGNHOXphWFJ2Y25rd0NnWUlLb1pJemowRUF3TURhQUF3WlFJeEFOcjI1RGR5OGo5OWFSK0lFaGErcGs2TzJJRE9GV3paWDdCZmxzelAxSnBadlNDSS9ZcWJJOFl5aDIydWdNOENrd0l3UlhTQTRTZTVYR0FyVXVBR1g4eXBtb1hJb0RjRVlSVXZEMGQvWll2WFQ1Q2hUUU9XbkFUQ0szT3cwWVc2QVJOVSJdfQ.eyJsZWdhbEhlYWRlciI6IkJ5IHVzaW5nIHRoaXMgbWV0YWRhdGEgc2VydmljZSwgeW91IGFyZSBzb2xlbWx5IHN3ZWFyIG5vdCB0byBkbyBldmlsISIsIm5vIjo0MiwibmV4dFVwZGF0ZSI6IjIwMjAtMDQtMDgiLCJlbnRyaWVzIjpbeyJhYWd1aWQiOiI5MjU2ZWMyOC1iNGYwLTQ0ODEtOWEzNi03ZDQyNDljYjhkNzUiLCJoYXNoIjoiUnlMby03Z2E4R2c2NmhpaWxGc2tRY1dDamZkMEZROXFsT19BN2EzTXlCYyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS85MjU2ZWMyOC1iNGYwLTQ0ODEtOWEzNi03ZDQyNDljYjhkNzUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTExLTI2In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNi0xMCJ9LHsiYWFndWlkIjoiZjdlZjliMjUtZjdmOS00NjdhLWFlYWYtNDYyMTdhMDJmMjM2IiwiaGFzaCI6Ik5EUFhPbXFqN0t6eFRJOGxRTUN2RkdKXzlmanJ6V1RHN1JXenhXYjlPVzAiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZjdlZjliMjUtZjdmOS00NjdhLWFlYWYtNDYyMTdhMDJmMjM2Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOC0xNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTAtMjIifSx7ImFhZ3VpZCI6IjE5ZTk2ZGUyLWM2MWUtNDgxOS04MmVlLTlmNGUyZTY2NjgyZCIsImhhc2giOiJlVmh6MUk0cWxDTFNJMkN0VGVNb2FTSjdRQVd6SkZhc2tWenBGZHNTdHVVIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzE5ZTk2ZGUyLWM2MWUtNDgxOS04MmVlLTlmNGUyZTY2NjgyZC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDgtMTAifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAyLTA1In0seyJhYWd1aWQiOiI4MzkxOGI5Mi02YjA3LTRhYzQtYmRlNi1lNTMxYTdiNTgzZGIiLCJoYXNoIjoiY1M1Y05NcmlLc0s3NGlwOFlueGtlSnRXYXhUYVIwQms5b2Y4NjJyN3d0ZyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84MzkxOGI5Mi02YjA3LTRhYzQtYmRlNi1lNTMxYTdiNTgzZGIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlNFTEZfQVNTRVJUSU9OX1NVQk1JVFRFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTEwLTIxIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0xNyJ9LHsiYWFndWlkIjoiMjk2ZjFkYWEtOTdkMC00MTc1LWI3OTEtM2NlMTI4MTc3NjZhIiwiaGFzaCI6IlZ2aUJwdjRSa2FCakJIQ3ZXMXl4eDVjZGV0S1RYX3BoVDZfNHlyWllObEkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMjk2ZjFkYWEtOTdkMC00MTc1LWI3OTEtM2NlMTI4MTc3NjZhLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wMi0wNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTEtMTEifSx7ImFhZ3VpZCI6ImRhOWY1MGZlLWJhZjUtNDE1Zi1hMjQ5LTBjMDk5YjBjNWI4ZiIsImhhc2giOiI0bl9JT3J0QUhjcDc0YjYwaW0xd01qNE5jMDZrOVhXOXJqblB1dGpucGYwIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2RhOWY1MGZlLWJhZjUtNDE1Zi1hMjQ5LTBjMDk5YjBjNWI4Zi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDEiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0xMi0yMSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTAtMDIifSx7ImFhZ3VpZCI6ImRkOGZhOGE1LTM2NzctNDgxOC1iZmNmLWU1ZDkwNTMyY2YxYyIsImhhc2giOiJ6MUdXTEFGdlR0bnFkb1NoaTUxM0tVTGNDcnFkX1NSalE5Ti1FVHdkcU40IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2RkOGZhOGE1LTM2NzctNDgxOC1iZmNmLWU1ZDkwNTMyY2YxYy5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMTAtMjcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA0LTA2In0seyJhYWd1aWQiOiJiOWY5YjlhYi04ODcxLTQ5MjAtYjI1YS04NzA3YWY2OGE2NjMiLCJoYXNoIjoiemVIeTI3aUstOWZQZV9XM0s0alZQUEdCblNvNWc1SXBCQWhFdzJCcjUzcyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9iOWY5YjlhYi04ODcxLTQ5MjAtYjI1YS04NzA3YWY2OGE2NjMuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wyIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDItMTAifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTEwIn0seyJhYWd1aWQiOiI1NTA4YTJhYi02ODFjLTRjNWUtYWY3NS1kOGY5MDgyMTQwZjciLCJoYXNoIjoiQzdlcjJLQURxRC1SSGtyVFVVMGdSNTdOaV8zZHZnSUdFdXBLeXNuU2owSSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS81NTA4YTJhYi02ODFjLTRjNWUtYWY3NS1kOGY5MDgyMTQwZjcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA2LTEyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMy0wNCJ9LHsiYWFndWlkIjoiZGY0YzAxZDQtNGExZi00MGEwLWFmZDgtMTI5MWI5ZDEyZGJiIiwiaGFzaCI6InQxeWNvNWpFX0tfdEdUZ3k2NnlyQi11QnpVd3pjRm5KRXBiZ0dCSjZnTlEiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZGY0YzAxZDQtNGExZi00MGEwLWFmZDgtMTI5MWI5ZDEyZGJiLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0xMS0wOSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTItMTMifSx7ImFhZ3VpZCI6ImExNjUzNzhiLTM2NzEtNDY5Mi04ZDkwLWY0NDJkNjA0OGVkYSIsImhhc2giOiIwZVQyQWw1dUJvMDEzUkFCbFhqYzYyUXRha1VBUVVwTUJMUXZXM21NZ2JzIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2ExNjUzNzhiLTM2NzEtNDY5Mi04ZDkwLWY0NDJkNjA0OGVkYS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDEiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wOC0yNyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDktMjYifSx7ImFhZ3VpZCI6IjkwZDI3MmY3LTgxZTUtNGU4Ny05MjY3LTVkYTgyYjJhYzMwMCIsImhhc2giOiItZ1BBUU1WMDcxcVpPNUprX01wdVN1M2ZlWVJMX1hqRG9NdVFTX29aUW5NIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzkwZDI3MmY3LTgxZTUtNGU4Ny05MjY3LTVkYTgyYjJhYzMwMC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wNS0wMSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDUtMjUifSx7ImFhZ3VpZCI6IjIxZjQ2OGI4LWVlZDgtNDM5Ny05OTI5LTgwNWIyYmY5ZDBjZCIsImhhc2giOiJUQUNsZFNyaU5QcDJkd1RKTE5DUmlUVmtkUVNSRGQzTnlmU0JsX19oZ3RJIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzIxZjQ2OGI4LWVlZDgtNDM5Ny05OTI5LTgwNWIyYmY5ZDBjZC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDItMjUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEwLTE3In0seyJhYWd1aWQiOiI4YTFmMWUxMy03NWYwLTRmZTAtOTM4Yy1iMjlmMTNjMjgyODEiLCJoYXNoIjoieWlNaFBKSGNMS1JXR2QzdlVqYjFqNFhVUTdUOGdtcjdRSm5PY1B4Um9lNCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84YTFmMWUxMy03NWYwLTRmZTAtOTM4Yy1iMjlmMTNjMjgyODEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDEtMTAifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA2LTE4In0seyJhYWd1aWQiOiJkNDcwMGUzMy1iOGRjLTQ3ZmYtOWY1Ni05MmE0Y2UzODhjM2YiLCJoYXNoIjoiVkZnYmhRM1Y1TUJGMzFwWWVJZHVFVjgwVElPWXY5SmstUlFKYVJiZllVUSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9kNDcwMGUzMy1iOGRjLTQ3ZmYtOWY1Ni05MmE0Y2UzODhjM2YuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA5LTA0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMi0yMSJ9LHsiYWFndWlkIjoiMTc2MmIxOTgtMGY3ZC00NTVmLWI4MTQtODdiNWUxYmI1YmZmIiwiaGFzaCI6Ik0tdHNBMHNSTlAwSkFYNDA5NXU1ME1kUWdzT2szb0ozOTcxdUNfbHpMeXMiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMTc2MmIxOTgtMGY3ZC00NTVmLWI4MTQtODdiNWUxYmI1YmZmLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJTRUxGX0FTU0VSVElPTl9TVUJNSVRURUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wMi0yMSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDItMDEifSx7ImFhZ3VpZCI6ImJlMzgyMTJiLWJjMTAtNDkyYi1hMDc4LTM5YmVhNDMzNzM5ZCIsImhhc2giOiIxQ0xDSmdwaEhTMGZwT2Y1c2Q1eVFPZlZrYjVucTJCM2ZQUEdLc1RNY0dBIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2JlMzgyMTJiLWJjMTAtNDkyYi1hMDc4LTM5YmVhNDMzNzM5ZC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0xMi0wMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDEtMTMifSx7ImFhZ3VpZCI6Ijc2MTBmZjQzLTFlYmQtNDliNy04OWNjLTI4OGEzNTBkNTdlMiIsImhhc2giOiJnSTMwNVFRZFg3dm5PX0hncThRd21ybmtiOGlmUFJOa1FUbTA0bjFXZUcwIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzc2MTBmZjQzLTFlYmQtNDliNy04OWNjLTI4OGEzNTBkNTdlMi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMTEtMjUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTI3In0seyJhYWd1aWQiOiI2MDEwM2E5OS01NDIxLTQ0MmUtODI3MS1mODI0YmVkZjY2NjIiLCJoYXNoIjoicFlPMW9kNFVfNUpGeUVUNnFYQTFQVU1pOE44bEkwZlIxMXFpaTZVVzVVcyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS82MDEwM2E5OS01NDIxLTQ0MmUtODI3MS1mODI0YmVkZjY2NjIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDYtMDkifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTIwIn0seyJhYWd1aWQiOiJjNWVlOGM1MC1kYmJmLTQ3NWYtYjVmZS0wOTgyNzI4YTVhMjIiLCJoYXNoIjoiOUVKcTl2REtLWHkxc0FyMVBlUEVSTUhYNkFEZEpBeE4zRG5jRkZob0pyTSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9jNWVlOGM1MC1kYmJmLTQ3NWYtYjVmZS0wOTgyNzI4YTVhMjIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wyIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDQtMjEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA5LTE3In0seyJhYWd1aWQiOiJlZmVmNjQ5My1lZWY5LTQ0Y2UtYjFiYy02ZTgzZTUxYzIwN2EiLCJoYXNoIjoiRFN1M3Y4WnRIV1hhTFZoN01EaVdCWWNpblZ6MlNWYUFXY3FGTmNLUDhQTSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9lZmVmNjQ5My1lZWY5LTQ0Y2UtYjFiYy02ZTgzZTUxYzIwN2EuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTAyLTIwIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0xNSJ9LHsiYWFndWlkIjoiY2EwYmMwNzUtOWFhZC00YWQzLWIzOGYtOWRhMjVkYzVjYWYxIiwiaGFzaCI6Im1WYXFxcHZrU1BKUmxsa00ySVVQSTd6THNpR3YyY2lGTEMxcUFnbWdBUGMiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvY2EwYmMwNzUtOWFhZC00YWQzLWIzOGYtOWRhMjVkYzVjYWYxLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wMS0xOSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTItMTcifSx7ImFhZ3VpZCI6IjVmMzljNDE1LWQwYjYtNDQxOC05ZmViLTEwZjQ1OTkzYmRmNCIsImhhc2giOiJVYzB3Qlk2MHBhTE1GeDlGMEFhMml5WjEyMDhwWlRRa1FNOFR3dzNBOXQ0IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzVmMzljNDE1LWQwYjYtNDQxOC05ZmViLTEwZjQ1OTkzYmRmNC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDItMTEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTE3In0seyJhYWd1aWQiOiI3NWUxNDIxNS0wZDY0LTQ1NDMtYWE4OC0wY2IzOTZjNTE3ZTgiLCJoYXNoIjoiWUx2MC1acmFJZ0JpeF9ibzNKSC1Cd1NFZFVwdFVHRExUejhZbUhkRVR3VSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS83NWUxNDIxNS0wZDY0LTQ1NDMtYWE4OC0wY2IzOTZjNTE3ZTguanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA3LTE4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNS0wOSJ9LHsiYWFndWlkIjoiZDNhZjg5ZDAtZmEwZi00ZmM4LThjODYtZmJlMWU3NjNiZjJlIiwiaGFzaCI6IlVHMEN5U3B3SkU3bHg3TEhaVFBtdFVjS2FSLTY2Ty0xSUZzNTRMamxVYWciLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZDNhZjg5ZDAtZmEwZi00ZmM4LThjODYtZmJlMWU3NjNiZjJlLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTAyLTAyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMi0wOCJ9LHsiYWFndWlkIjoiZmJmZTRkMjAtY2Y4MS00ZTU5LTkyY2MtY2EyMzQ3YzQwODQ1IiwiaGFzaCI6IkJpUWNCaEg0Y3ROTmVfTFptVVphY2V1a2xxcm1tMDlLRGxZVzhzSVR3VEkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZmJmZTRkMjAtY2Y4MS00ZTU5LTkyY2MtY2EyMzQ3YzQwODQ1Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA1LTE0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0yNiJ9LHsiYWFndWlkIjoiMDE5Mjk5ZjEtYzM0MC00ZTg2LTg3NGUtYjRiMmVkMWExNDQyIiwiaGFzaCI6InctUFBMbzMyS19PSkpldnJKWURvNVh0VVF3aUxZX1cwNFJDaGVhUmlrSkEiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMDE5Mjk5ZjEtYzM0MC00ZTg2LTg3NGUtYjRiMmVkMWExNDQyLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0xMS0wMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDgtMDQifSx7ImFhZ3VpZCI6IjBkYjk4MmJhLTViZDMtNDhiOS1hYWM3LTA4NjBmMzIzOTg1OSIsImhhc2giOiJ6em9KdWx1eXlKX1doV2FQcVJkMUFIYzFPNmVieHhkckxaWm9zeGVlNnNJIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzBkYjk4MmJhLTViZDMtNDhiOS1hYWM3LTA4NjBmMzIzOTg1OS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wNi0xOSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTAtMTYifSx7ImFhZ3VpZCI6IjZhYTExODlkLWU4OGEtNDRkYS04NWI5LTVlNDI0ZGZkMWY2OCIsImhhc2giOiJsSXhROFc0dUdyWWdhTV9MTk5WZG5YWklNRUNrMlZVMUU0ancwRzA5S29NIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzZhYTExODlkLWU4OGEtNDRkYS04NWI5LTVlNDI0ZGZkMWY2OC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMTItMTMifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTI3In0seyJhYWd1aWQiOiJkZmNiMDBhZC04MjhhLTRjODctYjMzMi0yYzFiZTU5ZGU4MjUiLCJoYXNoIjoiNEdwdXdrNWlLTkdfdW5Ta2NfZHJld191TC1PekpRR1pmTnI1N2J6bFhIWSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9kZmNiMDBhZC04MjhhLTRjODctYjMzMi0yYzFiZTU5ZGU4MjUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wyIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMTAtMjMifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTA2In0seyJhYWd1aWQiOiI4MDM4OTJjNC05NmM1LTRlMGQtYTM3OC0xN2U4YTNkZTJhMmIiLCJoYXNoIjoicEIwclVQOGpCeWUyN3RlcDd1MnlReS12Q2NtMnY3Y29peGNGTUJ6OFI4ayIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84MDM4OTJjNC05NmM1LTRlMGQtYTM3OC0xN2U4YTNkZTJhMmIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDItMDEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA3LTI2In0seyJhYWd1aWQiOiI2OTI0MTMzZC0zY2E1LTQzY2EtYTZhMy01ZmZiMGQ4Mzc2YTgiLCJoYXNoIjoiWFBlNFBLajFWblh6UmpHaUtXdi02c3JMQXJDTnlMclluRmtYNDFYTGkwWSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS82OTI0MTMzZC0zY2E1LTQzY2EtYTZhMy01ZmZiMGQ4Mzc2YTguanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA3LTAxIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOS0yNCJ9LHsiYWFndWlkIjoiMWNjOTZkNzgtMmI2My00ZmFmLWEyNjYtM2QxOWY3MjM0YWMyIiwiaGFzaCI6ImRiNXA4ODdPWU1MbGZHUUM3T3R6NE9DRmMyZHp3S2JJdlBfUWVkVkVYZjQiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMWNjOTZkNzgtMmI2My00ZmFmLWEyNjYtM2QxOWY3MjM0YWMyLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTEwLTIxIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOC0yNSJ9LHsiYWFndWlkIjoiZDIyNjE4MTAtMmZlOC00YTU1LTg1NjYtZDIwNmY3OTJhNmJlIiwiaGFzaCI6InU2R0xFV2xjalhzVlZKY1ZxaExSMXpTWDRxVEtfV01wQlg0X1JoVDZYc28iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZDIyNjE4MTAtMmZlOC00YTU1LTg1NjYtZDIwNmY3OTJhNmJlLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMiIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA0LTExIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMy0yNSJ9LHsiYWFndWlkIjoiMGRlM2M3ODEtNjc1OC00MTNkLWI2MzAtM2I0OWQ5Yjg5MWY4IiwiaGFzaCI6Ik5JQTVWN1NBYzB3ZmVjbGpJbzlkT3Z0a3JveEZnXzBwbUpvX1pGLVRsSEUiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMGRlM2M3ODEtNjc1OC00MTNkLWI2MzAtM2I0OWQ5Yjg5MWY4Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMnBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wOC0wNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDgtMDUifSx7ImFhZ3VpZCI6ImIyNGM2NmNkLTA2MzYtNDcwOC04YjIxLWM2OGM3NWI3NTIxNyIsImhhc2giOiJkdGgxQzh0ejlzSHhsQk01Slgxbk9tekxEQ3RNS2lTNzF3Rjk4WUNCX1VvIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2IyNGM2NmNkLTA2MzYtNDcwOC04YjIxLWM2OGM3NWI3NTIxNy5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wMS0yNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDUtMTQifSx7ImFhZ3VpZCI6IjM5YmRmYTMzLTI1NTItNDgyNi04NTE1LTFlNmRjZGQ5Y2VmYSIsImhhc2giOiJrZ2tGVFNOTE0wTVMwM2c3Q0tIUHhIbC1MX1VQZW54WmVXQ3RRTWZScnBzIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzM5YmRmYTMzLTI1NTItNDgyNi04NTE1LTFlNmRjZGQ5Y2VmYS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wOC0yNyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDktMjYifSx7ImFhZ3VpZCI6IjRjNTM4MjY2LWY1MTAtNDM4Yy1hNmYxLTA4ZDgxNjA0MzFhYSIsImhhc2giOiJSNjJiejNMUF9ydE5yQzBzLXZUclRFNkhCdlpSU25iSkR0a3FINFgwODhNIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzRjNTM4MjY2LWY1MTAtNDM4Yy1hNmYxLTA4ZDgxNjA0MzFhYS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDEtMTEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA5LTE2In0seyJhYWd1aWQiOiJiZmU1NzJlOC02MDY5LTRkODMtYTc5ZS1hYTg1NWUzODk5ZTgiLCJoYXNoIjoiS0RvUmRxSWJ5Mkc1bWZuWmNhMkgwejV4WU1hSlJfTlVkdUl4cXVYYVF3ayIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9iZmU1NzJlOC02MDY5LTRkODMtYTc5ZS1hYTg1NWUzODk5ZTguanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDktMDYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA2LTExIn0seyJhYWd1aWQiOiIxMThjMmYyMC00NzU2LTQwODktYWM2OS04MDM2NjllMWFjYWIiLCJoYXNoIjoiS2djTFhoUUVKcjNGTEd4c3ZKR3Aya194a0RNbmM0QnJwVlZfV1lMR2VHdyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8xMThjMmYyMC00NzU2LTQwODktYWM2OS04MDM2NjllMWFjYWIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA0LTIyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOS0yNyJ9LHsiYWFndWlkIjoiNDkyYjEzOWQtNGNmMy00NTQ0LWE5NDEtZjRiZmVjZmVmMDkxIiwiaGFzaCI6Im45aUhGdG1sOTNUU1dFSk5mZE4xTGtNYkNiZS1qWUlSY1pZcjY5LXZNZEEiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNDkyYjEzOWQtNGNmMy00NTQ0LWE5NDEtZjRiZmVjZmVmMDkxLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wMi0yNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDQtMjIifSx7ImFhZ3VpZCI6Ijg5YzIyMzFiLWI5OWYtNDhmZC04NmM0LTliOTgyMmFlYjg0NiIsImhhc2giOiI1OEM4VjZudzJhWGQ2Y0tMaFBWbF9rZUNjTmItRzhSV3pyYXUydkdiZHhrIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzg5YzIyMzFiLWI5OWYtNDhmZC04NmM0LTliOTgyMmFlYjg0Ni5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOC0yNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDItMDMifSx7ImFhZ3VpZCI6Ijk3MTdmNTNlLWIwNDAtNGQ1MC04ZjgyLTFiMGQ0YTZmZmFmYSIsImhhc2giOiJOUmk5a0F6Wkc5VVpXdl9EWDlzRTM1NnJFdnpxSUFEOTdqUk5OWEo4ZGxZIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzk3MTdmNTNlLWIwNDAtNGQ1MC04ZjgyLTFiMGQ0YTZmZmFmYS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNC0wMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTAtMTQifSx7ImFhZ3VpZCI6IjlhMDEzNzM5LTA3ZTgtNDU3MC04ZWFjLTc5ZWJmNTJlMDI2MiIsImhhc2giOiJTQ0NmWHJaTkZ0QUZQbGZVR09DcFJYcS1UZ3dUN0pUNW0yQ240LW9hSWQ0IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzlhMDEzNzM5LTA3ZTgtNDU3MC04ZWFjLTc5ZWJmNTJlMDI2Mi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDJwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDQtMDkifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTI4In0seyJhYWd1aWQiOiJiOGFiNGVjZi02YTgzLTQyMTYtYjNkNS1lNzRhNjRhZDc3MzciLCJoYXNoIjoicGd2NllmN01lVWE0RnZOVjFvS3NKVmF4YnBwOXpZWjdiN0pqeVlyV0xqNCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9iOGFiNGVjZi02YTgzLTQyMTYtYjNkNS1lNzRhNjRhZDc3MzcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA0LTA3In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMS0yNiJ9LHsiYWFndWlkIjoiOTFiMWYxNzQtYzIzNS00ZDFhLTkzMmQtYWQ4YWQ5ZDQyYWYyIiwiaGFzaCI6Ilo2RF83U0JIQk4zRGRGM3ZKSHNDUjRfckpkdGpYTlRXV2lTaTBlbDFKSUkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvOTFiMWYxNzQtYzIzNS00ZDFhLTkzMmQtYWQ4YWQ5ZDQyYWYyLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0xMi0xNSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDgtMTcifSx7ImFhZ3VpZCI6ImFhZDk2YjVjLTI2ZWItNDdmZi1hMWRkLTJiMTM0NjQ3MjMyZiIsImhhc2giOiJPaENEMURCYnU1TENsOTVWdnF0WVdpWE1tMmxXSUFDQ1h0RE53UTR6aG4wIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2FhZDk2YjVjLTI2ZWItNDdmZi1hMWRkLTJiMTM0NjQ3MjMyZi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDItMTEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTIzIn0seyJhYWd1aWQiOiJkY2ExN2Y0Ny0yNDk4LTQ5NzUtODA0Ni1mODY0ODFlMmQ2YTUiLCJoYXNoIjoieHJZRnVodE1kSm5lZVlhSmtqajJscnduNjdlWmZiUDhpcTUxd29qLW52RSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9kY2ExN2Y0Ny0yNDk4LTQ5NzUtODA0Ni1mODY0ODFlMmQ2YTUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA4LTA3In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOS0wNyJ9LHsiYWFndWlkIjoiY2JmMDhhZWYtODQyNC00MjMxLTliMGUtZDgzMWE0NWZmNjAwIiwiaGFzaCI6ImZIMHlXRXVkMjJQNWFpZXdEdl9wa3NRZHEtdlhGbVY4ZW9jQTI1alF0VVkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvY2JmMDhhZWYtODQyNC00MjMxLTliMGUtZDgzMWE0NWZmNjAwLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNi0wNSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDYtMTYifSx7ImFhZ3VpZCI6IjU1MjJlMjU1LTJkMjAtNGMxMy1hOGZkLWVmZjI0MTg5NmUwZCIsImhhc2giOiJEY1lHVWRXTkVTRUcwakVlX1dXVE5YU3VKdDNZUEpLekcxb0NhZzRJNnlvIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzU1MjJlMjU1LTJkMjAtNGMxMy1hOGZkLWVmZjI0MTg5NmUwZC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDQtMTcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEwLTA4In0seyJhYWd1aWQiOiI2Y2E0NjY2OC1lMGJhLTQ1ZWYtOGQyNi0wNmZlMGJhMmZiNmMiLCJoYXNoIjoiUUxnUkNkSU5vVTl2dHE5ZEE3OVdVX2F4RmVFVWo2ZDN0azM4bVpJemJOMCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS82Y2E0NjY2OC1lMGJhLTQ1ZWYtOGQyNi0wNmZlMGJhMmZiNmMuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTEyLTIyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0yNSJ9LHsiYWFndWlkIjoiYTkyMWE3ZGQtOGE3ZS00MzBiLTg0ZjItOGJjYTRjMWE5MmFkIiwiaGFzaCI6Il9xN2RoMHlPc1h2LWZSbDZncWVIcGpUeFVQVlhROEZXUWhUNm1aeFFoN0UiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYTkyMWE3ZGQtOGE3ZS00MzBiLTg0ZjItOGJjYTRjMWE5MmFkLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wNi0xMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTAtMjYifSx7ImFhZ3VpZCI6IjRlNjliMGRhLWU4ZDEtNGZjYi04OGE2LTI3YzA0Mzg5MDhlMyIsImhhc2giOiJFYTZKdzZ2UGdLU3d4Z0xnNEx3WjlSUmUzN19VUldjODRDSkNoZi10UENNIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzRlNjliMGRhLWU4ZDEtNGZjYi04OGE2LTI3YzA0Mzg5MDhlMy5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wOS0yOCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTEtMDgifSx7ImFhZ3VpZCI6IjkwNWM0YTg4LTZiZmMtNDYxYi04NTdkLWM0ZWU2MWFmZWIxMyIsImhhc2giOiJMVGQ4NkszQk5qOWNWMWtHU3pDaGlabTNndlBzdW50cmtLTXJqR2pxTGlrIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzkwNWM0YTg4LTZiZmMtNDYxYi04NTdkLWM0ZWU2MWFmZWIxMy5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDJwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMTAtMDEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA3LTIzIn0seyJhYWd1aWQiOiJhMGQ4YTQxMC0zNzdiLTQ4NWYtYTA3Mi1kNWVmMzU3NGRiN2UiLCJoYXNoIjoiTllBZzQtcjduU0RkTUhONkE0VFMyUElvc0FoeVc0ZmxJWXhiUkh6TVJkZyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9hMGQ4YTQxMC0zNzdiLTQ4NWYtYTA3Mi1kNWVmMzU3NGRiN2UuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlNFTEZfQVNTRVJUSU9OX1NVQk1JVFRFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTEyLTI0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNi0xMiJ9LHsiYWFndWlkIjoiZDgyYjg3M2QtZTUzZC00MjNiLTgyYzEtNTg5MWJkNDNiMTBmIiwiaGFzaCI6Ik1jM29oTUhQYXlhbnZ3MGRXZndxVzV3WXhNZnZEb2ZnZ0pzTzNhVmVOaDQiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZDgyYjg3M2QtZTUzZC00MjNiLTgyYzEtNTg5MWJkNDNiMTBmLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA5LTIxIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMy0yNSJ9LHsiYWFndWlkIjoiYjExMDg2YzYtMDI4ZC00ZDQzLTk0MmItZWZkNzgwNmJmOWQ3IiwiaGFzaCI6Impxck9TMjUzVWRCNjBFQk0tWEM3cjM5bExHVW5wbG90SngybGdvZXFNZnMiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYjExMDg2YzYtMDI4ZC00ZDQzLTk0MmItZWZkNzgwNmJmOWQ3Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMiIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTAzLTE2In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMi0wMSJ9LHsiYWFndWlkIjoiYWJjNmFiYWQtNjdiMS00ODkwLWExZDItYmM5Mzg2Mjc3OTE5IiwiaGFzaCI6IjBTZ0VIb2stOWJsUFZuLVhYSFRiRUtDa0haTHpKWHdObEkyaEVtZ3VFV1EiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYWJjNmFiYWQtNjdiMS00ODkwLWExZDItYmM5Mzg2Mjc3OTE5Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTAxLTAyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOS0wOSJ9LHsiYWFndWlkIjoiZjQwM2I2NzUtNTgxYS00NDkzLWJmODYtNzhhMDEyMTIxNGI1IiwiaGFzaCI6ImxnNlFqS3k1elYzc25KQ0ljblZmUWs3MDJmV3pvQ08yUDNyZHJGVkRHbGsiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZjQwM2I2NzUtNTgxYS00NDkzLWJmODYtNzhhMDEyMTIxNGI1Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNy0xNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDQtMDIifSx7ImFhZ3VpZCI6ImI4MjcwYzNjLTUzZTctNDVlZi05NDZmLTQyMjk5NzliODY0MiIsImhhc2giOiI1TXZxa1ZxU1JLYU5yQzJLWTFMLUZrOEVxUW9UVlZ2bjY3SmhhRjA1ZTk4IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2I4MjcwYzNjLTUzZTctNDVlZi05NDZmLTQyMjk5NzliODY0Mi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDQtMDMifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA3LTAxIn0seyJhYWd1aWQiOiI1Njk1OTk5Yy1hYWVmLTQ4NjQtODczNy1mY2ZmYzUzZDYzZjkiLCJoYXNoIjoiM3llS0pLR191alhMSHpDbjdHMkFqNG5xbmpkc0NGM2U4bFRUbWtWZzd1SSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS81Njk1OTk5Yy1hYWVmLTQ4NjQtODczNy1mY2ZmYzUzZDYzZjkuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDEtMTMifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA2LTAzIn0seyJhYWd1aWQiOiJiYjA3NTE2My1jNmI4LTRiOTMtYjMyZC00MTAyNGU4MzUwNWQiLCJoYXNoIjoidVAzSEpNeXdmMTA0M2dIN0duT0VFRjJkRGtOTGxaWldCaWNWaTMtam5EMCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9iYjA3NTE2My1jNmI4LTRiOTMtYjMyZC00MTAyNGU4MzUwNWQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDItMDUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAyLTE4In0seyJhYWd1aWQiOiJjMTQ4MWVlMS02YmI3LTQxODktYjgzZC0xNzE4MzJhNTEwMDQiLCJoYXNoIjoiQzJ1bmN4UEl1QXMtN2NmbXl6NUtGb2dYSjIwMlV3XzFlUDF3TUVyQTZnQSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9jMTQ4MWVlMS02YmI3LTQxODktYjgzZC0xNzE4MzJhNTEwMDQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6Ik5PVF9GSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA1LTIzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMi0yNCJ9LHsiYWFndWlkIjoiOWIwYjdjN2ItZWI2MS00ZGY1LWE5YTgtNjdmMjhmMTk4MzM3IiwiaGFzaCI6IlVIYURDbGp1S3RmRHdWVUxpZXdMQzQ4NEhpWVBqclNHQlp2M3FHMWlXWHMiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvOWIwYjdjN2ItZWI2MS00ZGY1LWE5YTgtNjdmMjhmMTk4MzM3Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA5LTIwIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOC0wNyJ9LHsiYWFndWlkIjoiNTE3MTE5ZjktNDdmZC00NGNlLTgzZGQtNTAzNjRlZGNhNjdhIiwiaGFzaCI6Ik16c0NiYnExQjRyQ2ExRVR1SzhsS1RrZVhUeGJ4S3FURFhjODhOUk1nVHciLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNTE3MTE5ZjktNDdmZC00NGNlLTgzZGQtNTAzNjRlZGNhNjdhLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTEyLTEwIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0wOSJ9LHsiYWFndWlkIjoiYzNjYTU4NjQtNzNlNi00YWUzLThhZWMtNWE0N2YzNDFjZjFmIiwiaGFzaCI6IlpESE5MV1MwMGl2YWc3OTlodks4bEx5eG9lS0Q1X3VZSm80WUNEY0Q4TUEiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYzNjYTU4NjQtNzNlNi00YWUzLThhZWMtNWE0N2YzNDFjZjFmLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNC0xOCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDItMjUifSx7ImFhZ3VpZCI6ImVlZWI2Y2Y0LTk5N2QtNGNlMy1iNzE2LWIwYzgyN2Y1OGQ5NyIsImhhc2giOiJ0Z2dudXRpTjYwYVVVMG9lc2U0YXp5WEkzYXhZX29EMEFYY1dsMXdSbXhRIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2VlZWI2Y2Y0LTk5N2QtNGNlMy1iNzE2LWIwYzgyN2Y1OGQ5Ny5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOC0xMiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDItMjQifSx7ImFhZ3VpZCI6IjNlNmU4YmQ4LTEzZTgtNDIyNC1hYThlLWE1NjI5NWQzN2Q4ZCIsImhhc2giOiJjYlJNUC1Qd0xac29UZjQtRHlvT3FneC1PSU9qRGRKUm9ybFZwNS1iaE93IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzNlNmU4YmQ4LTEzZTgtNDIyNC1hYThlLWE1NjI5NWQzN2Q4ZC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wNC0xNyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDQtMjQifSx7ImFhZ3VpZCI6ImMxYTg2ZjBhLTU4NTMtNGMzZS1hMTc0LWVkNjNjMzY5YzAxMSIsImhhc2giOiJVbzd5ZmhhNEpIZEJrSTJ3Y2JxUmI3UEFPZmhnNlg4VllFYUtLYjI3enpzIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2MxYTg2ZjBhLTU4NTMtNGMzZS1hMTc0LWVkNjNjMzY5YzAxMS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDQtMTcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTIzIn0seyJhYWd1aWQiOiI4OGIxODE3NS0wNWRkLTQwMzctYTRhYy1jZmI0OGM1M2ViNjciLCJoYXNoIjoiMkJ5Zi02WXVoMGx5eVFuVWxtYlR1YmVFNkFsUUVkbHZrbC1FMm5ieU1uQSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84OGIxODE3NS0wNWRkLTQwMzctYTRhYy1jZmI0OGM1M2ViNjcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlNFTEZfQVNTRVJUSU9OX1NVQk1JVFRFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTExLTI4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNC0wMiJ9LHsiYWFndWlkIjoiMjhmNzQ3ODAtMjRkNS00NGZiLTlmZDQtMjFmZDA0MWIzNjI4IiwiaGFzaCI6InhQbUdfdThPZkxVQ0wxc3ZtcnluRll0MkQ3eEJtVzgyWERON3YyQnhyLXciLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMjhmNzQ3ODAtMjRkNS00NGZiLTlmZDQtMjFmZDA0MWIzNjI4Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA5LTA1In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0wNiJ9LHsiYWFndWlkIjoiMDRlM2QzN2YtZjQ2YS00NWNlLWE2ZjktNGY1YzdkMzcxMDY4IiwiaGFzaCI6IlpacHpjU1dyMnVpTG1sRDA5ZFl5RXotZEFOcFB4OUlIVVJmWmQ0NEF6TkUiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMDRlM2QzN2YtZjQ2YS00NWNlLWE2ZjktNGY1YzdkMzcxMDY4Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTAxLTEzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOS0wMiJ9LHsiYWFndWlkIjoiY2UzMmQzMzktMGNhMy00YjkzLWEzM2UtMjE0NjlmOTI4Y2U4IiwiaGFzaCI6IjExSTNKWTNVWWlCSWpSYlk1UFMxajB1WkcxdHRBU1JXdldHRzRxTEJScVkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvY2UzMmQzMzktMGNhMy00YjkzLWEzM2UtMjE0NjlmOTI4Y2U4Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0xMS0yNyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMTcifSx7ImFhZ3VpZCI6IjJhZDljNDdhLTM1ZGItNGRiZC04MmE0LWUzOGU1ZWEwZGU2OCIsImhhc2giOiJGeVBkVnJNblJyZEtoWmxRR2RnZjM0Y1kyVzFkNHViSVdxN2FpbEEtWUhNIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzJhZDljNDdhLTM1ZGItNGRiZC04MmE0LWUzOGU1ZWEwZGU2OC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wMy0xOSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMTYifSx7ImFhZ3VpZCI6IjYxM2E3NzBjLWY1MjUtNDRkZi04NmQ3LWE4MjQyN2YxOTdkZiIsImhhc2giOiI0ZEpkZGcxSjBHdWVmdW5yYmRsajZqTXZkSG15U3RhS1lJdDJFU2tlaklJIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzYxM2E3NzBjLWY1MjUtNDRkZi04NmQ3LWE4MjQyN2YxOTdkZi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0xMC0wNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDYtMjYifSx7ImFhZ3VpZCI6IjVjNTM2YmJmLTU4ZjQtNDdlYi1hZmUwLTM3M2I2OGE3MGJjZCIsImhhc2giOiIzb0tHb0pNT1NMd29WMlBVaEUyNUNhT1RlNVU4RDYxaGVVcEgwVWZsN2tNIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzVjNTM2YmJmLTU4ZjQtNDdlYi1hZmUwLTM3M2I2OGE3MGJjZC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDJwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDctMTQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA3LTA1In0seyJhYWd1aWQiOiI5OTcyN2IyYS1lOWNjLTRhODItYTVmZC01NTdmMWMxNWNkNjkiLCJoYXNoIjoiaHN5SWJ4eC1LbG51eVlCQVFEQjJRYjEyaGZlMF9ORllTVXRCcjJkNGJTTSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS85OTcyN2IyYS1lOWNjLTRhODItYTVmZC01NTdmMWMxNWNkNjkuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wyIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDUtMTEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA3LTEwIn0seyJhYWd1aWQiOiIwNTg0YjE0ZS04OGQ1LTRiMjEtYTllOC1hNTczYzY4NWQ1NzYiLCJoYXNoIjoibEoyOGJ3TmpnOHVFZkluOTZEaS00WXdpUTBXMFhRbkNZaXF5NGxWV1NVQSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8wNTg0YjE0ZS04OGQ1LTRiMjEtYTllOC1hNTczYzY4NWQ1NzYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA3LTI3In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNS0wNiJ9LHsiYWFndWlkIjoiYWM1Y2RkOWItZDU1Ny00ZDJkLWJkOGItNGYyNzY0N2QyNTNhIiwiaGFzaCI6Img4ZG5oaV82VWNUN2hmNjhSOWlSZzMwX3NoYjJNVmlqNHR3dzJJN2QtNk0iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYWM1Y2RkOWItZDU1Ny00ZDJkLWJkOGItNGYyNzY0N2QyNTNhLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMiIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA0LTE0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0yMCJ9LHsiYWFndWlkIjoiZWZiYWQyNzQtNDgyNi00ZTI2LWIwYWYtMDM1YjNjZjVkNTZmIiwiaGFzaCI6ImZvY0ZBb0hUMnVDeFBxQ1NIWG9IZXNUbkkzQWZucXFMdmdCeTlXYzY4R00iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZWZiYWQyNzQtNDgyNi00ZTI2LWIwYWYtMDM1YjNjZjVkNTZmLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA0LTI1In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMS0wOCJ9LHsiYWFndWlkIjoiYjM1YjFiMzItNTdiMy00MjE0LWFlMTMtOTE2MjIzNWFhMWU5IiwiaGFzaCI6ImIxal9yMkl3ZExTRFFEZnRVMlpPWVpCNTVRcGNhcGlwN3BrQUppTU03a0EiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYjM1YjFiMzItNTdiMy00MjE0LWFlMTMtOTE2MjIzNWFhMWU5Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTEyLTI2In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNS0wNCJ9LHsiYWFndWlkIjoiMjc2YmExMTgtMTU1MS00NDk5LWI5ZGEtZTkzMzQ5MjdkNTZjIiwiaGFzaCI6InhDeGlOejhfdEdwX1hTV2JxY0RDZlpEYURET2E1OVE5Vk1ab3N4Nko3V3ciLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMjc2YmExMTgtMTU1MS00NDk5LWI5ZGEtZTkzMzQ5MjdkNTZjLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wNS0yMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDYtMTcifSx7ImFhZ3VpZCI6Ijc1YTllMTQwLTQ3YzQtNGQ3Yi05NGI1LTFkNjkwNjYyNTQ4NSIsImhhc2giOiJ6VHF1cDI2TXY4WGFvWElMZ1YxRUhJVTFQM0MySC1xanItS3ZQTURVanNFIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzc1YTllMTQwLTQ3YzQtNGQ3Yi05NGI1LTFkNjkwNjYyNTQ4NS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDYtMTYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA0LTA0In0seyJhYWd1aWQiOiI5N2M0MTQ4Yi01NTYyLTQ2NWEtYTFiYS0xMzkzMmJhMzM5NDciLCJoYXNoIjoiRExPc0NiUWRSVldTR3VqRGN6NzNCZzdEaHhiSGtyWjBLNUR1d2JndG1zOCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS85N2M0MTQ4Yi01NTYyLTQ2NWEtYTFiYS0xMzkzMmJhMzM5NDcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMTAtMTQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAzLTIzIn0seyJhYWd1aWQiOiI3Mzg1ODE0NS05YmNlLTQ4NzUtYWEwOC00MDQ2MTFiMjVlNjIiLCJoYXNoIjoiZWNBdHpyMnFUNzlmSl91UG1MUldMUGREcVhPejFBendZa3NRc0lIZ29zcyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS83Mzg1ODE0NS05YmNlLTQ4NzUtYWEwOC00MDQ2MTFiMjVlNjIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDctMDgifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEyLTAxIn0seyJhYWd1aWQiOiI4YmI3OTM4MS1jNDUyLTRmMzctYjMwZS00N2NjMTBkZjcyZjgiLCJoYXNoIjoicFlqWlkyYnVtRHoxYXF1cC01aWZjak1nQVJkY0VfaTY2cUctVHdWcHFsVSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84YmI3OTM4MS1jNDUyLTRmMzctYjMwZS00N2NjMTBkZjcyZjguanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA5LTE5In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOS0xNyJ9LHsiYWFndWlkIjoiMDRiOTYyMmItYWMyOS00OTZlLWFmODUtMjAwMmFhZmY4MzUzIiwiaGFzaCI6IjdLYU1jSnBnWnN5VGpSLU1YLUxuXzVQNHdEdjJLWWhHQ25fdDNOMHc3NGMiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMDRiOTYyMmItYWMyOS00OTZlLWFmODUtMjAwMmFhZmY4MzUzLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTAzLTI4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0xMiJ9LHsiYWFndWlkIjoiZGFlYWI0ZjctMmUwMC00Y2QyLWIzMzUtYzRmMTk1NjJhODliIiwiaGFzaCI6IkhsVDkwejgwSFFRRXRsYU41Y1BydUtFR19ZaHhwbDhKaTlGS3B2MVl6MW8iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZGFlYWI0ZjctMmUwMC00Y2QyLWIzMzUtYzRmMTk1NjJhODliLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wMS0yMiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDEtMTEifSx7ImFhZ3VpZCI6ImRhMzdjNDk1LTA5NGYtNDBhZC04MTJmLTVlYWJhMjM2YTE0ZiIsImhhc2giOiJYSENzZnFBSW4xeDNQVGUyeGlVMkhfVGtySWFMLUxJOUcwYTkza1pGaWRvIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2RhMzdjNDk1LTA5NGYtNDBhZC04MTJmLTVlYWJhMjM2YTE0Zi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDJwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDktMjAifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA0LTAxIn0seyJhYWd1aWQiOiJlMzNiZjM2Yy0wZmQ4LTRiMzUtOTFjOS03NmY1NzlhYmFjNGQiLCJoYXNoIjoiUDdxOVd4WWRud3pOcU9XemF0eVo5YzVRUWNpWnBvanhYbHIwMXowNmZqYyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9lMzNiZjM2Yy0wZmQ4LTRiMzUtOTFjOS03NmY1NzlhYmFjNGQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6Ik5PVF9GSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA5LTIwIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMy0wOSJ9LHsiYWFndWlkIjoiNzFhMzBjMWQtOGFlZi00MmRmLTlhYjQtYTEzYmIyNGMzZmIwIiwiaGFzaCI6Ik0tU1gycV9zYXNiTGJQUlN4OWQwM0FZcW9lNXJTb2NkcE4wS1Fvc0ZtR0EiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNzFhMzBjMWQtOGFlZi00MmRmLTlhYjQtYTEzYmIyNGMzZmIwLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA5LTA4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMS0yNiJ9LHsiYWFndWlkIjoiZDcyNWZkNGQtZDZkZS00MTg0LThhZDctYzFmOWFlMTVmYjdmIiwiaGFzaCI6ImRNOHJ5OW1ldEJ3WmVFY3oyZlR2dVk4eDNVUjZORjBoZmlmOUJQNTl5ZFUiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZDcyNWZkNGQtZDZkZS00MTg0LThhZDctYzFmOWFlMTVmYjdmLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTAzLTIzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOS0yMiJ9LHsiYWFndWlkIjoiMjE3ZGViYzQtZGRiMi00MjgyLWE1MWItMTNiZWFkMjViYTkwIiwiaGFzaCI6Ik83UHVhdTY5Yjl4eEMwQVZhY21uRHF2MGVraGJRcjV3S3pON0R1MVNXXzQiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMjE3ZGViYzQtZGRiMi00MjgyLWE1MWItMTNiZWFkMjViYTkwLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOC0xMSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDQtMTYifSx7ImFhZ3VpZCI6IjJjMGFmOGIyLTVkZGYtNDY0NS1hOGEzLWQyMWUxY2UxMjcwOSIsImhhc2giOiJ6Y05oVlp5QzBwUDJjcU9XRjF3RXE3eTh4YThob0poYm54QW1vX190YXNZIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzJjMGFmOGIyLTVkZGYtNDY0NS1hOGEzLWQyMWUxY2UxMjcwOS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wNy0wOCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDEtMTkifSx7ImFhZ3VpZCI6IjUwNTVlMjE5LTQwZTYtNDQ4MC1hNWI2LWFlNjE0OTFkNzllMSIsImhhc2giOiJXVUlPZ0NtXzgtVGhhY2R6eU5rdWJKT2lvWHZVUlJzZFpzc1hfbDJCSVBBIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzUwNTVlMjE5LTQwZTYtNDQ4MC1hNWI2LWFlNjE0OTFkNzllMS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMTAtMTEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA5LTAzIn0seyJhYWd1aWQiOiIxMjBiYTZjZS01MmZlLTQ0ODctODg0NS1kNWJjMjYxNWM2MzQiLCJoYXNoIjoiNVYyTDlVcVZSVVhBSENONDNNSlgwZE5qcEI5cTVUMTRveDJiZ3JIVlJfdyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8xMjBiYTZjZS01MmZlLTQ0ODctODg0NS1kNWJjMjYxNWM2MzQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA3LTE5In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOS0wNSJ9LHsiYWFndWlkIjoiNzA0OWMwM2EtNTYzMi00YTIwLTk1MTQtZWY4MjhkMjRmNWUwIiwiaGFzaCI6Ii1uZjVXcnpZYTJCakFmTUxGZERzT2YzWU9yV2VyNnc4ckktVkRUdUhicEkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNzA0OWMwM2EtNTYzMi00YTIwLTk1MTQtZWY4MjhkMjRmNWUwLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0xMi0xMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDgtMjIifSx7ImFhZ3VpZCI6ImJlOGQ5ZWIxLTVhOWUtNDYyMC04OGU4LWI1OTkyZjU3OGUwMiIsImhhc2giOiJLdXFEVGV3Q00wMjRaaFBUc0NNbzFkZWlPUjM1WVl1b1dTT3BPam9mUUwwIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2JlOGQ5ZWIxLTVhOWUtNDYyMC04OGU4LWI1OTkyZjU3OGUwMi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDgtMTQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTA4In0seyJhYWd1aWQiOiIxZTcxMTVjMC00ZjIzLTRmZDgtODM0MC04ZjAwMTllZDlmZTkiLCJoYXNoIjoiNmNqQk9sWllZZzhGOXFRR0w4ek4yc0J5ODBxdnhILURwaU85RElodEttSSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8xZTcxMTVjMC00ZjIzLTRmZDgtODM0MC04ZjAwMTllZDlmZTkuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA0LTE4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMi0wNyJ9LHsiYWFndWlkIjoiYmU5ZWIwZGEtNjMwNy00ODA0LThhZmQtZTJlZjFiMWZjZGY1IiwiaGFzaCI6InBrS2tiYllRUEp4aEJRd2E4b29kbGFEaVVKZ2lBdEN4My01TF9UdTRtT00iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYmU5ZWIwZGEtNjMwNy00ODA0LThhZmQtZTJlZjFiMWZjZGY1Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOC0wNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMTkifV19.zcJYY99FeiSNCKYpRb5zVW9zUyX2E8CjnuMm9DxsEAHGjp4w3X1ThwOACqP3Owd_18Sf2D7cpjtyE5HFnqTmkAgolang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/testdata/MetadataTOCParsing-F3.jwt000077500000000000000000001265761414201525100304710ustar00rootroot00000000000000eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlDenpDQ0FuV2dBd0lCQWdJUEJJQm5TZDR3ZTcxUmRhSnRjL1h6TUFvR0NDcUdTTTQ5QkFNQ01HY3hDekFKQmdOVkJBWVRBbFZUTVJZd0ZBWURWUVFLREExR1NVUlBJRUZzYkdsaGJtTmxNU2N3SlFZRFZRUUxEQjVHUVV0RklFMWxkR0ZrWVhSaElGUlBReUJUYVdkdWFXNW5JRVpCUzBVeEZ6QVZCZ05WQkFNTURrWkJTMFVnUTBFdE1TQkdRVXRGTUI0WERURTNNREl3TVRBd01EQXdNRm9YRFRNd01ERXpNVEl6TlRrMU9Wb3dlREVMTUFrR0ExVUVCaE1DVlZNeEZqQVVCZ05WQkFvTURVWkpSRThnUVd4c2FXRnVZMlV4SnpBbEJnTlZCQXNNSGtaQlMwVWdUV1YwWVdSaGRHRWdWRTlESUZOcFoyNXBibWNnUmtGTFJURW9NQ1lHQTFVRUF3d2ZSa0ZMUlNCTlpYUmhaR0YwWVNCVVQwTWdVMmxuYm1WeUlEUWdSa0ZMUlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkhrUUV6NVBnbk1hM0xYb2ZCYWlPc1lsTWNabmNBNlh1TXBCRkNvVEU0eE0vYWJTRGpjUVREcW1DRVdTdms0eHJqL3BZajNUdzdkSXd2ZkpLUWlNVmFpamdmSXdnZTh3Q3dZRFZSMFBCQVFEQWdiQU1Bd0dBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRkx3QU10ZkhrVWdmbHc2bXlvUGt3WTB4U0g3bU1COEdBMVVkSXdRWU1CYUFGRkJhVWJ4bzloS1U5TVNQQVhPeUFkenVqRDh5TUQ4R0ExVWRId1E0TURZd05LQXlvRENHTG1oMGRIQnpPaTh2Wm1sa2IyRnNiR2xoYm1ObExtTnZMbTU2TDIxa2N5OWpjbXd2VFVSVFEwRXRNUzVqY213d1VRWURWUjBnQkVvd1NEQkdCZ3NyQmdFRUFZTGxIQUVEQVRBM01EVUdDQ3NHQVFVRkJ3SUJGaWxvZEhSd2N6b3ZMMlpwWkc5aGJHeHBZVzVqWlM1amJ5NXVlaTl0WkhNdmNtVndiM05wZEc5eWVUQUtCZ2dxaGtqT1BRUURBZ05JQURCRkFpRUF5TVRQVG02L0RQZUJDNitkRlVyTmRBemZiOUN3SEpxSW5oN1lCbmNXbW1JQ0lHcXZMSUNhM2xnUndPRXRtNEhpNXZIWjVxVThybFZSaXhKeGpZa1VacVg3IiwiTUlJQzRUQ0NBbWVnQXdJQkFnSVBCRS9kajhyak5xbGxWTHJDaGpTa01Bb0dDQ3FHU000OUJBTURNR2N4Q3pBSkJnTlZCQVlUQWxWVE1SWXdGQVlEVlFRS0RBMUdTVVJQSUVGc2JHbGhibU5sTVNjd0pRWURWUVFMREI1R1FVdEZJRTFsZEdGa1lYUmhJRlJQUXlCVGFXZHVhVzVuSUVaQlMwVXhGekFWQmdOVkJBTU1Ea1pCUzBVZ1VtOXZkQ0JHUVV0Rk1CNFhEVEUzTURJd01UQXdNREF3TUZvWERUUXdNREV6TVRJek5UazFPVm93WnpFTE1Ba0dBMVVFQmhNQ1ZWTXhGakFVQmdOVkJBb01EVVpKUkU4Z1FXeHNhV0Z1WTJVeEp6QWxCZ05WQkFzTUhrWkJTMFVnVFdWMFlXUmhkR0VnVkU5RElGTnBaMjVwYm1jZ1JrRkxSVEVYTUJVR0ExVUVBd3dPUmtGTFJTQkRRUzB4SUVaQlMwVXdXVEFUQmdjcWhrak9QUUlCQmdncWhrak9QUU1CQndOQ0FBVExmZi9Lb3F6TnNQMm5mK085QlFaWmpoblk5NFBXNkZaNlFCSzdxNTQzMXJhb1lEUUVNKzVacm1UZmFwWFAxQ3c4VTZnUEN4SFJxU0FoL1dMakVNVFJvNEgxTUlIeU1Bc0dBMVVkRHdRRUF3SUJCakFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQjBHQTFVZERnUVdCQlJRV2xHOGFQWVNsUFRFandGenNnSGM3b3cvTWpBZkJnTlZIU01FR0RBV2dCVGQ5NXJJSE8vaFg5T2g2OXN6WHpEMGFobVpXVEEvQmdOVkhSOEVPREEyTURTZ01xQXdoaTVvZEhSd2N6b3ZMMlpwWkc5aGJHeHBZVzVqWlM1amJ5NXVlaTl0WkhNdlkzSnNMMDFFVTFKUFQxUXVZM0pzTUZFR0ExVWRJQVJLTUVnd1JnWUxLd1lCQkFHQzVSd0JBd0V3TnpBMUJnZ3JCZ0VGQlFjQ0FSWXBhSFIwY0hNNkx5OW1hV1J2WVd4c2FXRnVZMlV1WTI4dWJub3ZiV1J6TDNKbGNHOXphWFJ2Y25rd0NnWUlLb1pJemowRUF3TURhQUF3WlFJeEFOcjI1RGR5OGo5OWFSK0lFaGErcGs2TzJJRE9GV3paWDdCZmxzelAxSnBadlNDSS9ZcWJJOFl5aDIydWdNOENrd0l3UlhTQTRTZTVYR0FyVXVBR1g4eXBtb1hJb0RjRVlSVXZEMGQvWll2WFQ1Q2hUUU9XbkFUQ0szT3cwWVc2QVJOVSJdfQ.eyJsZWdhbEhlYWRlciI6IkJ5IHVzaW5nIHRoaXMgbWV0YWRhdGEgc2VydmljZSwgeW91IGFyZSBzb2xlbWx5IHN3ZWFyIG5vdCB0byBkbyBldmlsISIsIm5vIjo0MiwibmV4dFVwZGF0ZSI6IjIwMjAtMDQtMDgiLCJlbnRyaWVzIjpbeyJhYWd1aWQiOiJhZDAzYTdkOC05OTVjLTQwYmEtYWIzNS1hM2QzNjU0YzdiYzQiLCJoYXNoIjoiaE5SLWk4bmRRZUhtUG95ajR2R3J2a3B4WURIeHFCbnZpWWkzLU5WSm92SSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9hZDAzYTdkOC05OTVjLTQwYmEtYWIzNS1hM2QzNjU0YzdiYzQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDUtMDIifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTE0In0seyJhYWd1aWQiOiI4NzQyZDRjMS1mNDViLTQzYmYtYTU4ZS0zYjFlYjE2NDE3YTQiLCJoYXNoIjoibk85aU5aTkJDUUs3VzJ3OXd5Rkk2dXZwb2xFVUU3VE1VVG5ZT0VUQWZ1YyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84NzQyZDRjMS1mNDViLTQzYmYtYTU4ZS0zYjFlYjE2NDE3YTQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMTAtMDQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA2LTE3In0seyJhYWd1aWQiOiI2Yzk5Y2E4YS0xMzRhLTQ2NmUtODgwYi1hN2NmMzA2M2JlMWIiLCJoYXNoIjoidmRWRWdlMU9HVkg0MzFhcFRqYkVkTnhHanRpOUdKYzk2MF9NR2J6UHh1VSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS82Yzk5Y2E4YS0xMzRhLTQ2NmUtODgwYi1hN2NmMzA2M2JlMWIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDUtMTIifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAzLTI0In0seyJhYWd1aWQiOiI4OGUwNDRjYy01NGJkLTRjOWYtYTAyNC0zZGJlYjFkNDI1OWIiLCJoYXNoIjoiX1N1SWtlclh2d00zX0NjcEFKUzBCNXVvaWtFZ25ybk9uT05FZk5zeDlNRSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84OGUwNDRjYy01NGJkLTRjOWYtYTAyNC0zZGJlYjFkNDI1OWIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDEtMTIifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAzLTE4In0seyJhYWd1aWQiOiIxYzIyNmE2OC01NWY0LTQyOTMtYjg3My04NjJkMjFiZjg1MzgiLCJoYXNoIjoiZ2hPOGFoekxGTnJ1OTl5OEJob3hOTzIteUs3d2dFRjlYNWRaZlBabEpSVSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8xYzIyNmE2OC01NWY0LTQyOTMtYjg3My04NjJkMjFiZjg1MzguanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlNFTEZfQVNTRVJUSU9OX1NVQk1JVFRFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTAxLTIwIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOC0yMCJ9LHsiYWFndWlkIjoiNzBhOWU2OTUtNTFiNC00YzExLWFiMTYtZTNiZTRjN2NkYWY3IiwiaGFzaCI6IkFiamExaThSZmw4bVJ4YVlXVkZVZ1V6YWxiWDBzNzRaWHM3SFU3UFNSNkUiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNzBhOWU2OTUtNTFiNC00YzExLWFiMTYtZTNiZTRjN2NkYWY3Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA2LTE3In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOC0wNSJ9LHsiYWFndWlkIjoiNjIzZWFlOTYtMWFjZS00NDc2LThlMWItNTU5NjA2NTI4ZjZlIiwiaGFzaCI6IjVwTHo3c1pFWG9EZXdEcWR5VHYxYU1qVERZT2lzVnpST1Z2bUo0emFWQnciLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNjIzZWFlOTYtMWFjZS00NDc2LThlMWItNTU5NjA2NTI4ZjZlLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTExLTA4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0wNiJ9LHsiYWFndWlkIjoiMTQ5YzFmMTktOGJhMS00MTVjLTliNmYtMjY3M2E5NTQ1YTNlIiwiaGFzaCI6ImtERk1xRXRYX09OVGZ6c3I0U21ldFczYjhLTnJLamRWVXI1ejZycjJaMTAiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMTQ5YzFmMTktOGJhMS00MTVjLTliNmYtMjY3M2E5NTQ1YTNlLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNi0yNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTItMTYifSx7ImFhZ3VpZCI6ImJlODg1ZjZmLWI5ZDQtNDc2Yi1hOGIwLTAwZjA5ZmE2ZTA4NCIsImhhc2giOiJOb1dxYWVmTklNVWM1OUxoR2ZxUHVyd2F0aHNscEJ1N2U2Z2pmdjRvVFBnIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2JlODg1ZjZmLWI5ZDQtNDc2Yi1hOGIwLTAwZjA5ZmE2ZTA4NC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDMtMTQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA5LTEzIn0seyJhYWd1aWQiOiI4YjQzYzhkNi1mZjE0LTQxOGEtYjk0YS02ODA4ODQ5MzM5MzYiLCJoYXNoIjoiLW9MWHYyRWZtVlRycXdPTkJFOXVHa285OHpxeDYzQnFyS1NDZG5CWm53RSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84YjQzYzhkNi1mZjE0LTQxOGEtYjk0YS02ODA4ODQ5MzM5MzYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlNFTEZfQVNTRVJUSU9OX1NVQk1JVFRFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA3LTAzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0xNiJ9LHsiYWFndWlkIjoiZmU1MDM0ZWQtOGFmMy00YWUyLThiYzUtMTZiZDcxMWNkNjJiIiwiaGFzaCI6IlVZUTAyQXBSUG1TdkR3UlR6SmVfNTZ5Nl9zTmVXd3ZUZC1ZVVhkNFN1WW8iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZmU1MDM0ZWQtOGFmMy00YWUyLThiYzUtMTZiZDcxMWNkNjJiLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTAzLTA0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0yMCJ9LHsiYWFndWlkIjoiNWQ4NzFkYTgtNjdlNC00NDc2LTg2NGQtM2U3MmUyZDY2N2ZhIiwiaGFzaCI6ImVmRzdIZXBLLWFmcGNzS3pELW1vNVg3blpzY1ROSDlJX0VZS3plQzlZR00iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNWQ4NzFkYTgtNjdlNC00NDc2LTg2NGQtM2U3MmUyZDY2N2ZhLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJTRUxGX0FTU0VSVElPTl9TVUJNSVRURUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0xMC0xMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDYtMDcifSx7ImFhZ3VpZCI6IjQ3NzE1ZThmLWY1MjAtNDhlNy1hZTFlLWU4M2M3OTFiODAzYSIsImhhc2giOiJKaGRoSl9BU2RiRExFMUpxaXJqcGF3SzU5MWtlNmpPYXNxTnRXWG1NT3ZrIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzQ3NzE1ZThmLWY1MjAtNDhlNy1hZTFlLWU4M2M3OTFiODAzYS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMTItMDkifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTA2In0seyJhYWd1aWQiOiI0OGMyOTU3OS0yNmIxLTQ1MDctODQ4Yy1hNDRkNzM0ZTMzNjEiLCJoYXNoIjoiQVJwRTQzMUVfaVdXUXVULTM5eWNxMmxCdVlDWE55TUNoTFlZWE9WdWFVOCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS80OGMyOTU3OS0yNmIxLTQ1MDctODQ4Yy1hNDRkNzM0ZTMzNjEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMTAtMjAifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAyLTIzIn0seyJhYWd1aWQiOiJkODQzNmYxNC1iNTdhLTQwYWEtOWRmNS02ZjUyMTFiM2JiMjciLCJoYXNoIjoiTkNOTjFEYVlTSXJHdXdmNmh3M1lselNBMFFoV2U0M0c5SmhqMFpzTm9xcyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9kODQzNmYxNC1iNTdhLTQwYWEtOWRmNS02ZjUyMTFiM2JiMjcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlNFTEZfQVNTRVJUSU9OX1NVQk1JVFRFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA4LTI1In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0wNCJ9LHsiYWFndWlkIjoiYjI2NjY3NGItYjY0MC00MzViLTg3MTEtMmQzZmJlZTA3ZDRiIiwiaGFzaCI6Ik9XaTFmQmVYUGVlWlFxNkdFRVhQVUIyNWZLdzlGUEwxQmlWVktHT0FHMkkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYjI2NjY3NGItYjY0MC00MzViLTg3MTEtMmQzZmJlZTA3ZDRiLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wNC0yNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMDUifSx7ImFhZ3VpZCI6ImQ3OTIyMjg5LWVjZGEtNDYwOC04NGQ3LTAwMmZmZjRhNGY5OCIsImhhc2giOiJ0U1pCTUxSZUx2UFgtZ1VkUDRlaWdsekZJek1hX19odEJsZFhOT1M3QlVZIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2Q3OTIyMjg5LWVjZGEtNDYwOC04NGQ3LTAwMmZmZjRhNGY5OC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wMS0xNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTEtMTUifSx7ImFhZ3VpZCI6IjM0MmE3NDliLTZmZGYtNDQzMy1iMmE3LTM5MWRlNDlhMDgxNSIsImhhc2giOiIyQW5sUl9xZEd1c0NfbUQ2MnVoQ2o3MFVvek5iOU4xQ2ZJS3JITjJXY1VNIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzM0MmE3NDliLTZmZGYtNDQzMy1iMmE3LTM5MWRlNDlhMDgxNS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNS0wNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDktMTcifSx7ImFhZ3VpZCI6IjRjY2U0MTAwLTQ3MDItNDUwMS05MWJkLTA5ZGQwYjYxMTg4OSIsImhhc2giOiJOX1VYNlJVT2xmOGZ1N2Z3SWpwUWRxUUZ6T0wyR1ZCZ3RlbE0wQXM5b1VjIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzRjY2U0MTAwLTQ3MDItNDUwMS05MWJkLTA5ZGQwYjYxMTg4OS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wNy0yOCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTEtMjEifSx7ImFhZ3VpZCI6IjFkOWFkYmMxLTEzMjUtNDBhYS1hYWZjLTc2YWNhN2VjN2VkOCIsImhhc2giOiI2UWRPaGlVUHMwZFZDdktGZ1d5TGNHNzZtN3pLWWhIcy16eC13aV8zUU9ZIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzFkOWFkYmMxLTEzMjUtNDBhYS1hYWZjLTc2YWNhN2VjN2VkOC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wNS0yNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDUtMDEifSx7ImFhZ3VpZCI6IjcxMTQ4ZGFhLTM1ZDQtNDk4YS1iZWQ5LWQ4NDM4OGI1MTRjNCIsImhhc2giOiJMWllIa1VCNmQ4M2FTX2tScGhTUl8yMEYtelBULXdnYnRyNjM2RXcyZWNJIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzcxMTQ4ZGFhLTM1ZDQtNDk4YS1iZWQ5LWQ4NDM4OGI1MTRjNC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDctMjgifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTIwIn0seyJhYWd1aWQiOiI0Zjg2OGFiOS03Yzk5LTQ3ZTctYWZiYi02MjBlMDY1NDYwMzkiLCJoYXNoIjoiN1R6OGE3Nkp3eU1LY1Z2OWw5MHJseXhoRmQyMG1wNGFVcW5lN1J2Mk9DMCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS80Zjg2OGFiOS03Yzk5LTQ3ZTctYWZiYi02MjBlMDY1NDYwMzkuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6Ik5PVF9GSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA3LTIyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMS0yMyJ9LHsiYWFndWlkIjoiMTg4MWViNDktZGI1Yy00ODgyLThlNGMtYTVlZjgxOGY1NDA3IiwiaGFzaCI6IlhndVR4THkzT0lFa2RLOFhYS0xWSkp5ME04cS14bG1nNW1GYTdsM2Y2bVkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMTg4MWViNDktZGI1Yy00ODgyLThlNGMtYTVlZjgxOGY1NDA3Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA4LTI4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNC0xNSJ9LHsiYWFndWlkIjoiNWQ3MTAzZTAtNDJmNS00NDU3LTllYjEtNTc4ZGM5OWVmOWNjIiwiaGFzaCI6ImNVRU1VWlJPN0ZTMWI0dURJdTNWYi1WUTRieF9PeGprYlh3cXZJZzZHR2ciLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNWQ3MTAzZTAtNDJmNS00NDU3LTllYjEtNTc4ZGM5OWVmOWNjLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA0LTE4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMC0xMCJ9LHsiYWFndWlkIjoiODdjNmFmZmItZTc3Mi00NTY2LWI2MzItNDI0NTUwYzc0N2RjIiwiaGFzaCI6ImJ6NHhINDh2NFdIOG9ha2NFdmc2eExGcWQ0QU9qT1lWT2dJd0NNaEw5QnciLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvODdjNmFmZmItZTc3Mi00NTY2LWI2MzItNDI0NTUwYzc0N2RjLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTEyLTI4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMS0xOSJ9LHsiYWFndWlkIjoiNjNmZTc4ODItZWU3YS00MTVkLTk2MDgtNDkwOWI2ZTQyNmUxIiwiaGFzaCI6ImVXRGJMVVhGZGN3ZzFGc0dqMGlGZHJLQzlqdzVLX0h6VnJ5N2wxNEVBQ0EiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNjNmZTc4ODItZWU3YS00MTVkLTk2MDgtNDkwOWI2ZTQyNmUxLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wNS0wNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDMtMTgifSx7ImFhZ3VpZCI6ImU5NjU4MGUwLWUyZTItNDY0Yi1hMjU5LWJjYTllNGRiZmVmMCIsImhhc2giOiJNWDhiTWFnVlBZeFE1MGJVbWotS0laamlkMFp1VlFWNURSc18wcjFDUjhzIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2U5NjU4MGUwLWUyZTItNDY0Yi1hMjU5LWJjYTllNGRiZmVmMC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDEiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0xMS0wNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDItMTEifSx7ImFhZ3VpZCI6ImIxNzUxNTgxLTNhMDctNDc5Ni04YjdiLTkwMmI0ZTRjYzY4NCIsImhhc2giOiIyTXZyYkl5aDRmWFkxUXhzOWdCS0lEUl9NQmhhSWg0am9oLWZ5anNTTEdzIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2IxNzUxNTgxLTNhMDctNDc5Ni04YjdiLTkwMmI0ZTRjYzY4NC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wMS0xOSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTAtMTgifSx7ImFhZ3VpZCI6IjJhM2Y5OGFhLTcwNmYtNDA4NS1iYzc3LTQ5YjhhNTkzNjZlYiIsImhhc2giOiJuTWZoQnVvY1hfZ1o0amk2MTJGNl9fYkllclpDb1NfWldnV1Jiay1uWjBjIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzJhM2Y5OGFhLTcwNmYtNDA4NS1iYzc3LTQ5YjhhNTkzNjZlYi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiTk9UX0ZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDQtMjMifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA5LTI2In0seyJhYWd1aWQiOiIxMTNjYmU1Mi0yYWIyLTRmODgtYWEwYi03ODdhYzI1MmNlNWUiLCJoYXNoIjoiVGFha3NUMXlQaHp3WVBQbmZvN0tDRkhNSUxoc3J2RFhNZjAyOXJpSVgtUSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8xMTNjYmU1Mi0yYWIyLTRmODgtYWEwYi03ODdhYzI1MmNlNWUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDUtMTIifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEyLTIwIn0seyJhYWd1aWQiOiI3NWQ0MjMxOS1iNWQ0LTQwNjMtYWI4Zi1jZDZiNmZhODgzYjYiLCJoYXNoIjoiVnAxeWpOUEFVRTVaRjAyZFktWkkxektVM0ZET2RVUDBxdzhJTDBPWUR2SSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS83NWQ0MjMxOS1iNWQ0LTQwNjMtYWI4Zi1jZDZiNmZhODgzYjYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wyIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMTItMTcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTA4In0seyJhYWd1aWQiOiI2ODYyMjFjOS1mZGJmLTRjNzUtOWY2NS1lNjM0YTM2MmI3MmUiLCJoYXNoIjoiYzNoSGU1UTRoRUpJSUYydkxhdkFuUWpqV0taT0FpSGx3V1ZHWVkzT3gxTSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS82ODYyMjFjOS1mZGJmLTRjNzUtOWY2NS1lNjM0YTM2MmI3MmUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTAzLTIzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMi0yMiJ9LHsiYWFndWlkIjoiZTU2ZjM5ZWEtY2I2Yy00Mzg2LWE4YmMtZTk4NTEzMzhlYTMxIiwiaGFzaCI6ImQ5bVd6WXdLWnIybll4NnZXWWVxOGNHSWlmYndBb0RDZUxkZTBDOC1rS0kiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZTU2ZjM5ZWEtY2I2Yy00Mzg2LWE4YmMtZTk4NTEzMzhlYTMxLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNS0yMSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDUtMDgifSx7ImFhZ3VpZCI6ImI4NmIzNjQyLWZjMjUtNDRhOS1hOTI3LWNlZjc0MWJmZmQ0MSIsImhhc2giOiJ6SjlQa216bzVqVlNPeHpaTWtvUXliSFBlc0RidGY2MHNuU2lQeWdSRW9zIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2I4NmIzNjQyLWZjMjUtNDRhOS1hOTI3LWNlZjc0MWJmZmQ0MS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wMS0wNSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDQtMTQifSx7ImFhZ3VpZCI6Ijk2NmM1MDk5LWViMTYtNDM4OS04NDdhLTEwZjBlYjQ0NGI1MSIsImhhc2giOiJ5aWJvUE0tQWx3LUFfN2FxazVYTGNSZTNrdV9oMlhkaHFiZVpWbFlVd19RIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzk2NmM1MDk5LWViMTYtNDM4OS04NDdhLTEwZjBlYjQ0NGI1MS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDYtMDcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAxLTA2In0seyJhYWd1aWQiOiIzNjdlOWYyNi04NjM4LTRhZjQtODVmYS0wOTViMGMwMTcxZTYiLCJoYXNoIjoiWkpJT3BXRW5aWVdPYThyXzJVZEZRMDVIcXAyaTlRa3A0UC1GVmxXUmM1ZyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8zNjdlOWYyNi04NjM4LTRhZjQtODVmYS0wOTViMGMwMTcxZTYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA2LTAzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMi0xNyJ9LHsiYWFndWlkIjoiMmQ0M2Q4NjUtYmEzNy00NWU2LWI2ZmUtZWVlMjIxYzAwYzQxIiwiaGFzaCI6ImFvRmpHNVdrWDFQSkI0cWxnZXAwSWp1YV82dTRadE41NUhDUGVIRkt3SzgiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMmQ0M2Q4NjUtYmEzNy00NWU2LWI2ZmUtZWVlMjIxYzAwYzQxLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA5LTIxIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOC0wMiJ9LHsiYWFndWlkIjoiNTRiM2ZmNzgtM2RjYS00NzQ1LWE3MzgtMDhjNTVkZWI3YWNmIiwiaGFzaCI6Im1uTndkaFpNQ2Y5NllaUVdtZGtXWlpZdHcycDk1UEZOR3ROeFVSYzg3VkEiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNTRiM2ZmNzgtM2RjYS00NzQ1LWE3MzgtMDhjNTVkZWI3YWNmLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wMi0wMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDgtMDYifSx7ImFhZ3VpZCI6ImMzN2M5MWY3LTAyODUtNDNlNC1hNDIxLTA4ZmE4NWI3NTFlNyIsImhhc2giOiJKTmtxYzBMblRiWVp3dE5Xd25DQkMzcjc3RjVGVllHWTdJS1huenJqMFljIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2MzN2M5MWY3LTAyODUtNDNlNC1hNDIxLTA4ZmE4NWI3NTFlNy5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMTAtMDYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTExIn0seyJhYWd1aWQiOiJiNmEzMTBhNS1mZGUxLTQ3MmMtOGE4My1kOTgyYmYxY2JlZDkiLCJoYXNoIjoiRnFFNmNUTEs1b210Z19qREt6SE5FZl9BVXFTMElQUkZIdnRhaFlRY1p2OCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9iNmEzMTBhNS1mZGUxLTQ3MmMtOGE4My1kOTgyYmYxY2JlZDkuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wyIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMTAtMjAifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA5LTE2In0seyJhYWd1aWQiOiI2Njc0ZmE4NS0wMTYwLTQ5ODQtYjRkMS0wOGQyZGFhMTBiYjIiLCJoYXNoIjoiNzJrT2wwd1BiTThMZFJ6UERlRzZqWEN0Z01LSDlpMTBMbmdMRzFVaWk1VSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS82Njc0ZmE4NS0wMTYwLTQ5ODQtYjRkMS0wOGQyZGFhMTBiYjIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA4LTIyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0xMyJ9LHsiYWFndWlkIjoiOWJjZWQ2NTAtMzg1Yy00ZmJmLThjNjMtNTM1NWU5NTMxNjE2IiwiaGFzaCI6InlFLXdQTUc0VUlvMVFfRDRpOW1Wd2xMdnh2RUd5cDdLbmJwSzM5YTRkZ1EiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvOWJjZWQ2NTAtMzg1Yy00ZmJmLThjNjMtNTM1NWU5NTMxNjE2Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTAyLTIyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMy0xOCJ9LHsiYWFndWlkIjoiMGIwNzUxNGUtNGJkOC00NDFjLTlhYmYtYmRhMTc5YzJjNjA3IiwiaGFzaCI6InpwcjVrRThnRXVwVDN4NlphRjZveVhLYnpCV0VkOXBvTGxzdnhhTHVWVDAiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMGIwNzUxNGUtNGJkOC00NDFjLTlhYmYtYmRhMTc5YzJjNjA3Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMnBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0xMC0yNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDYtMTgifSx7ImFhZ3VpZCI6IjJmOGY5NDc4LTQzZTktNDc4YS04ZDYwLWMzNzE2NTg0MjA2OCIsImhhc2giOiJZMVJlM29LN3dRd3ZRXzBSQ1E4Q3dvUWZSRkxmOHQ2VGIxeHRDcEE5aXJvIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzJmOGY5NDc4LTQzZTktNDc4YS04ZDYwLWMzNzE2NTg0MjA2OC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wNi0xOCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDItMjYifSx7ImFhZ3VpZCI6IjJlNWRkYWMwLTM3NzQtNGVlMy05YzNkLTNiNjQ3MjE2NjJlMiIsImhhc2giOiJoejY2UkhEVjduOGdtLTF5eDdteDJDSXFWV09NLUZCOVBhZDdhNGE1Sm1zIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzJlNWRkYWMwLTM3NzQtNGVlMy05YzNkLTNiNjQ3MjE2NjJlMi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDEtMjgifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTA0In0seyJhYWd1aWQiOiI2N2MwYTlmZi00NTNjLTQxN2YtYjM3NC02NzA3MzQwNzgxOTEiLCJoYXNoIjoiaDV0eEM1MlhIT2VXWlF3aTltUVJiSHE5WmJabDFjd0JGWEhXOG9QcThhSSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS82N2MwYTlmZi00NTNjLTQxN2YtYjM3NC02NzA3MzQwNzgxOTEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wyIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDktMDUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAxLTAyIn0seyJhYWd1aWQiOiI3OTRjZTQyNS05YTNiLTRjNjAtOGYwMi0xMzNmZjNiY2YyMTYiLCJoYXNoIjoiNE5pS3ZVZUFhRk5ZUzd3SllQV01hNC1tSXZzT0g5Tko0N1h5LXhJTDlzQSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS83OTRjZTQyNS05YTNiLTRjNjAtOGYwMi0xMzNmZjNiY2YyMTYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDgtMTgifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTIwIn0seyJhYWd1aWQiOiI0MjJmZTdjYi1hNzVjLTRiNDQtYTZlMi1iODBlMDdiYmEzZmYiLCJoYXNoIjoiTEpSUUVtQnZGX2pva1dTZm11ZTV2QkpkTmU5VjBTa2p1c2llVzVGa0tXVSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS80MjJmZTdjYi1hNzVjLTRiNDQtYTZlMi1iODBlMDdiYmEzZmYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDEtMjIifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTEyIn0seyJhYWd1aWQiOiI2MzkzYjZmZi04NTZhLTRhMjgtYTlmNi1mZjBkYWU4YmNkYjUiLCJoYXNoIjoiMjRUUHJhNkpCUTJZRVk4aHFCZUpMcVQ4WDFxbDM0M09JZkxaN0t6SmNYdyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS82MzkzYjZmZi04NTZhLTRhMjgtYTlmNi1mZjBkYWU4YmNkYjUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMTItMjcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA0LTE2In0seyJhYWd1aWQiOiIzYWJlM2Q4MC1mYzVmLTQwYjgtODU0MC05Zjk2ODNmMDFlNDUiLCJoYXNoIjoiV0tZMUJZMUVKcmFfQnZxQncyazIwZzA4SDR5LXB4RVFQNGVpdVJ0OVg1OCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8zYWJlM2Q4MC1mYzVmLTQwYjgtODU0MC05Zjk2ODNmMDFlNDUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTExLTI1In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNC0wNyJ9LHsiYWFndWlkIjoiZGNiZjdiZWMtYWE0ZS00MzM5LWEyOTItOWVlMWM5ZjhiODIzIiwiaGFzaCI6Ilc3OC1BRi1ZUFA3bHJUSG9ldFM1dEdsZU9HbS1lMGhNcXpyRGpQMVZHNFUiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZGNiZjdiZWMtYWE0ZS00MzM5LWEyOTItOWVlMWM5ZjhiODIzLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMiIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA5LTE4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNS0xOSJ9LHsiYWFndWlkIjoiNTkwZGNmNzUtZDFjYS00NDQ1LThmNmEtNjI2ZmVjYmNhMDNlIiwiaGFzaCI6ImJ0MVhJTFp5SmpUWGxFYU5URld1VmJFT0FRbS1WRzJVSUJnaDEtNXlqVU0iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNTkwZGNmNzUtZDFjYS00NDQ1LThmNmEtNjI2ZmVjYmNhMDNlLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wOC0yNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTItMDQifSx7ImFhZ3VpZCI6IjJlNzNlZjZlLWI2OGEtNDUyNi04NDgwLWEwNzg1NjJkNjljYSIsImhhc2giOiJXS2xPQjY1dkhuazdYZEFuOUg4Wi1YUEZXdXlYeUpYRUVIMXFpN3dFekpZIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzJlNzNlZjZlLWI2OGEtNDUyNi04NDgwLWEwNzg1NjJkNjljYS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDEiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0xMi0yMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDYtMTYifSx7ImFhZ3VpZCI6IjJmYTE3ZDFkLTJmMTctNDI0NS1iMDYyLTU2NWNmMjA2OTZmMiIsImhhc2giOiJYcWU2MV83dXBTakhOdXVnSm1wbDBxeVU5NVgxUDROZ0k2R0l0MTh0cjcwIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzJmYTE3ZDFkLTJmMTctNDI0NS1iMDYyLTU2NWNmMjA2OTZmMi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDktMjUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTA4In0seyJhYWd1aWQiOiJjNWI0Y2ViZi1hOGJkLTQxYTItOWI3Yi05NDg5OTU0ZDZjMTMiLCJoYXNoIjoiZkRqZVNOM25WMUs5eUNwV1A4cURFZnJCZHN0SU4tNUdVcFhfOUxTRVVUZyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9jNWI0Y2ViZi1hOGJkLTQxYTItOWI3Yi05NDg5OTU0ZDZjMTMuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA2LTA3In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNi0wNyJ9LHsiYWFndWlkIjoiZDhkYWRkY2MtZjBlMy00M2YzLTg1MTAtMWZkNDBmZjE2MGU1IiwiaGFzaCI6IldzTkRROFQtam1DSkFiY05ydkdEdEE1VXFfazFZdmhhb2tiMkJyMDhLZmMiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZDhkYWRkY2MtZjBlMy00M2YzLTg1MTAtMWZkNDBmZjE2MGU1Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wMy0wMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTEtMjgifSx7ImFhZ3VpZCI6ImQzOWU2YTg2LTZiZTktNDBlMy05MWQxLTMxMjc5YzA0NmJmNCIsImhhc2giOiJjSEFBdHktZzY1Vk9nU2dNb0tBTEx1WlBOYllfS19XR2R5dmk4VUx5U3ZvIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2QzOWU2YTg2LTZiZTktNDBlMy05MWQxLTMxMjc5YzA0NmJmNC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiTk9UX0ZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDEtMTIifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA3LTA2In0seyJhYWd1aWQiOiI0NDNmMDhlNS05Zjc3LTQ5MTUtYTdlMC1hN2Y0MWZhOWQ2NDciLCJoYXNoIjoiY3ZabTJ4TnVhSEJwQjViZnlId0dBaWtlSk9tMTl3TGRqY1ZvV2djc3RsWSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS80NDNmMDhlNS05Zjc3LTQ5MTUtYTdlMC1hN2Y0MWZhOWQ2NDcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlNFTEZfQVNTRVJUSU9OX1NVQk1JVFRFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTEwLTE1In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMi0wMSJ9LHsiYWFndWlkIjoiNjIxOTQ4ZDktMzRkOC00MzBiLWI2OTctNTNmNmQ2YjVlMzY2IiwiaGFzaCI6IlZYOUxmanVIbjFNWE02Sjc5VUJvQWJjMjhUY3ptQW5MWmhzWDd6T1hSWmsiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNjIxOTQ4ZDktMzRkOC00MzBiLWI2OTctNTNmNmQ2YjVlMzY2Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTExLTA5In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOC0wMSJ9LHsiYWFndWlkIjoiMzY1OTViZTEtMmU3Mi00NTNkLTgxYTQtYTIyNmQwYzIwYzc4IiwiaGFzaCI6IjJNN2hQSERSMWxJSmo5cGU3bTBYY1ZWUkxhcnE3dFFGZmdrTGM2czdYcFEiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMzY1OTViZTEtMmU3Mi00NTNkLTgxYTQtYTIyNmQwYzIwYzc4Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA3LTA2In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0wNCJ9LHsiYWFndWlkIjoiOTk3YWJkOTQtMGVmOC00YmM1LTgyY2MtYTcyMmEwNjgxOTM5IiwiaGFzaCI6IjM2LVpzUWdGYmhRdjJaYjBxRUNCTGF1c2c0YlNJTW95M0w4RHFYclpfVlUiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvOTk3YWJkOTQtMGVmOC00YmM1LTgyY2MtYTcyMmEwNjgxOTM5Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wMS0yNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDUtMjQifSx7ImFhZ3VpZCI6IjgwN2Q3NzQ4LWY5ZTktNDA0MS1iNWQzLWRiMThkM2JlZDFkYyIsImhhc2giOiJONmd5aHp2YjZQRWE2dFFNUjA5em9GV2hDUUxUbHNadDQ2ZktJeE5zY2pZIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzgwN2Q3NzQ4LWY5ZTktNDA0MS1iNWQzLWRiMThkM2JlZDFkYy5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMTEtMDQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEwLTIwIn0seyJhYWd1aWQiOiI5MWMxNzNkYy02YThkLTQzZjItODhlZC04NzY5N2JhNmIyNTYiLCJoYXNoIjoiWWxuQjFzQWhKX0RXTUl2a0ZaWDAwR2t6THotMU5FYTh5VXBZUkp4ZVZXQSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS85MWMxNzNkYy02YThkLTQzZjItODhlZC04NzY5N2JhNmIyNTYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMTEtMTIifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTAyIn0seyJhYWd1aWQiOiJhYzE5YTBjOC1kOTZjLTRmZjQtOGMyYi1hZTA1ZDc3ZjQ4NDYiLCJoYXNoIjoiRFBZZHN2TmNSWEM1R1hRV1llU0V1ZV9GTjBsYzdCQnNOdTUwSzZFT2NSOCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9hYzE5YTBjOC1kOTZjLTRmZjQtOGMyYi1hZTA1ZDc3ZjQ4NDYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTAyLTAzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMi0yNSJ9LHsiYWFndWlkIjoiZTk1MmJmMzMtYjY4OS00MWUyLTljYjctOGJjZDczOTkzMGM1IiwiaGFzaCI6Il8zNWVXQUZfTjJDWnpBM3Z4WWtjamFoNzFjSEQ3UlcyT1I5bDE5Ym1wZmMiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZTk1MmJmMzMtYjY4OS00MWUyLTljYjctOGJjZDczOTkzMGM1Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wNy0yNyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDMtMTcifSx7ImFhZ3VpZCI6IjY2NWIzMzYyLTkzNjAtNGQwZS1iMDAwLTVmMzIyNWY1ZGU2OCIsImhhc2giOiJVcWJoVDdjeU9fOGRQaFp5MEpxbWlOaEhLOW0xZWNyQUtESUVvMjEya19FIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzY2NWIzMzYyLTkzNjAtNGQwZS1iMDAwLTVmMzIyNWY1ZGU2OC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDgtMTUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTIzIn0seyJhYWd1aWQiOiIxYjhiYWIwNC1iMDJlLTRjNmQtODYzYy1mZjhiYjZhNDQwZDEiLCJoYXNoIjoiUElkbVRzUUtTWS00UlNLaXVfMWZQT19ndXJrZ0ZZaUY2aVhyLU5hVzdQdyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8xYjhiYWIwNC1iMDJlLTRjNmQtODYzYy1mZjhiYjZhNDQwZDEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDktMTMifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTAyIn0seyJhYWd1aWQiOiJhYTZiNTYxZS0zZmRjLTRhNTItODllYS02NWMyYjE4OWJkNzEiLCJoYXNoIjoiRlRZTU9sTlpXZXN1TjVyYmV6Q3Rwd0Nja3VjdklMb3RaaHBzM0pFT05ZUSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9hYTZiNTYxZS0zZmRjLTRhNTItODllYS02NWMyYjE4OWJkNzEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlNFTEZfQVNTRVJUSU9OX1NVQk1JVFRFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA3LTE3In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMi0wOCJ9LHsiYWFndWlkIjoiYTlkOGNiYjctNjEzMi00YTBlLTgxYmEtMmY1MjBmNDkwMjgyIiwiaGFzaCI6IjlMb21Sb1RwUHBRenhTcC1VeG95OGc0dEg3X3RwRGNpOGJzZ1BDbXJ4OUkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYTlkOGNiYjctNjEzMi00YTBlLTgxYmEtMmY1MjBmNDkwMjgyLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMnBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wMy0xNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDgtMjMifSx7ImFhZ3VpZCI6IjZiMDZmMjRkLTAwMjAtNGZkMC04NWJiLTdkYjhjMzlhZTVmMyIsImhhc2giOiJrT2xsM2l5R25pcElXcDdEaUNhTjFXekFxTTg5T3Ffd0liZW00SDdUaWFFIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzZiMDZmMjRkLTAwMjAtNGZkMC04NWJiLTdkYjhjMzlhZTVmMy5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wNC0yMSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTItMTAifSx7ImFhZ3VpZCI6IjJlYTM4NmM1LWJlMWYtNDYzYS05ODczLTcxMDJhMzMwMmM0NyIsImhhc2giOiJJOW1oV0dLbmVyVXJMOG56TGJPUi01bmZTOVdLODZRTWxCRTNzYWZNTk9zIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzJlYTM4NmM1LWJlMWYtNDYzYS05ODczLTcxMDJhMzMwMmM0Ny5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDktMjYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEwLTIxIn0seyJhYWd1aWQiOiJiYTRhZDFjNy1kYjdiLTRiYzEtOGExMi04YTk4ZDJmOTY3MDMiLCJoYXNoIjoiS3h4Y3gtTEJ1VlhFVzJTbzROeURqdDlrOHd3RGlmRzFYd25PWFdZV3BObyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9iYTRhZDFjNy1kYjdiLTRiYzEtOGExMi04YTk4ZDJmOTY3MDMuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wyIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDEtMjYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA3LTAyIn0seyJhYWd1aWQiOiI1MTNjNmIxZi01ZmMyLTRhZjMtYmY2ZS05NTFmNTUyYTA4ZDAiLCJoYXNoIjoiMUNIaEpGNWloX3g4U0g3a3lxUkQwbWYyRzIxX3FSbWpnLTBUZzBycEFxTSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS81MTNjNmIxZi01ZmMyLTRhZjMtYmY2ZS05NTFmNTUyYTA4ZDAuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTAyLTE4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMS0wMiJ9LHsiYWFndWlkIjoiNDBjMmMxNTktY2E4NS00YTI2LTk5Y2MtOTdjMTc3ZTU4MzQ1IiwiaGFzaCI6IjFJMEo0dFVqeTFIS1ZSNjVrS1J2bWdKbktJc3pOQmhBLVBaNzJvc0ZRRjQiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNDBjMmMxNTktY2E4NS00YTI2LTk5Y2MtOTdjMTc3ZTU4MzQ1Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wNi0yNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDQtMTMifSx7ImFhZ3VpZCI6IjI5NWFjNWM1LTJkMmUtNGIwMS1iYzAzLWFlY2FlMmZmYTg4NyIsImhhc2giOiJiN0Q3N0YzdVNQNGp1ZmNpWTM5eDd0WUY2QnU4MjVjVW04bEpDU3ZVNU9jIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzI5NWFjNWM1LTJkMmUtNGIwMS1iYzAzLWFlY2FlMmZmYTg4Ny5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDgtMDMifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTI0In0seyJhYWd1aWQiOiI0ZmE5MTcxMS1iMDdiLTQyY2ItODAyNC1iYjkzM2RjNjc0ZmQiLCJoYXNoIjoiZDhvNllWY2loNXc1cXBEejNfa1VfelBVUG5xemJQbVZwSVd3RjJOMjRQWSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS80ZmE5MTcxMS1iMDdiLTQyY2ItODAyNC1iYjkzM2RjNjc0ZmQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTAyLTIzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMy0wNSJ9LHsiYWFndWlkIjoiNGU1NGQxMzktZjU2ZC00NDM0LWE2MjItMmNiMjIyZWUxMTFlIiwiaGFzaCI6IkhFdkZiQ09mVW96NGxPb2lFOHpfTkRoRjZ2QzBtVE9kMndvSDN6NjNEMm8iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNGU1NGQxMzktZjU2ZC00NDM0LWE2MjItMmNiMjIyZWUxMTFlLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTAxLTI4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNi0wNCJ9LHsiYWFndWlkIjoiODc2MmI1MzYtODRiMS00M2ViLThiNjctNzhkMzE5ZDI5NTI5IiwiaGFzaCI6InpQTHZOVmQ2MGpsWkxxV0hMamZDT3U0NnM1Zm5fdDVwczFRZ1lRUV9LM28iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvODc2MmI1MzYtODRiMS00M2ViLThiNjctNzhkMzE5ZDI5NTI5Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMnBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0xMC0xMCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMDIifSx7ImFhZ3VpZCI6IjJhYjNkYTFlLTI5MjEtNDBmMi04M2M4LWQ2NGEyYzBiZGY5OSIsImhhc2giOiJfSW50R29sYzdiR1dUa0VuMTZCLXc2R0diSWJ4VFg0TzB0dVRWWFlOZldZIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzJhYjNkYTFlLTI5MjEtNDBmMi04M2M4LWQ2NGEyYzBiZGY5OS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDYtMjEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTI0In0seyJhYWd1aWQiOiJlOGI2Njg0NS02Y2Y4LTQwNWEtYjhhOS1hNDI2YmQ2ZTQzZmEiLCJoYXNoIjoidE5DVjU1MkdSUVpFV3VCTUY5OWxxWnFDMzZwMzA0THZEeW9maGFpNG8zVSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9lOGI2Njg0NS02Y2Y4LTQwNWEtYjhhOS1hNDI2YmQ2ZTQzZmEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTExLTE0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0wMSJ9LHsiYWFndWlkIjoiMjU5NDY5MzktMzY2My00YWE0LWE4YmMtYzc0ZWE5NDg1MmI2IiwiaGFzaCI6IkVRZC1JNjZhQnJZeGs5cVJQNXljM0Y2Vkl2ZEpHUmQ0UWVfcDdvQ0VXOFUiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMjU5NDY5MzktMzY2My00YWE0LWE4YmMtYzc0ZWE5NDg1MmI2Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMnBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wOS0xNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDktMTQifSx7ImFhZ3VpZCI6IjMzZDdmMTIxLTYxOTYtNGRlYy1iMjRkLWM1OWRmMTc0ZGM5NiIsImhhc2giOiI4UDlTQ0RYcHg1aDdtZ3ZLQzlVSGNJY0FLbzd4NkRXOTJEVjB2N2ZLaDlNIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzMzZDdmMTIxLTYxOTYtNGRlYy1iMjRkLWM1OWRmMTc0ZGM5Ni5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0xMC0yNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTItMDMifSx7ImFhZ3VpZCI6ImNkZjU0NGRlLTRlMjctNDA2ZS05NWU2LTFlMjdlZWQwYzMxYSIsImhhc2giOiJBaUpndlBURjJsTzdJSkJvNXloc3Y0YVFlSXZhTzdXb3RhVElJRWhzSzJnIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2NkZjU0NGRlLTRlMjctNDA2ZS05NWU2LTFlMjdlZWQwYzMxYS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDMtMDQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA2LTI1In0seyJhYWd1aWQiOiJhZjdhNDVkNC00Njk3LTQ0ZGMtYWYyZS1kZmIxYjQ2NjRiZDQiLCJoYXNoIjoiaGFtLXVndTFoS2FoeW9WVkxQVVUtX0F3dTZGNUtfOHVHUmUxdy1pRVVVVSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9hZjdhNDVkNC00Njk3LTQ0ZGMtYWYyZS1kZmIxYjQ2NjRiZDQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTEyLTE2In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMy0wOCJ9LHsiYWFndWlkIjoiNmVlZWUzNmUtNTczOC00ODI2LWI1ZGItYzcxNTExMGZkZTFkIiwiaGFzaCI6Ik9udUcyN1dNUFFDRExfWXlhTEc3aGtYMDBHZk1OdkZNX25wSnVhMW9weGciLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNmVlZWUzNmUtNTczOC00ODI2LWI1ZGItYzcxNTExMGZkZTFkLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMnBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOS0yNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMTgifSx7ImFhZ3VpZCI6IjE4OGI3MjhkLTE1ODUtNGFiMS1hNmVhLTM3MzVjM2M1ZDNhNCIsImhhc2giOiIyQXdEdDF6cVdSZ2pYQk40NGdNQXFTZFM3Q1hyMUNlTGNmdjVISnI5a1NZIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzE4OGI3MjhkLTE1ODUtNGFiMS1hNmVhLTM3MzVjM2M1ZDNhNC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDMtMTMifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTAxIn0seyJhYWd1aWQiOiI1M2E0MTQ2My03ZDJmLTRmZmEtOWFkZS00YmFmYzViODIyZWEiLCJoYXNoIjoiNFJEOEhaYnZHaUE3N2paWDQwSWxQcmRIUnB4MVpDZ3hseVZnU1NmbjJnOCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS81M2E0MTQ2My03ZDJmLTRmZmEtOWFkZS00YmFmYzViODIyZWEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wyIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDItMDEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTIzIn0seyJhYWd1aWQiOiJlMWRkZjdiMC1iMWMwLTQ0NDctYTkwYy00NjlkOWViMzQyOTkiLCJoYXNoIjoiTlZScERVNFQ3UEQ1WDRyWHdURkVqVVFvRklWTXZNVXhnYmJlSlN1R1R1VSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9lMWRkZjdiMC1iMWMwLTQ0NDctYTkwYy00NjlkOWViMzQyOTkuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDYtMjgifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAyLTAyIn0seyJhYWd1aWQiOiI0NzMyMmZjMy04Mzc2LTRiYjktYTliNi1kMTBlYzc2YmRlMDYiLCJoYXNoIjoiNnBYX3d0Y2ozMFhZU2NENTU2M1E1d2V3SzhlU0pBUWQwakpzd2Nodl9CZyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS80NzMyMmZjMy04Mzc2LTRiYjktYTliNi1kMTBlYzc2YmRlMDYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6Ik5PVF9GSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTAyLTE0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0xMSJ9LHsiYWFndWlkIjoiNzEzOWY2YzgtYWU2OC00NTU2LWJkYTktZmU2MDExYjQ5ZDFlIiwiaGFzaCI6IlVGaUhBMWdoaXZnREthQnBGaTJVMjdlSlBraVhXRlNKOW9xc1RKV2EtY0kiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNzEzOWY2YzgtYWU2OC00NTU2LWJkYTktZmU2MDExYjQ5ZDFlLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJTRUxGX0FTU0VSVElPTl9TVUJNSVRURUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0xMi0yNSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMjcifSx7ImFhZ3VpZCI6ImY0Yjc3NDNjLTMwMjMtNGViZS04YzA3LWMzZmFiODAzMTFhZCIsImhhc2giOiJ2WTM5dzFpMjBKazZuRVFtajRtcmVyVnlZOXJ1bkNSRE1IVnBnWXNQa01BIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2Y0Yjc3NDNjLTMwMjMtNGViZS04YzA3LWMzZmFiODAzMTFhZC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDItMDMifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAxLTIzIn0seyJhYWd1aWQiOiI5ODQ5Y2QzMS0yYjZjLTQxODUtOWU5Mi1hZDJhYjI1YzQ2ZGUiLCJoYXNoIjoiSXRNaklPelNFN0NWU1hYMlJHRldPeGxmeXVpZEtrRkZoSm8tWFJZVjJuNCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS85ODQ5Y2QzMS0yYjZjLTQxODUtOWU5Mi1hZDJhYjI1YzQ2ZGUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlNFTEZfQVNTRVJUSU9OX1NVQk1JVFRFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA2LTIzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0yNyJ9LHsiYWFndWlkIjoiY2E5ZDhiMWUtYzdjNi00YmM5LWJiODItNGZiZmZkNzgzOWUwIiwiaGFzaCI6ImFjT1B3bVduM0RibzFFOXh3dWhZaDgxWjFWN21JMTRIUWVUbV96T1A2YTAiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvY2E5ZDhiMWUtYzdjNi00YmM5LWJiODItNGZiZmZkNzgzOWUwLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA2LTI1In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0yNSJ9LHsiYWFndWlkIjoiMGNiOWMxOTctMGZiMC00YTgyLWJlMjktOWI1NGMwOWNkOWM3IiwiaGFzaCI6ImtCTjNKRFdodHdjNzhrWmpvUTdYOUFTTEhDYk5WYUVOV3JsZjVKQzJ1d1kiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMGNiOWMxOTctMGZiMC00YTgyLWJlMjktOWI1NGMwOWNkOWM3Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMnBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0xMC0yNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMDYifSx7ImFhZ3VpZCI6IjRkNDM2NjcxLThmZTAtNDA3MS1iNDEwLTY4ZGY0YWRkZmM0MSIsImhhc2giOiJ2TUtSZ2h1X19wVGlfZlY2NlJYZEJQQlBmLVhIRHdSY2NCZFJHb0tTWW5ZIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzRkNDM2NjcxLThmZTAtNDA3MS1iNDEwLTY4ZGY0YWRkZmM0MS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0xMC0wNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMTgifSx7ImFhZ3VpZCI6ImZhYmQwMTk1LTAxMDUtNDA1YS1iNGFmLTU5NmIzNGZhNDFjNiIsImhhc2giOiJISWNBTzZTaHJDdEdnWDU4T2FGZHlmcFRJcEs5cWExc0tkbE5YYTNWQUVrIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2ZhYmQwMTk1LTAxMDUtNDA1YS1iNGFmLTU5NmIzNGZhNDFjNi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDktMjQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA5LTA2In0seyJhYWd1aWQiOiJjYWQ3MjZhMC05YzBkLTRlODktYWVkZS1iZTNmNjE2MDBkNGYiLCJoYXNoIjoiMERCRGZiaGVHS3NKY0lzbzhROXZVOWdCMlN5U1ZLcWo5YlQ5a1k3aFphRSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9jYWQ3MjZhMC05YzBkLTRlODktYWVkZS1iZTNmNjE2MDBkNGYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wyIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMTEtMjUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA0LTA0In0seyJhYWd1aWQiOiIyYTFjODAyMC03Y2MzLTQyZWQtOGIxMC03YzAzODhiMGU1ODYiLCJoYXNoIjoiU0xzLXVhdEZTS0s1Sk5IUEVzekM2NWRWcG9TaUl6Z2Ywa21kdjh6UFhKbyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8yYTFjODAyMC03Y2MzLTQyZWQtOGIxMC03YzAzODhiMGU1ODYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wyIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDktMDQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAyLTEwIn0seyJhYWd1aWQiOiI1OGE1N2ZjYi05MTMyLTRjOTgtYjMyMi00MDIzNGFlZGM1YzIiLCJoYXNoIjoiWUdoNXJwZVVGaVZ6alBhVjltWXNpWHVaazZVenY0a2xSWGN5ZzhPSUlRZyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS81OGE1N2ZjYi05MTMyLTRjOTgtYjMyMi00MDIzNGFlZGM1YzIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA1LTE1In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMi0yMCJ9LHsiYWFndWlkIjoiYzc5ODg4NTQtMWU2MC00MDQ2LThmNDItMzE5ZDkwMjY2NjM0IiwiaGFzaCI6IjBEOG9TbkFBOG5qQ3M3dWItRmhPVVlCY2VnME9rYlNHY0xsaXVHNGsybVkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYzc5ODg4NTQtMWU2MC00MDQ2LThmNDItMzE5ZDkwMjY2NjM0Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wNC0yOCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMjgifV19.CUPr4wFz1-lf-w5QeTXw2uiAyO8bjwWF1BuVjQoCH90Cn-Ifmuf2w3l9fwV7T218yI1jqGz-1BydmM4FvCYDtggolang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/testdata/MetadataTOCParsing-F4.jwt000077500000000000000000001304351414201525100304570ustar00rootroot00000000000000eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlDenpDQ0FuV2dBd0lCQWdJUEJLV3k0ZEhyQ1FQeHREcnc5MnRUTUFvR0NDcUdTTTQ5QkFNQ01HY3hDekFKQmdOVkJBWVRBbFZUTVJZd0ZBWURWUVFLREExR1NVUlBJRUZzYkdsaGJtTmxNU2N3SlFZRFZRUUxEQjVHUVV0RklFMWxkR0ZrWVhSaElGUlBReUJUYVdkdWFXNW5JRVpCUzBVeEZ6QVZCZ05WQkFNTURrWkJTMFVnUTBFdE1TQkdRVXRGTUI0WERURTNNREl3TVRBd01EQXdNRm9YRFRNd01ERXpNVEl6TlRrMU9Wb3dlREVMTUFrR0ExVUVCaE1DVlZNeEZqQVVCZ05WQkFvTURVWkpSRThnUVd4c2FXRnVZMlV4SnpBbEJnTlZCQXNNSGtaQlMwVWdUV1YwWVdSaGRHRWdWRTlESUZOcFoyNXBibWNnUmtGTFJURW9NQ1lHQTFVRUF3d2ZSa0ZMUlNCTlpYUmhaR0YwWVNCVVQwTWdVMmxuYm1WeUlEUWdSa0ZMUlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkhrUUV6NVBnbk1hM0xYb2ZCYWlPc1lsTWNabmNBNlh1TXBCRkNvVEU0eE0vYWJTRGpjUVREcW1DRVdTdms0eHJqL3BZajNUdzdkSXd2ZkpLUWlNVmFpamdmSXdnZTh3Q3dZRFZSMFBCQVFEQWdiQU1Bd0dBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRkx3QU10ZkhrVWdmbHc2bXlvUGt3WTB4U0g3bU1COEdBMVVkSXdRWU1CYUFGRkJhVWJ4bzloS1U5TVNQQVhPeUFkenVqRDh5TUQ4R0ExVWRId1E0TURZd05LQXlvRENHTG1oMGRIQnpPaTh2Wm1sa2IyRnNiR2xoYm1ObExtTnZMbTU2TDIxa2N5OWpjbXd2VFVSVFEwRXRNUzVqY213d1VRWURWUjBnQkVvd1NEQkdCZ3NyQmdFRUFZTGxIQUVEQVRBM01EVUdDQ3NHQVFVRkJ3SUJGaWxvZEhSd2N6b3ZMMlpwWkc5aGJHeHBZVzVqWlM1amJ5NXVlaTl0WkhNdmNtVndiM05wZEc5eWVUQUtCZ2dxaGtqT1BRUURBZ05JQURCRkFpQWg3QXlFZzZ3SmdrRTZzdGZDdUtyMGExVkJkL3NWd1JkZmI0V0FXT1pLc0FJaEFMYktYUVRFNEl1aTlET0kxV0c0c1ZVVXJFQSs0cFZ4VzVxL2RwQ2ttbEx0IiwiTUlJRkRUQ0NBL1dnQXdJQkFnSVBCTmZQVnpTTnZiS09HMGVHQnVFSk1BMEdDU3FHU0liM0RRRUJDd1VBTUZBeEN6QUpCZ05WQkFZVEFsVlRNUll3RkFZRFZRUUtEQTFHU1VSUElFRnNiR2xoYm1ObE1Ta3dKd1lEVlFRRERDQkdTVVJQSUVGc2JHbGhibU5sY3lCR1FVdEZJRkp2YjNRZ1EwRWdMU0JUTVRBZUZ3MHhOekF5TURFd01EQXdNREJhRncwek5UQXhNekV5TXpVNU5UbGFNRzR4Q3pBSkJnTlZCQVlUQWxWVE1Tc3dLUVlEVlFRS0RDSkdTVVJQSUVGc2JHbGhibU5sY3lCR1FVdEZJRlJ5ZFhOMElGTmxjblpwWTJWek1USXdNQVlEVlFRRERDbEdTVVJQSUVGc2JHbGhibU5sY3lCR1FVdEZJRWx1ZEdWeWJtVjBJRUYxZEdodmNtbDBlU0JHTVRDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTUVIbUZmYk55cFB1cTk0aytTU0NpVXZYU3Vtb2xZcEhZSGlrUGFWMmpRYmJYdkd1Sit3OHl4ekhHVVJGWlFMZkNGVnJUWjI2OWVidlkycE5saFVTcE5KYzdTcGhvbFNyOXRDanVIZEdMM3V2QmRweGFaanZ0ZFZFNnluNVp2Q3h5eC9oQWd1RWRrZFB1VkVtZFZEcjY0YzY4ZDI4b2kvM1lzRm5JYnFNbnVYdjhwcXZGYXNHamRUV0ZDM2F1SkdkdTJ2NjVzQlU0dldjckVGZFlqME1nd09EMGxvWUhiKzB6S0s5d3hmaVpQVVY4SEVaYkt3RFdmNWpvdWFjSmVXWjMyNFdGMUxIT2pXcnhIZ29EUUJpenMycVVGSnZDTmluc2FDU001SlN4UXVsTUdkYkRVVVN2WTNuaWt6bnJ5TnJONmYvT1JuZmsyK0tJenRjdDJrT0ljQ0F3RUFBYU9DQWNRd2dnSEFNQXNHQTFVZER3UUVBd0lCaGpCTEJnTlZIU0FFUkRCQ01FQUdCbWVCREFFQ0FqQTJNRFFHQ0NzR0FRVUZCd0lCRmlob2RIUndjem92TDJacFpHOWhiR3hwWVc1alpTNWpieTV1ZWk5ellXWmxkSGx1WlhSd2Eya3ZNQjBHQTFVZEpRUVdNQlFHQ0NzR0FRVUZCd01CQmdnckJnRUZCUWNEQWpBU0JnTlZIUk1CQWY4RUNEQUdBUUgvQWdFQU1CMEdBMVVkRGdRV0JCU2oyaGZnaURUYnlhWmNBSkJMV3l3Z0ZBUDFCekFmQmdOVkhTTUVHREFXZ0JTcU52OUJhZEtkaWp2WUhHWFRXOTVyY0MyVWtEQjBCZ05WSFI4RWJUQnJNR21nWjZCbGhtTm9kSFJ3Y3pvdkwyWnBaRzloYkd4cFlXNWpaUzVqYnk1dWVpOXpZV1psZEhsdVpYUndhMmt2WTNKc0wwWkpSRThsTWpCR1lXdGxKVEl3VW05dmRDVXlNRU5sY25ScFptbGpZWFJsSlRJd1FYVjBhRzl5YVhSNUpUSXdNakF4T0M1amNtd3dld1lJS3dZQkJRVUhBUUVFYnpCdE1Hc0dDQ3NHQVFVRkJ6QUJobDlvZEhSd2N6b3ZMMlpwWkc5aGJHeHBZVzVqWlM1amJ5NXVlaTl6WVdabGRIbHVaWFJ3YTJrdlJrbEVUeVV5TUVaaGEyVWxNakJTYjI5MEpUSXdRMlZ5ZEdsbWFXTmhkR1VsTWpCQmRYUm9iM0pwZEhrbE1qQXlNREU0TG1OeWREQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFpT09IMFlBK3EvWUdDWTc5a2ZLVS9aUWpiSzBNc1J3Q3paRzlTL200aXdJY3pRM0dha09GSDdyeTR5RnFRNThjTys5Z2JWcnNCaEg1NEJJME13UzVpQ1hqaHYxYmdrMUhsdHc4S0hSb3NsSnJ5RFFQelIzUzJFTXZ4K2x6eDJYdjZzMlh4dkhSUkM4S1FZVC9PV2RmaTlDZkI5ZFFvS2NkbTVsMWZEOWdWVjZteGV6a3JRbDdDMEtmZTRacHkxNDdIT29aMDRyT3hseHR0M1dIc0ZnV0wvTW4wZGJiQVMweHhDTmR3ODhJaUxON0d6S3pScmJ3NmNIc0JEYXZ4bFhGY0p1OFZxU2pOTVJGREgxUDRBR2JTZVg4eXVEMWdzN3d2bHJBeWRvTHZxNjdQUDI0d1U0QjF1UVluWUVtQzVvQXZzNnFTdmxwdERiTnM3Y2hNeTBhcHc9PSJdfQ.eyJsZWdhbEhlYWRlciI6IkJ5IHVzaW5nIHRoaXMgbWV0YWRhdGEgc2VydmljZSwgeW91IGFyZSBzb2xlbWx5IHN3ZWFyIG5vdCB0byBkbyBldmlsISIsIm5vIjo0MiwibmV4dFVwZGF0ZSI6IjIwMjAtMDQtMDgiLCJlbnRyaWVzIjpbeyJhYWd1aWQiOiIyMWUyNjcwMy04ODI2LTQxZjItOWI2Yi1jZmQ1MzA0MTI5OTciLCJoYXNoIjoiaXNXMzFUSTZDQzlsR3lhRXpidzlUeFl3dXEwc005S2VuMDBDbDRvd1dqcyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8yMWUyNjcwMy04ODI2LTQxZjItOWI2Yi1jZmQ1MzA0MTI5OTcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6Ik5PVF9GSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTAyLTE2In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMi0yOCJ9LHsiYWFndWlkIjoiYmIyZjc2MDYtOWU3Ny00YjFiLTg2NWItMzRkYjk1OWZmZDI5IiwiaGFzaCI6IlRXSFZON1dkY1RYbWh4bDN2N2N5Q2RnVU9aaENmSWdKemt5S3Qwck1UMjAiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYmIyZjc2MDYtOWU3Ny00YjFiLTg2NWItMzRkYjk1OWZmZDI5Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTEyLTE5In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNC0xMCJ9LHsiYWFndWlkIjoiMTUzM2NkODctNTliOC00NDAyLTllYWQtODk3NGRkNzJjZDZiIiwiaGFzaCI6Ii1BVFRuRXpSOExSd0R3eXBJb1daR1BkeXkzaWkteWY1c0xvckQ0V2E1U0EiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMTUzM2NkODctNTliOC00NDAyLTllYWQtODk3NGRkNzJjZDZiLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0xMC0wMSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDktMTkifSx7ImFhZ3VpZCI6Ijc4Y2Y0OWZkLWI0MjgtNDQyNS04ZTMzLWUzNjFmY2MxOWY5MiIsImhhc2giOiJEcVhyVkstZHdES2xTTHRGdGZFck80WFJDb25fczBUcnN5cGZVMjYwNU5NIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzc4Y2Y0OWZkLWI0MjgtNDQyNS04ZTMzLWUzNjFmY2MxOWY5Mi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOS0yNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMDEifSx7ImFhZ3VpZCI6ImRiM2Y2MjUxLWQyOWYtNDgwMS05MDI5LWI1OWE5MzViMzhmNiIsImhhc2giOiJ2VjZzVVRnc3U1Mm5QdG9fa1JyYW4zd3FDMDhOYmJyQm4zOFJNSHZiV3JZIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2RiM2Y2MjUxLWQyOWYtNDgwMS05MDI5LWI1OWE5MzViMzhmNi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDctMTkifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTEzIn0seyJhYWd1aWQiOiIwNjM0ZmMzYS02MTZkLTQxNWUtYmQzYS0zNGJiZDM4NTY1ZGYiLCJoYXNoIjoidUVBNzZfSW1oYzNsdVF2X05IZGVRVEdNejVzX3h1Z09kNHpfeFNwQ01mNCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8wNjM0ZmMzYS02MTZkLTQxNWUtYmQzYS0zNGJiZDM4NTY1ZGYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA3LTA0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0wNSJ9LHsiYWFndWlkIjoiOTIzMmM5NmEtYmQ5MC00NTc5LThkY2EtNmQwMmVmZTEzOTIwIiwiaGFzaCI6ImZtZ3N3QTdHZ3lJcEFJd3UyOTBrcFBsNm5rQ3o0MzZ6ck1Fa3FIaVVBR2MiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvOTIzMmM5NmEtYmQ5MC00NTc5LThkY2EtNmQwMmVmZTEzOTIwLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wMi0yNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDItMjgifSx7ImFhZ3VpZCI6IjIwMzhkNDIzLWNiYjQtNDRjZi04OTNhLTc1NTg0OGE2MmNkNiIsImhhc2giOiJvLVY4YS1LTk5PbXhmNjNELUM2cGlkNkxEeEd0cll2NlN5czF4cnQxeVZVIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzIwMzhkNDIzLWNiYjQtNDRjZi04OTNhLTc1NTg0OGE2MmNkNi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wNy0wOCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTEtMDkifSx7ImFhZ3VpZCI6IjE0YTQwMzEwLTY4NmItNGM3Yi04YzgxLWE0MzYzMDVmZGYzNSIsImhhc2giOiJBWjRQTlRrRGlPOVB6QmxybFoxZVR3Zy00Yk90SVBNclkzSU1Gb0M3VzNNIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzE0YTQwMzEwLTY4NmItNGM3Yi04YzgxLWE0MzYzMDVmZGYzNS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMTAtMTMifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTA5In0seyJhYWd1aWQiOiI4M2E2MTYzYy0xMjJlLTQ5ZTItYTBhOC1jNGUzYTZmZDEyYTUiLCJoYXNoIjoiZ0hhTG5WUVNlS3NaTElRaGN1NzlqRUZudk5HRUdxWmVFcHh3S0xLV3MxQSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84M2E2MTYzYy0xMjJlLTQ5ZTItYTBhOC1jNGUzYTZmZDEyYTUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDQtMTQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAxLTE2In0seyJhYWd1aWQiOiJhOTBlNjUxZi1jMmY5LTRiZDQtYmE2Mi1lYzAxODEzOTIyMzkiLCJoYXNoIjoiLTFsbW1zVE42MDQ5SThDdXk1WHNKTzE1MHM3V2JQeHhKOUl4bncxV05mcyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9hOTBlNjUxZi1jMmY5LTRiZDQtYmE2Mi1lYzAxODEzOTIyMzkuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA0LTA1In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMS0wNCJ9LHsiYWFndWlkIjoiMjA5NjAxYmUtOWQ5Ny00ODEyLTgyMWMtNjE0N2QxMWFkMDNkIiwiaGFzaCI6IlE2Wm81OVZIN1NRdWxMUGQ3emJXM2dkMnk4NEx5aEFhZzVaZVdXMmpwRUkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMjA5NjAxYmUtOWQ5Ny00ODEyLTgyMWMtNjE0N2QxMWFkMDNkLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTExLTExIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNS0xNiJ9LHsiYWFndWlkIjoiMTVlN2ZlOTMtYTQ0ZC00Y2Q4LTlhOTctNjNiYmU3ZjQwNzcxIiwiaGFzaCI6InZCZ2FHVFJ0aDhUb0FET3lBMHpSOVdRbDZEQTBMYlF2YlpGeE9LNUk1RWsiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMTVlN2ZlOTMtYTQ0ZC00Y2Q4LTlhOTctNjNiYmU3ZjQwNzcxLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJTRUxGX0FTU0VSVElPTl9TVUJNSVRURUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0xMC0xMSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDYtMDQifSx7ImFhZ3VpZCI6ImU1MjVlZjczLTI2ZmUtNDVhNi05NDEyLWQ1ZmUxOGYxMGUyYiIsImhhc2giOiJITF9KYUQtRnJmUGpFcHd4eVhzdHAzRm5NYVZaNUtzNnBIRU0zQXRSU2tJIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2U1MjVlZjczLTI2ZmUtNDVhNi05NDEyLWQ1ZmUxOGYxMGUyYi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDYtMjQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAzLTI4In0seyJhYWd1aWQiOiJmMjc3MWJkMy00ODQzLTQ4NzctYTM4OS00NjgzYmUwYzI4NDAiLCJoYXNoIjoiVUFTM09obXlScE9fb084NjVmMWFUTHNLSExlQUZUME1QMXBrSExnZFlBQSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9mMjc3MWJkMy00ODQzLTQ4NzctYTM4OS00NjgzYmUwYzI4NDAuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDUtMjYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAxLTI2In0seyJhYWd1aWQiOiIyNWFiZGM4Mi0xMjIyLTQ3N2UtOGU4YS04YzNmYWFhMDFiOWQiLCJoYXNoIjoiWHA3UVNXSWF2N04wd0xaV1lubHdfaTM0bVN5Zmk4SHZGTDZVcnNnVFdNWSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8yNWFiZGM4Mi0xMjIyLTQ3N2UtOGU4YS04YzNmYWFhMDFiOWQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMTEtMjQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTI3In0seyJhYWd1aWQiOiJhOTgzMWIwOS0wMzkxLTRiZmMtYTRkNS0yNzBlMGVhMGVmMjIiLCJoYXNoIjoiSEx4ZFhUVVZzZXd1akxNNkV3anNoR3R2Vm0tRXQ2Y3UzX3FMeWdYTWRYQSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9hOTgzMWIwOS0wMzkxLTRiZmMtYTRkNS0yNzBlMGVhMGVmMjIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDQtMjYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA5LTE1In0seyJhYWd1aWQiOiJkMWM4Yjk5Yy00NWI5LTRlNjMtODA1ZS02M2Y2N2RiM2ZkZDUiLCJoYXNoIjoiSnR5eVEtcmI5Z1RoenBvRmVqV29LOXNNd0hTa3FST2FsakxFdEs1SThydyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9kMWM4Yjk5Yy00NWI5LTRlNjMtODA1ZS02M2Y2N2RiM2ZkZDUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDItMjYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTA1In0seyJhYWd1aWQiOiJiMDUxNzhkMy00NTM1LTQ3YWQtYTgwZi00MWY1YWU4MWViNWQiLCJoYXNoIjoicjdSY1U2eXlBak1rN2t2QmpDeWU3WnNBeUlMa1dxa0VLNlRjV2dneXM2RSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9iMDUxNzhkMy00NTM1LTQ3YWQtYTgwZi00MWY1YWU4MWViNWQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMTAtMDMifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTA2In0seyJhYWd1aWQiOiJmMDM5ZGUwMS0wMWRmLTQxNDMtOGQzMC1iZmIzNTkzYzY3ZmYiLCJoYXNoIjoiUTNCTGpHbmZYQ2hDVjNQYnk3Qm5ab3kteFhLZVVPS3I2bXMyX1NKMzRxMCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9mMDM5ZGUwMS0wMWRmLTQxNDMtOGQzMC1iZmIzNTkzYzY3ZmYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTAxLTIzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOS0xNiJ9LHsiYWFndWlkIjoiYTdlMWM5NDQtMzk0MS00Y2ZkLThiZTYtMmZjODIyNTg0NzdkIiwiaGFzaCI6Im1tN3FBU3hsUkZiVmlYdkdQTEJtd1pRLVdpUVkxejlOVjRwVk0zNml3czAiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYTdlMWM5NDQtMzk0MS00Y2ZkLThiZTYtMmZjODIyNTg0NzdkLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA0LTEzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMi0xNSJ9LHsiYWFndWlkIjoiMDczMmIyMzctMTM5Zi00YWY5LWEyZTQtNDE0ZmMxOTYyZGI4IiwiaGFzaCI6IlhiM1RwYk53eWJxVXZSOUlOakt5V1lHRklPTDUtVnR2aFJrQVRZTFlOVnciLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMDczMmIyMzctMTM5Zi00YWY5LWEyZTQtNDE0ZmMxOTYyZGI4Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0xMC0wNyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDYtMTgifSx7ImFhZ3VpZCI6ImM5ZWIyMWFiLWJiZmYtNDE1OS1iZDE2LTg0MDAzMWMzMDA3ZiIsImhhc2giOiI0RTllZ0hQVTExSHk4QmVtNTRnWC1aZlc5dTBIWGgwby1rWlBEeGVaZDRFIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2M5ZWIyMWFiLWJiZmYtNDE1OS1iZDE2LTg0MDAzMWMzMDA3Zi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDgtMTUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTIzIn0seyJhYWd1aWQiOiI5NmIzNDdmOC1kNmU0LTRjZTctYmZjMy1mMzNkZWEyYThiZjgiLCJoYXNoIjoiRDFPdmZIS2F2YjNCQWZFb09JZjFic2Nrek9NcUpTUzFTSzJTRmhVLUU0MCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS85NmIzNDdmOC1kNmU0LTRjZTctYmZjMy1mMzNkZWEyYThiZjguanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTEwLTA5In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNC0yOCJ9LHsiYWFndWlkIjoiYTI2OGE1ZmYtZGZiNC00NGU0LTk0ZWMtNGRmYTdkN2FjN2EyIiwiaGFzaCI6IjZoQ0NERjkzWXJISkVsTGdSbi0tSzItU3NYbnhRMUZ1SThuajRYREF0TmMiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYTI2OGE1ZmYtZGZiNC00NGU0LTk0ZWMtNGRmYTdkN2FjN2EyLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJTRUxGX0FTU0VSVElPTl9TVUJNSVRURUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNy0xNSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDItMTQifSx7ImFhZ3VpZCI6ImMxNGRmYTc2LWEyOWEtNGNiZi1hMzczLTllYWEzMjRjYmFiMSIsImhhc2giOiJnOFZnTS1ZcjJHM05GalBqSS1Od0w1NlZUXzZicDJmV3Z0U3kyN0JnNGs0IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2MxNGRmYTc2LWEyOWEtNGNiZi1hMzczLTllYWEzMjRjYmFiMS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wMS0yMCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDYtMjcifSx7ImFhZ3VpZCI6IjVlMGFkMjE1LTYzZjktNGI0Ny1iZjNmLTFjOTFiZWRkZTdkNSIsImhhc2giOiJWUjk5MENyaFVqcXRfaDN2X0lULUlsTGwwa3FSaG52Q1BzZEk2QXBteGJ3IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzVlMGFkMjE1LTYzZjktNGI0Ny1iZjNmLTFjOTFiZWRkZTdkNS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDctMDcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAzLTIzIn0seyJhYWd1aWQiOiIyYWU3MzZhMi0wZDZhLTQ2MjYtODg5Yy00MjE0NTM4ZDc5NzIiLCJoYXNoIjoiUnJoWnFwaXlMcU9WOVNnSmtlNjJ0M1cyalZvLWhQY2k1Skp6OTNVd3NaNCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8yYWU3MzZhMi0wZDZhLTQ2MjYtODg5Yy00MjE0NTM4ZDc5NzIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDktMjIifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA2LTIxIn0seyJhYWd1aWQiOiI2MjdjNDkyZC0xMzY4LTRkZTktYjY2MS1hYmJkZDA1OTZkMGEiLCJoYXNoIjoibV9QenBoV2FmNDMyY3JDbGpKZWxEVGxmLUhBcGppbGF5RkRmcE51VjhHQSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS82MjdjNDkyZC0xMzY4LTRkZTktYjY2MS1hYmJkZDA1OTZkMGEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDctMDYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTAxIn0seyJhYWd1aWQiOiIwMWIyZjkxMi1jMDFmLTRjODgtODc5Ni1iM2EyODJlNDA1M2EiLCJoYXNoIjoicUxNT2VveEVNUGdYX2puX0ZPbWJaQWllTmtLT2ZEcnZ5dzlPQ0RSYzFvbyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8wMWIyZjkxMi1jMDFmLTRjODgtODc5Ni1iM2EyODJlNDA1M2EuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDYtMTUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA3LTA0In0seyJhYWd1aWQiOiJhZGFmMjVjYi1kODRhLTRlMGYtYWRjZi0xMmYwZGY3YzE0ZDkiLCJoYXNoIjoieTh2ZFlSS3YtRFRZWGttbmZfdWRPYnpMMkdBV2owZlU4bGtQenE1ei0wNCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9hZGFmMjVjYi1kODRhLTRlMGYtYWRjZi0xMmYwZGY3YzE0ZDkuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6Ik5PVF9GSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTAyLTIyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMi0yMCJ9LHsiYWFndWlkIjoiNzgxNjFjMTItMmIyZS00M2NkLTlhNjAtMzk5YjYzMjdhZGI5IiwiaGFzaCI6ImxxRGxOcEdmeXlodkY1TVJHdjhLYW1jVW9ZQWhwQ0J4c2pjYVIteHFmakUiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNzgxNjFjMTItMmIyZS00M2NkLTlhNjAtMzk5YjYzMjdhZGI5Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0xMC0yMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDQtMjEifSx7ImFhZ3VpZCI6IjlhODQ3NmQzLTA5ZmQtNDI4MC05ZGI0LThmY2QxZDYyNjk0MiIsImhhc2giOiJwTEFRdzc3T3MyNWFYd0x2ZTRiZ2xQaDBZWHFZUFVLSlExcGZMR2ZPUlVnIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzlhODQ3NmQzLTA5ZmQtNDI4MC05ZGI0LThmY2QxZDYyNjk0Mi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0xMi0xNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDMtMjUifSx7ImFhZ3VpZCI6ImNlMDRiZDY5LTNmNjEtNGRmYy04ODcwLTQ3NzdlMTI2MWM2OCIsImhhc2giOiJnNGFiUXVpR0x3RFh6d3IyQm83NFFuS3JXUWRMTEU2YmVhUWJSdWV4alc4IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2NlMDRiZDY5LTNmNjEtNGRmYy04ODcwLTQ3NzdlMTI2MWM2OC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDEiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOC0xNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDUtMTgifSx7ImFhZ3VpZCI6ImJjNGNlNmMxLWViY2YtNDdiZC1hNDZhLWIwNDU0ZDM4ZmMyNCIsImhhc2giOiJtTWpwNGhpN1IyQ0Q2SFY0ZnUzS0FWVGxkaHU1ckRHNk9wTE1SdERYUkdFIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2JjNGNlNmMxLWViY2YtNDdiZC1hNDZhLWIwNDU0ZDM4ZmMyNC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMTItMDkifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTE0In0seyJhYWd1aWQiOiJiN2I0ZjUzZC1kZTE3LTRlNzMtYTk0YS1hNWRkMzQ0YWQ1YzIiLCJoYXNoIjoicXRsaWdfc3FpRWhNM0pGME1wRUZUSTZTOVJBdmd5ZDRNVHNYY0ZoZEhzZyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9iN2I0ZjUzZC1kZTE3LTRlNzMtYTk0YS1hNWRkMzQ0YWQ1YzIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6Ik5PVF9GSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTExLTIzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNS0xOSJ9LHsiYWFndWlkIjoiYzE3YWNiNWMtNGIzNy00ZjYwLThiZWMtOGI0NWNkNTIxZTE4IiwiaGFzaCI6Ik5IejR1WTRUTHp2X3hFSE96ckhNMGR4d2NBT1loWW1nNWhjR1hwSUd1NnciLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYzE3YWNiNWMtNGIzNy00ZjYwLThiZWMtOGI0NWNkNTIxZTE4Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMnBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0xMC0yMiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDgtMjgifSx7ImFhZ3VpZCI6IjA4OWZmNjI1LTdjMzktNGFmNy1iYzRiLTIwNmRhZTJkZWQyNSIsImhhc2giOiJCZnZ0ZHRCcmtoOV8xZGdmYllWX3VoeFppTklRS3NjRzhlaXBjMFpFaUxFIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzA4OWZmNjI1LTdjMzktNGFmNy1iYzRiLTIwNmRhZTJkZWQyNS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wMy0xMCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDMtMDgifSx7ImFhZ3VpZCI6IjU3M2EyOWIzLWIzNmQtNDg2Zi05ZTE2LTNhODRiM2Q5NDExMCIsImhhc2giOiJUZEE3b2FuTnFsX2llU2Q4dVJEZE4ySDlGNVRQeTJ0QlZOeE8yS3pUWjlRIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzU3M2EyOWIzLWIzNmQtNDg2Zi05ZTE2LTNhODRiM2Q5NDExMC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDEiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wMS0xMSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDItMDQifSx7ImFhZ3VpZCI6ImEwMmJjZGUwLWZmMTUtNDg4My05ZGY4LTAwZjk1MTM4MzFmNyIsImhhc2giOiJwTnY0dl9kOUJnbm9xMERjc0dxT0NCR3V5enZickNEOUc1aTBha0xGeUVvIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2EwMmJjZGUwLWZmMTUtNDg4My05ZGY4LTAwZjk1MTM4MzFmNy5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0xMi0yMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDMtMjQifSx7ImFhZ3VpZCI6Ijg5ZmU2Mzc3LWU0MDktNDM1ZS05MDA2LTZmOGM0MjQzOWQ2NiIsImhhc2giOiJpWTFkdkxpSGF4bHFJMTVCMmFRbEp2VUNtWTIwQjl1RFNETG96ZUFDQV9NIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzg5ZmU2Mzc3LWU0MDktNDM1ZS05MDA2LTZmOGM0MjQzOWQ2Ni5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wMi0wMiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDItMDUifSx7ImFhZ3VpZCI6ImE2NWUwZmM3LTY4ZDEtNGVjMC04OTcxLTU0Nzk5ZmQ2OWQzMiIsImhhc2giOiJRSklnREtxemdjeXN3N19mYWozcmtVT2x4ZlhMcENhc1lRNzd6UHFlajlZIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2E2NWUwZmM3LTY4ZDEtNGVjMC04OTcxLTU0Nzk5ZmQ2OWQzMi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiTk9UX0ZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDUtMTUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTIwIn0seyJhYWd1aWQiOiI4ZjU5NGE3Ni1hY2Q0LTQ3MWMtYmVlZS03NDhiYzAxYTYxMjQiLCJoYXNoIjoicFczR0JtZzQtdmJBcXloaHdmaEFzZnVsWGJoOEo4cXIzMTQ1d0ZDSHV2MCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84ZjU5NGE3Ni1hY2Q0LTQ3MWMtYmVlZS03NDhiYzAxYTYxMjQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA1LTI3In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMC0yMyJ9LHsiYWFndWlkIjoiZGY2OWE0OGUtNDBhOS00N2NiLTgzY2MtMTEwMzM2NDAyN2QwIiwiaGFzaCI6InBJV1VNdXFYV3d3aUxSd1QyRGs4NzI3OENrdVRiTUFQd3FyejdNUmk1RXMiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZGY2OWE0OGUtNDBhOS00N2NiLTgzY2MtMTEwMzM2NDAyN2QwLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMiIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA0LTEyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNS0wOSJ9LHsiYWFndWlkIjoiNzQ0ZDI0NTktYTZiOS00OWViLTkwMTQtZjgyOTM3YTJlZTg0IiwiaGFzaCI6ImxkV19yZnUyYUt1d29SLWVUcUpyRGZoT2NIQzNjcmgtbWU5OGU5V3NVTHMiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNzQ0ZDI0NTktYTZiOS00OWViLTkwMTQtZjgyOTM3YTJlZTg0Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTAzLTE5In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0yNSJ9LHsiYWFndWlkIjoiNTg0ZjBhMDAtOTY0MC00YmJlLWE3OTUtNzg1MDRjZjI0YjZjIiwiaGFzaCI6IlpqdDF1RlI0a2oyUnN4WHdDSU5hWWI0eFZrcTFVektDUUxFallHN0gyY0kiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNTg0ZjBhMDAtOTY0MC00YmJlLWE3OTUtNzg1MDRjZjI0YjZjLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA2LTI3In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOS0wMiJ9LHsiYWFndWlkIjoiODkyN2NiOTAtZmI3Yy00ZTAzLWIzYzEtZTJlZTlkOTY2NTEzIiwiaGFzaCI6IndsODhzblRqTm5IZmVsZnljdUk3RFdENkhhY3Q2SllfVU1UY3pOTFVsWlEiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvODkyN2NiOTAtZmI3Yy00ZTAzLWIzYzEtZTJlZTlkOTY2NTEzLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTAyLTEwIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMy0wNSJ9LHsiYWFndWlkIjoiNTJiYjdiYTYtYTExYS00NzJmLWEyMjItMWU2ZDdkM2ExOTg2IiwiaGFzaCI6IjhIQkhCS3JRWGs2Y21BODNsaTBsRGU2bW5jYVhBcEhLTjIyd3NHaTZmWUUiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNTJiYjdiYTYtYTExYS00NzJmLWEyMjItMWU2ZDdkM2ExOTg2Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOC0wNyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTItMTEifSx7ImFhZ3VpZCI6IjE2ZmUxZTEzLTBjMDktNGVlOS04NjlmLTA3N2U0ZGQzYjBmNCIsImhhc2giOiI0YkR0MFNzLWgxaUMzU1ppMUZ4SjVpcnF1MVlnOUo0OWtSWk5GclE0RXE4IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzE2ZmUxZTEzLTBjMDktNGVlOS04NjlmLTA3N2U0ZGQzYjBmNC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiTk9UX0ZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDEtMDgifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTE1In0seyJhYWd1aWQiOiIxNDJiZjc4MC1jMzBlLTQ0ZjQtODE0Ny1mNDk5MzMwZGRjOTciLCJoYXNoIjoiRUFuU0hhWUNZLXNkRVRVdHNvV1A4YWxvd29uaWxVa1IxS3U0R2FoMmZ6ayIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8xNDJiZjc4MC1jMzBlLTQ0ZjQtODE0Ny1mNDk5MzMwZGRjOTcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTAzLTEzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0wOCJ9LHsiYWFndWlkIjoiY2I4YTk3ZTItODY5OC00MTBiLWE5NDMtOTFhZDk5NTM1ZTQ1IiwiaGFzaCI6IlhidDZMejBQUkgwV2VLQlVoRlRxVllmMlo0dERTdG5DSjZVOWRab0QyWVEiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvY2I4YTk3ZTItODY5OC00MTBiLWE5NDMtOTFhZDk5NTM1ZTQ1Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wNy0xNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDEtMDEifSx7ImFhZ3VpZCI6ImVlZDQ3MWJjLTIwZjctNDZhOC04YjM5LWY0Y2YxZjU0NzI2YyIsImhhc2giOiJsdWVwS3FVVDZERFZsMDZaRnlhSHpjQkxBWmVDV1JESzNuOWxtS1RhblJrIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2VlZDQ3MWJjLTIwZjctNDZhOC04YjM5LWY0Y2YxZjU0NzI2Yy5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wMi0xMCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTEtMTYifSx7ImFhZ3VpZCI6IjM4ZDAzMTIzLTc1MmEtNGE3MC1iN2Q2LTdkYmY0Zjk4MDFkNCIsImhhc2giOiJMOGNvY25TQkEtNGlRd29wQU8tcUg5T20yclhUcWRNRC1JMFIwZGpZbzd3IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzM4ZDAzMTIzLTc1MmEtNGE3MC1iN2Q2LTdkYmY0Zjk4MDFkNC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0xMS0yMCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTAtMTIifSx7ImFhZ3VpZCI6IjEzNDY5NjRhLWM5YTAtNGQyZC05MDYxLTEzYTg3Njk5OGYwNCIsImhhc2giOiJka3JuQjJXc2tNaDdNYlExV2ZyZTgyVE03VTBrQzNFSlhVbXByclBjTHRJIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzEzNDY5NjRhLWM5YTAtNGQyZC05MDYxLTEzYTg3Njk5OGYwNC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0xMS0yNSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDUtMjAifSx7ImFhZ3VpZCI6IjlmYmZhYmMzLWQyYWYtNDk3Yy04YTgyLWFkYzRjMmI3YThiMiIsImhhc2giOiJVX2tLQjhMSzlraDhSaE94aHU3YkVPQVhrSzN1cVdTQXJDY3U4SkF1alZJIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzlmYmZhYmMzLWQyYWYtNDk3Yy04YTgyLWFkYzRjMmI3YThiMi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDJwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDctMTIifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAzLTA4In0seyJhYWd1aWQiOiI5NGZmMjFkMi1kYzY1LTQwMjItYjljOS04MWE1ZWQwMjI5ZmEiLCJoYXNoIjoia0tXQ1Nuak5iRGJxNUwxX1luYkwyNERNMkZWTUtjcDZ4SDFSb0ZMZnZLayIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS85NGZmMjFkMi1kYzY1LTQwMjItYjljOS04MWE1ZWQwMjI5ZmEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6Ik5PVF9GSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA3LTIyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0xMCJ9LHsiYWFndWlkIjoiMzAxNjkyMWEtMjliNS00NzI1LWI5NTktY2VmZjYzMDIzNWY4IiwiaGFzaCI6Inp0SE8xTEFwUXh2RUJIaTVaUWNZUzZOdGFUUEVlTk83RVM4WkNWc2FWV0UiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMzAxNjkyMWEtMjliNS00NzI1LWI5NTktY2VmZjYzMDIzNWY4Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTEwLTI2In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0xNSJ9LHsiYWFndWlkIjoiNTNiMDlkY2EtMzJjOS00YzI3LTlkZjItMWRmODc4N2JiYmQzIiwiaGFzaCI6IkJDOWt2ZTJ6SldUcS1MWlR2cVZxZjVvejYxLXlvbHB2LTJpeDFkX1paLVEiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNTNiMDlkY2EtMzJjOS00YzI3LTlkZjItMWRmODc4N2JiYmQzLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNy0xNSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDQtMTQifSx7ImFhZ3VpZCI6Ijk3OGI4OGRjLWZlMTYtNDkxZS05OTFiLTZhNWNhNzIzMzExOCIsImhhc2giOiJhaUxaRDVrRHZ4SkRZTEg2cmR3bk1FSXVxc1RSQWh6OUlzc2dza1VyajlzIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzk3OGI4OGRjLWZlMTYtNDkxZS05OTFiLTZhNWNhNzIzMzExOC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMTAtMDIifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAxLTA4In0seyJhYWd1aWQiOiJlYmM1ZGNmOC0yNzdkLTQyN2EtODQ1OS0zYjllMjUxN2ZlYzIiLCJoYXNoIjoicWVhTE8tRjBFOUVzSklBQVNlM1hUOGJsNjNsVWNaZlRmVHpfM3lpQ1hYdyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9lYmM1ZGNmOC0yNzdkLTQyN2EtODQ1OS0zYjllMjUxN2ZlYzIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDUtMTIifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA3LTA5In0seyJhYWd1aWQiOiJjYmM3ZWM4Ny1iMTcyLTQ2ZmUtYWMwZC04MmNjMGJiNTNiZDUiLCJoYXNoIjoiN2pUWjVIVVlrNFlDVHlJRGM5bWFTV3dROVJrXzhyWGszbEw3MVFrS3hTMCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9jYmM3ZWM4Ny1iMTcyLTQ2ZmUtYWMwZC04MmNjMGJiNTNiZDUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlNFTEZfQVNTRVJUSU9OX1NVQk1JVFRFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA3LTIzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMS0xMiJ9LHsiYWFndWlkIjoiN2ZlZGY1NGUtNzU1Ni00MWQ5LWJlNTAtODU2YTkxZmU5YWU2IiwiaGFzaCI6IlFZd3MzWEJWSlVrY0xRcnpmMGNlQWRCX0J6TmVMcGJjMXhMUEJScjEtNmMiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvN2ZlZGY1NGUtNzU1Ni00MWQ5LWJlNTAtODU2YTkxZmU5YWU2Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJTRUxGX0FTU0VSVElPTl9TVUJNSVRURUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOC0wOSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDMtMjQifSx7ImFhZ3VpZCI6IjgyYjFhMGZjLTM3NTQtNDMwMi1iOGQ3LTA1OWU1MGVhYjExOCIsImhhc2giOiJqTXRmRVluTkpBQ09senpTVDVxZHNhOWFqXzJiQ0UzMkJmVmg4NzRFTV80IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzgyYjFhMGZjLTM3NTQtNDMwMi1iOGQ3LTA1OWU1MGVhYjExOC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiTk9UX0ZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDctMTcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA2LTEwIn0seyJhYWd1aWQiOiIxMjQ1NzkyMC0xYWM4LTQ5YmMtOGRmNS1iNmQ4M2ZhZDczMWIiLCJoYXNoIjoiZ1FQS1l3eUZISWctLTBHV3NIZWpmTzhSRklQMTV2cmlxVHFwcnpqSGtVRSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8xMjQ1NzkyMC0xYWM4LTQ5YmMtOGRmNS1iNmQ4M2ZhZDczMWIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTAxLTExIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOC0xMiJ9LHsiYWFndWlkIjoiYzIyMzFiNTMtNjRkMS00ZGI4LWE2MzEtYTcwZDcyYzYwNGYxIiwiaGFzaCI6InQ4c2t0V2o2VW16am51ZEhlTkY2U1RwX2FRZEE4UEt0T0FhbTZiUUdSa0UiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYzIyMzFiNTMtNjRkMS00ZGI4LWE2MzEtYTcwZDcyYzYwNGYxLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTAzLTE0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMy0xNCJ9LHsiYWFndWlkIjoiYWZhZmE1N2UtMzI0ZS00NGRiLWFjYjUtNGIzMWM2NGVlODFiIiwiaGFzaCI6Ii1WT01EakhWSzcyVTB3ZGJYNzJMOG1DZDNxUW83V1otN1J4SXlaSjRGQVkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYWZhZmE1N2UtMzI0ZS00NGRiLWFjYjUtNGIzMWM2NGVlODFiLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJTRUxGX0FTU0VSVElPTl9TVUJNSVRURUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0xMC0wOSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDktMDcifSx7ImFhZ3VpZCI6IjBjMTk4NGFmLWE2NmMtNDZlMC1hNjY0LTA5NGNiMjkxNjhjMCIsImhhc2giOiJ6dGFwLTF1TUFOb08tVHRNRmt1Rnd1VVN0al9PenR6ejUyU2ZwMkRfdTY4IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzBjMTk4NGFmLWE2NmMtNDZlMC1hNjY0LTA5NGNiMjkxNjhjMC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiTk9UX0ZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMTItMDcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAyLTIyIn0seyJhYWd1aWQiOiIyZjlmNDVkMS1iMzdjLTRhODUtOWVlZC1jZjRkMGJiNmY5NmYiLCJoYXNoIjoiOXQ2aTdYdVV1THNlNFJwbV9YOE44MGhpcV9MMnhOZy02dGlLb2RlTEhYYyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8yZjlmNDVkMS1iMzdjLTRhODUtOWVlZC1jZjRkMGJiNmY5NmYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wyIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDEtMjEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAyLTIyIn0seyJhYWd1aWQiOiIxN2M0MDJkZS05ZTFkLTRlOGYtYjNiMC01M2E5YTA5Y2E2OWQiLCJoYXNoIjoicUtUTllRZVdyRXlndUQyUzh5T2p2M1ZrYVdhODFsVGFoWUZ6MldzWm1hVSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8xN2M0MDJkZS05ZTFkLTRlOGYtYjNiMC01M2E5YTA5Y2E2OWQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6Ik5PVF9GSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA4LTAxIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMS0xMCJ9LHsiYWFndWlkIjoiNjk4NzhmZGUtYzJjMy00ODI5LTg3YmUtYzFiYmE1OTdiZWNiIiwiaGFzaCI6IlE4OUN1YWh0dEQyNjVhVTNtMkpvSWtQQVZ2cXh3dnpoS25GdWZyay0tRkUiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNjk4NzhmZGUtYzJjMy00ODI5LTg3YmUtYzFiYmE1OTdiZWNiLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0xMi0xMiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTEtMTgifSx7ImFhZ3VpZCI6ImRjYWMzZDAxLWE2MDEtNDA2NC1iYzgyLWQ2ODQ2OWMyOThkNyIsImhhc2giOiJvRjlhdE9xM3pzTEJ1ZV9mOW9YUDdqTDBpb1dEUFVsc0c2UmM4VXBSYUFFIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2RjYWMzZDAxLWE2MDEtNDA2NC1iYzgyLWQ2ODQ2OWMyOThkNy5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDItMDUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEyLTEwIn0seyJhYWd1aWQiOiIwMGQ3M2ZkYi1iMDFmLTRmOTctOGMyMC00ODQ1MDkxNTk2ZTQiLCJoYXNoIjoiNUdUWXdSWHg3QzZyUjAxTnJ3TzNyQ1VZYVZxZjZaQ2hydXVKdUNvdmdTQSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8wMGQ3M2ZkYi1iMDFmLTRmOTctOGMyMC00ODQ1MDkxNTk2ZTQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDItMjQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEyLTE5In0seyJhYWd1aWQiOiIxOTk2NmMzNy04ZGM0LTRhNjItOWNlYy00NmQyNmYxZTdhYjQiLCJoYXNoIjoiQTdSb1FiTjNId05GRUhLdnhRM05hdmZPMGs4eGZjX3lLTnVKU1JZSVNSRSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8xOTk2NmMzNy04ZGM0LTRhNjItOWNlYy00NmQyNmYxZTdhYjQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wyIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDEtMjAifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA5LTI1In0seyJhYWd1aWQiOiJjMDljYzg0NC02MTkwLTQwZDEtOTZlMC0xMzhjNWRkMTRiZTEiLCJoYXNoIjoidkhGWUhELUowOHNhVGVUMnpVWnBKdkRZV2piNGxNTmNwNmpQa3FJYlVvUSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9jMDljYzg0NC02MTkwLTQwZDEtOTZlMC0xMzhjNWRkMTRiZTEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDctMDQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTIxIn0seyJhYWd1aWQiOiI4MGQwYzQxMy03YmRjLTRiOTAtYjgzYS1mZThmOGM4NjMyMTgiLCJoYXNoIjoiWGdobWtNck1IUUVwcnlubGpiTWdVRVRteEtWTzZPZmR1ejlUdlh1MldWRSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84MGQwYzQxMy03YmRjLTRiOTAtYjgzYS1mZThmOGM4NjMyMTguanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6Ik5PVF9GSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTEwLTEyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0wMyJ9LHsiYWFndWlkIjoiM2I0N2Y1YTUtYzQ0Yy00NzMzLWFhNDktZmY3YmQ5NTc0YTJjIiwiaGFzaCI6IkFnd2NrbEE1bU55UWlyOTZNSnoyYW1zRWFhWmdmTEVJWnZnN2xMNFNkVUkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvM2I0N2Y1YTUtYzQ0Yy00NzMzLWFhNDktZmY3YmQ5NTc0YTJjLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMiIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTEwLTE2In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0xMCJ9LHsiYWFndWlkIjoiMThkMWZkNTQtZGVlMi00YmM0LWFlZmEtYzdkNjMxNjJiZWYyIiwiaGFzaCI6InMzelF5WG1ESjBoLW1zcFhLR3R1M0ZFNUlmY0tndU9wZUxnbmk2SkdWeEEiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMThkMWZkNTQtZGVlMi00YmM0LWFlZmEtYzdkNjMxNjJiZWYyLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wNy0yMCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTEtMTUifSx7ImFhZ3VpZCI6IjM1NmY1YzQ2LTg1MzYtNGQ3MS1hMTE4LTFkYzQ0ZDAyNzVlZiIsImhhc2giOiJYa1RsMkxjWFNOMk9kaWNqS2o0NXdVelZ1Y0ExeHcxMEV0aDlRMzl3TWZ3IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzM1NmY1YzQ2LTg1MzYtNGQ3MS1hMTE4LTFkYzQ0ZDAyNzVlZi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDJwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDMtMDgifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTA4In0seyJhYWd1aWQiOiJiNjYwZDI5Yy1iYzA5LTQ0ZWQtOWUxNi0xMDAyZGQzNjkyOGMiLCJoYXNoIjoiSk1LU0h3VDEzYmR6Q1RHR2w1eFNlMXJMUUFDcm1QX2czUVYxN3h3TEFkRSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9iNjYwZDI5Yy1iYzA5LTQ0ZWQtOWUxNi0xMDAyZGQzNjkyOGMuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlNFTEZfQVNTRVJUSU9OX1NVQk1JVFRFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTEwLTAyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMS0xMSJ9LHsiYWFndWlkIjoiZTE1YmQ2NDgtMjM2Ni00NzVhLTgxNDMtNmNlNzU2NzY2NzI1IiwiaGFzaCI6Ik1PWXJ4blNXM3dIQW1WNVJxX3J6MlRBWGtfRkNYaWViMHQwbVhUWXBHQkUiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZTE1YmQ2NDgtMjM2Ni00NzVhLTgxNDMtNmNlNzU2NzY2NzI1Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0xMC0wMSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDEtMTQifSx7ImFhZ3VpZCI6ImIxOWRmOWE3LTVhNjQtNDUxOC1hNzYyLThmZGU4ZjZiMGJkYSIsImhhc2giOiJERWsxWVhrY0JHVmRaVDZPTEwxcG1uYkVndWRRUHV2TGxRTFpkQWxJS0NNIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2IxOWRmOWE3LTVhNjQtNDUxOC1hNzYyLThmZGU4ZjZiMGJkYS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDJwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDgtMTAifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAzLTE2In0seyJhYWd1aWQiOiJjYjAxM2ZlNS1kNjIzLTRiZjEtYjhhNi1jNjZiMmM3NTRhNzQiLCJoYXNoIjoiWHh6LUVSZDFVb01zZWRRelR0OW8tbWt4VlRvWVFZZlNyUnltcDBpdHc3MCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9jYjAxM2ZlNS1kNjIzLTRiZjEtYjhhNi1jNjZiMmM3NTRhNzQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMTEtMjQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAyLTI1In0seyJhYWd1aWQiOiIxNTg5OGZjOC0yODAzLTQzZjMtOGM0Yy01YzVkMmM5M2U5ODAiLCJoYXNoIjoiSGVSNGJaeDFPYy1zLV9xc3Q1QUpqTFJQb2ttMU1zdWRiSndJMGRGY1hxYyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8xNTg5OGZjOC0yODAzLTQzZjMtOGM0Yy01YzVkMmM5M2U5ODAuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDYtMjYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTA5In0seyJhYWd1aWQiOiJkNGQ1ZjQxMS1lMWE3LTQyMzEtYjI1Zi1hNGE5YmQ5YTNmNDciLCJoYXNoIjoiNUhzelc2TENqTlA3TENWaklmVDdwd3VzQUw3dTl0U2hfR09CWU9VN2FESSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9kNGQ1ZjQxMS1lMWE3LTQyMzEtYjI1Zi1hNGE5YmQ5YTNmNDcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTEyLTAxIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOC0yNSJ9LHsiYWFndWlkIjoiYzhmN2FlOGQtYThiZi00Y2MyLWI5ZWUtNTU5MTRkOTRmODFjIiwiaGFzaCI6Im90VnIyTXFDenVLUk1XZl9lVFN3QUNqbm9rUXlIaHdwd0Rwc0JMOXE3eEEiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYzhmN2FlOGQtYThiZi00Y2MyLWI5ZWUtNTU5MTRkOTRmODFjLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOS0xMCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDQtMTMifSx7ImFhZ3VpZCI6IjA1MjEyYmVlLTMzYjgtNDRkNy1iMzlhLWJkNzg1ODk5NzE1MSIsImhhc2giOiJCRVp4UVVwVUlGUGhBT1dIOTdkLXZYN3c4LTBZY09DNjNKWXoydmg0c20wIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzA1MjEyYmVlLTMzYjgtNDRkNy1iMzlhLWJkNzg1ODk5NzE1MS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDktMDYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAzLTExIn0seyJhYWd1aWQiOiIwMjQ5NmMyNi0xZDk3LTRhYzMtYWNkMi1iODIwMWMxYTFjY2MiLCJoYXNoIjoiWWZzbjlMbmFmMkdFd1RuVGRINGliQWozSFN5R1VsZlNrbEZBdGxJRUVLbyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8wMjQ5NmMyNi0xZDk3LTRhYzMtYWNkMi1iODIwMWMxYTFjY2MuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDItMTQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEwLTA4In0seyJhYWd1aWQiOiI1ZTBiMDNkZS04MWFjLTQ2Y2UtYmQ0Ny1kZjhiNjZiMTZjZDkiLCJoYXNoIjoiNTlFYXgxODRLNDU0c1l4dnRYWWVIRzVkZFM2Uk1JUl9JWG5vcnlwOVJ5RSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS81ZTBiMDNkZS04MWFjLTQ2Y2UtYmQ0Ny1kZjhiNjZiMTZjZDkuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTEwLTI4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMC0xMSJ9LHsiYWFndWlkIjoiNDY0NjA5MzYtZjM4Yy00ODk4LWIwYjItYmQzZTk4MGE4NDNkIiwiaGFzaCI6IkFuSks4RHhsUzhVeTdJX3JvMXhIV1dJRnNrRm9tRE90UFh4cjJNX3lrRVkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNDY0NjA5MzYtZjM4Yy00ODk4LWIwYjItYmQzZTk4MGE4NDNkLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJTRUxGX0FTU0VSVElPTl9TVUJNSVRURUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNS0wMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDMtMDQifSx7ImFhZ3VpZCI6ImQ2NWE4ZTMyLThiYmYtNGQwZS04NTU0LWU0MDAwYmYxMzljOSIsImhhc2giOiJ1ZzFwZ3ZYdzd2LTVSQ3JIRjl5SXppX0JrUFRVdjNZOW1PNG9UaV91cnlnIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2Q2NWE4ZTMyLThiYmYtNGQwZS04NTU0LWU0MDAwYmYxMzljOS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDktMTYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA5LTA3In0seyJhYWd1aWQiOiJlMTEzYTMxNS1iYmJkLTQ5ZDItYjJiNC1hN2U0YjhlMTY0ZTciLCJoYXNoIjoidTVKVl9PSG41M3BHWE1tUTI1dFF0UnR6VXBTUnZnVmpBVnd2OGVFa3didyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9lMTEzYTMxNS1iYmJkLTQ5ZDItYjJiNC1hN2U0YjhlMTY0ZTcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMTAtMjAifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTAxIn0seyJhYWd1aWQiOiI4ZGJmMWFmMC0wZTFjLTRkOGEtOGU4Mi1jYjVlZTY5MWI4YmEiLCJoYXNoIjoibmNfV0hxdkFrYThfM3FIWFdEMjBEcEFING40YTd2R25XVDVldkxxM19yYyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84ZGJmMWFmMC0wZTFjLTRkOGEtOGU4Mi1jYjVlZTY5MWI4YmEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA4LTAyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0xNCJ9LHsiYWFndWlkIjoiMThhYjAwNDEtM2Y0MS00ODJhLTllYjEtNjM4MmQ0NzQ5ZTQzIiwiaGFzaCI6InRtcjAwVUJxWWdiMks1U3lFX3c3SjMtMmVaY3JmbkhiODJuSlRMdlZGRFkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMThhYjAwNDEtM2Y0MS00ODJhLTllYjEtNjM4MmQ0NzQ5ZTQzLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wOC0xOCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMDQifSx7ImFhZ3VpZCI6ImU1OGM5MTE4LWE3YjQtNDRiMS1iYTk1LTgzM2EyZmVkNWVlYyIsImhhc2giOiJVdUU2WWRXbFA1Mk1hNy1TclBRdDRQdTdxQVIzeVluU01RbDRFVkp0VHhzIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2U1OGM5MTE4LWE3YjQtNDRiMS1iYTk1LTgzM2EyZmVkNWVlYy5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDJwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMTAtMjIifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA2LTIzIn0seyJhYWd1aWQiOiJmYzNkZThkMC1iYTI2LTQxZTUtOTY0My05NmE1NmY3NmFhNzEiLCJoYXNoIjoiVkxiQk5mRGtQNDdNakJNVnhvT0huM29FY1VPUU5HY1NJRzhJSmtiQVhZdyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9mYzNkZThkMC1iYTI2LTQxZTUtOTY0My05NmE1NmY3NmFhNzEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA4LTI3In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNC0yNCJ9LHsiYWFndWlkIjoiYTFmMzlmMTMtYjMyNi00MDQ0LTliOTktZTQwNjQ5ZjYyZGE3IiwiaGFzaCI6IklnaVBiNXQtM3VUTV9RTHV4MUhMd1drd2NhVjQ1SUJnVWJfTzA2NlJ6Y00iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYTFmMzlmMTMtYjMyNi00MDQ0LTliOTktZTQwNjQ5ZjYyZGE3Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTExLTE3In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMC0xOSJ9LHsiYWFndWlkIjoiODQ3NTg3NzgtOWFjZi00MTJhLWFlNWEtZGU1NDU2NmQyMjNkIiwiaGFzaCI6ImZmVlBXRGVqX3NQajI1U040dmRaek85YnhEVDFQVmg5OU1hS2pBYWZzWWMiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvODQ3NTg3NzgtOWFjZi00MTJhLWFlNWEtZGU1NDU2NmQyMjNkLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0xMS0yMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTItMTMifSx7ImFhZ3VpZCI6IjNkZTU2OTdkLTcwMzUtNGQ4Ni1iOWJhLWQ1NjAwNTU0ZDUyZSIsImhhc2giOiJIN0xaTmlSekxmWEFyVHkxam5GWWlwZDR3a2dLQzVKZ2syVy02SWFJM2pzIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzNkZTU2OTdkLTcwMzUtNGQ4Ni1iOWJhLWQ1NjAwNTU0ZDUyZS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNS0yOCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDgtMjIifSx7ImFhZ3VpZCI6ImNiYTk3M2FlLWM0NGEtNDQ5NC1hYWEwLWM2MTM2Y2ViZGU3MiIsImhhc2giOiJTUFEtYWthaGlXSUlxQ2pCOUtJOUFyVXVwMS1mYUhLcXREZ3FicHgzZ0pNIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2NiYTk3M2FlLWM0NGEtNDQ5NC1hYWEwLWM2MTM2Y2ViZGU3Mi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDJwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDgtMTIifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTE2In0seyJhYWd1aWQiOiJjNTlhYTI5NC03ODNlLTQ1MTgtYmU3OC0zZDI1YmU2NWE3ZWQiLCJoYXNoIjoiQWRQLVY3ZTBuS3dxSTNSYkVBcHVNOGhmb0N2bUVzYlAxQlRpdFdsYVNkSSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9jNTlhYTI5NC03ODNlLTQ1MTgtYmU3OC0zZDI1YmU2NWE3ZWQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA1LTA0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0wMiJ9XX0.kWmSgoYyXzEXkFJuMrVPrjQYgbVh2c88wlNE8c1490iD6E_wVyYoHJ6ZWoDsvzpCj_vxKFuYEIOGid5fWdMmqggolang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/testdata/MetadataTOCParsing-P1.jwt000077500000000000000000001270011414201525100304610ustar00rootroot00000000000000eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlDenpDQ0FuV2dBd0lCQWdJUEJLV3k0ZEhyQ1FQeHREcnc5MnRUTUFvR0NDcUdTTTQ5QkFNQ01HY3hDekFKQmdOVkJBWVRBbFZUTVJZd0ZBWURWUVFLREExR1NVUlBJRUZzYkdsaGJtTmxNU2N3SlFZRFZRUUxEQjVHUVV0RklFMWxkR0ZrWVhSaElGUlBReUJUYVdkdWFXNW5JRVpCUzBVeEZ6QVZCZ05WQkFNTURrWkJTMFVnUTBFdE1TQkdRVXRGTUI0WERURTNNREl3TVRBd01EQXdNRm9YRFRNd01ERXpNVEl6TlRrMU9Wb3dlREVMTUFrR0ExVUVCaE1DVlZNeEZqQVVCZ05WQkFvTURVWkpSRThnUVd4c2FXRnVZMlV4SnpBbEJnTlZCQXNNSGtaQlMwVWdUV1YwWVdSaGRHRWdWRTlESUZOcFoyNXBibWNnUmtGTFJURW9NQ1lHQTFVRUF3d2ZSa0ZMUlNCTlpYUmhaR0YwWVNCVVQwTWdVMmxuYm1WeUlEUWdSa0ZMUlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkhrUUV6NVBnbk1hM0xYb2ZCYWlPc1lsTWNabmNBNlh1TXBCRkNvVEU0eE0vYWJTRGpjUVREcW1DRVdTdms0eHJqL3BZajNUdzdkSXd2ZkpLUWlNVmFpamdmSXdnZTh3Q3dZRFZSMFBCQVFEQWdiQU1Bd0dBMVVkRXdFQi93UUNNQUF3SFFZRFZSME9CQllFRkx3QU10ZkhrVWdmbHc2bXlvUGt3WTB4U0g3bU1COEdBMVVkSXdRWU1CYUFGRkJhVWJ4bzloS1U5TVNQQVhPeUFkenVqRDh5TUQ4R0ExVWRId1E0TURZd05LQXlvRENHTG1oMGRIQnpPaTh2Wm1sa2IyRnNiR2xoYm1ObExtTnZMbTU2TDIxa2N5OWpjbXd2VFVSVFEwRXRNUzVqY213d1VRWURWUjBnQkVvd1NEQkdCZ3NyQmdFRUFZTGxIQUVEQVRBM01EVUdDQ3NHQVFVRkJ3SUJGaWxvZEhSd2N6b3ZMMlpwWkc5aGJHeHBZVzVqWlM1amJ5NXVlaTl0WkhNdmNtVndiM05wZEc5eWVUQUtCZ2dxaGtqT1BRUURBZ05JQURCRkFpQWg3QXlFZzZ3SmdrRTZzdGZDdUtyMGExVkJkL3NWd1JkZmI0V0FXT1pLc0FJaEFMYktYUVRFNEl1aTlET0kxV0c0c1ZVVXJFQSs0cFZ4VzVxL2RwQ2ttbEx0IiwiTUlJQzRUQ0NBbWVnQXdJQkFnSVBCRS9kajhyak5xbGxWTHJDaGpTa01Bb0dDQ3FHU000OUJBTURNR2N4Q3pBSkJnTlZCQVlUQWxWVE1SWXdGQVlEVlFRS0RBMUdTVVJQSUVGc2JHbGhibU5sTVNjd0pRWURWUVFMREI1R1FVdEZJRTFsZEdGa1lYUmhJRlJQUXlCVGFXZHVhVzVuSUVaQlMwVXhGekFWQmdOVkJBTU1Ea1pCUzBVZ1VtOXZkQ0JHUVV0Rk1CNFhEVEUzTURJd01UQXdNREF3TUZvWERUUXdNREV6TVRJek5UazFPVm93WnpFTE1Ba0dBMVVFQmhNQ1ZWTXhGakFVQmdOVkJBb01EVVpKUkU4Z1FXeHNhV0Z1WTJVeEp6QWxCZ05WQkFzTUhrWkJTMFVnVFdWMFlXUmhkR0VnVkU5RElGTnBaMjVwYm1jZ1JrRkxSVEVYTUJVR0ExVUVBd3dPUmtGTFJTQkRRUzB4SUVaQlMwVXdXVEFUQmdjcWhrak9QUUlCQmdncWhrak9QUU1CQndOQ0FBVExmZi9Lb3F6TnNQMm5mK085QlFaWmpoblk5NFBXNkZaNlFCSzdxNTQzMXJhb1lEUUVNKzVacm1UZmFwWFAxQ3c4VTZnUEN4SFJxU0FoL1dMakVNVFJvNEgxTUlIeU1Bc0dBMVVkRHdRRUF3SUJCakFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQjBHQTFVZERnUVdCQlJRV2xHOGFQWVNsUFRFandGenNnSGM3b3cvTWpBZkJnTlZIU01FR0RBV2dCVGQ5NXJJSE8vaFg5T2g2OXN6WHpEMGFobVpXVEEvQmdOVkhSOEVPREEyTURTZ01xQXdoaTVvZEhSd2N6b3ZMMlpwWkc5aGJHeHBZVzVqWlM1amJ5NXVlaTl0WkhNdlkzSnNMMDFFVTFKUFQxUXVZM0pzTUZFR0ExVWRJQVJLTUVnd1JnWUxLd1lCQkFHQzVSd0JBd0V3TnpBMUJnZ3JCZ0VGQlFjQ0FSWXBhSFIwY0hNNkx5OW1hV1J2WVd4c2FXRnVZMlV1WTI4dWJub3ZiV1J6TDNKbGNHOXphWFJ2Y25rd0NnWUlLb1pJemowRUF3TURhQUF3WlFJeEFOcjI1RGR5OGo5OWFSK0lFaGErcGs2TzJJRE9GV3paWDdCZmxzelAxSnBadlNDSS9ZcWJJOFl5aDIydWdNOENrd0l3UlhTQTRTZTVYR0FyVXVBR1g4eXBtb1hJb0RjRVlSVXZEMGQvWll2WFQ1Q2hUUU9XbkFUQ0szT3cwWVc2QVJOVSJdfQ.eyJsZWdhbEhlYWRlciI6IkJ5IHVzaW5nIHRoaXMgbWV0YWRhdGEgc2VydmljZSwgeW91IGFyZSBzb2xlbWx5IHN3ZWFyIG5vdCB0byBkbyBldmlsISIsIm5vIjo0MiwibmV4dFVwZGF0ZSI6IjIwMjAtMDQtMDgiLCJlbnRyaWVzIjpbeyJhYWd1aWQiOiI5MjEwMTJmOC0xYTczLTRiMGYtYWE4MS1jZDIxYzZiOWJmNzUiLCJoYXNoIjoiVFNBLW81ekZPVlF5bXNRTWZDTGZ5OUhEcmpyT3dUWVdmSU5xeWVFQ2oyZyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS85MjEwMTJmOC0xYTczLTRiMGYtYWE4MS1jZDIxYzZiOWJmNzUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlVTRVJfVkVSSUZJQ0FUSU9OX0JZUEFTUyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTEyLTE3In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNC0xNyJ9LHsiYWFndWlkIjoiMTk3NzQ3MzUtMjc1Ni00M2ZhLWFiZDktMzI0OGY3YzcxNzUwIiwiaGFzaCI6IlZYdEhxb1FnaTBPNTRXTjRJcHktbExrRllpYUNjb3YxMndyZTdETjMtYzgiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMTk3NzQ3MzUtMjc1Ni00M2ZhLWFiZDktMzI0OGY3YzcxNzUwLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNS0xNSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTItMTMifSx7ImFhZ3VpZCI6IjY2YmU4NjhlLTJhODEtNDczMS1iMmQ5LTZlMmY3OGE5Zjk4YyIsImhhc2giOiI5RXF6ZWdoY0hUOVc0V1d4MURCdTkwSUhiSEVqUWJmMWZLRGlqNlVGNUdRIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzY2YmU4NjhlLTJhODEtNDczMS1iMmQ5LTZlMmY3OGE5Zjk4Yy5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiTk9UX0ZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDQtMjcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAxLTE4In0seyJhYWd1aWQiOiJkMTVlNjMzNi02MGNkLTQzMmQtYjAxMi0xMDJiNThiOGI2ODAiLCJoYXNoIjoic1J5WUgzY3ZGYzgybTg4czFWSkpSMWlwSkVodEYzdHNrXzhOTjlhYXBXVSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9kMTVlNjMzNi02MGNkLTQzMmQtYjAxMi0xMDJiNThiOGI2ODAuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA2LTIyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMC0xMCJ9LHsiYWFndWlkIjoiN2JmZjY1YjktY2Q1Yi00MmJiLWFlNWYtMGI4OTFjZDRhMWIyIiwiaGFzaCI6IjhKOFlUMms3TnRjb1JCMWRvTkJrYTlsUGZDdWxsbl9yMEN6V0JKTnZZaUUiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvN2JmZjY1YjktY2Q1Yi00MmJiLWFlNWYtMGI4OTFjZDRhMWIyLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJTRUxGX0FTU0VSVElPTl9TVUJNSVRURUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0xMi0wMSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTItMjYifSx7ImFhZ3VpZCI6ImFlNGU2NWFjLWM3MzgtNDI4ZC1iMGMyLThkNDRjOTZmNTU3OCIsImhhc2giOiJNRjJIcWtKYldFWjVGbW1QYWhkeHRjSzNMLVFkUXUzWDVVMDRndk9kRngwIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2FlNGU2NWFjLWM3MzgtNDI4ZC1iMGMyLThkNDRjOTZmNTU3OC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDUtMjIifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA2LTEwIn0seyJhYWd1aWQiOiJmZjA5MWJhZi0xYjc4LTQxNmMtYjcyYi04MGE3NTI2YzE0MzEiLCJoYXNoIjoiWmdsQW5tSVpJWjBvSndnSmR4YmJ2cjZKM2dmMEJHdWNDT1d1RjEtdXc4SSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9mZjA5MWJhZi0xYjc4LTQxNmMtYjcyYi04MGE3NTI2YzE0MzEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA3LTE4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMi0yNCJ9LHsiYWFndWlkIjoiZTc1OWZmZDktMjViZC00ZGRiLTkzNTUtZGQwYTM1ZGM0ZTliIiwiaGFzaCI6Im5JcVo3YzFFSmYyTTJhZG51SzZ1YlI5UmtsWVFRdXJacmJnWDRxdDNhZFkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZTc1OWZmZDktMjViZC00ZGRiLTkzNTUtZGQwYTM1ZGM0ZTliLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wOS0wOSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDgtMTgifSx7ImFhZ3VpZCI6IjA5NjQxMWY0LTM4MDgtNDMwZS1iZjI2LWYyZmI2ZGFmOGJlYSIsImhhc2giOiJiRXRFeW9Wa2MtWC15cHVGb0FJajhzNHhLS1RadzN3ekQ3SXVEbm9CVUU4IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzA5NjQxMWY0LTM4MDgtNDMwZS1iZjI2LWYyZmI2ZGFmOGJlYS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wNy0wMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDItMDEifSx7ImFhZ3VpZCI6IjYzNGI0NzhjLWZiNGEtNDYwOS05MDhkLTM3ZWE2NjU2NTA3MSIsImhhc2giOiJjaU80ZmRlYXdfelFycFpYZGhaSC1wbEN4bFpBSXVITzdyajlNeHJHazdRIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzYzNGI0NzhjLWZiNGEtNDYwOS05MDhkLTM3ZWE2NjU2NTA3MS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOC0xNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDEtMDgifSx7ImFhZ3VpZCI6IjI0MDUwN2NkLTBiYWItNGE0NS05YWQwLWJiODc2MDIzNzFmMyIsImhhc2giOiJRcU5VUzQwemc3b1lqY05VcVMzSnpJWml1RFFCdE9FWmdTZ0EyWG1LNHg4IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzI0MDUwN2NkLTBiYWItNGE0NS05YWQwLWJiODc2MDIzNzFmMy5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDYtMDEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTIxIn0seyJhYWd1aWQiOiI0NTZiMGIzOS0xYmM5LTRkOTQtYTBlYy1iZDk2MjU3NDA4YjEiLCJoYXNoIjoibTdlai1vODJKZldUb2NQeVdmSFdGYWZPeXNNSHdNaGxjUnN2dkRKaVkxNCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS80NTZiMGIzOS0xYmM5LTRkOTQtYTBlYy1iZDk2MjU3NDA4YjEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkFUVEVTVEFUSU9OX0tFWV9DT01QUk9NSVNFIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDctMTUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAzLTE3In0seyJhYWd1aWQiOiIzMzIwYmMyNS1kY2NhLTQ1ODMtODBlZC1iMjAwODgzN2ZmOTAiLCJoYXNoIjoibXVVTEN4QW45ZzZUdS1zYS1UaUFvanRWSkRhUVdhblJLRnpGcVB3TnpzWSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8zMzIwYmMyNS1kY2NhLTQ1ODMtODBlZC1iMjAwODgzN2ZmOTAuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDMtMTAifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA2LTA5In0seyJhYWd1aWQiOiJiMDRkZDIwMS1jOTc1LTQ1Y2UtYWVhNi1hOTJlYWM3NjZmMzIiLCJoYXNoIjoiRTdHbHpyR3gwYldOUlRzSHA5VmlNQzNSNGZGS21tUVVkRE9jY3ZZMXNhSSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9iMDRkZDIwMS1jOTc1LTQ1Y2UtYWVhNi1hOTJlYWM3NjZmMzIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTAxLTIzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOS0xMyJ9LHsiYWFndWlkIjoiYzQ3YWM0ZmUtYTNhMC00YWI2LWJjNDctMTRjOTMwNTYyNDU0IiwiaGFzaCI6ImRwX2xoT053azBVZXIyQ1BOOVhVT0dBZm1jbEFMSjkwamlEQndSckhhY0UiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYzQ3YWM0ZmUtYTNhMC00YWI2LWJjNDctMTRjOTMwNTYyNDU0Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOC0xMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDQtMTMifSx7ImFhZ3VpZCI6ImI1ZTNhODE4LTE3YTgtNGFhMi1hNzgzLTFkMWY1Y2QwMGU1MyIsImhhc2giOiJHVFhnYTZSZW1FcmlmSXBob2R5TWYtelFMWl92RkxPY3JxY0NtZllVY3o0IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2I1ZTNhODE4LTE3YTgtNGFhMi1hNzgzLTFkMWY1Y2QwMGU1My5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiTk9UX0ZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDMtMTkifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAxLTIzIn0seyJhYWd1aWQiOiIwNTIxMGUwZC0zYTkyLTQ4ZGQtYTdhOS1jMzJhODYyOWU5YzAiLCJoYXNoIjoiWmxZbHI3V1htdl9PVVNERXliUHZZV1BiMUNzVmhYLS1pa3ZYVjRVcjcwTSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8wNTIxMGUwZC0zYTkyLTQ4ZGQtYTdhOS1jMzJhODYyOWU5YzAuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDctMTQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAyLTI4In0seyJhYWd1aWQiOiI5NjgyY2VlZC1jNjYwLTRlYWItOTk1Zi01MzBiOTI2MWM1YTEiLCJoYXNoIjoic2l0NG1xWU0zbEVSWTNJenBSYVR5bTFiY3pqWU9ZbXZLYXpfRHhKQU1xTSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS85NjgyY2VlZC1jNjYwLTRlYWItOTk1Zi01MzBiOTI2MWM1YTEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA5LTE4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMy0yMiJ9LHsiYWFndWlkIjoiNDI0NDMzZjctMjcxMC00NTkyLWFhYmMtYjM5OTc5NThiMDc5IiwiaGFzaCI6IjFucXJlN0ZBemlMSVJ1VE95ZHQwUmx5aF9ESzY4RTJfT204LVlwWjVQTGciLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNDI0NDMzZjctMjcxMC00NTkyLWFhYmMtYjM5OTc5NThiMDc5Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMnBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNS0yNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMTQifSx7ImFhZ3VpZCI6Ijk2ZTExNTE1LTYzMzgtNDU1Zi05NzY1LWI3OTI2NjM4YjQ0NCIsImhhc2giOiJhRGJKcFhaOEFxYTdRR0pSXzk2U2pjRi1hOWpHUU5UeVFKY3g5bEF6MEhJIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzk2ZTExNTE1LTYzMzgtNDU1Zi05NzY1LWI3OTI2NjM4YjQ0NC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDMtMjcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA3LTA1In0seyJhYWd1aWQiOiI4MzBmMjJmZi0zYzJmLTQ2NjktYTQxMi1iMTk1OGYwNzBkNTkiLCJoYXNoIjoiSHM0aVk2UmtyUjJONzdFd2tvcmI0Tk95NkxDYXhlSTFmbWs2a3BwaXBvbyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84MzBmMjJmZi0zYzJmLTQ2NjktYTQxMi1iMTk1OGYwNzBkNTkuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wyIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDUtMDEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTExIn0seyJhYWd1aWQiOiIzNjAyNzhjOS03MjlkLTQxYWQtOGI4NS0xOWVlN2Q4ZDk2NmEiLCJoYXNoIjoiMjlIaUNyenkxMHRGUnBYODVHUTZUakd0Qy1weEpZSXptTVlqNW9oUUU1SSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8zNjAyNzhjOS03MjlkLTQxYWQtOGI4NS0xOWVlN2Q4ZDk2NmEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDYtMjYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTI1In0seyJhYWd1aWQiOiIzZDI2Y2U4NS04ODI2LTQyODktOWVjMS03MDU3YmJjNDg0N2EiLCJoYXNoIjoidUlvZ3RKdldaVDZHUVdaZFdMUWNRLWVKVm9MSGxYTXRueDA1R1NQUGdEayIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8zZDI2Y2U4NS04ODI2LTQyODktOWVjMS03MDU3YmJjNDg0N2EuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTEwLTIzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0wMSJ9LHsiYWFndWlkIjoiMjBhYmI1MzEtNDY4Yy00NjU5LWE5YzUtZmIyMTQ1NjljMjE0IiwiaGFzaCI6IkRDSk5GNFVNckMxcWdVMVVnZmxfWWYtd2dNN2o5MXh4eGp2RWY0OHAxbzQiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMjBhYmI1MzEtNDY4Yy00NjU5LWE5YzUtZmIyMTQ1NjljMjE0Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMiIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTEwLTA1In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMi0yMCJ9LHsiYWFndWlkIjoiYTQ2YjNmODItYzViMy00ZTZiLTk2ZjMtODkzOTAyMjk2NzljIiwiaGFzaCI6Ii1nQkV0em5zc1hoQ0wwY05vczg4Y3BaQTZhb3V3bkdzWGx3XzQwYkV6N2MiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYTQ2YjNmODItYzViMy00ZTZiLTk2ZjMtODkzOTAyMjk2NzljLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJTRUxGX0FTU0VSVElPTl9TVUJNSVRURUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wMS0wMiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDItMjcifSx7ImFhZ3VpZCI6IjdhY2QyMDk3LThiYjItNDFjYy1iM2Y2LTZhMDNiZmU0NDkwMiIsImhhc2giOiJ2NXFIMlFNeVlSMWRjMVROdmxHLVhkYlVULW85aU1YaENlSzFqWWNOdGljIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzdhY2QyMDk3LThiYjItNDFjYy1iM2Y2LTZhMDNiZmU0NDkwMi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDUtMjcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTE4In0seyJhYWd1aWQiOiJhMTU3NjVjMi0yOWU5LTRlNzMtYjFlYS05ZGIzN2I0NWYxY2YiLCJoYXNoIjoiTWJ5SzZISkRxVGFld0JSb1puU09mdWF3Z1lacGJlcTVnbHAtTkdUbnFhayIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9hMTU3NjVjMi0yOWU5LTRlNzMtYjFlYS05ZGIzN2I0NWYxY2YuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA4LTA4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMC0xMCJ9LHsiYWFndWlkIjoiOGMzM2ViYjctNjIyMy00NTdkLTk1NmUtNjFhMDUwZmFhNTdkIiwiaGFzaCI6IkV2cV9ETnBXaVk1alJGNzZwNTRfRXFqS2lXRnVnUGFKMHBwUkluUmhkNTQiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvOGMzM2ViYjctNjIyMy00NTdkLTk1NmUtNjFhMDUwZmFhNTdkLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMiIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA1LTI4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMy0yOCJ9LHsiYWFndWlkIjoiNmQyNjg3YzMtODEyZS00ZmMyLTgwZWItNzA2ZDc3N2EwNzFjIiwiaGFzaCI6Ill2ekl4V0k2WjFsSDhjaEpHSmpQZWgwNTZDQjFxcGNKWkhPRTRVNEFad3ciLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNmQyNjg3YzMtODEyZS00ZmMyLTgwZWItNzA2ZDc3N2EwNzFjLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJTRUxGX0FTU0VSVElPTl9TVUJNSVRURUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wOC0xMCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDYtMTEifSx7ImFhZ3VpZCI6ImMxYzhiNGYyLWQ2YjEtNGY4My1iMzAxLThkZDk1M2U0YmM3ZCIsImhhc2giOiJMaFd6bEZKdzlMVWcxUEZlcFI4TjAyX1hndkw0SnV0MHg2bTJrNEc4OFdRIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2MxYzhiNGYyLWQ2YjEtNGY4My1iMzAxLThkZDk1M2U0YmM3ZC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMTEtMDUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTEyIn0seyJhYWd1aWQiOiI3ZThmNzczOS1jOTdkLTRiZjAtYTNhZC04YTJmMTkwZmI5N2UiLCJoYXNoIjoiVWJKQXJVMXhTMTdNaFFsU3dnbWZYdjVXenAwY3lXNjJkZkJMR2dYYmFxVSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS83ZThmNzczOS1jOTdkLTRiZjAtYTNhZC04YTJmMTkwZmI5N2UuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA2LTI3In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNi0wMyJ9LHsiYWFndWlkIjoiNjQ2OTk3ZmEtOTY4NC00YWJiLWE3NDEtNTY2NThjMzAwZTg4IiwiaGFzaCI6Ijg1dFN1WndJa1BydnRNM1NPQzl3V2luVmp6aW56THFNQk1nM1d6VEM2OWsiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNjQ2OTk3ZmEtOTY4NC00YWJiLWE3NDEtNTY2NThjMzAwZTg4Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOS0xOSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDMtMjQifSx7ImFhZ3VpZCI6IjFjZTNjOWFhLWQwZGMtNGY1NC05MzgzLTcwNGVlMjA1NmY4OCIsImhhc2giOiJqdm1ScUI4cGJmd1g0YTBFNUZTUVRnZTBpc1lqXzEtSDZjMUpCN1FxR0swIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzFjZTNjOWFhLWQwZGMtNGY1NC05MzgzLTcwNGVlMjA1NmY4OC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDgtMjQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTIzIn0seyJhYWd1aWQiOiJlNmRlZjZiNy00Mzc3LTQ1MTYtYTRhOC0yOTZkNjA0NWY0OTYiLCJoYXNoIjoiMWo1UzhvUlE3V25ramd5VkxUSXdzejFlTG5TRS1aek9FSVAtSk9LM0RiUSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9lNmRlZjZiNy00Mzc3LTQ1MTYtYTRhOC0yOTZkNjA0NWY0OTYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDItMjEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTI3In0seyJhYWd1aWQiOiJmN2JiOGYxNy04ZWZiLTQ3NGYtOTI0Zi1jNTQ1OTI2MGRmN2MiLCJoYXNoIjoiMlJWakl0d2VQUVdZOVBSVWpMNExTQ25PNDBVcHMxeHJCX0d5S3B0VTFNWSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9mN2JiOGYxNy04ZWZiLTQ3NGYtOTI0Zi1jNTQ1OTI2MGRmN2MuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTAyLTE0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNi0xMyJ9LHsiYWFndWlkIjoiZDBlYzBmODEtY2UzYi00YWU1LWI1ZjgtNWQwZWRjNmU4MjBmIiwiaGFzaCI6Ik1VMk9rNWkwcjZjamFwY2RzdzV2bXN0UEo3S09GNGEzeUNPdjlpOWpQUkUiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZDBlYzBmODEtY2UzYi00YWU1LWI1ZjgtNWQwZWRjNmU4MjBmLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMiIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA5LTI4In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNi0wMyJ9LHsiYWFndWlkIjoiNzgxMjNkYWEtNWIxNS00OGMyLWI0NmUtNzlkNTBjYWFiZWIxIiwiaGFzaCI6IkpobTZvRVF2eTZ6enduLTNOaDc1WlFrUmFDak5yaU16b0Frd3lXOEpHN3ciLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNzgxMjNkYWEtNWIxNS00OGMyLWI0NmUtNzlkNTBjYWFiZWIxLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMnBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOC0yNyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDYtMTgifSx7ImFhZ3VpZCI6IjM3NjgyOGJiLTJlOWEtNGE0OC04YmM5LTZkMTEyNjliODNhMCIsImhhc2giOiJXQjg0ZWJjcEZLQzdUTmV6RmhMTS1BcXgxREJoX3RXenB5c1dTeXRBaXRRIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzM3NjgyOGJiLTJlOWEtNGE0OC04YmM5LTZkMTEyNjliODNhMC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDctMDUifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAyLTEyIn0seyJhYWd1aWQiOiJkODYwMGY0Ny1iMDBhLTRjNWItYjdlZC05MzU1MWZkZDc1NzkiLCJoYXNoIjoiMVpQYnd3cHJfMnZuRGxXWlkwSWxWbmc5akZ6VjhFUV9VSUVfcW9BMnJvVSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9kODYwMGY0Ny1iMDBhLTRjNWItYjdlZC05MzU1MWZkZDc1NzkuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkFUVEVTVEFUSU9OX0tFWV9DT01QUk9NSVNFIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMTEtMjAifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA3LTA0In0seyJhYWd1aWQiOiJiN2ZhNjZiNy00YmEyLTRiZDItYWQ1My0zYWNkNzM2Yzk3NzAiLCJoYXNoIjoid29QU1FyaDhoREttMC1NV2Jtc1RIT2JESVVDUjJJMzlTLTlUM2kwYTM4ayIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9iN2ZhNjZiNy00YmEyLTRiZDItYWQ1My0zYWNkNzM2Yzk3NzAuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlVTRVJfS0VZX1BIWVNJQ0FMX0NPTVBST01JU0UiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wNS0xNyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTEtMTQifSx7ImFhZ3VpZCI6ImZiMTFjZjI1LTRkMTctNDUyYS1iNzEwLTM2MGExMWU0NDI1MCIsImhhc2giOiJvd0JLSmlEclktdjNHNDdNQmdsMS1QV1k3T1RtVUlWeVI5bW8zODZWd0tzIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2ZiMTFjZjI1LTRkMTctNDUyYS1iNzEwLTM2MGExMWU0NDI1MC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDctMjEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA0LTI1In0seyJhYWd1aWQiOiI3ZjYxMWRlMS0xYzhjLTQ2OTctODI2Yy0zYzI1ZjI1MWMzYjkiLCJoYXNoIjoiR2ZvRW90QnpIc1VhOGNybUNSTHJxaU15dzd4UVV2ZTh4VFF4NS1fdDUySSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS83ZjYxMWRlMS0xYzhjLTQ2OTctODI2Yy0zYzI1ZjI1MWMzYjkuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlNFTEZfQVNTRVJUSU9OX1NVQk1JVFRFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA5LTA0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMi0xOCJ9LHsiYWFndWlkIjoiYWM3ODE1MzUtZTlhMi00ZWUxLTk3MTUtODcyYTcyMmRiNzQ4IiwiaGFzaCI6IkVYT3dEYmZjWG1wOUJ2ZjRmbXJEbTVlcU53SHlGNGpxVEJMUXczcTdBM1EiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYWM3ODE1MzUtZTlhMi00ZWUxLTk3MTUtODcyYTcyMmRiNzQ4Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJTRUxGX0FTU0VSVElPTl9TVUJNSVRURUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wMy0yNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDMtMTEifSx7ImFhZ3VpZCI6IjliZmU2NTgzLWQwMWEtNGRhNi1iOWMwLTMzZmRmOTBjYjJjZiIsImhhc2giOiI5R05CcGw1aUE1LW9ueGJZM2lxbjJuV29KVFEwX3NCRGdtaFBRZGVjQTFRIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzliZmU2NTgzLWQwMWEtNGRhNi1iOWMwLTMzZmRmOTBjYjJjZi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDItMjEifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA0LTIwIn0seyJhYWd1aWQiOiJhZjkwZDZkZS1mODY3LTQ5YjItODI3NS0wY2Y3NDc4MTBlYTciLCJoYXNoIjoiRVhWSWRlZE9uSTFBTXppV1NIbjcySmhac25yT0d3TTZwb0Nkdkp5MU9iNCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9hZjkwZDZkZS1mODY3LTQ5YjItODI3NS0wY2Y3NDc4MTBlYTcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTExLTE1In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0xNSJ9LHsiYWFndWlkIjoiZjI0ODViODctMTA5Mi00NjUzLWI5MjktNGE3MDU1ZTkxNThhIiwiaGFzaCI6IkY2M3djVzVTSW95alBySmlHaEUzS3hDUDNJZ04tZUl5UTcyV01HUmlxUWMiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZjI0ODViODctMTA5Mi00NjUzLWI5MjktNGE3MDU1ZTkxNThhLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMnBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wMS0xNyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTAtMjYifSx7ImFhZ3VpZCI6ImY5MTUyMzNjLTE0NGItNDcyMC05NmMzLWNiMDRmYmM1YzRjYyIsImhhc2giOiI3SXhHMFV3UzQ5dzFaN3hfMmMxUEt6ZnJsNG95RWNzdjZ5NE5UcU5UUFJRIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2Y5MTUyMzNjLTE0NGItNDcyMC05NmMzLWNiMDRmYmM1YzRjYy5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDIiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0xMS0yMCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDQtMjAifSx7ImFhZ3VpZCI6ImJjNjhlZGZhLTI4MzQtNGZiYS1iMGZlLTBiYTIyMzc1M2IyMCIsImhhc2giOiJ0S1laLWxPZnI2UEUwUWlyRWxSZTlQd2p3bFlOYnViN3U0d1ZURFFtNGFFIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2JjNjhlZGZhLTI4MzQtNGZiYS1iMGZlLTBiYTIyMzc1M2IyMC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDQtMDkifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAxLTE0In0seyJhYWd1aWQiOiJkYjM5ZDM0NC1kNzE4LTQyMzMtYTYyZC0xNjY4MTM4YzE4ZGMiLCJoYXNoIjoibU1wU00tMVJTaUtMYnVnM3VPZmd2WURhdmZNcXZCa0pwWXR5bVdXNE9iVSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9kYjM5ZDM0NC1kNzE4LTQyMzMtYTYyZC0xNjY4MTM4YzE4ZGMuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6Ik5PVF9GSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA1LTA5In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wOS0yMCJ9LHsiYWFndWlkIjoiMjRhZGZhMzEtYjc3ZC00MDg5LTk4OWEtNDU0MGJkNDAyYzdjIiwiaGFzaCI6Il8zWkVlOFNNQUhhZ21RUGNYUEUzSHliQzJVa2wtOW45YV9XZG9wRUhqVjAiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMjRhZGZhMzEtYjc3ZC00MDg5LTk4OWEtNDU0MGJkNDAyYzdjLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMnBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wNS0yNiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDMtMjgifSx7ImFhZ3VpZCI6Ijc5ZGZiMWY0LTdmMzQtNDkxZS04OWQ5LTVhM2NiNDY2MzkyZCIsImhhc2giOiJYQTJKblRGc3F2c2RxdGJRZGM4YWNHRWdVS2JvNEpXbnBXOXdFNVhjYUU0IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzc5ZGZiMWY0LTdmMzQtNDkxZS04OWQ5LTVhM2NiNDY2MzkyZC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDUtMTAifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA0LTA4In0seyJhYWd1aWQiOiIyNGRjOGUxOC04OWI0LTQyZDUtYWI3MS1lZjAyODhjN2M4N2IiLCJoYXNoIjoiNWp5YUExZ3JENkNDUV9IOEtBLU96YTVwNDNtT19oNEVCT0JpUFg3Uy12OCIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8yNGRjOGUxOC04OWI0LTQyZDUtYWI3MS1lZjAyODhjN2M4N2IuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wyIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDgtMDkifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA0LTAxIn0seyJhYWd1aWQiOiI3YTgyNzk5Mi1kYjY0LTQ3MTgtOGJjMi0wYWZlY2VhNDhjYmEiLCJoYXNoIjoiXzBoU3FnWjBGZkNrakduWF9iSVl6MDFQZWtZQzN5al8yMDJzM0JDLURxUSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS83YTgyNzk5Mi1kYjY0LTQ3MTgtOGJjMi0wYWZlY2VhNDhjYmEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDgtMDMifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA0LTIzIn0seyJhYWd1aWQiOiI1ODY2MzY4My03ZDNjLTRjNmQtOWMxNi01MTc1NDI1NTE4NTIiLCJoYXNoIjoiVXBfc0psS1R2QjNzZWkzeFZXdF83WTBrdmNoZGl0dVF0MDY0SEpUNTI0QSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS81ODY2MzY4My03ZDNjLTRjNmQtOWMxNi01MTc1NDI1NTE4NTIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA1LTIyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0yNSJ9LHsiYWFndWlkIjoiOWViYjQzZTAtYWMwNS00Yjc2LTkwMzQtMzkwYmUxODI2NWFiIiwiaGFzaCI6IlRiN2lpZ0V2Vktnd2FiWVUtbC1qdmlJalJyZzZZYU1UcFNmeUxmX2ZyUXciLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvOWViYjQzZTAtYWMwNS00Yjc2LTkwMzQtMzkwYmUxODI2NWFiLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMXBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0xMi0xMiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDYtMDUifSx7ImFhZ3VpZCI6ImUxOWQ2NGQwLWE3ZGMtNDUxNC1iYWY3LTYwYTAwNjliYTJiMCIsImhhc2giOiJKeEFvNDF3T2syY3gtdWVnVmtZbW9mbWZYeEtJZEg2eEdrZHRXb19CODZjIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2UxOWQ2NGQwLWE3ZGMtNDUxNC1iYWY3LTYwYTAwNjliYTJiMC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDJwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDMtMTcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAyLTI3In0seyJhYWd1aWQiOiI1NzdiZmJkMi1mYTdlLTRlY2MtYTUzNS01NDVjZTlmODdiNTUiLCJoYXNoIjoiWmxmM2IyRndCSjI0U2NjRXpwT3FnOTdPN1oxRjJxSkVzdXNFSUFkc0t4RSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS81NzdiZmJkMi1mYTdlLTRlY2MtYTUzNS01NDVjZTlmODdiNTUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA3LTEwIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMC0wMSJ9LHsiYWFndWlkIjoiMWNhYmQzZWYtNDYyNi00YTE3LWJlMDMtMTliYmU1ZDlmYjdhIiwiaGFzaCI6IjlfYk9uU1UtbU1FQXQ0UkJfYTFuWFNmRDh1dTljR3FqTEwtUlh0ZWxrc3ciLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMWNhYmQzZWYtNDYyNi00YTE3LWJlMDMtMTliYmU1ZDlmYjdhLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA1LTE1In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMC0xOSJ9LHsiYWFndWlkIjoiN2QxNWRlMTYtNjg1Ny00NzFiLWFkZjAtMTRjYmQwY2QzYTAxIiwiaGFzaCI6IkEwN1poQldJSUQyc1VkU2VuSnFiYk5pVmpkZ0hHYnlueWJTTkNyd2p6UzQiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvN2QxNWRlMTYtNjg1Ny00NzFiLWFkZjAtMTRjYmQwY2QzYTAxLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA5LTAxIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0wNiJ9LHsiYWFndWlkIjoiNWIyZWZkMGEtNWRhZS00YThkLTkzODgtYmM5MmUzZDk3ZTBiIiwiaGFzaCI6Im56dHBjZk1BdDRhNDhPcVFGZWxxQ2VQdlh1dlRmTXl2MDJ1V09WOFdXZlkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNWIyZWZkMGEtNWRhZS00YThkLTkzODgtYmM5MmUzZDk3ZTBiLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJVU0VSX0tFWV9SRU1PVEVfQ09NUFJPTUlTRSIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTAxLTAxIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMy0wNSJ9LHsiYWFndWlkIjoiYWVkMDI5YzYtYjFkMS00NTEzLWJhZTktMGZhMmZhYzEzYjA0IiwiaGFzaCI6IjMyYVBNSjFHYkxZSEJtVWhGUW1wVTlJb2U2WEo1LVFZMXl4OV9JOC15RkEiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYWVkMDI5YzYtYjFkMS00NTEzLWJhZTktMGZhMmZhYzEzYjA0Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA5LTA0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0yNyJ9LHsiYWFndWlkIjoiYjNjMTI4Y2EtYzc3My00MWVjLWJjMWUtMzM0MDIxMWFlMDAwIiwiaGFzaCI6ImxFZVQycjVERDNtUzdJTmk4ci1fN0VqdkM1bnZTbkZWRWdGWG1pTWF0QmsiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYjNjMTI4Y2EtYzc3My00MWVjLWJjMWUtMzM0MDIxMWFlMDAwLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0xMS0yNCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDktMDcifSx7ImFhZ3VpZCI6ImNmODM5ZTM5LWZkN2QtNDc1NC1iNzc1LTU1MjExOWFiZmJhNyIsImhhc2giOiJvSUZYMDRJVDljcXV5R3d5OFVCNVVJZ1VzME5naFdwNmRWemNycmZUMmpRIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2NmODM5ZTM5LWZkN2QtNDc1NC1iNzc1LTU1MjExOWFiZmJhNy5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wMS0xMCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDQtMDgifSx7ImFhZ3VpZCI6IjAyNDQwNjY3LTNkOGItNDU3Yy05NTIyLTFiOWZiZWJkZWQwYiIsImhhc2giOiJIdEpyQldKVVc5cHdJWmZYTFZ2TF83azJidVdidnhUVVJucUl3VlpCS0E4IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzAyNDQwNjY3LTNkOGItNDU3Yy05NTIyLTFiOWZiZWJkZWQwYi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDEiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wMi0xMSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTItMjQifSx7ImFhZ3VpZCI6IjI0MjI5NmJlLWYzYjktNDk4Mi1iODBkLTNmM2VmNTkzOTgyNiIsImhhc2giOiJra1pweDZqXzgtYmZmVTlrOXNHQ3JtNzc2TWtBQmE4a2dNejJGWnRISlZFIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzI0MjI5NmJlLWYzYjktNDk4Mi1iODBkLTNmM2VmNTkzOTgyNi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDEiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOS0wNyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTItMDcifSx7ImFhZ3VpZCI6ImRlZWQyOTMxLTMyMjQtNDFhMS1iZmMxLTJiZDU2OGI5N2RlOCIsImhhc2giOiJySzdlUmN4OEZPa2pXQ3dnTkR2eFVRaTd2c1VWQmJrTVJlLWtOSlY0ZlJjIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2RlZWQyOTMxLTMyMjQtNDFhMS1iZmMxLTJiZDU2OGI5N2RlOC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMDctMTgifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEwLTIyIn0seyJhYWd1aWQiOiI1YzFkYjhlNS05MjA4LTRiYmItYTU4YS04ZGVmZWM0NzVmYmUiLCJoYXNoIjoiWXZmSnpNTFg5X0llbjV1OGtrSzF3NHRIRkFjMUN5azdPXzFDMFhoRnBzVSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS81YzFkYjhlNS05MjA4LTRiYmItYTU4YS04ZGVmZWM0NzVmYmUuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTAxLTAzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNi0yNSJ9LHsiYWFndWlkIjoiNWI0MGMzMTEtZGIxOC00MTUyLTk2NGUtOGIyZjNmMzNkNzc0IiwiaGFzaCI6IlNmcFhERzFtQXgyU084VkkybEpCNE5ka1N4UGRBUnB4MTB2ZzlxVlVCRG8iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNWI0MGMzMTEtZGIxOC00MTUyLTk2NGUtOGIyZjNmMzNkNzc0Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wMS0wNSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDctMTIifSx7ImFhZ3VpZCI6IjAwZGUxMDUyLTY3MDItNDRkOS1hNDY0LWJmZTlhMWY4YTk5YSIsImhhc2giOiJhSlV1Y3FUUVo3LWlNYUlKX3phV0c1bVFYVTRGdmRCTFpBZjVuOGxhT2IwIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzAwZGUxMDUyLTY3MDItNDRkOS1hNDY0LWJmZTlhMWY4YTk5YS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDJwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTUtMTItMjMifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA2LTIxIn0seyJhYWd1aWQiOiI4ZTEzYTcxMS0zNDdkLTQ4MTAtOGU2Yy02YTM0Nzk0ZWZhYTciLCJoYXNoIjoiN1ZremJwb0Izcnpqblg1OHMtbTBSTjRwQW5pWHdaWmdZaVdoM0NBTFFLRSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84ZTEzYTcxMS0zNDdkLTQ4MTAtOGU2Yy02YTM0Nzk0ZWZhYTcuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDEtMTQifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTAxLTIyIn0seyJhYWd1aWQiOiJmY2E4MTlhYy1lNzQ5LTRkMzgtYjQzNy0xOTkwMDgxNWFhNzMiLCJoYXNoIjoiRnphc0ZhYnh6RUtUYmtNYy1EeEtleDM4YU1ndGZaOVRiaURqYWRnVXM2QSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9mY2E4MTlhYy1lNzQ5LTRkMzgtYjQzNy0xOTkwMDgxNWFhNzMuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDgtMjAifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA4LTI2In0seyJhYWd1aWQiOiIwZmFlNmQwYi1iMGJjLTRhZDctYmZjNC04MjMxOTY4OTFhMjMiLCJoYXNoIjoidDlRVFhfNEZGM0JWNFpPbFVjOU1NcFpHb0tKY3Nqa01HcjVqVnVhajFPUSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8wZmFlNmQwYi1iMGJjLTRhZDctYmZjNC04MjMxOTY4OTFhMjMuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDctMDcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA2LTI1In0seyJhYWd1aWQiOiIxMzE1YmQ0My1kNmIyLTRhMTUtYTE1Zi0yNWRiYWQxYWI1NDgiLCJoYXNoIjoiVmg1R2d4VXlIOFR5X3lYUWhzaG1fTnFKdXpxNTVGajZIVDZUVEpIUHZkSSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS8xMzE1YmQ0My1kNmIyLTRhMTUtYTE1Zi0yNWRiYWQxYWI1NDguanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTAyLTIxIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0wMyJ9LHsiYWFndWlkIjoiZGJiMGU2MDctNmFhZC00NzE0LWFiMTgtYjY5YTMwZTdhMzcwIiwiaGFzaCI6Ik5ELTBuZE95VFE1NDR0Z2Y0aTlSMW8yNUhHU3lOeTd0QXRDRzhuMExlX0UiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZGJiMGU2MDctNmFhZC00NzE0LWFiMTgtYjY5YTMwZTdhMzcwLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMiIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA1LTA0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNS0wNCJ9LHsiYWFndWlkIjoiYzk0ZDUzODUtNTJjYi00N2Y3LTk2NWYtNGEyMzBmOTM2MTI5IiwiaGFzaCI6ImRfYzczTy1LemdnMmdMZDBuSnBGV0FUd05VVURkMzVHZGlsOERVUWc2T00iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvYzk0ZDUzODUtNTJjYi00N2Y3LTk2NWYtNGEyMzBmOTM2MTI5Lmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MM3BsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wNi0yOCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDMtMTYifSx7ImFhZ3VpZCI6Ijc1MzdlODJiLWQ5NzgtNGQ4NS1hMWE5LWEwNzZmMTU5OTg1MSIsImhhc2giOiJoSDA0ZkZWUEhVT0hJR1JZOTh0TU45NjV5anhNbTZSRGNqbmR5SjBOU2E4IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzc1MzdlODJiLWQ5NzgtNGQ4NS1hMWE5LWEwNzZmMTU5OTg1MS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDNwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMTAtMDkifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA5LTE4In0seyJhYWd1aWQiOiI2NWNjMGNiNS00NmEyLTQyZDQtYWJjMy01ODc2ZjA4MDdkMDEiLCJoYXNoIjoiYWN0THAzQktOTENxQVhCRkNZN2F0WjNjc05MSllDM0VDUDF6NGV0SnhnRSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS82NWNjMGNiNS00NmEyLTQyZDQtYWJjMy01ODc2ZjA4MDdkMDEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTA1LTE1In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMS0xMCJ9LHsiYWFndWlkIjoiZDk4ZDdkOTctYmJhNi00Y2UyLWFjMjEtODA4YmM5NmUwZjJlIiwiaGFzaCI6ImVrSkJzcEVzenRmU0RzX0hZckptM1dwRE5WYTRsRjJOR095dXFCb3ZwZlkiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZDk4ZDdkOTctYmJhNi00Y2UyLWFjMjEtODA4YmM5NmUwZjJlLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMSIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTAzLTAzIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMS0wMiJ9LHsiYWFndWlkIjoiMzViYzA1MjQtNGVlOS00MjUxLWE3ZmYtMjE3MzBkZGNmOGUwIiwiaGFzaCI6Inl3SnFWMTVweXlJNkNMbnJnTDYyQlQ0UFU5ZFlCOWtJV0p2RU1pWDZidU0iLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMzViYzA1MjQtNGVlOS00MjUxLWE3ZmYtMjE3MzBkZGNmOGUwLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMnBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNS0xNSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDUtMTIifSx7ImFhZ3VpZCI6ImEyM2I5YzNkLWUxNWMtNGNjMC1iOTQ5LWNhOGE3OWYzY2NhNiIsImhhc2giOiJqa3VoUnU0MHcxR2tVa2VHbkMxa3hjVXc5T05jNlpVODEzc185Tm51cWE0IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2EyM2I5YzNkLWUxNWMtNGNjMC1iOTQ5LWNhOGE3OWYzY2NhNi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiVVNFUl9LRVlfUEhZU0lDQUxfQ09NUFJPTUlTRSIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA2LTI0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wNy0wMyJ9LHsiYWFndWlkIjoiMTBlOGQyM2QtNTc5ZC00NTBhLTlmYTMtNDVlMDA3YjE4MjBkIiwiaGFzaCI6IlpVelFGX3REazhGZzNEZVltVzRFZVNGdHV6QWREaWJ0SXV1SkR6Ql9YLWMiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvMTBlOGQyM2QtNTc5ZC00NTBhLTlmYTMtNDVlMDA3YjE4MjBkLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0wNS0wMiJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDItMDkifSx7ImFhZ3VpZCI6Ijk0M2I0N2I5LTg1ZDctNDk4Zi1iMjFmLWNjZmNjM2I5ZmIzZCIsImhhc2giOiJ4ZVBVRWZ5YXA3SklabVRoWHk2cDYtMW5QWE1ZZFVrU25id0lPdnFZNktzIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzk0M2I0N2I5LTg1ZDctNDk4Zi1iMjFmLWNjZmNjM2I5ZmIzZC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wOS0wOCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDgtMjcifSx7ImFhZ3VpZCI6IjY0ZDk3ODczLTYyOWMtNGEyOC04YjZmLWYxYTM5NGZkMzE1YiIsImhhc2giOiI2SElBQ0pDNWJnWUgtUk5yd0t4SkdacTVNRlQ4TGt6ekFyeWp0bUxteERBIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzY0ZDk3ODczLTYyOWMtNGEyOC04YjZmLWYxYTM5NGZkMzE1Yi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDFwbHVzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDktMjgifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEwLTE5In0seyJhYWd1aWQiOiI1ZTNjYWEzNC01ZTEzLTQ2ZTMtOGZlNC1kNTVkMzNjNTI3YmIiLCJoYXNoIjoiaGNWYnpsRmpXWFlaNFY2RjVUdFBBckFHUExxZXRjVWs3OGppS0Njdno3USIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS81ZTNjYWEzNC01ZTEzLTQ2ZTMtOGZlNC1kNTVkMzNjNTI3YmIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wycGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTAzLTI0In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMS0wMiJ9LHsiYWFndWlkIjoiZDUyNjgwMDMtZTA3ZS00ZGRkLWIzMmItYWI4NzgzNDIxNzkzIiwiaGFzaCI6ImRIU3NwWjdRNU9wWVF2WVhqYjNNTU9TcDJJbDNSaEdFVjZzdmNaTENXRFEiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvZDUyNjgwMDMtZTA3ZS00ZGRkLWIzMmItYWI4NzgzNDIxNzkzLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJTRUxGX0FTU0VSVElPTl9TVUJNSVRURUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0xMC0wNyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTEtMTkifSx7ImFhZ3VpZCI6ImRhZTIyNjhhLTQyMmItNGFiNy1iNDk4LTBmYzg5ZWVkZjVlYSIsImhhc2giOiJrbUI4anBrQVJhMVNqYmVsQ01FSVB2UkVuc1Zmb1pXRmhwandIa1RWbElNIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2RhZTIyNjhhLTQyMmItNGFiNy1iNDk4LTBmYzg5ZWVkZjVlYS5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDUtMDYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA5LTI2In0seyJhYWd1aWQiOiI0NDdlYzMwNi1mZDU0LTQxYWEtYTFhNC0xNzliMjdlMGRjYjgiLCJoYXNoIjoiWFJZN1JWbDNXM1FLeXhaMmVBX01MdXBjLXVWM2RLMkFHcnF1QTRMYzlUUSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS80NDdlYzMwNi1mZDU0LTQxYWEtYTFhNC0xNzliMjdlMGRjYjguanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDMtMTYifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEwLTA1In0seyJhYWd1aWQiOiI0MDA2ZGJhNy00NDcyLTQyM2MtYmVkZC0zOTgyNjA2ODU3MmEiLCJoYXNoIjoiYWJaY1N2aDg0bDJrRWgtc2cwajhYX2owdUc4MU5WN3N2VDVLd1RFeHhwRSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS80MDA2ZGJhNy00NDcyLTQyM2MtYmVkZC0zOTgyNjA2ODU3MmEuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDMtMTcifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEyLTA2In0seyJhYWd1aWQiOiJlNjRhNzdhNi03MTI4LTQxNjgtODAyYi04MjkyOTgwYjIzOGQiLCJoYXNoIjoidUotUlhaNjhmZVBLai1nV0o2UEE5Zzh3VW55ZXU4OHgtLWtMbzhQT051dyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS9lNjRhNzdhNi03MTI4LTQxNjgtODAyYi04MjkyOTgwYjIzOGQuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IlNFTEZfQVNTRVJUSU9OX1NVQk1JVFRFRCIsImVmZmVjdGl2ZURhdGUiOiIyMDE1LTA4LTI3In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0xMC0xMiJ9LHsiYWFndWlkIjoiNmZkMDNjYWYtNWQ5NS00YzFkLTg2MjAtZTRlMWU5ODg4M2JiIiwiaGFzaCI6IlpRS2cwRjR2SER4SXMtcWpNMkVDRGxTLXlFWk9JeUhRejVMYjRkT3RXbkEiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvNmZkMDNjYWYtNWQ5NS00YzFkLTg2MjAtZTRlMWU5ODg4M2JiLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJOT1RfRklET19DRVJUSUZJRUQiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNi0wOC0wMSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMTEtMDYifSx7ImFhZ3VpZCI6IjZjNWEwOTk5LTY0YmQtNDEwMy1iNzY0LWQ2NTRjODA0NTJjMiIsImhhc2giOiJMekNoRG5PVkxtNllIRmNPbnJJU09taVk0cWM3UlhsaEZ0TmlhbVd3RjJJIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzZjNWEwOTk5LTY0YmQtNDEwMy1iNzY0LWQ2NTRjODA0NTJjMi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiVVNFUl9LRVlfUkVNT1RFX0NPTVBST01JU0UiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0xMi0xMyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDUtMDYifSx7ImFhZ3VpZCI6ImNmY2VlNzRkLTIwNmMtNDU0OS04Yjc4LTBjYzE0ZGU0ZDAwNiIsImhhc2giOiJPbzBVa28zNkFnWkdRdW5wWHNucnAyZ2xMeGhXRXpkLUZnMVAwYjhPTFkwIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2NmY2VlNzRkLTIwNmMtNDU0OS04Yjc4LTBjYzE0ZGU0ZDAwNi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0xMi0xOCJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDYtMDMifSx7ImFhZ3VpZCI6IjU2OTI4ZDdhLWQ1YmUtNGE4Yi04NmI1LWM5YmRkZDFkM2FlMCIsImhhc2giOiJ1UHkxUDB6U2lPcUM2OUZBaUp6b082ckk5SHJ5OS01RTFCdzh6NXhPdHo4IiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzU2OTI4ZDdhLWQ1YmUtNGE4Yi04NmI1LWM5YmRkZDFkM2FlMC5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiRklET19DRVJUSUZJRURfTDMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNS0wOC0xNyJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDQtMDQifSx7ImFhZ3VpZCI6ImFlNTk3ZGExLTQ0YjUtNGQ3Yi1iZmRmLWU1ZGI0YTNjNzI4NyIsImhhc2giOiJ5X1UyZWNYUFZhNHRwZ1dnRmJtUDk0a1BLSVpSUktuMzYwSnExd1pLOTNnIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhL2FlNTk3ZGExLTQ0YjUtNGQ3Yi1iZmRmLWU1ZGI0YTNjNzI4Ny5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiU0VMRl9BU1NFUlRJT05fU1VCTUlUVEVEIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMTItMTkifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA3LTA4In0seyJhYWd1aWQiOiI0YTE2NDQzMi04OWE1LTRkOTAtYWE2OS03NTcwM2M0ZTg1MDkiLCJoYXNoIjoiU1RUbW9mWFprcEVSR1RTa0owaGdWVXJXMW5aUHZRWGlOSTB2dzNUaFdCRSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS80YTE2NDQzMi04OWE1LTRkOTAtYWE2OS03NTcwM2M0ZTg1MDkuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wyIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDMtMjAifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTEyLTA5In0seyJhYWd1aWQiOiI1MDY2OGZhOS03ZThlLTQ2NDgtYmUzOS1hYjJkZWM5OGFlNTIiLCJoYXNoIjoiMkJHdHFFRG1LRUNraFFLQ1BzM3FlaW1kTDZMYmNPd0laZ04zdVVRMzZBdyIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS81MDY2OGZhOS03ZThlLTQ2NDgtYmUzOS1hYjJkZWM5OGFlNTIuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTQtMDYtMTIifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTA1LTE5In0seyJhYWd1aWQiOiI4MmJlZjQ3MS0xOTQxLTQ1ZDItOGFhNC01ZjgxNzE1YjRlMGYiLCJoYXNoIjoiSjROcnJNaXY5WkprS0otTnlrRnZoRjh6aFhQMVVBekNKaTRURFFwMms3VSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84MmJlZjQ3MS0xOTQxLTQ1ZDItOGFhNC01ZjgxNzE1YjRlMGYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wzcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE2LTAzLTEyIn1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMS0yOCJ9LHsiYWFndWlkIjoiN2U5YjlhNzYtMmQzNi00ZDAzLTk2Y2MtMTA3YzQ0OTNmYzJkIiwiaGFzaCI6ImNfRTlDY3dhbmt5cFBRTGw2WFBQTDZxVzFzQTR5aFRHRGVERVVpalR1ZUEiLCJ1cmwiOiJodHRwczovL2ZpZG9hbGxpYW5jZS5jby5uei9tZHMvbWV0YWRhdGEvN2U5YjlhNzYtMmQzNi00ZDAzLTk2Y2MtMTA3YzQ0OTNmYzJkLmpzb24iLCJzdGF0dXNSZXBvcnRzIjpbeyJzdGF0dXMiOiJGSURPX0NFUlRJRklFRF9MMnBsdXMiLCJlZmZlY3RpdmVEYXRlIjoiMjAxNC0xMi0yNSJ9XSwidGltZU9mTGFzdFN0YXR1c0NoYW5nZSI6IjIwMTctMDMtMTkifSx7ImFhZ3VpZCI6IjE4NTNhYjY4LWFlMDUtNDIyYS1hNzdhLWZhYjQxOTQ5MTkxMiIsImhhc2giOiJ1MW8yVFZVREt1ZHBFMzZ6TjRPNFNUcWF5VUk1d3JMU1h4d3E4YzBvTkhjIiwidXJsIjoiaHR0cHM6Ly9maWRvYWxsaWFuY2UuY28ubnovbWRzL21ldGFkYXRhLzE4NTNhYjY4LWFlMDUtNDIyYS1hNzdhLWZhYjQxOTQ5MTkxMi5qc29uIiwic3RhdHVzUmVwb3J0cyI6W3sic3RhdHVzIjoiVVNFUl9WRVJJRklDQVRJT05fQllQQVNTIiwiZWZmZWN0aXZlRGF0ZSI6IjIwMTYtMDgtMTMifV0sInRpbWVPZkxhc3RTdGF0dXNDaGFuZ2UiOiIyMDE3LTExLTExIn0seyJhYWd1aWQiOiI4MTEwNDA5My00YzA1LTQ0ZTctYTJjZC1hZDczZjU4ZjM5ZWYiLCJoYXNoIjoiU1ZNb1huVlFkSTc2ZHR3Qk40STA0QnRRbjZPOUtlRVhMTHJDMEtNVnRUUSIsInVybCI6Imh0dHBzOi8vZmlkb2FsbGlhbmNlLmNvLm56L21kcy9tZXRhZGF0YS84MTEwNDA5My00YzA1LTQ0ZTctYTJjZC1hZDczZjU4ZjM5ZWYuanNvbiIsInN0YXR1c1JlcG9ydHMiOlt7InN0YXR1cyI6IkZJRE9fQ0VSVElGSUVEX0wxcGx1cyIsImVmZmVjdGl2ZURhdGUiOiIyMDE0LTA3LTI2In1dLCJ0aW1lT2ZMYXN0U3RhdHVzQ2hhbmdlIjoiMjAxNy0wMi0xNSJ9XX0.SV4XvewlXWHFW0p734jaMKtRIlsyUV2SeAx8CoJ9Ffyhe-iCP4edn8SjducgDxFmz3JHrWswyvMjUfieYAIbNwTestMetadataStatementParsing-F1.json000066400000000000000000000242741414201525100327210ustar00rootroot00000000000000golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/testdataewogICAgImFhZ3VpZCI6ICIzYzlmMGYzNC01NzU0LTQ4YmUtYWRlZi03ODc1NzI5NGE3YWEiLAogICAgImFsdGVybmF0aXZlRGVzY3JpcHRpb25zIjogewogICAgICAgICJydS1SVSI6ICLQktC40YDRgtGD0LDQu9GM0L3Ri9C5IFNlY3AyNTZSMSBDVEFQMiDQsNGD0YLQtdC90YLQuNGE0LjQutCw0YLQvtGAINC00LvRjyDRgtC10YHRgtC40YDQvtCy0LDQvdC40LUg0YHQtdGA0LLQtdGA0L7QsiDQvdCwINGB0L7QvtGC0LLQtdGC0YHQstC40LUg0YHQv9C10YbQuNGE0LjQutCw0YbQuNC4IEZJRE8yIDNjOWYwZjM0LTU3NTQtNDhiZS1hZGVmLTc4NzU3Mjk0YTdhYSIKICAgIH0sCiAgICAiYXNzZXJ0aW9uU2NoZW1lIjogIkZJRE9WMiIsCiAgICAiYXR0YWNobWVudEhpbnQiOiAyLAogICAgImF0dGVzdGF0aW9uUm9vdENlcnRpZmljYXRlcyI6IFsKICAgICAgICAiTUlJRndEQ0NBNmdDQ1FDTm0xdTU2b1J3WFRBTkJna3Foa2lHOXcwQkFRc0ZBRENCb1RFWU1CWUdBMVVFQXd3UFJrbEVUeklnVkVWVFZDQlNUMDlVTVRFd0x3WUpLb1pJaHZjTkFRa0JGaUpqYjI1bWIzSnRZVzVqWlMxMGIyOXNjMEJtYVdSdllXeHNhV0Z1WTJVdWIzSm5NUll3RkFZRFZRUUtEQTFHU1VSUElFRnNiR2xoYm1ObE1Rd3dDZ1lEVlFRTERBTkRWMGN4Q3pBSkJnTlZCQVlUQWxWVE1Rc3dDUVlEVlFRSURBSk5XVEVTTUJBR0ExVUVCd3dKVjJGclpXWnBaV3hrTUI0WERURTRNRE14TmpFME16VXlOMW9YRFRRMU1EZ3dNVEUwTXpVeU4xb3dnYUV4R0RBV0JnTlZCQU1NRDBaSlJFOHlJRlJGVTFRZ1VrOVBWREV4TUM4R0NTcUdTSWIzRFFFSkFSWWlZMjl1Wm05eWJXRnVZMlV0ZEc5dmJITkFabWxrYjJGc2JHbGhibU5sTG05eVp6RVdNQlFHQTFVRUNnd05Sa2xFVHlCQmJHeHBZVzVqWlRFTU1Bb0dBMVVFQ3d3RFExZEhNUXN3Q1FZRFZRUUdFd0pWVXpFTE1Ba0dBMVVFQ0F3Q1RWa3hFakFRQmdOVkJBY01DVmRoYTJWbWFXVnNaRENDQWlJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFMMTFVNXlBSVZMTXJMM3hTOHU4eXNNU2RPa0Rlb1RPK1JjQXkrdVhYcDZrNFNDK2pPeTM3Z0lDRXRZSStNS1FWMUVNZU1NZjNyTTF1ZVpBTzNpUEZhME5FZGkvb1E3bnBuR2pCTkk4d016RDhGZk5lNnJXdHprRGFIcHNaVy8vL013V0RwR3lKUitYeWpjcTZVNHZTOWJTNnpaN2pzbHcwT2N6eDRVc1lnT3NJVVhTU0JhR09yUmJ4Si9KQzVnbkRZRVl2dE5NK1BEUGN6TE5LQXloZHZCWldOV0hyN01aMFA1VGVKUWNYc0FvU2hSWDJZOFU4ZlJOSm03U2VpRktEUDBObi9RS3hPU3Q3ekdQNHh0OW5NYXNFMXEyWlRkYXIyK1cxM0NSejM3UkkwWldwcS8rWXF1b0ViWjdVajdObUJUY3FoYjI2MG5tREVSMkZwd3dZd1BTYXJrOTJJWmJhbW96QjhkN09FSTFqSmdzcmpKaEthbjBFbVJhV1ZCcEhUNHhZS2RFdTdyMDlTMEpoS3lVKzUyV0RtbVZRVE1wWUxybTRYbDdoUnh5UHlCWWthbHJvenNHbVBzOHZsaE5xM1ZzVmJ5QlNNU3BFbVVhZUFhN0xMRTkvVmgwYWdKTFZGSGgxZWhZS0pwekhubW1CWFVxeDBGejNhZm1EbTFOWDBzcjNPLzZ4SXgxVlNUVmlUM0tOeEJZcFZIMXFqSEFUTHp1eGNXbW0rNzVmY0pNaVBZUFNNWFZtUmIzUTFsOTFBTTRCQmVXaGxQM0ZiYzdnRHkwcitzN20wc0dTNlBUMkoyckdvZzJyVXhuSit6Q00xMU03RGVPMFhNMm5ueTR1UllQUGs5dzJFWHpmdnRkdmllWVUvNVJCNFJEbTVUR3hIaEdYVlpVZ2FjNUFnTUJBQUV3RFFZSktvWklodmNOQVFFTEJRQURnZ0lCQUZ0MlhHZDNrNUdwYk8xRVVtM3U2MHpUMWZFNnU2cE9zY3AxNTZrNVZuc0hnYUhSSGRJQVBOTGVMTm1SN3k1T25yWGJoMTNDckd3VTFxODRqakpYcHYrdjE0eFVDYzVpMDF5b3BGVFFGTHI0QTdOSHAybk5ZZk5oaElWU0ZBZ1c0M0VmbEpmbGJMRWVsQ0p6eExsV2I1Qm9Ec1plZU5tRVFzWElNMW1KMjZSM3IwZHpzSEJiMHV5KzhMTlIxZ2RWcWRqaEM4Qkx5M2doNCtCV3VpZHlaTnQwN0x2ZURzU0ZXNXJjajV3UnJTeDloWFBJeVZwalFTbGpOdlk3TVZUb3VxSnpOQUFRTXNUS2tYUGtUWGxkQ29wOVFvOVVQa0hSUm0wbDdMTHRkYU9vWHJjdDBZbW9jZjh6eGY5YkZOaXc5ZjRXUllRTTZzTWh6dDgrcy9vRGlsbzRRaGNVZ2VKRWlFUEVTaTZ5bllUVjYyU0hBNGVNdW5VSjVkbENhUm5GaVI5RFRJbUZhNUlSemllMzI2L25XL1NQQ2FLYy95ckZJaWhNTWpKb1NBUGhwVGIvSzZ5SE9VRzhyK0tpUXV0N056cUdWMzAxcFE5dTYyZEdMNU9pMVZYbUNGbEUycmFtWnMxNUJOT1V5QW8yQ0JiUkpnM2pLY2R1LzhRQzZvampEdlE4NjMrN0xQdG43NHdKQzVScFVKc1MwR2hRV2dxNXBBWE8zd0E2MVVvYnhpNk1rT3BDQzB6Qld4L2Q0Q3FwUzRqNGhGZ3hXQlRYWDQ4aWhQdStoSXhJRi9BeGJxdFB2cUxNRXhXL3haSVRuNkFycFd5UTllNFNVVnIzbjNGMzNhcDFYZER5WjB2d0ZjbTE4SlFBdHN2WFQ2cUNMcldPWG5IVWdmbi8rVml1IgogICAgXSwKICAgICJhdHRlc3RhdGlvblR5cGVzIjogWwogICAgICAgIDE1ODc5LAogICAgICAgIDE1ODgwCiAgICBdLAogICAgImF1dGhlbnRpY2F0aW9uQWxnb3JpdGhtIjogMSwKICAgICJhdXRoZW50aWNhdG9yVmVyc2lvbiI6IDIsCiAgICAiY3J5cHRvU3RyZW5ndGgiOiAxMjgsCiAgICAiZGVzY3JpcHRpb24iOiAiVmlydHVhbCBTZWNwMjU2UjEgRklETzIgQ29uZm9ybWFuY2UgVGVzdGluZyBDVEFQMiBBdXRoZW50aWNhdG9yIDNjOWYwZjM0LTU3NTQtNDhiZS1hZGVmLTc4NzU3Mjk0YTdhYSIsCiAgICAiaWNvbiI6ICJkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQUNBQUFBQWdDQUlBQUFEOEdPMmpBQUFBQ1hCSVdYTUFBQzRqQUFBdUl3RjRwVDkyQUFBS1QybERRMUJRYUc5MGIzTm9iM0FnU1VORElIQnliMlpwYkdVQUFIamFuVk5uVkZQcEZqMzMzdlJDUzRpQWxFdHZVaFVJSUZKQ2k0QVVrU1lxSVFrUVNvZ2hvZGtWVWNFUlJVVUVHOGlnaUFPT2pvQ01GVkVzRElvSzJBZmtJYUtPZzZPSWlzcjc0WHVqYTlhODkrYk4vclhYUHVlczg1Mnp6d2ZBQ0F5V1NETlJOWUFNcVVJZUVlQ0R4OFRHNGVRdVFJRUtKSEFBRUFpelpDRnovU01CQVBoK1BEd3JJc0FIdmdBQmVOTUxDQURBVFp2QU1CeUgvdy9xUXBsY0FZQ0VBY0Iwa1RoTENJQVVBRUI2amtLbUFFQkdBWUNkbUNaVEFLQUVBR0RMWTJMakFGQXRBR0FuZitiVEFJQ2QrSmw3QVFCYmxDRVZBYUNSQUNBVFpZaEVBR2c3QUt6UFZvcEZBRmd3QUJSbVM4UTVBTmd0QURCSlYyWklBTEMzQU1ET0VBdXlBQWdNQURCUmlJVXBBQVI3QUdESUl5TjRBSVNaQUJSRzhsYzg4U3V1RU9jcUFBQjRtYkk4dVNRNVJZRmJDQzF4QjFkWExoNG96a2tYS3hRMllRSmhta0F1d25tWkdUS0JOQS9nODh3QUFLQ1JGUkhnZy9QOWVNNE9yczdPTm82MkRsOHQ2cjhHL3lKaVl1UCs1YytyY0VBQUFPRjBmdEgrTEMrekdvQTdCb0J0L3FJbDdnUm9YZ3VnZGZlTFpySVBRTFVBb09uYVYvTncrSDQ4UEVXaGtMbloyZVhrNU5oS3hFSmJZY3BYZmY1bndsL0FWLzFzK1g0OC9QZjE0TDdpSklFeVhZRkhCUGpnd3N6MFRLVWN6NUlKaEdMYzVvOUgvTGNMLy93ZDB5TEVTV0s1V0NvVTQxRVNjWTVFbW96ek1xVWlpVUtTS2NVbDB2OWs0dDhzK3dNKzN6VUFzR28rQVh1UkxhaGRZd1AyU3ljUVdIVEE0dmNBQVBLN2I4SFVLQWdEZ0dpRDRjOTMvKzgvL1VlZ0pRQ0Faa21TY1FBQVhrUWtMbFRLc3ovSENBQUFSS0NCS3JCQkcvVEJHQ3pBQmh6QkJkekJDL3hnTm9SQ0pNVENRaEJDQ21TQUhISmdLYXlDUWlpR3piQWRLbUF2MUVBZE5NQlJhSWFUY0E0dXdsVzREajF3RC9waENKN0JLTHlCQ1FSQnlBZ1RZU0hhaUFGaWlsZ2pqZ2dYbVlYNEljRklCQktMSkNESmlCUlJJa3VSTlVneFVvcFVJRlZJSGZJOWNnSTVoMXhHdXBFN3lBQXlndnlHdkVjeGxJR3lVVDNVRExWRHVhZzNHb1JHb2d2UVpIUXhtbzhXb0p2UWNyUWFQWXcyb2VmUXEyZ1AybzgrUThjd3dPZ1lCelBFYkRBdXhzTkNzVGdzQ1pOank3RWlyQXlyeGhxd1Zxd0R1NG4xWTgreGR3UVNnVVhBQ1RZRWQwSWdZUjVCU0ZoTVdFN1lTS2dnSENRMEVkb0pOd2tEaEZIQ0p5S1RxRXUwSnJvUitjUVlZakl4aDFoSUxDUFdFbzhUTHhCN2lFUEVOeVFTaVVNeUo3bVFBa214cEZUU0V0SkcwbTVTSStrc3FaczBTQm9qazhuYVpHdXlCem1VTENBcnlJWGtuZVRENURQa0crUWg4bHNLbldKQWNhVDRVK0lvVXNwcVNobmxFT1UwNVFabG1ESkJWYU9hVXQyb29WUVJOWTlhUXEyaHRsS3ZVWWVvRXpSMW1qbk5neFpKUzZXdG9wWFRHbWdYYVBkcHIraDB1aEhkbFI1T2w5Qlgwc3ZwUitpWDZBUDBkd3dOaGhXRHg0aG5LQm1iR0FjWVp4bDNHSytZVEtZWjA0c1p4MVF3TnpIcm1PZVpENWx2VlZncXRpcDhGWkhLQ3BWS2xTYVZHeW92VkttcXBxcmVxZ3RWODFYTFZJK3BYbE45cmtaVk0xUGpxUW5VbHF0VnFwMVE2MU1iVTJlcE82aUhxbWVvYjFRL3BINVovWWtHV2NOTXcwOURwRkdnc1YvanZNWWdDMk1aczNnc0lXc05xNFoxZ1RYRUpySE4yWHgyS3J1WS9SMjdpejJxcWFFNVF6TktNMWV6VXZPVVpqOEg0NWh4K0p4MFRnbm5LS2VYODM2SzNoVHZLZUlwRzZZMFRMa3haVnhycXBhWGxsaXJTS3RScTBmcnZUYXU3YWVkcHIxRnUxbjdnUTVCeDBvblhDZEhaNC9PQlozblU5bFQzYWNLcHhaTlBUcjFyaTZxYTZVYm9idEVkNzl1cCs2WW5yNWVnSjVNYjZmZWViM24raHg5TC8xVS9XMzZwL1ZIREZnR3N3d2tCdHNNemhnOHhUVnhiendkTDhmYjhWRkRYY05BUTZWaGxXR1g0WVNSdWRFOG85VkdqVVlQakduR1hPTWs0MjNHYmNhakpnWW1JU1pMVGVwTjdwcFNUYm1tS2FZN1REdE14ODNNemFMTjFwazFtejB4MXpMbm0rZWIxNXZmdDJCYWVGb3N0cWkydUdWSnN1UmFwbG51dHJ4dWhWbzVXYVZZVlZwZHMwYXRuYTBsMXJ1dHU2Y1JwN2xPazA2cm50Wm53N0R4dHNtMnFiY1pzT1hZQnR1dXRtMjJmV0ZuWWhkbnQ4V3V3KzZUdlpOOXVuMk4vVDBIRFlmWkRxc2RXaDErYzdSeUZEcFdPdDZhenB6dVAzM0Y5SmJwTDJkWXp4RFAyRFBqdGhQTEtjUnBuVk9iMDBkbkYyZTVjNFB6aUl1SlM0TExMcGMrTHBzYnh0M0l2ZVJLZFBWeFhlRjYwdldkbTdPYnd1Mm8yNi91TnU1cDdvZmNuOHcwbnltZVdUTnowTVBJUStCUjVkRS9DNStWTUd2ZnJINVBRMCtCWjdYbkl5OWpMNUZYcmRld3Q2VjNxdmRoN3hjKzlqNXluK00rNHp3MzNqTGVXVi9NTjhDM3lMZkxUOE52bmwrRjMwTi9JLzlrLzNyLzBRQ25nQ1VCWndPSmdVR0JXd0w3K0hwOEliK09QenJiWmZheTJlMUJqS0M1UVJWQmo0S3RndVhCclNGb3lPeVFyU0gzNTVqT2tjNXBEb1ZRZnVqVzBBZGg1bUdMdzM0TUo0V0hoVmVHUDQ1d2lGZ2EwVEdYTlhmUjNFTnozMFQ2UkpaRTNwdG5NVTg1cnkxS05TbytxaTVxUE5vM3VqUzZQOFl1WmxuTTFWaWRXRWxzU3h3NUxpcXVObTVzdnQvODdmT0g0cDNpQytON0Y1Z3Z5RjF3ZWFIT3d2U0ZweGFwTGhJc09wWkFUSWhPT0pUd1FSQXFxQmFNSmZJVGR5V09Dbm5DSGNKbklpL1JOdEdJMkVOY0toNU84a2dxVFhxUzdKRzhOWGtreFRPbExPVzVoQ2Vwa0x4TURVemRtenFlRnBwMklHMHlQVHE5TVlPU2taQnhRcW9oVFpPMlorcG41bVoyeTZ4bGhiTCt4VzZMdHk4ZWxRZkphN09RckFWWkxRcTJRcWJvVkZvbzF5b0hzbWRsVjJhL3pZbktPWmFybml2TjdjeXp5dHVRTjV6dm4vL3RFc0lTNFpLMnBZWkxWeTBkV09hOXJHbzVzanh4ZWRzSzR4VUZLNFpXQnF3OHVJcTJLbTNWVDZ2dFY1ZXVmcjBtZWsxcmdWN0J5b0xCdFFGcjZ3dFZDdVdGZmV2YzErMWRUMWd2V2QrMVlmcUduUnMrRlltS3JoVGJGNWNWZjlnbzNIamxHNGR2eXIrWjNKUzBxYXZFdVdUUFp0Sm02ZWJlTFo1YkRwYXFsK2FYRG00TjJkcTBEZDlXdE8zMTlrWGJMNWZOS051N2c3WkR1YU8vUExpOFphZkp6czA3UDFTa1ZQUlUrbFEyN3RMZHRXSFgrRzdSN2h0N3ZQWTA3TlhiVzd6My9UN0p2dHRWQVZWTjFXYlZaZnRKKzdQM1A2NkpxdW40bHZ0dFhhMU9iWEh0eHdQU0EvMEhJdzYyMTduVTFSM1NQVlJTajlZcjYwY094eCsrL3AzdmR5ME5OZzFWalp6RzRpTndSSG5rNmZjSjMvY2VEVHJhZG94N3JPRUgweDkySFdjZEwycENtdkthUnB0VG12dGJZbHU2VDh3KzBkYnEzbnI4UjlzZkQ1dzBQRmw1U3ZOVXlXbmE2WUxUazJmeXo0eWRsWjE5Zmk3NTNHRGJvclo3NTJQTzMyb1BiKys2RUhUaDBrWC9pK2M3dkR2T1hQSzRkUEt5MitVVFY3aFhtcTg2WDIzcWRPbzgvcFBUVDhlN25MdWFycmxjYTdudWVyMjFlMmIzNlJ1ZU44N2Q5TDE1OFJiLzF0V2VPVDNkdmZONmIvZkY5L1hmRnQxK2NpZjl6c3U3MlhjbjdxMjhUN3hmOUVEdFFkbEQzWWZWUDF2KzNOanYzSDlxd0hlZzg5SGNSL2NHaFlQUC9wSDFqdzlEQlkrWmo4dUdEWWJybmpnK09UbmlQM0w5NmZ5blE4OWt6eWFlRi82aS9zdXVGeFl2ZnZqVjY5Zk8wWmpSb1pmeWw1Ty9iWHlsL2VyQTZ4bXYyOGJDeGg2K3lYZ3pNVjcwVnZ2dHdYZmNkeDN2bzk4UFQrUjhJSDhvLzJqNXNmVlQwS2Y3a3htVGsvOEVBNWp6L0dNekxkc0FBQUFnWTBoU1RRQUFlaVVBQUlDREFBRDUvd0FBZ09rQUFIVXdBQURxWUFBQU9wZ0FBQmR2a2wvRlJnQUFBdGhKUkVGVWVOcnNsdDlMazFFWXg3L3ZOdGUwdlhPazd5UzdxeVdCWXZuaklrdEdVMHZEQ3drdFY0S1hwdjN3Qi80QkJpSWEvUUMxd2prVlV4TnNVdXV1emQxazZpQkxDeElGemNEWE9UWndZOHIyc3IxcnA0dVhadW9nZ3J5SmZTOGVlTDZjNTN3NDUrRTVISW9RZ29PVUNBZXNHQ0FHaUFFQXlYNkxaZG4xOVhXR1lkUnE5VDhna04xcWEyMFZEbFZaY1pVUVlwdVpLUzB0SFRjYTl5d3o2SHVycTZzL3pzNlNQMmtYd0dJMkF6aktxSFE2M2Z0M2s0U1Fwb1lHQU1XRlJYdktMbW9MQUF3T0RQd2RvTGRIRDJCa2FPaDM4NDNKNUhLNTlwVFYxZHdFOEdwOGZQK09TNHRMNXJmbUg2R1FrTzcwb0x1emMyand1U29wMmRCck9DeW5rNUtPOVBYM1oyWmtNQ2twcXl2ZkdJWUJjTCs5dzJxZEtDb3FDZ1FDQUhpZUYyb2ZQM3hrTXIxVzBJcmF1bHB0UVlIUDd3TkY3ZTJCTmw4RElPMzRDUUFOZCt1N3U3b0FTRUFCcUt1cEpZUlU2YTREb0dYeHFhb1VwWndXQTlhSkNVSkk0UVV0Z0ZQcWt3blNRd0Q2OVByb1Z4UU1CdHZiMmlpS2V0RFJ3Zk44S0JUaU9PN1prNmNBK25vTkxNc0N5TW84emZuOUhNZmxuTWtDc0xTNE9EMDFEVUIzOVJvaHhPbDB5aE1TNGlpUjNXNlBiTHN6QjNGeGNiUkNRUWhSSkNaS0pCS3hXQ3lUeWVSeUdvQlVLdjB5L3htQVRsY3BpNCtYeVdRYWpRYUF6K2VibXB3RVVGNVJEa0NsVWhWcUMzZ1NucCtiaXo0SG5OOFB3Ty8zUjV4QWdNdk56azVta2tXVUNNRHE2bmZCZHpnMkJEQ3RVQUJ3T2wyL2ZJZEFpZzRJQm9PUktJam5lUVZOYjNtM2lpK1hpRUhwK3d6cEdlbHV0L3VsMFFnZ0VBaVVYU203ZGVmMnZaYVd0TFMwaFlXdkgrWSs1Wi9OeThuTmpmNVVTQ1NTU0l3NDRYRFk0ZGhRS3BYRHc4TmlpcXB2YkJ3ZGVWRjFvd29BdTdhV21uck0wS1BmM3Q2K1ZGTGMxTng4UHUvYzZOaVlTQ1NLUHNrZXQyZDVlZG5qOFVRY3I5ZHJYN2U3M1p0Q3lySnJWcXMxSEE0VFFwWlhWcnhlcitDN045MFdpOFZtcyswZkN5cjJxNGdCWW9EL0FQQnpBSTZWTnFHUVBVcW5BQUFBQUVsRlRrU3VRbUNDIiwKICAgICJpc1NlY29uZEZhY3Rvck9ubHkiOiBmYWxzZSwKICAgICJrZXlQcm90ZWN0aW9uIjogMTAsCiAgICAibWF0Y2hlclByb3RlY3Rpb24iOiA0LAogICAgIm9wZXJhdGluZ0VudiI6ICJTZWN1cmUgRWxlbWVudCAoU0UpIiwKICAgICJwcm90b2NvbEZhbWlseSI6ICJmaWRvMiIsCiAgICAicHVibGljS2V5QWxnQW5kRW5jb2RpbmciOiAyNjAsCiAgICAidGNEaXNwbGF5IjogMCwKICAgICJ1cHYiOiBbCiAgICAgICAgewogICAgICAgICAgICAibWFqb3IiOiAxLAogICAgICAgICAgICAibWlub3IiOiAwCiAgICAgICAgfQogICAgXSwKICAgICJ1c2VyVmVyaWZpY2F0aW9uRGV0YWlscyI6IFsKICAgICAgICBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJ1c2VyVmVyaWZpY2F0aW9uIjogMQogICAgICAgICAgICB9CiAgICAgICAgXQogICAgXQp9TestMetadataStatementParsing-P1.json000066400000000000000000000242741414201525100327330ustar00rootroot00000000000000golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/testdataewogICAgImFhZ3VpZCI6ICIwOTY0MTFmNC0zODA4LTQzMGUtYmYyNi1mMmZiNmRhZjhiZWEiLAogICAgImFsdGVybmF0aXZlRGVzY3JpcHRpb25zIjogewogICAgICAgICJydS1SVSI6ICLQktC40YDRgtGD0LDQu9GM0L3Ri9C5IFNlY3AyNTZSMSBDVEFQMiDQsNGD0YLQtdC90YLQuNGE0LjQutCw0YLQvtGAINC00LvRjyDRgtC10YHRgtC40YDQvtCy0LDQvdC40LUg0YHQtdGA0LLQtdGA0L7QsiDQvdCwINGB0L7QvtGC0LLQtdGC0YHQstC40LUg0YHQv9C10YbQuNGE0LjQutCw0YbQuNC4IEZJRE8yIDA5NjQxMWY0LTM4MDgtNDMwZS1iZjI2LWYyZmI2ZGFmOGJlYSIKICAgIH0sCiAgICAiYXNzZXJ0aW9uU2NoZW1lIjogIkZJRE9WMiIsCiAgICAiYXR0YWNobWVudEhpbnQiOiAyLAogICAgImF0dGVzdGF0aW9uUm9vdENlcnRpZmljYXRlcyI6IFsKICAgICAgICAiTUlJRndEQ0NBNmdDQ1FDTm0xdTU2b1J3WFRBTkJna3Foa2lHOXcwQkFRc0ZBRENCb1RFWU1CWUdBMVVFQXd3UFJrbEVUeklnVkVWVFZDQlNUMDlVTVRFd0x3WUpLb1pJaHZjTkFRa0JGaUpqYjI1bWIzSnRZVzVqWlMxMGIyOXNjMEJtYVdSdllXeHNhV0Z1WTJVdWIzSm5NUll3RkFZRFZRUUtEQTFHU1VSUElFRnNiR2xoYm1ObE1Rd3dDZ1lEVlFRTERBTkRWMGN4Q3pBSkJnTlZCQVlUQWxWVE1Rc3dDUVlEVlFRSURBSk5XVEVTTUJBR0ExVUVCd3dKVjJGclpXWnBaV3hrTUI0WERURTRNRE14TmpFME16VXlOMW9YRFRRMU1EZ3dNVEUwTXpVeU4xb3dnYUV4R0RBV0JnTlZCQU1NRDBaSlJFOHlJRlJGVTFRZ1VrOVBWREV4TUM4R0NTcUdTSWIzRFFFSkFSWWlZMjl1Wm05eWJXRnVZMlV0ZEc5dmJITkFabWxrYjJGc2JHbGhibU5sTG05eVp6RVdNQlFHQTFVRUNnd05Sa2xFVHlCQmJHeHBZVzVqWlRFTU1Bb0dBMVVFQ3d3RFExZEhNUXN3Q1FZRFZRUUdFd0pWVXpFTE1Ba0dBMVVFQ0F3Q1RWa3hFakFRQmdOVkJBY01DVmRoYTJWbWFXVnNaRENDQWlJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFMMTFVNXlBSVZMTXJMM3hTOHU4eXNNU2RPa0Rlb1RPK1JjQXkrdVhYcDZrNFNDK2pPeTM3Z0lDRXRZSStNS1FWMUVNZU1NZjNyTTF1ZVpBTzNpUEZhME5FZGkvb1E3bnBuR2pCTkk4d016RDhGZk5lNnJXdHprRGFIcHNaVy8vL013V0RwR3lKUitYeWpjcTZVNHZTOWJTNnpaN2pzbHcwT2N6eDRVc1lnT3NJVVhTU0JhR09yUmJ4Si9KQzVnbkRZRVl2dE5NK1BEUGN6TE5LQXloZHZCWldOV0hyN01aMFA1VGVKUWNYc0FvU2hSWDJZOFU4ZlJOSm03U2VpRktEUDBObi9RS3hPU3Q3ekdQNHh0OW5NYXNFMXEyWlRkYXIyK1cxM0NSejM3UkkwWldwcS8rWXF1b0ViWjdVajdObUJUY3FoYjI2MG5tREVSMkZwd3dZd1BTYXJrOTJJWmJhbW96QjhkN09FSTFqSmdzcmpKaEthbjBFbVJhV1ZCcEhUNHhZS2RFdTdyMDlTMEpoS3lVKzUyV0RtbVZRVE1wWUxybTRYbDdoUnh5UHlCWWthbHJvenNHbVBzOHZsaE5xM1ZzVmJ5QlNNU3BFbVVhZUFhN0xMRTkvVmgwYWdKTFZGSGgxZWhZS0pwekhubW1CWFVxeDBGejNhZm1EbTFOWDBzcjNPLzZ4SXgxVlNUVmlUM0tOeEJZcFZIMXFqSEFUTHp1eGNXbW0rNzVmY0pNaVBZUFNNWFZtUmIzUTFsOTFBTTRCQmVXaGxQM0ZiYzdnRHkwcitzN20wc0dTNlBUMkoyckdvZzJyVXhuSit6Q00xMU03RGVPMFhNMm5ueTR1UllQUGs5dzJFWHpmdnRkdmllWVUvNVJCNFJEbTVUR3hIaEdYVlpVZ2FjNUFnTUJBQUV3RFFZSktvWklodmNOQVFFTEJRQURnZ0lCQUZ0MlhHZDNrNUdwYk8xRVVtM3U2MHpUMWZFNnU2cE9zY3AxNTZrNVZuc0hnYUhSSGRJQVBOTGVMTm1SN3k1T25yWGJoMTNDckd3VTFxODRqakpYcHYrdjE0eFVDYzVpMDF5b3BGVFFGTHI0QTdOSHAybk5ZZk5oaElWU0ZBZ1c0M0VmbEpmbGJMRWVsQ0p6eExsV2I1Qm9Ec1plZU5tRVFzWElNMW1KMjZSM3IwZHpzSEJiMHV5KzhMTlIxZ2RWcWRqaEM4Qkx5M2doNCtCV3VpZHlaTnQwN0x2ZURzU0ZXNXJjajV3UnJTeDloWFBJeVZwalFTbGpOdlk3TVZUb3VxSnpOQUFRTXNUS2tYUGtUWGxkQ29wOVFvOVVQa0hSUm0wbDdMTHRkYU9vWHJjdDBZbW9jZjh6eGY5YkZOaXc5ZjRXUllRTTZzTWh6dDgrcy9vRGlsbzRRaGNVZ2VKRWlFUEVTaTZ5bllUVjYyU0hBNGVNdW5VSjVkbENhUm5GaVI5RFRJbUZhNUlSemllMzI2L25XL1NQQ2FLYy95ckZJaWhNTWpKb1NBUGhwVGIvSzZ5SE9VRzhyK0tpUXV0N056cUdWMzAxcFE5dTYyZEdMNU9pMVZYbUNGbEUycmFtWnMxNUJOT1V5QW8yQ0JiUkpnM2pLY2R1LzhRQzZvampEdlE4NjMrN0xQdG43NHdKQzVScFVKc1MwR2hRV2dxNXBBWE8zd0E2MVVvYnhpNk1rT3BDQzB6Qld4L2Q0Q3FwUzRqNGhGZ3hXQlRYWDQ4aWhQdStoSXhJRi9BeGJxdFB2cUxNRXhXL3haSVRuNkFycFd5UTllNFNVVnIzbjNGMzNhcDFYZER5WjB2d0ZjbTE4SlFBdHN2WFQ2cUNMcldPWG5IVWdmbi8rVml1IgogICAgXSwKICAgICJhdHRlc3RhdGlvblR5cGVzIjogWwogICAgICAgIDE1ODc5LAogICAgICAgIDE1ODgwCiAgICBdLAogICAgImF1dGhlbnRpY2F0aW9uQWxnb3JpdGhtIjogMSwKICAgICJhdXRoZW50aWNhdG9yVmVyc2lvbiI6IDIsCiAgICAiY3J5cHRvU3RyZW5ndGgiOiAxMjgsCiAgICAiZGVzY3JpcHRpb24iOiAiVmlydHVhbCBTZWNwMjU2UjEgRklETzIgQ29uZm9ybWFuY2UgVGVzdGluZyBDVEFQMiBBdXRoZW50aWNhdG9yIDA5NjQxMWY0LTM4MDgtNDMwZS1iZjI2LWYyZmI2ZGFmOGJlYSIsCiAgICAiaWNvbiI6ICJkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQUNBQUFBQWdDQUlBQUFEOEdPMmpBQUFBQ1hCSVdYTUFBQzRqQUFBdUl3RjRwVDkyQUFBS1QybERRMUJRYUc5MGIzTm9iM0FnU1VORElIQnliMlpwYkdVQUFIamFuVk5uVkZQcEZqMzMzdlJDUzRpQWxFdHZVaFVJSUZKQ2k0QVVrU1lxSVFrUVNvZ2hvZGtWVWNFUlJVVUVHOGlnaUFPT2pvQ01GVkVzRElvSzJBZmtJYUtPZzZPSWlzcjc0WHVqYTlhODkrYk4vclhYUHVlczg1Mnp6d2ZBQ0F5V1NETlJOWUFNcVVJZUVlQ0R4OFRHNGVRdVFJRUtKSEFBRUFpelpDRnovU01CQVBoK1BEd3JJc0FIdmdBQmVOTUxDQURBVFp2QU1CeUgvdy9xUXBsY0FZQ0VBY0Iwa1RoTENJQVVBRUI2amtLbUFFQkdBWUNkbUNaVEFLQUVBR0RMWTJMakFGQXRBR0FuZitiVEFJQ2QrSmw3QVFCYmxDRVZBYUNSQUNBVFpZaEVBR2c3QUt6UFZvcEZBRmd3QUJSbVM4UTVBTmd0QURCSlYyWklBTEMzQU1ET0VBdXlBQWdNQURCUmlJVXBBQVI3QUdESUl5TjRBSVNaQUJSRzhsYzg4U3V1RU9jcUFBQjRtYkk4dVNRNVJZRmJDQzF4QjFkWExoNG96a2tYS3hRMllRSmhta0F1d25tWkdUS0JOQS9nODh3QUFLQ1JGUkhnZy9QOWVNNE9yczdPTm82MkRsOHQ2cjhHL3lKaVl1UCs1YytyY0VBQUFPRjBmdEgrTEMrekdvQTdCb0J0L3FJbDdnUm9YZ3VnZGZlTFpySVBRTFVBb09uYVYvTncrSDQ4UEVXaGtMbloyZVhrNU5oS3hFSmJZY3BYZmY1bndsL0FWLzFzK1g0OC9QZjE0TDdpSklFeVhZRkhCUGpnd3N6MFRLVWN6NUlKaEdMYzVvOUgvTGNMLy93ZDB5TEVTV0s1V0NvVTQxRVNjWTVFbW96ek1xVWlpVUtTS2NVbDB2OWs0dDhzK3dNKzN6VUFzR28rQVh1UkxhaGRZd1AyU3ljUVdIVEE0dmNBQVBLN2I4SFVLQWdEZ0dpRDRjOTMvKzgvL1VlZ0pRQ0Faa21TY1FBQVhrUWtMbFRLc3ovSENBQUFSS0NCS3JCQkcvVEJHQ3pBQmh6QkJkekJDL3hnTm9SQ0pNVENRaEJDQ21TQUhISmdLYXlDUWlpR3piQWRLbUF2MUVBZE5NQlJhSWFUY0E0dXdsVzREajF3RC9waENKN0JLTHlCQ1FSQnlBZ1RZU0hhaUFGaWlsZ2pqZ2dYbVlYNEljRklCQktMSkNESmlCUlJJa3VSTlVneFVvcFVJRlZJSGZJOWNnSTVoMXhHdXBFN3lBQXlndnlHdkVjeGxJR3lVVDNVRExWRHVhZzNHb1JHb2d2UVpIUXhtbzhXb0p2UWNyUWFQWXcyb2VmUXEyZ1AybzgrUThjd3dPZ1lCelBFYkRBdXhzTkNzVGdzQ1pOank3RWlyQXlyeGhxd1Zxd0R1NG4xWTgreGR3UVNnVVhBQ1RZRWQwSWdZUjVCU0ZoTVdFN1lTS2dnSENRMEVkb0pOd2tEaEZIQ0p5S1RxRXUwSnJvUitjUVlZakl4aDFoSUxDUFdFbzhUTHhCN2lFUEVOeVFTaVVNeUo3bVFBa214cEZUU0V0SkcwbTVTSStrc3FaczBTQm9qazhuYVpHdXlCem1VTENBcnlJWGtuZVRENURQa0crUWg4bHNLbldKQWNhVDRVK0lvVXNwcVNobmxFT1UwNVFabG1ESkJWYU9hVXQyb29WUVJOWTlhUXEyaHRsS3ZVWWVvRXpSMW1qbk5neFpKUzZXdG9wWFRHbWdYYVBkcHIraDB1aEhkbFI1T2w5Qlgwc3ZwUitpWDZBUDBkd3dOaGhXRHg0aG5LQm1iR0FjWVp4bDNHSytZVEtZWjA0c1p4MVF3TnpIcm1PZVpENWx2VlZncXRpcDhGWkhLQ3BWS2xTYVZHeW92VkttcXBxcmVxZ3RWODFYTFZJK3BYbE45cmtaVk0xUGpxUW5VbHF0VnFwMVE2MU1iVTJlcE82aUhxbWVvYjFRL3BINVovWWtHV2NOTXcwOURwRkdnc1YvanZNWWdDMk1aczNnc0lXc05xNFoxZ1RYRUpySE4yWHgyS3J1WS9SMjdpejJxcWFFNVF6TktNMWV6VXZPVVpqOEg0NWh4K0p4MFRnbm5LS2VYODM2SzNoVHZLZUlwRzZZMFRMa3haVnhycXBhWGxsaXJTS3RScTBmcnZUYXU3YWVkcHIxRnUxbjdnUTVCeDBvblhDZEhaNC9PQlozblU5bFQzYWNLcHhaTlBUcjFyaTZxYTZVYm9idEVkNzl1cCs2WW5yNWVnSjVNYjZmZWViM24raHg5TC8xVS9XMzZwL1ZIREZnR3N3d2tCdHNNemhnOHhUVnhiendkTDhmYjhWRkRYY05BUTZWaGxXR1g0WVNSdWRFOG85VkdqVVlQakduR1hPTWs0MjNHYmNhakpnWW1JU1pMVGVwTjdwcFNUYm1tS2FZN1REdE14ODNNemFMTjFwazFtejB4MXpMbm0rZWIxNXZmdDJCYWVGb3N0cWkydUdWSnN1UmFwbG51dHJ4dWhWbzVXYVZZVlZwZHMwYXRuYTBsMXJ1dHU2Y1JwN2xPazA2cm50Wm53N0R4dHNtMnFiY1pzT1hZQnR1dXRtMjJmV0ZuWWhkbnQ4V3V3KzZUdlpOOXVuMk4vVDBIRFlmWkRxc2RXaDErYzdSeUZEcFdPdDZhenB6dVAzM0Y5SmJwTDJkWXp4RFAyRFBqdGhQTEtjUnBuVk9iMDBkbkYyZTVjNFB6aUl1SlM0TExMcGMrTHBzYnh0M0l2ZVJLZFBWeFhlRjYwdldkbTdPYnd1Mm8yNi91TnU1cDdvZmNuOHcwbnltZVdUTnowTVBJUStCUjVkRS9DNStWTUd2ZnJINVBRMCtCWjdYbkl5OWpMNUZYcmRld3Q2VjNxdmRoN3hjKzlqNXluK00rNHp3MzNqTGVXVi9NTjhDM3lMZkxUOE52bmwrRjMwTi9JLzlrLzNyLzBRQ25nQ1VCWndPSmdVR0JXd0w3K0hwOEliK09QenJiWmZheTJlMUJqS0M1UVJWQmo0S3RndVhCclNGb3lPeVFyU0gzNTVqT2tjNXBEb1ZRZnVqVzBBZGg1bUdMdzM0TUo0V0hoVmVHUDQ1d2lGZ2EwVEdYTlhmUjNFTnozMFQ2UkpaRTNwdG5NVTg1cnkxS05TbytxaTVxUE5vM3VqUzZQOFl1WmxuTTFWaWRXRWxzU3h3NUxpcXVObTVzdnQvODdmT0g0cDNpQytON0Y1Z3Z5RjF3ZWFIT3d2U0ZweGFwTGhJc09wWkFUSWhPT0pUd1FSQXFxQmFNSmZJVGR5V09Dbm5DSGNKbklpL1JOdEdJMkVOY0toNU84a2dxVFhxUzdKRzhOWGtreFRPbExPVzVoQ2Vwa0x4TURVemRtenFlRnBwMklHMHlQVHE5TVlPU2taQnhRcW9oVFpPMlorcG41bVoyeTZ4bGhiTCt4VzZMdHk4ZWxRZkphN09RckFWWkxRcTJRcWJvVkZvbzF5b0hzbWRsVjJhL3pZbktPWmFybml2TjdjeXp5dHVRTjV6dm4vL3RFc0lTNFpLMnBZWkxWeTBkV09hOXJHbzVzanh4ZWRzSzR4VUZLNFpXQnF3OHVJcTJLbTNWVDZ2dFY1ZXVmcjBtZWsxcmdWN0J5b0xCdFFGcjZ3dFZDdVdGZmV2YzErMWRUMWd2V2QrMVlmcUduUnMrRlltS3JoVGJGNWNWZjlnbzNIamxHNGR2eXIrWjNKUzBxYXZFdVdUUFp0Sm02ZWJlTFo1YkRwYXFsK2FYRG00TjJkcTBEZDlXdE8zMTlrWGJMNWZOS051N2c3WkR1YU8vUExpOFphZkp6czA3UDFTa1ZQUlUrbFEyN3RMZHRXSFgrRzdSN2h0N3ZQWTA3TlhiVzd6My9UN0p2dHRWQVZWTjFXYlZaZnRKKzdQM1A2NkpxdW40bHZ0dFhhMU9iWEh0eHdQU0EvMEhJdzYyMTduVTFSM1NQVlJTajlZcjYwY094eCsrL3AzdmR5ME5OZzFWalp6RzRpTndSSG5rNmZjSjMvY2VEVHJhZG94N3JPRUgweDkySFdjZEwycENtdkthUnB0VG12dGJZbHU2VDh3KzBkYnEzbnI4UjlzZkQ1dzBQRmw1U3ZOVXlXbmE2WUxUazJmeXo0eWRsWjE5Zmk3NTNHRGJvclo3NTJQTzMyb1BiKys2RUhUaDBrWC9pK2M3dkR2T1hQSzRkUEt5MitVVFY3aFhtcTg2WDIzcWRPbzgvcFBUVDhlN25MdWFycmxjYTdudWVyMjFlMmIzNlJ1ZU44N2Q5TDE1OFJiLzF0V2VPVDNkdmZONmIvZkY5L1hmRnQxK2NpZjl6c3U3MlhjbjdxMjhUN3hmOUVEdFFkbEQzWWZWUDF2KzNOanYzSDlxd0hlZzg5SGNSL2NHaFlQUC9wSDFqdzlEQlkrWmo4dUdEWWJybmpnK09UbmlQM0w5NmZ5blE4OWt6eWFlRi82aS9zdXVGeFl2ZnZqVjY5Zk8wWmpSb1pmeWw1Ty9iWHlsL2VyQTZ4bXYyOGJDeGg2K3lYZ3pNVjcwVnZ2dHdYZmNkeDN2bzk4UFQrUjhJSDhvLzJqNXNmVlQwS2Y3a3htVGsvOEVBNWp6L0dNekxkc0FBQUFnWTBoU1RRQUFlaVVBQUlDREFBRDUvd0FBZ09rQUFIVXdBQURxWUFBQU9wZ0FBQmR2a2wvRlJnQUFBdGhKUkVGVWVOcnNsdDlMazFFWXg3L3ZOdGUwdlhPazd5UzdxeVdCWXZuaklrdEdVMHZEQ3drdFY0S1hwdjN3Qi80QkJpSWEvUUMxd2prVlV4TnNVdXV1emQxazZpQkxDeElGemNEWE9UWndZOHIyc3IxcnA0dVhadW9nZ3J5SmZTOGVlTDZjNTN3NDUrRTVISW9RZ29PVUNBZXNHQ0FHaUFFQXlYNkxaZG4xOVhXR1lkUnE5VDhna04xcWEyMFZEbFZaY1pVUVlwdVpLUzB0SFRjYTl5d3o2SHVycTZzL3pzNlNQMmtYd0dJMkF6aktxSFE2M2Z0M2s0U1Fwb1lHQU1XRlJYdktMbW9MQUF3T0RQd2RvTGRIRDJCa2FPaDM4NDNKNUhLNTlwVFYxZHdFOEdwOGZQK09TNHRMNXJmbUg2R1FrTzcwb0x1emMyand1U29wMmRCck9DeW5rNUtPOVBYM1oyWmtNQ2twcXl2ZkdJWUJjTCs5dzJxZEtDb3FDZ1FDQUhpZUYyb2ZQM3hrTXIxVzBJcmF1bHB0UVlIUDd3TkY3ZTJCTmw4RElPMzRDUUFOZCt1N3U3b0FTRUFCcUt1cEpZUlU2YTREb0dYeHFhb1VwWndXQTlhSkNVSkk0UVV0Z0ZQcWt3blNRd0Q2OVByb1Z4UU1CdHZiMmlpS2V0RFJ3Zk44S0JUaU9PN1prNmNBK25vTkxNc0N5TW84emZuOUhNZmxuTWtDc0xTNE9EMDFEVUIzOVJvaHhPbDB5aE1TNGlpUjNXNlBiTHN6QjNGeGNiUkNRUWhSSkNaS0pCS3hXQ3lUeWVSeUdvQlVLdjB5L3htQVRsY3BpNCtYeVdRYWpRYUF6K2VibXB3RVVGNVJEa0NsVWhWcUMzZ1NucCtiaXo0SG5OOFB3Ty8zUjV4QWdNdk56azVta2tXVUNNRHE2bmZCZHpnMkJEQ3RVQUJ3T2wyL2ZJZEFpZzRJQm9PUktJam5lUVZOYjNtM2lpK1hpRUhwK3d6cEdlbHV0L3VsMFFnZ0VBaVVYU203ZGVmMnZaYVd0TFMwaFlXdkgrWSs1Wi9OeThuTmpmNVVTQ1NTU0l3NDRYRFk0ZGhRS3BYRHc4TmlpcXB2YkJ3ZGVWRjFvd29BdTdhV21uck0wS1BmM3Q2K1ZGTGMxTng4UHUvYzZOaVlTQ1NLUHNrZXQyZDVlZG5qOFVRY3I5ZHJYN2U3M1p0Q3lySnJWcXMxSEE0VFFwWlhWcnhlcitDN045MFdpOFZtcyswZkN5cjJxNGdCWW9EL0FQQnpBSTZWTnFHUVBVcW5BQUFBQUVsRlRrU3VRbUNDIiwKICAgICJpc1NlY29uZEZhY3Rvck9ubHkiOiBmYWxzZSwKICAgICJrZXlQcm90ZWN0aW9uIjogMTAsCiAgICAibWF0Y2hlclByb3RlY3Rpb24iOiA0LAogICAgIm9wZXJhdGluZ0VudiI6ICJTZWN1cmUgRWxlbWVudCAoU0UpIiwKICAgICJwcm90b2NvbEZhbWlseSI6ICJmaWRvMiIsCiAgICAicHVibGljS2V5QWxnQW5kRW5jb2RpbmciOiAyNjAsCiAgICAidGNEaXNwbGF5IjogMCwKICAgICJ1cHYiOiBbCiAgICAgICAgewogICAgICAgICAgICAibWFqb3IiOiAxLAogICAgICAgICAgICAibWlub3IiOiAwCiAgICAgICAgfQogICAgXSwKICAgICJ1c2VyVmVyaWZpY2F0aW9uRGV0YWlscyI6IFsKICAgICAgICBbCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICJ1c2VyVmVyaWZpY2F0aW9uIjogMQogICAgICAgICAgICB9CiAgICAgICAgXQogICAgXQp9golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/webauthn/000077500000000000000000000000001414201525100240435ustar00rootroot00000000000000golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/webauthn/authenticator.go000066400000000000000000000045571414201525100272570ustar00rootroot00000000000000package webauthn import ( p "github.com/duo-labs/webauthn/protocol" ) type Authenticator struct { // The AAGUID of the authenticator. An AAGUID is defined as an array containing the globally unique // identifier of the authenticator model being sought. AAGUID []byte // SignCount -Upon a new login operation, the Relying Party compares the stored signature counter value // with the new signCount value returned in the assertion’s authenticator data. If this new // signCount value is less than or equal to the stored value, a cloned authenticator may // exist, or the authenticator may be malfunctioning. SignCount uint32 // CloneWarning - This is a signal that the authenticator may be cloned, i.e. at least two copies of the // credential private key may exist and are being used in parallel. Relying Parties should incorporate // this information into their risk scoring. Whether the Relying Party updates the stored signature // counter value in this case, or not, or fails the authentication ceremony or not, is Relying Party-specific. CloneWarning bool } // Allow for easy marhsalling of authenticator options that are provided to the user func SelectAuthenticator(att string, rrk *bool, uv string) p.AuthenticatorSelection { return p.AuthenticatorSelection{ AuthenticatorAttachment: p.AuthenticatorAttachment(att), RequireResidentKey: rrk, UserVerification: p.UserVerificationRequirement(uv), } } // VerifyCounter // Step 17 of §7.2. about verifying attestation. If the signature counter value authData.signCount // is nonzero or the value stored in conjunction with credential’s id attribute is nonzero, then // run the following sub-step: // // If the signature counter value authData.signCount is // // → Greater than the signature counter value stored in conjunction with credential’s id attribute. // Update the stored signature counter value, associated with credential’s id attribute, to be the value of // authData.signCount. // // → Less than or equal to the signature counter value stored in conjunction with credential’s id attribute. // This is a signal that the authenticator may be cloned, see CloneWarning above for more information. func (a *Authenticator) UpdateCounter(authDataCount uint32) { if authDataCount <= a.SignCount && (authDataCount != 0 || a.SignCount != 0) { a.CloneWarning = true } a.SignCount = authDataCount } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/webauthn/authenticator_test.go000066400000000000000000000054161414201525100303110ustar00rootroot00000000000000package webauthn import ( "reflect" "testing" p "github.com/duo-labs/webauthn/protocol" ) func TestAuthenticator_UpdateCounter(t *testing.T) { type fields struct { AAGUID []byte SignCount uint32 CloneWarning bool } type args struct { authDataCount uint32 } tests := []struct { name string fields fields args args wantWarning bool }{ { "Increased counter", fields{ AAGUID: make([]byte, 16), SignCount: 1, CloneWarning: false, }, args{ authDataCount: 2, }, false, }, { "Unchanged counter", fields{ AAGUID: make([]byte, 16), SignCount: 1, CloneWarning: false, }, args{ authDataCount: 1, }, true, }, { "Decreased counter", fields{ AAGUID: make([]byte, 16), SignCount: 2, CloneWarning: false, }, args{ authDataCount: 1, }, true, }, { "Zero counter", fields{ AAGUID: make([]byte, 16), SignCount: 0, CloneWarning: false, }, args{ authDataCount: 0, }, false, }, { "Counter returned to zero", fields{ AAGUID: make([]byte, 16), SignCount: 1, CloneWarning: false, }, args{ authDataCount: 0, }, true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { a := &Authenticator{ AAGUID: tt.fields.AAGUID, SignCount: tt.fields.SignCount, CloneWarning: tt.fields.CloneWarning, } a.UpdateCounter(tt.args.authDataCount) if a.CloneWarning != tt.wantWarning { t.Errorf("Clone warning result [%v] does not match expectation: [%v]", a.CloneWarning, tt.wantWarning) return } }) } } func TestSelectAuthenticator(t *testing.T) { type args struct { att string rrk *bool uv string } tests := []struct { name string args args want p.AuthenticatorSelection }{ {"Generate Correct Authenticator Selection", args{ att: "platform", rrk: p.ResidentKeyUnrequired(), uv: "preferred", }, p.AuthenticatorSelection{ AuthenticatorAttachment: p.Platform, RequireResidentKey: p.ResidentKeyUnrequired(), UserVerification: p.VerificationPreferred, }, }, {"Generate Correct Authenticator Selection", args{ att: "cross-platform", rrk: p.ResidentKeyRequired(), uv: "required", }, p.AuthenticatorSelection{ AuthenticatorAttachment: p.CrossPlatform, RequireResidentKey: p.ResidentKeyRequired(), UserVerification: p.VerificationRequired, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := SelectAuthenticator(tt.args.att, tt.args.rrk, tt.args.uv); !reflect.DeepEqual(got, tt.want) { t.Errorf("SelectAuthenticator() = %v, want %v", got, tt.want) } }) } } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/webauthn/credential.go000066400000000000000000000031311414201525100265020ustar00rootroot00000000000000package webauthn import ( "github.com/duo-labs/webauthn/protocol" ) // Credential contains all needed information about a WebAuthn credential for storage type Credential struct { // A probabilistically-unique byte sequence identifying a public key credential source and its authentication assertions. ID []byte // The public key portion of a Relying Party-specific credential key pair, generated by an authenticator and returned to // a Relying Party at registration time (see also public key credential). The private key portion of the credential key // pair is known as the credential private key. Note that in the case of self attestation, the credential key pair is also // used as the attestation key pair, see self attestation for details. PublicKey []byte // The attestation format used (if any) by the authenticator when creating the credential. AttestationType string // The Authenticator information for a given certificate Authenticator Authenticator } // MakeNewCredential will return a credential pointer on successful validation of a registration response func MakeNewCredential(c *protocol.ParsedCredentialCreationData) (*Credential, error) { newCredential := &Credential{ ID: c.Response.AttestationObject.AuthData.AttData.CredentialID, PublicKey: c.Response.AttestationObject.AuthData.AttData.CredentialPublicKey, AttestationType: c.Response.AttestationObject.Format, Authenticator: Authenticator{ AAGUID: c.Response.AttestationObject.AuthData.AttData.AAGUID, SignCount: c.Response.AttestationObject.AuthData.Counter, }, } return newCredential, nil } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/webauthn/credential_test.go000066400000000000000000000012541414201525100275450ustar00rootroot00000000000000package webauthn import ( "reflect" "testing" "github.com/duo-labs/webauthn/protocol" ) func TestMakeNewCredential(t *testing.T) { type args struct { c *protocol.ParsedCredentialCreationData } tests := []struct { name string args args want *Credential wantErr bool }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := MakeNewCredential(tt.args.c) if (err != nil) != tt.wantErr { t.Errorf("MakeNewCredential() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { t.Errorf("MakeNewCredential() = %v, want %v", got, tt.want) } }) } } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/webauthn/doc.go000066400000000000000000000003111414201525100251320ustar00rootroot00000000000000// Contains the API functionality of the library. After creating and configuring a webauthn object, users can // call the object to create and validate web authentication credentials. package webauthn golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/webauthn/login.go000066400000000000000000000154231414201525100255070ustar00rootroot00000000000000package webauthn import ( "bytes" "encoding/base64" "net/http" "github.com/duo-labs/webauthn/protocol" ) // BEGIN REGISTRATION // These objects help us creat the CredentialCreationOptions // that will be passed to the authenticator via the user client // LoginOption is used to provide parameters that modify the default Credential Assertion Payload that is sent to the user. type LoginOption func(*protocol.PublicKeyCredentialRequestOptions) // Creates the CredentialAssertion data payload that should be sent to the user agent for beginning the // login/assertion process. The format of this data can be seen in §5.5 of the WebAuthn specification // (https://www.w3.org/TR/webauthn/#assertion-options). These default values can be amended by providing // additional LoginOption parameters. This function also returns sessionData, that must be stored by the // RP in a secure manner and then provided to the FinishLogin function. This data helps us verify the // ownership of the credential being retreived. func (webauthn *WebAuthn) BeginLogin(user User, opts ...LoginOption) (*protocol.CredentialAssertion, *SessionData, error) { challenge, err := protocol.CreateChallenge() if err != nil { return nil, nil, err } credentials := user.WebAuthnCredentials() if len(credentials) == 0 { // If the user does not have any credentials, we cannot do login return nil, nil, protocol.ErrBadRequest.WithDetails("Found no credentials for user") } var allowedCredentials = make([]protocol.CredentialDescriptor, len(credentials)) for i, credential := range credentials { var credentialDescriptor protocol.CredentialDescriptor credentialDescriptor.CredentialID = credential.ID credentialDescriptor.Type = protocol.PublicKeyCredentialType allowedCredentials[i] = credentialDescriptor } requestOptions := protocol.PublicKeyCredentialRequestOptions{ Challenge: challenge, Timeout: webauthn.Config.Timeout, RelyingPartyID: webauthn.Config.RPID, UserVerification: webauthn.Config.AuthenticatorSelection.UserVerification, AllowedCredentials: allowedCredentials, } for _, setter := range opts { setter(&requestOptions) } newSessionData := SessionData{ Challenge: base64.RawURLEncoding.EncodeToString(challenge), UserID: user.WebAuthnID(), AllowedCredentialIDs: requestOptions.GetAllowedCredentialIDs(), UserVerification: requestOptions.UserVerification, } response := protocol.CredentialAssertion{requestOptions} return &response, &newSessionData, nil } // Updates the allowed credential list with Credential Descripiptors, discussed in §5.10.3 // (https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialdescriptor) with user-supplied values func WithAllowedCredentials(allowList []protocol.CredentialDescriptor) LoginOption { return func(cco *protocol.PublicKeyCredentialRequestOptions) { cco.AllowedCredentials = allowList } } // Request a user verification preference func WithUserVerification(userVerification protocol.UserVerificationRequirement) LoginOption { return func(cco *protocol.PublicKeyCredentialRequestOptions) { cco.UserVerification = userVerification } } // Request additional extensions for assertion func WithAssertionExtensions(extensions protocol.AuthenticationExtensions) LoginOption { return func(cco *protocol.PublicKeyCredentialRequestOptions) { cco.Extensions = extensions } } // Take the response from the client and validate it against the user credentials and stored session data func (webauthn *WebAuthn) FinishLogin(user User, session SessionData, response *http.Request) (*Credential, error) { parsedResponse, err := protocol.ParseCredentialRequestResponse(response) if err != nil { return nil, err } return webauthn.ValidateLogin(user, session, parsedResponse) } // ValidateLogin takes a parsed response and validates it against the user credentials and session data func (webauthn *WebAuthn) ValidateLogin(user User, session SessionData, parsedResponse *protocol.ParsedCredentialAssertionData) (*Credential, error) { if !bytes.Equal(user.WebAuthnID(), session.UserID) { return nil, protocol.ErrBadRequest.WithDetails("ID mismatch for User and Session") } // Step 1. If the allowCredentials option was given when this authentication ceremony was initiated, // verify that credential.id identifies one of the public key credentials that were listed in // allowCredentials. // NON-NORMATIVE Prior Step: Verify that the allowCredentials for the sesssion are owned by the user provided userCredentials := user.WebAuthnCredentials() var credentialFound bool if len(session.AllowedCredentialIDs) > 0 { var credentialsOwned bool for _, userCredential := range userCredentials { for _, allowedCredentialID := range session.AllowedCredentialIDs { if bytes.Equal(userCredential.ID, allowedCredentialID) { credentialsOwned = true break } credentialsOwned = false } } if !credentialsOwned { return nil, protocol.ErrBadRequest.WithDetails("User does not own all credentials from the allowedCredentialList") } for _, allowedCredentialID := range session.AllowedCredentialIDs { if bytes.Equal(parsedResponse.RawID, allowedCredentialID) { credentialFound = true break } } if !credentialFound { return nil, protocol.ErrBadRequest.WithDetails("User does not own the credential returned") } } // Step 2. If credential.response.userHandle is present, verify that the user identified by this value is // the owner of the public key credential identified by credential.id. // This is in part handled by our Step 1 userHandle := parsedResponse.Response.UserHandle if userHandle != nil && len(userHandle) > 0 { if !bytes.Equal(userHandle, user.WebAuthnID()) { return nil, protocol.ErrBadRequest.WithDetails("userHandle and User ID do not match") } } // Step 3. Using credential’s id attribute (or the corresponding rawId, if base64url encoding is inappropriate // for your use case), look up the corresponding credential public key. var loginCredential Credential for _, cred := range userCredentials { if bytes.Equal(cred.ID, parsedResponse.RawID) { loginCredential = cred credentialFound = true break } credentialFound = false } if !credentialFound { return nil, protocol.ErrBadRequest.WithDetails("Unable to find the credential for the returned credential ID") } shouldVerifyUser := session.UserVerification == protocol.VerificationRequired rpID := webauthn.Config.RPID rpOrigin := webauthn.Config.RPOrigin // Handle steps 4 through 16 validError := parsedResponse.Verify(session.Challenge, rpID, rpOrigin, shouldVerifyUser, loginCredential.PublicKey) if validError != nil { return nil, validError } // Handle step 17 loginCredential.Authenticator.UpdateCounter(parsedResponse.Response.AuthenticatorData.Counter) return &loginCredential, nil } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/webauthn/login_test.go000066400000000000000000000010011414201525100265310ustar00rootroot00000000000000package webauthn import ( "testing" "github.com/duo-labs/webauthn/protocol" ) func TestLogin_FinishLoginFailure(t *testing.T) { user := &defaultUser{ id: []byte("123"), } session := SessionData{ UserID: []byte("ABC"), } webauthn := &WebAuthn{} credential, err := webauthn.FinishLogin(user, session, nil) if err == nil { t.Errorf("FinishLogin() error = nil, want %v", protocol.ErrBadRequest.Type) } if credential != nil { t.Errorf("FinishLogin() credential = %v, want nil", credential) } } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/webauthn/main.go000066400000000000000000000027771414201525100253330ustar00rootroot00000000000000package webauthn import ( "fmt" "net/url" "github.com/duo-labs/webauthn/protocol" ) var defaultTimeout = 60000 // WebAuthn is the primary interface of this package and contains the request handlers that should be called. type WebAuthn struct { Config *Config } // The config values required for proper type Config struct { RPDisplayName string RPID string RPOrigin string RPIcon string // Defaults for generating options AttestationPreference protocol.ConveyancePreference AuthenticatorSelection protocol.AuthenticatorSelection Timeout int Debug bool } // Validate that the config flags in Config are properly set func (config *Config) validate() error { if len(config.RPDisplayName) == 0 { return fmt.Errorf("Missing RPDisplayName") } if len(config.RPID) == 0 { return fmt.Errorf("Missing RPID") } _, err := url.Parse(config.RPID) if err != nil { return fmt.Errorf("RPID not valid URI: %+v", err) } if config.Timeout == 0 { config.Timeout = defaultTimeout } if config.RPOrigin == "" { config.RPOrigin = config.RPID } else { u, err := url.Parse(config.RPOrigin) if err != nil { return fmt.Errorf("RPOrigin not valid URL: %+v", err) } config.RPOrigin = protocol.FullyQualifiedOrigin(u) } return nil } // Create a new WebAuthn object given the proper config flags func New(config *Config) (*WebAuthn, error) { if err := config.validate(); err != nil { return nil, fmt.Errorf("Configuration error: %+v", err) } return &WebAuthn{ config, }, nil } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/webauthn/registration.go000066400000000000000000000132301414201525100271030ustar00rootroot00000000000000package webauthn import ( "bytes" "encoding/base64" "net/http" "github.com/duo-labs/webauthn/protocol" "github.com/duo-labs/webauthn/protocol/webauthncose" ) // BEGIN REGISTRATION // These objects help us creat the CredentialCreationOptions // that will be passed to the authenticator via the user client type RegistrationOption func(*protocol.PublicKeyCredentialCreationOptions) // Generate a new set of registration data to be sent to the client and authenticator. func (webauthn *WebAuthn) BeginRegistration(user User, opts ...RegistrationOption) (*protocol.CredentialCreation, *SessionData, error) { challenge, err := protocol.CreateChallenge() if err != nil { return nil, nil, err } webAuthnUser := protocol.UserEntity{ ID: user.WebAuthnID(), DisplayName: user.WebAuthnDisplayName(), CredentialEntity: protocol.CredentialEntity{ Name: user.WebAuthnName(), Icon: user.WebAuthnIcon(), }, } relyingParty := protocol.RelyingPartyEntity{ ID: webauthn.Config.RPID, CredentialEntity: protocol.CredentialEntity{ Name: webauthn.Config.RPDisplayName, Icon: webauthn.Config.RPIcon, }, } credentialParams := defaultRegistrationCredentialParameters() rrk := false authSelection := protocol.AuthenticatorSelection{ RequireResidentKey: &rrk, UserVerification: protocol.VerificationPreferred, } creationOptions := protocol.PublicKeyCredentialCreationOptions{ Challenge: challenge, RelyingParty: relyingParty, User: webAuthnUser, Parameters: credentialParams, AuthenticatorSelection: authSelection, Timeout: webauthn.Config.Timeout, Attestation: webauthn.Config.AttestationPreference, } for _, setter := range opts { setter(&creationOptions) } response := protocol.CredentialCreation{Response: creationOptions} newSessionData := SessionData{ Challenge: base64.RawURLEncoding.EncodeToString(challenge), UserID: user.WebAuthnID(), } if err != nil { return nil, nil, protocol.ErrParsingData.WithDetails("Error packing session data") } return &response, &newSessionData, nil } // Provide non-default parameters regarding the authenticator to select. func WithAuthenticatorSelection(authenticatorSelection protocol.AuthenticatorSelection) RegistrationOption { return func(cco *protocol.PublicKeyCredentialCreationOptions) { cco.AuthenticatorSelection = authenticatorSelection } } // Provide non-default parameters regarding credentials to exclude from retrieval. func WithExclusions(excludeList []protocol.CredentialDescriptor) RegistrationOption { return func(cco *protocol.PublicKeyCredentialCreationOptions) { cco.CredentialExcludeList = excludeList } } // Provide non-default parameters regarding whether the authenticator should attest to the credential. func WithConveyancePreference(preference protocol.ConveyancePreference) RegistrationOption { return func(cco *protocol.PublicKeyCredentialCreationOptions) { cco.Attestation = preference } } // Provide extension parameter to registration options func WithExtensions(extension protocol.AuthenticationExtensions) RegistrationOption { return func(cco *protocol.PublicKeyCredentialCreationOptions) { cco.Extensions = extension } } // Take the response from the authenticator and client and verify the credential against the user's credentials and // session data. func (webauthn *WebAuthn) FinishRegistration(user User, session SessionData, response *http.Request) (*Credential, error) { parsedResponse, err := protocol.ParseCredentialCreationResponse(response) if err != nil { return nil, err } return webauthn.CreateCredential(user, session, parsedResponse) } // CreateCredential verifies a parsed response against the user's credentials and session data. func (webauthn *WebAuthn) CreateCredential(user User, session SessionData, parsedResponse *protocol.ParsedCredentialCreationData) (*Credential, error) { if !bytes.Equal(user.WebAuthnID(), session.UserID) { return nil, protocol.ErrBadRequest.WithDetails("ID mismatch for User and Session") } shouldVerifyUser := webauthn.Config.AuthenticatorSelection.UserVerification == protocol.VerificationRequired invalidErr := parsedResponse.Verify(session.Challenge, shouldVerifyUser, webauthn.Config.RPID, webauthn.Config.RPOrigin) if invalidErr != nil { return nil, invalidErr } return MakeNewCredential(parsedResponse) } func defaultRegistrationCredentialParameters() []protocol.CredentialParameter { return []protocol.CredentialParameter{ protocol.CredentialParameter{ Type: protocol.PublicKeyCredentialType, Algorithm: webauthncose.AlgES256, }, protocol.CredentialParameter{ Type: protocol.PublicKeyCredentialType, Algorithm: webauthncose.AlgES384, }, protocol.CredentialParameter{ Type: protocol.PublicKeyCredentialType, Algorithm: webauthncose.AlgES512, }, protocol.CredentialParameter{ Type: protocol.PublicKeyCredentialType, Algorithm: webauthncose.AlgRS256, }, protocol.CredentialParameter{ Type: protocol.PublicKeyCredentialType, Algorithm: webauthncose.AlgRS384, }, protocol.CredentialParameter{ Type: protocol.PublicKeyCredentialType, Algorithm: webauthncose.AlgRS512, }, protocol.CredentialParameter{ Type: protocol.PublicKeyCredentialType, Algorithm: webauthncose.AlgPS256, }, protocol.CredentialParameter{ Type: protocol.PublicKeyCredentialType, Algorithm: webauthncose.AlgPS384, }, protocol.CredentialParameter{ Type: protocol.PublicKeyCredentialType, Algorithm: webauthncose.AlgPS512, }, protocol.CredentialParameter{ Type: protocol.PublicKeyCredentialType, Algorithm: webauthncose.AlgEdDSA, }, } } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/webauthn/registration_test.go000066400000000000000000000010451414201525100301430ustar00rootroot00000000000000package webauthn import ( "testing" "github.com/duo-labs/webauthn/protocol" ) func TestRegistration_FinishRegistrationFailure(t *testing.T) { user := &defaultUser{ id: []byte("123"), } session := SessionData{ UserID: []byte("ABC"), } webauthn := &WebAuthn{} credential, err := webauthn.FinishRegistration(user, session, nil) if err == nil { t.Errorf("FinishRegistration() error = nil, want %v", protocol.ErrBadRequest.Type) } if credential != nil { t.Errorf("FinishRegistration() credential = %v, want nil", credential) } } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/webauthn/session.go000066400000000000000000000010541414201525100260550ustar00rootroot00000000000000package webauthn import "github.com/duo-labs/webauthn/protocol" // SessionData is the data that should be stored by the Relying Party for // the duration of the web authentication ceremony type SessionData struct { Challenge string `json:"challenge"` UserID []byte `json:"user_id"` AllowedCredentialIDs [][]byte `json:"allowed_credentials,omitempty"` UserVerification protocol.UserVerificationRequirement `json:"userVerification"` } golang-github-duo-labs-webauthn-0.0~git20210727.9f1b88e/webauthn/user.go000066400000000000000000000016521414201525100253540ustar00rootroot00000000000000package webauthn // User is built to interface with the Relying Party's User entry and // elaborate the fields and methods needed for WebAuthn type User interface { // User ID according to the Relying Party WebAuthnID() []byte // User Name according to the Relying Party WebAuthnName() string // Display Name of the user WebAuthnDisplayName() string // User's icon url WebAuthnIcon() string // Credentials owned by the user WebAuthnCredentials() []Credential } type defaultUser struct { id []byte } var _ User = (*defaultUser)(nil) func (user *defaultUser) WebAuthnID() []byte { return user.id } func (user *defaultUser) WebAuthnName() string { return "newUser" } func (user *defaultUser) WebAuthnDisplayName() string { return "New User" } func (user *defaultUser) WebAuthnIcon() string { return "https://pics.com/avatar.png" } func (user *defaultUser) WebAuthnCredentials() []Credential { return []Credential{} }