pax_global_header00006660000000000000000000000064145232055360014517gustar00rootroot0000000000000052 comment=a3545dfc9422d450aff99000607f8e1fc561bbd7 go-attestation-0.5.1/000077500000000000000000000000001452320553600144645ustar00rootroot00000000000000go-attestation-0.5.1/.github/000077500000000000000000000000001452320553600160245ustar00rootroot00000000000000go-attestation-0.5.1/.github/dependabot.yml000066400000000000000000000001551452320553600206550ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: "gomod" directory: "/" schedule: interval: "weekly" go-attestation-0.5.1/.github/workflows/000077500000000000000000000000001452320553600200615ustar00rootroot00000000000000go-attestation-0.5.1/.github/workflows/codeql-analysis.yml000066400000000000000000000013431452320553600236750ustar00rootroot00000000000000name: "CodeQL" on: push: branches: [master] pull_request: branches: [master] schedule: - cron: '0 14 * * 3' jobs: analyze: name: Analyze runs-on: ubuntu-latest strategy: fail-fast: false matrix: language: ['go'] steps: - name: Checkout repository uses: actions/checkout@v2 with: fetch-depth: 2 - run: git checkout HEAD^2 if: ${{ github.event_name == 'pull_request' }} - name: Initialize CodeQL uses: github/codeql-action/init@v1 with: languages: ${{ matrix.language }} - name: Autobuild uses: github/codeql-action/autobuild@v1 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 go-attestation-0.5.1/.github/workflows/golangci-lint.yml000066400000000000000000000005601452320553600233340ustar00rootroot00000000000000name: golangci-lint on: pull_request: permissions: contents: read jobs: golangci: name: lint runs-on: ubuntu-latest steps: - uses: actions/setup-go@v3 with: go-version: 1.20.x - uses: actions/checkout@v3 - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: version: v1.53.3 go-attestation-0.5.1/.github/workflows/test.yml000066400000000000000000000034021452320553600215620ustar00rootroot00000000000000on: push: branches: [master] pull_request: # Workaround for SHA1 on Go 1.18. There are some kinks to be worked out. See # the tracking issue for more info: https://github.com/golang/go/issues/41682 env: GODEBUG: x509sha1=1 name: Test jobs: test-linux: strategy: matrix: go-version: [1.20.x] runs-on: ubuntu-latest steps: - name: Install Go uses: actions/setup-go@v2 with: go-version: ${{ matrix.go-version }} - name: Checkout code uses: actions/checkout@v2 - name: Test run: go test ./... test-linux-tpm12: strategy: matrix: go-version: [1.20.x] runs-on: ubuntu-latest steps: - name: Install Go uses: actions/setup-go@v2 with: go-version: ${{ matrix.go-version }} - name: Checkout code uses: actions/checkout@v2 - name: Install libtspi run: sudo apt-get install -y libtspi-dev - name: Test run: go test -tags tspi ./... test-macos: strategy: matrix: go-version: [1.20.x] runs-on: macos-latest steps: - name: Install Go uses: actions/setup-go@v2 with: go-version: ${{ matrix.go-version }} - name: Checkout code uses: actions/checkout@v2 # See https://github.com/google/go-tpm-tools#macos-dev - name: Test run: C_INCLUDE_PATH="$(brew --prefix openssl@1.1)/include" LIBRARY_PATH="$(brew --prefix openssl@1.1)/lib" go test ./... test-windows: strategy: matrix: go-version: [1.20.x] runs-on: windows-latest steps: - name: Install Go uses: actions/setup-go@v2 with: go-version: ${{ matrix.go-version }} - name: Checkout code uses: actions/checkout@v2 - name: Test run: go build ./... go-attestation-0.5.1/.golangci.yaml000066400000000000000000000000711452320553600172070ustar00rootroot00000000000000linters: enable: - gofmt disable: - errcheck go-attestation-0.5.1/CONTRIBUTING.md000066400000000000000000000021151452320553600167140ustar00rootroot00000000000000# How to Contribute We'd love to accept your patches and contributions to this project. There are just a few small guidelines you need to follow. ## Contributor License Agreement Contributions to this project must be accompanied by a Contributor License Agreement. You (or your employer) retain the copyright to your contribution; this simply gives us permission to use and redistribute your contributions as part of the project. Head over to to see your current agreements on file or to sign a new one. You generally only need to submit a CLA once, so if you've already submitted one (even if it was for a different project), you probably don't need to do it again. ## Code reviews All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more information on using pull requests. ## Community Guidelines This project follows [Google's Open Source Community Guidelines](https://opensource.google.com/conduct/). go-attestation-0.5.1/LICENSE000066400000000000000000000261361452320553600155010ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. go-attestation-0.5.1/README.md000066400000000000000000000106351452320553600157500ustar00rootroot00000000000000Go-Attestation ============== [![GoDoc](https://godoc.org/github.com/google/go-attestation/attest?status.svg)](https://godoc.org/github.com/google/go-attestation/attest) Go-Attestation abstracts remote attestation operations across a variety of platforms and TPMs, enabling remote validation of machine identity and state. This project attempts to provide high level primitives for both client and server logic. Talks on this project: * _"Making Device Identity Trustworthy"_ - Open Source Summit Europe - October 2019 - ([Slides](https://static.sched.com/hosted_files/osseu19/ec/Device%20Identity.pdf)) * _"Using TPMs to Cryptographically Verify Devices at Scale"_ - Open Source Summit North America - September 2019 - ([Video](https://www.youtube.com/watch?v=EmEymlA5Q5Q) 39min) * _"Making Remote Attestation Useful on Linux"_ - Linux Security Summit - September 2019 - ([Video](https://www.youtube.com/watch?v=TKva_h66Ptc) 26min) ## Status Go-Attestation is under active development. Expect API changes at any time. Please note that this is not an official Google product. TPM 1.2 support is best effort, meaning we will accept fixes for TPM 1.2, but testing is not covered by CI. ## Installation The go-attestation package is installable using go get: `go get github.com/google/go-attestation/attest` ### TPM1.2 By default, go-attestation does not build in TPM1.2 support on Linux. Linux users must install [`libtspi`](http://trousers.sourceforge.net/) and its headers if they need TPM 1.2 support. This can be installed on debian-based systems using: `sudo apt-get install libtspi-dev`. Then, build go-attestation with the `tspi` [build tag](https://pkg.go.dev/go/build#hdr-Build_Constraints) `go build --tags=tspi`. Windows users can use go-attestation with TPM1.2 by default. ## Example: device identity TPMs can be used to identify a device remotely and provision unique per-device hardware-bound keys. TPMs are provisioned with a set of Endorsement Keys (EKs) by the manufacturer. These optionally include a certificate signed by the manufacturer and act as a TPM's identity. For privacy reasons the EK can't be used to sign or encrypt data directly, and is instead used to attest to the presence of a signing key, an Attestation Key (AK), on the same TPM. (Newer versions of the spec may allow the EK to sign directly.) During attestation, a TPM generates an AK and proves to a certificate authority that the AK is on the same TPM as a EK. If the certificate authority trusts the EK, it can transitively trust the AK, for example by issuing a certificate for the AK. To perform attestation, the client generates an AK and sends the EK and AK parameters to the server: ```go // Client generates an AK and sends it to the server config := &attest.OpenConfig{} tpm, err := attest.OpenTPM(config) if err != nil { // handle error } eks, err := tpm.EKs() if err != nil { // handle error } ek := eks[0] akConfig := &attest.AKConfig{} ak, err := tpm.NewAK(akConfig) if err != nil { // handle error } attestParams := ak.AttestationParameters() akBytes, err := ak.Marshal() if err != nil { // handle error } if err := os.WriteFile("encrypted_aik.json", akBytes, 0600); err != nil { // handle error } // send TPM version, EK, and attestParams to the server ``` The server uses the EK and AK parameters to generate a challenge encrypted to the EK, returning the challenge to the client. During this phase, the server determines if it trusts the EK, either by chaining its certificate to a known manufacturer and/or querying an inventory system. ```go // Server validates EK and/or EK certificate params := attest.ActivationParameters{ TPMVersion: tpmVersion, EK: ek.Public, AK: attestParams, } secret, encryptedCredentials, err := params.Generate() if err != nil { // handle error } // return encrypted credentials to client ``` The client proves possession of the AK by decrypting the challenge and returning the same secret to the server. ```go // Client decrypts the credential akBytes, err := os.ReadFile("encrypted_aik.json") if err != nil { // handle error } ak, err := tpm.LoadAK(akBytes) if err != nil { // handle error } secret, err := ak.ActivateCredential(tpm, encryptedCredentials) if err != nil { // handle error } // return secret to server ``` At this point, the server records the AK and EK association and allows the client to use its AK as a credential (e.g. by issuing it a client certificate). go-attestation-0.5.1/attest/000077500000000000000000000000001452320553600157705ustar00rootroot00000000000000go-attestation-0.5.1/attest/activation.go000066400000000000000000000212651452320553600204660ustar00rootroot00000000000000package attest import ( "bytes" "crypto" "crypto/rand" "crypto/rsa" "errors" "fmt" "io" "github.com/google/go-tpm/legacy/tpm2" tpm1 "github.com/google/go-tpm/tpm" // TODO(jsonp): Move activation generation code to internal package. "github.com/google/go-tpm/legacy/tpm2/credactivation" "github.com/google/go-tspi/verification" ) const ( // minRSABits is the minimum accepted bit size of an RSA key. minRSABits = 2048 // activationSecretLen is the size in bytes of the generated secret // which is generated for credential activation. activationSecretLen = 32 // symBlockSize is the block size used for symmetric ciphers used // when generating the credential activation challenge. symBlockSize = 16 // tpm20GeneratedMagic is a magic tag when can only be present on a // TPM structure if the structure was generated wholly by the TPM. tpm20GeneratedMagic = 0xff544347 ) // ActivationParameters encapsulates the inputs for activating an AK. type ActivationParameters struct { // TPMVersion holds the version of the TPM, either 1.2 or 2.0. TPMVersion TPMVersion // EK, the endorsement key, describes an asymmetric key whose // private key is permanently bound to the TPM. // // Activation will verify that the provided EK is held on the same // TPM as the AK. However, it is the caller's responsibility to // ensure the EK they provide corresponds to the the device which // they are trying to associate the AK with. EK crypto.PublicKey // AK, the Attestation Key, describes the properties of // an asymmetric key (managed by the TPM) which signs attestation // structures. // The values from this structure can be obtained by calling // Parameters() on an attest.AK. AK AttestationParameters // Rand is a source of randomness to generate a seed and secret for the // challenge. // // If nil, this defaults to crypto.Rand. Rand io.Reader } // checkAKParameters examines properties of an AK and a creation // attestation, to determine if it is suitable for use as an attestation key. func (p *ActivationParameters) checkAKParameters() error { switch p.TPMVersion { case TPMVersion12: return p.checkTPM12AKParameters() case TPMVersion20: return p.checkTPM20AKParameters() default: return fmt.Errorf("TPM version %d not supported", p.TPMVersion) } } func (p *ActivationParameters) checkTPM12AKParameters() error { // TODO(jsonp): Implement helper to parse public blobs, ie: // func ParsePublic(publicBlob []byte) (crypto.Public, error) pub, err := tpm1.UnmarshalPubRSAPublicKey(p.AK.Public) if err != nil { return fmt.Errorf("unmarshalling public key: %v", err) } if bits := pub.Size() * 8; bits < minRSABits { return fmt.Errorf("attestation key too small: must be at least %d bits but was %d bits", minRSABits, bits) } return nil } func (p *ActivationParameters) checkTPM20AKParameters() error { if len(p.AK.CreateSignature) < 8 { return fmt.Errorf("signature is too short to be valid: only %d bytes", len(p.AK.CreateSignature)) } pub, err := tpm2.DecodePublic(p.AK.Public) if err != nil { return fmt.Errorf("DecodePublic() failed: %v", err) } _, err = tpm2.DecodeCreationData(p.AK.CreateData) if err != nil { return fmt.Errorf("DecodeCreationData() failed: %v", err) } att, err := tpm2.DecodeAttestationData(p.AK.CreateAttestation) if err != nil { return fmt.Errorf("DecodeAttestationData() failed: %v", err) } if att.Type != tpm2.TagAttestCreation { return fmt.Errorf("attestation does not apply to creation data, got tag %x", att.Type) } // TODO: Support ECC AKs. switch pub.Type { case tpm2.AlgRSA: if pub.RSAParameters.KeyBits < minRSABits { return fmt.Errorf("attestation key too small: must be at least %d bits but was %d bits", minRSABits, pub.RSAParameters.KeyBits) } default: return fmt.Errorf("public key of alg 0x%x not supported", pub.Type) } // Compute & verify that the creation data matches the digest in the // attestation structure. nameHash, err := pub.NameAlg.Hash() if err != nil { return fmt.Errorf("HashConstructor() failed: %v", err) } h := nameHash.New() h.Write(p.AK.CreateData) if !bytes.Equal(att.AttestedCreationInfo.OpaqueDigest, h.Sum(nil)) { return errors.New("attestation refers to different public key") } // Make sure the AK has sane key parameters (Attestation can be faked if an AK // can be used for arbitrary signatures). // We verify the following: // - Key is TPM backed. // - Key is TPM generated. // - Key is a restricted key (means it cannot do arbitrary signing/decrypt ops). // - Key cannot be duplicated. // - Key was generated by a call to TPM_Create*. if att.Magic != tpm20GeneratedMagic { return errors.New("creation attestation was not produced by a TPM") } if (pub.Attributes & tpm2.FlagFixedTPM) == 0 { return errors.New("AK is exportable") } if ((pub.Attributes & tpm2.FlagRestricted) == 0) || ((pub.Attributes & tpm2.FlagFixedParent) == 0) || ((pub.Attributes & tpm2.FlagSensitiveDataOrigin) == 0) { return errors.New("provided key is not limited to attestation") } // Verify the attested creation name matches what is computed from // the public key. match, err := att.AttestedCreationInfo.Name.MatchesPublic(pub) if err != nil { return err } if !match { return errors.New("creation attestation refers to a different key") } // Check the signature over the attestation data verifies correctly. pk := rsa.PublicKey{E: int(pub.RSAParameters.Exponent()), N: pub.RSAParameters.Modulus()} signHash, err := pub.RSAParameters.Sign.Hash.Hash() if err != nil { return err } hsh := signHash.New() hsh.Write(p.AK.CreateAttestation) verifyHash, err := pub.RSAParameters.Sign.Hash.Hash() if err != nil { return err } if len(p.AK.CreateSignature) < 8 { return fmt.Errorf("signature invalid: length of %d is shorter than 8", len(p.AK.CreateSignature)) } sig, err := tpm2.DecodeSignature(bytes.NewBuffer(p.AK.CreateSignature)) if err != nil { return fmt.Errorf("DecodeSignature() failed: %v", err) } if err := rsa.VerifyPKCS1v15(&pk, verifyHash, hsh.Sum(nil), sig.RSA.Signature); err != nil { return fmt.Errorf("could not verify attestation: %v", err) } return nil } // Generate returns a credential activation challenge, which can be provided // to the TPM to verify the AK parameters given are authentic & the AK // is present on the same TPM as the EK. // // The caller is expected to verify the secret returned from the TPM as // as result of calling ActivateCredential() matches the secret returned here. // The caller should use subtle.ConstantTimeCompare to avoid potential // timing attack vectors. func (p *ActivationParameters) Generate() (secret []byte, ec *EncryptedCredential, err error) { if err := p.checkAKParameters(); err != nil { return nil, nil, err } if p.EK == nil { return nil, nil, errors.New("no EK provided") } rnd, secret := p.Rand, make([]byte, activationSecretLen) if rnd == nil { rnd = rand.Reader } if _, err = io.ReadFull(rnd, secret); err != nil { return nil, nil, fmt.Errorf("error generating activation secret: %v", err) } switch p.TPMVersion { case TPMVersion12: ec, err = p.generateChallengeTPM12(rnd, secret) case TPMVersion20: ec, err = p.generateChallengeTPM20(secret) default: return nil, nil, fmt.Errorf("unrecognised TPM version: %v", p.TPMVersion) } if err != nil { return nil, nil, err } return secret, ec, nil } func (p *ActivationParameters) generateChallengeTPM20(secret []byte) (*EncryptedCredential, error) { att, err := tpm2.DecodeAttestationData(p.AK.CreateAttestation) if err != nil { return nil, fmt.Errorf("DecodeAttestationData() failed: %v", err) } if att.AttestedCreationInfo == nil { return nil, fmt.Errorf("attestation was not for a creation event") } if att.AttestedCreationInfo.Name.Digest == nil { return nil, fmt.Errorf("attestation creation info name has no digest") } cred, encSecret, err := credactivation.Generate(att.AttestedCreationInfo.Name.Digest, p.EK, symBlockSize, secret) if err != nil { return nil, fmt.Errorf("credactivation.Generate() failed: %v", err) } return &EncryptedCredential{ Credential: cred, Secret: encSecret, }, nil } func (p *ActivationParameters) generateChallengeTPM12(rand io.Reader, secret []byte) (*EncryptedCredential, error) { pk, ok := p.EK.(*rsa.PublicKey) if !ok { return nil, fmt.Errorf("got EK of type %T, want an RSA key", p.EK) } var ( cred, encSecret []byte err error ) if p.AK.UseTCSDActivationFormat { cred, encSecret, err = verification.GenerateChallengeEx(pk, p.AK.Public, secret) } else { cred, encSecret, err = generateChallenge12(rand, pk, p.AK.Public, secret) } if err != nil { return nil, fmt.Errorf("challenge generation failed: %v", err) } return &EncryptedCredential{ Credential: cred, Secret: encSecret, }, nil } go-attestation-0.5.1/attest/activation_test.go000066400000000000000000000105401452320553600215170ustar00rootroot00000000000000package attest import ( "bytes" "crypto/rsa" "encoding/base64" "math/big" "math/rand" "testing" ) func decodeBase10(base10 string, t *testing.T) *big.Int { i, ok := new(big.Int).SetString(base10, 10) if !ok { t.Fatalf("failed decode of base10: %q", base10) } return i } func decodeBase64(in string, t *testing.T) []byte { out, err := base64.StdEncoding.DecodeString(in) if err != nil { t.Fatal(err) } return out } func ekCertSigner(t *testing.T) *rsa.PrivateKey { return &rsa.PrivateKey{ PublicKey: rsa.PublicKey{ N: decodeBase10("14314132931241006650998084889274020608918049032671858325988396851334124245188214251956198731333464217832226406088020736932173064754214329009979944037640912127943488972644697423190955557435910767690712778463524983667852819010259499695177313115447116110358524558307947613422897787329221478860907963827160223559690523660574329011927531289655711860504630573766609239332569210831325633840174683944553667352219670930408593321661375473885147973879086994006440025257225431977751512374815915392249179976902953721486040787792801849818254465486633791826766873076617116727073077821584676715609985777563958286637185868165868520557", t), E: 3, }, D: decodeBase10("9542755287494004433998723259516013739278699355114572217325597900889416163458809501304132487555642811888150937392013824621448709836142886006653296025093941418628992648429798282127303704957273845127141852309016655778568546006839666463451542076964744073572349705538631742281931858219480985907271975884773482372966847639853897890615456605598071088189838676728836833012254065983259638538107719766738032720239892094196108713378822882383694456030043492571063441943847195939549773271694647657549658603365629458610273821292232646334717612674519997533901052790334279661754176490593041941863932308687197618671528035670452762731", t), Primes: []*big.Int{ decodeBase10("130903255182996722426771613606077755295583329135067340152947172868415809027537376306193179624298874215608270802054347609836776473930072411958753044562214537013874103802006369634761074377213995983876788718033850153719421695468704276694983032644416930879093914927146648402139231293035971427838068945045019075433", t), decodeBase10("109348945610485453577574767652527472924289229538286649661240938988020367005475727988253438647560958573506159449538793540472829815903949343191091817779240101054552748665267574271163617694640513549693841337820602726596756351006149518830932261246698766355347898158548465400674856021497190430791824869615170301029", t), }, } } func TestActivationTPM20(t *testing.T) { priv := ekCertSigner(t) rand := rand.New(rand.NewSource(123456)) // These parameters represent an AK generated on a real-world, infineon TPM. params := ActivationParameters{ TPMVersion: TPMVersion20, AK: AttestationParameters{ Public: decodeBase64("AAEACwAFBHIAIJ3/y/NsODrmmfuYaNxty4nXFTiEvigDkiwSQVi/rSKuABAAFAAECAAAAAAAAQC/08gj/04z4xGMIVTmr02lzhI5epufXgU831xEpf2qpXfvtNGUfqTcgWF2EUux2HDPqgcj59dtXRobQdlr4uCGNzfZIGAej4JusLa4MjpG6W2DtJPot6F1Mry63talzJ36U47niy9Iesd34CO2p9Xk3+86ZmBnQ6PQ2roUNK3l7bKz6cFLM9drOLwCqU0AUl6pHvzYPPz+xXsPl3iaA2cM97oneUiJNmJM7wtR9OcaKyIA4wVlX5TndB9NwWq5Iuj8q2Sp40Dg0noXXGSPliAtVD8flkXtAcuI9UHkQbzu9cGPRdSJPMn743GONg3bYalFtcgh2VpACXkPbXB32J7B", t), CreateData: decodeBase64("AAAAAAAg47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFUBAAsAIgALWI9hwDRB3zYSkannqM5z0J1coQNA1Jz/oCRxJQwTaNwAIgALmyFYBhHeIU3FUKIAPgXFD3NXyasP3siQviDEyH7avu4AAA==", t), CreateAttestation: decodeBase64("/1RDR4AaACIAC41+jhmEOue1MZhJjIk79ENar6i15rBvamXLpQnGTBCOAAAAAAAAD3GRNfU4syzJ1jQGATDCDteFC5C4ACIAC3ToMYGy9GXxcf8A0HvOuLOHbU7HPEppM47C7CMcU8TtACBDmJFUFO1f5+BYevaYdd3VtfMCsxIuHhoTZJczzLP2BA==", t), CreateSignature: decodeBase64("ABQABAEALVzJSnKRJU39gHjETaI89/sM1L6HwBPGNekw6NojSW8bwD5/W1cLRDakCsYKUQu68mmbjs8xaIVBRvVM2YWP10tbTWNB0iJc9b8rERhkk3QIIFm/XsiVZsb0mysTxfeh8zygaAKQ/50sYyzp+raD0Ho0mYIRKJOEdQ6chsBflM3eB8mCXGTugUfrET80q3iu0gncaKWbfxQaQUb9ZTPSJrTN64HQ9tlOfnGT+8++WA3hV0NqKMnoAqiI9GZnI5MPXs6XxEncu/GJLJpAYZakBiS74Jvlr34Pur32B4xjm1M25AUGHEIgb6r49S0sV+hzaKu45858lQRMXj01GcyBhw==", t), }, EK: &rsa.PublicKey{ E: priv.E, N: priv.N, }, Rand: rand, } secret, _, err := params.Generate() if err != nil { t.Fatalf("Generate() returned err: %v", err) } if got, want := secret, decodeBase64("0vhS7HtORX9uf/iyQ8Sf9WkpJuoJ1olCfTjSZuyNNxY=", t); !bytes.Equal(got, want) { t.Fatalf("secret = %v, want %v", got, want) } } go-attestation-0.5.1/attest/application_key.go000066400000000000000000000075411452320553600215010ustar00rootroot00000000000000// Copyright 2021 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package attest import ( "crypto" "crypto/ecdsa" "crypto/rsa" "fmt" "io" ) type key interface { close(tpmBase) error marshal() ([]byte, error) certificationParameters() CertificationParameters sign(tpmBase, []byte, crypto.PublicKey, crypto.SignerOpts) ([]byte, error) decrypt(tpmBase, []byte) ([]byte, error) blobs() ([]byte, []byte, error) } // Key represents a key which can be used for signing and decrypting // outside-TPM objects. type Key struct { key key pub crypto.PublicKey tpm tpmBase } // signer implements crypto.Signer returned by Key.Private(). type signer struct { key key pub crypto.PublicKey tpm tpmBase } // Sign signs digest with the TPM-stored private signing key. func (s *signer) Sign(r io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { return s.key.sign(s.tpm, digest, s.pub, opts) } // Public returns the public key corresponding to the private signing key. func (s *signer) Public() crypto.PublicKey { return s.pub } // Algorithm indicates an asymmetric algorithm to be used. type Algorithm string // Algorithm types supported. const ( ECDSA Algorithm = "ECDSA" RSA Algorithm = "RSA" ) // KeyConfig encapsulates parameters for minting keys. type KeyConfig struct { // Algorithm to be used, either RSA or ECDSA. Algorithm Algorithm // Size is used to specify the bit size of the key or elliptic curve. For // example, '256' is used to specify curve P-256. Size int // Parent describes the Storage Root Key that will be used as a parent. // If nil, the default SRK (i.e. RSA with handle 0x81000001) is assumed. // Supported only by TPM 2.0 on Linux. Parent *ParentKeyConfig } // defaultConfig is used when no other configuration is specified. var defaultConfig = &KeyConfig{ Algorithm: ECDSA, Size: 256, } // Public returns the public key corresponding to the private key. func (k *Key) Public() crypto.PublicKey { return k.pub } // Private returns an object allowing to use the TPM-backed private key. // For now it implements only crypto.Signer. func (k *Key) Private(pub crypto.PublicKey) (crypto.PrivateKey, error) { switch pub.(type) { case *rsa.PublicKey: if _, ok := k.pub.(*rsa.PublicKey); !ok { return nil, fmt.Errorf("incompatible public key types: %T != %T", pub, k.pub) } case *ecdsa.PublicKey: if _, ok := k.pub.(*ecdsa.PublicKey); !ok { return nil, fmt.Errorf("incompatible public key types: %T != %T", pub, k.pub) } default: return nil, fmt.Errorf("unsupported public key type: %T", pub) } return &signer{k.key, k.pub, k.tpm}, nil } // Close unloads the key from the system. func (k *Key) Close() error { return k.key.close(k.tpm) } // Marshal encodes the key in a format that can be loaded with tpm.LoadKey(). // This method exists to allow consumers to store the key persistently and load // it as a later time. Users SHOULD NOT attempt to interpret or extract values // from this blob. func (k *Key) Marshal() ([]byte, error) { return k.key.marshal() } // CertificationParameters returns information about the key required to // verify key certification. func (k *Key) CertificationParameters() CertificationParameters { return k.key.certificationParameters() } // Blobs returns public and private blobs to be used by tpm2.Load(). func (k *Key) Blobs() (pub, priv []byte, err error) { return k.key.blobs() } go-attestation-0.5.1/attest/application_key_test.go000066400000000000000000000266121452320553600225400ustar00rootroot00000000000000// Copyright 2021 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. //go:build (!localtest || !tpm12) && cgo && !gofuzz // +build !localtest !tpm12 // +build cgo // +build !gofuzz // NOTE: simulator requires cgo, hence the build tag. package attest import ( "bytes" "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/asn1" "math/big" "testing" ) func TestSimTPM20KeyCreateAndLoad(t *testing.T) { sim, tpm := setupSimulatedTPM(t) defer sim.Close() testKeyCreateAndLoad(t, tpm) } func TestTPM20KeyCreateAndLoad(t *testing.T) { if !*testLocal { t.SkipNow() } tpm, err := OpenTPM(nil) if err != nil { t.Fatalf("OpenTPM() failed: %v", err) } defer tpm.Close() testKeyCreateAndLoad(t, tpm) } func testKeyCreateAndLoad(t *testing.T, tpm *TPM) { ak, err := tpm.NewAK(nil) if err != nil { t.Fatalf("NewAK() failed: %v", err) } for _, test := range []struct { name string opts *KeyConfig }{ { name: "default", opts: nil, }, { name: "ECDSAP256-SHA256", opts: &KeyConfig{ Algorithm: ECDSA, Size: 256, }, }, { name: "ECDSAP384-SHA384", opts: &KeyConfig{ Algorithm: ECDSA, Size: 384, }, }, { name: "ECDSAP521-SHA512", opts: &KeyConfig{ Algorithm: ECDSA, Size: 521, }, }, { name: "RSA-1024", opts: &KeyConfig{ Algorithm: RSA, Size: 1024, }, }, { name: "RSA-2048", opts: &KeyConfig{ Algorithm: RSA, Size: 2048, }, }, } { t.Run(test.name, func(t *testing.T) { sk, err := tpm.NewKey(ak, test.opts) if err != nil { t.Fatalf("NewKey() failed: %v", err) } defer sk.Close() enc, err := sk.Marshal() if err != nil { t.Fatalf("sk.Marshal() failed: %v", err) } if err := sk.Close(); err != nil { t.Fatalf("sk.Close() failed: %v", err) } loaded, err := tpm.LoadKey(enc) if err != nil { t.Fatalf("LoadKey() failed: %v", err) } defer loaded.Close() k1, k2 := sk.key.(*wrappedKey20), loaded.key.(*wrappedKey20) if !bytes.Equal(k1.public, k2.public) { t.Error("Original & loaded Key public blobs did not match.") t.Logf("Original = %v", k1.public) t.Logf("Loaded = %v", k2.public) } priv1, err := sk.Private(sk.Public()) if err != nil { t.Fatalf("sk.Private() failed: %v", err) } signer1, ok := priv1.(crypto.Signer) if !ok { t.Fatalf("want crypto.Signer, got %T", priv1) } pk1, err := x509.MarshalPKIXPublicKey(signer1.Public()) if err != nil { t.Fatalf("cannot marshal public key: %v", err) } priv2, err := loaded.Private(loaded.Public()) if err != nil { t.Fatalf("loaded.Private() failed: %v", err) } signer2, ok := priv2.(crypto.Signer) if !ok { t.Fatalf("want crypto.Signer, got %T", priv2) } pk2, err := x509.MarshalPKIXPublicKey(signer2.Public()) if err != nil { t.Fatalf("cannot marshal public key: %v", err) } if !bytes.Equal(pk1, pk2) { t.Error("public keys do not match") } }) } } func TestSimTPM20KeySign(t *testing.T) { sim, tpm := setupSimulatedTPM(t) defer sim.Close() testKeySign(t, tpm) } func TestTPM20KeySign(t *testing.T) { if !*testLocal { t.SkipNow() } tpm, err := OpenTPM(nil) if err != nil { t.Fatalf("OpenTPM() failed: %v", err) } defer tpm.Close() testKeySign(t, tpm) } func testKeySign(t *testing.T, tpm *TPM) { ak, err := tpm.NewAK(nil) if err != nil { t.Fatalf("NewAK() failed: %v", err) } for _, test := range []struct { name string keyOpts *KeyConfig signOpts crypto.SignerOpts digest []byte }{ { name: "default", keyOpts: nil, signOpts: nil, digest: []byte("12345678901234567890123456789012"), }, { name: "ECDSAP256-SHA256", keyOpts: &KeyConfig{ Algorithm: ECDSA, Size: 256, }, signOpts: nil, digest: []byte("12345678901234567890123456789012"), }, { name: "ECDSAP384-SHA384", keyOpts: &KeyConfig{ Algorithm: ECDSA, Size: 384, }, signOpts: nil, digest: []byte("123456789012345678901234567890121234567890123456"), }, { name: "ECDSAP521-SHA512", keyOpts: &KeyConfig{ Algorithm: ECDSA, Size: 521, }, signOpts: nil, digest: []byte("1234567890123456789012345678901212345678901234567890123456789012"), }, { name: "RSA2048-PKCS1v15-SHA256", keyOpts: &KeyConfig{ Algorithm: RSA, Size: 2048, }, signOpts: crypto.SHA256, digest: []byte("12345678901234567890123456789012"), }, { name: "RSA2048-PKCS1v15-SHA384", keyOpts: &KeyConfig{ Algorithm: RSA, Size: 2048, }, signOpts: crypto.SHA384, digest: []byte("123456789012345678901234567890121234567890123456"), }, { name: "RSA2048-PKCS1v15-SHA512", keyOpts: &KeyConfig{ Algorithm: RSA, Size: 2048, }, signOpts: crypto.SHA512, digest: []byte("1234567890123456789012345678901212345678901234567890123456789012"), }, { name: "RSA2048-PSS-SHA256", keyOpts: &KeyConfig{ Algorithm: RSA, Size: 2048, }, signOpts: &rsa.PSSOptions{ SaltLength: rsa.PSSSaltLengthAuto, Hash: crypto.SHA256, }, digest: []byte("12345678901234567890123456789012"), }, { name: "RSA2048-PSS-SHA384", keyOpts: &KeyConfig{ Algorithm: RSA, Size: 2048, }, signOpts: &rsa.PSSOptions{ SaltLength: rsa.PSSSaltLengthAuto, Hash: crypto.SHA384, }, digest: []byte("123456789012345678901234567890121234567890123456"), }, { name: "RSA2048-PSS-SHA512", keyOpts: &KeyConfig{ Algorithm: RSA, Size: 2048, }, signOpts: &rsa.PSSOptions{ SaltLength: rsa.PSSSaltLengthAuto, Hash: crypto.SHA512, }, digest: []byte("1234567890123456789012345678901212345678901234567890123456789012"), }, { name: "RSA2048-PSS-SHA256, explicit salt len", keyOpts: &KeyConfig{ Algorithm: RSA, Size: 2048, }, signOpts: &rsa.PSSOptions{ SaltLength: 32, Hash: crypto.SHA256, }, digest: []byte("12345678901234567890123456789012"), }, { name: "RSA2048-PSS-SHA384, explicit salt len", keyOpts: &KeyConfig{ Algorithm: RSA, Size: 2048, }, signOpts: &rsa.PSSOptions{ SaltLength: 48, Hash: crypto.SHA384, }, digest: []byte("123456789012345678901234567890121234567890123456"), }, { name: "RSA2048-PSS-SHA512, explicit salt len", keyOpts: &KeyConfig{ Algorithm: RSA, Size: 2048, }, signOpts: &rsa.PSSOptions{ SaltLength: 64, Hash: crypto.SHA512, }, digest: []byte("1234567890123456789012345678901212345678901234567890123456789012"), }, } { t.Run(test.name, func(t *testing.T) { sk, err := tpm.NewKey(ak, test.keyOpts) if err != nil { t.Fatalf("NewKey() failed: %v", err) } defer sk.Close() pub := sk.Public() priv, err := sk.Private(pub) if err != nil { t.Fatalf("sk.Private() failed: %v", err) } signer, ok := priv.(crypto.Signer) if !ok { t.Fatalf("want crypto.Signer, got %T", priv) } sig, err := signer.Sign(rand.Reader, test.digest, test.signOpts) if err != nil { t.Fatalf("signer.Sign() failed: %v", err) } if test.keyOpts == nil || test.keyOpts.Algorithm == ECDSA { verifyECDSA(t, pub, test.digest, sig) } else { verifyRSA(t, pub, test.digest, sig, test.signOpts) } }) } } func verifyECDSA(t *testing.T, pub crypto.PublicKey, digest, sig []byte) { t.Helper() parsed := struct{ R, S *big.Int }{} _, err := asn1.Unmarshal(sig, &parsed) if err != nil { t.Fatalf("signature parsing failed: %v", err) } pubECDSA, ok := pub.(*ecdsa.PublicKey) if !ok { t.Fatalf("want *ecdsa.PublicKey, got %T", pub) } if !ecdsa.Verify(pubECDSA, digest[:], parsed.R, parsed.S) { t.Fatalf("ecdsa.Verify() failed") } } func verifyRSA(t *testing.T, pub crypto.PublicKey, digest, sig []byte, opts crypto.SignerOpts) { t.Helper() pubRSA, ok := pub.(*rsa.PublicKey) if !ok { t.Fatalf("want *rsa.PublicKey, got %T", pub) } if pss, ok := opts.(*rsa.PSSOptions); ok { if err := rsa.VerifyPSS(pubRSA, opts.HashFunc(), digest, sig, pss); err != nil { t.Fatalf("rsa.VerifyPSS(): %v", err) } } else { if err := rsa.VerifyPKCS1v15(pubRSA, opts.HashFunc(), digest, sig); err != nil { t.Fatalf("signature verification failed: %v", err) } } } func TestSimTPM20KeyOpts(t *testing.T) { sim, tpm := setupSimulatedTPM(t) defer sim.Close() testKeyOpts(t, tpm) } func TestTPM20KeyOpts(t *testing.T) { if !*testLocal { t.SkipNow() } tpm, err := OpenTPM(nil) if err != nil { t.Fatalf("OpenTPM() failed: %v", err) } defer tpm.Close() testKeyOpts(t, tpm) } func testKeyOpts(t *testing.T, tpm *TPM) { ak, err := tpm.NewAK(nil) if err != nil { t.Fatalf("NewAK() failed: %v", err) } for _, test := range []struct { name string opts *KeyConfig err bool }{ { name: "wrong alg", opts: &KeyConfig{ Algorithm: "fake alg", }, err: true, }, { name: "wrong size", opts: &KeyConfig{ Algorithm: ECDSA, Size: 1234, }, err: true, }, { name: "default", opts: nil, err: false, }, { name: "ECDSAP256", opts: &KeyConfig{ Algorithm: ECDSA, Size: 256, }, err: false, }, { name: "ECDSAP384", opts: &KeyConfig{ Algorithm: ECDSA, Size: 384, }, err: false, }, { name: "ECDSAP521", opts: &KeyConfig{ Algorithm: ECDSA, Size: 521, }, err: false, }, { name: "RSA-1024", opts: &KeyConfig{ Algorithm: RSA, Size: 1024, }, err: false, }, { name: "RSA-2048", opts: &KeyConfig{ Algorithm: RSA, Size: 2048, }, err: false, }, } { t.Run(test.name, func(t *testing.T) { sk, err := tpm.NewKey(ak, test.opts) if !test.err && err != nil { t.Fatalf("NewKey() failed: %v", err) } if test.err { if err == nil { sk.Close() t.Fatalf("NewKey(): expected err != nil") } return } defer sk.Close() expected := test.opts if expected == nil { expected = defaultConfig } switch pub := sk.Public().(type) { case *ecdsa.PublicKey: if expected.Algorithm != ECDSA { t.Errorf("incorrect key type generated, expected %q, got EC", expected.Algorithm) } sizeToCurve := map[int]elliptic.Curve{ 256: elliptic.P256(), 384: elliptic.P384(), 521: elliptic.P521(), } expectedCurve, ok := sizeToCurve[expected.Size] if !ok { t.Fatalf("cannot match curve to key size %d", expected.Size) } if expectedCurve != pub.Curve { t.Errorf("incorrect curve, expected %v, got %v", expectedCurve, pub.Curve) } case *rsa.PublicKey: if expected.Algorithm != RSA { t.Errorf("incorrect key type, expected %q, got RSA", expected.Algorithm) } if pub.Size()*8 != expected.Size { t.Errorf("incorrect key size, expected %d, got %d", expected.Size, pub.Size()*8) } default: t.Errorf("unsupported key type: %T", pub) } }) } } go-attestation-0.5.1/attest/attest-tool/000077500000000000000000000000001452320553600202475ustar00rootroot00000000000000go-attestation-0.5.1/attest/attest-tool/README.md000066400000000000000000000017461452320553600215360ustar00rootroot00000000000000# attest-tool `attest-tool` is a simple utility to exercise attestation-related operations on your system. ## Building attest-tool If your system has git and a [Go 1.15+ compiler](https://golang.org/dl/) installed, you can install `attest-tool` from source by running the following commands: ```shell git clone 'https://github.com/google/go-attestation' && cd go-attestation/attest/attest-tool go build -o attest-tool ./ # compiled to ./attest-tool ``` ## Testing attestation readiness The main use-case of `attest-tool` is testing whether attestation works on the local system. Once `attest-tool` has been built, you can run it in self-test mode like this: ```shell ./attest-tool self-test ``` After a few seconds, it should print out a 'PASS' message, or a 'FAIL' message with a description of what went wrong. On Linux, `attest-tool` either needs to be run as root, or granted access to the TPM (`/dev/tpmrm0`) device & event log (`/sys/kernel/security/tpm0/binary_bios_measurements`) go-attestation-0.5.1/attest/attest-tool/attest-tool.go000066400000000000000000000175041452320553600230640ustar00rootroot00000000000000// Binary attest-tool performs attestation operations on the local system. package main import ( "bytes" "crypto/ecdsa" "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/hex" "encoding/json" "encoding/pem" "errors" "flag" "fmt" "os" "github.com/google/go-attestation/attest" "github.com/google/go-attestation/attest/attest-tool/internal" ) var ( keyPath = flag.String("key", "ak.json", "Path to the key file") nonceHex = flag.String("nonce", "", "Hex string to use as nonce when quoting") randomNonce = flag.Bool("random-nonce", false, "Generate a random nonce instead of using one provided") useSHA256 = flag.Bool("sha256", false, "Use SHA256 for quote operatons") ) func main() { flag.Parse() if *randomNonce { n := make([]byte, 8) rand.Read(n) *nonceHex = hex.EncodeToString(n) } tpm, err := attest.OpenTPM(nil) if err != nil { fmt.Fprintf(os.Stderr, "Error opening the TPM: %v\n", err) os.Exit(1) } err = runCommand(tpm) tpm.Close() if err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } } func selftestCredentialActivation(tpm *attest.TPM, ak *attest.AK) error { eks, err := tpm.EKs() if err != nil { return fmt.Errorf("EKs() failed: %v", err) } if len(eks) == 0 { return errors.New("no EK present") } ek := eks[0].Public // Test credential activation. ap := attest.ActivationParameters{ TPMVersion: tpm.Version(), EK: ek, AK: ak.AttestationParameters(), } secret, ec, err := ap.Generate() if err != nil { return fmt.Errorf("failed to generate activation challenge: %v", err) } decryptedSecret, err := ak.ActivateCredential(tpm, *ec) if err != nil { return fmt.Errorf("failed to generate activate credential: %v", err) } if !bytes.Equal(secret, decryptedSecret) { return errors.New("credential activation produced incorrect secret") } return nil } func selftestAttest(tpm *attest.TPM, ak *attest.AK) error { // This nonce is used in generating the quote. As this is a selftest, // it's set to an arbitrary value. nonce := []byte{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8} pub, err := attest.ParseAKPublic(tpm.Version(), ak.AttestationParameters().Public) if err != nil { return fmt.Errorf("failed to parse ak public: %v", err) } if _, err := tpm.MeasurementLog(); err != nil { return fmt.Errorf("no event log available: %v", err) } attestation, err := tpm.AttestPlatform(ak, nonce, nil) if err != nil { return fmt.Errorf("failed to attest: %v", err) } for i, quote := range attestation.Quotes { if err := pub.Verify(quote, attestation.PCRs, nonce); err != nil { return fmt.Errorf("failed to verify quote[%d]: %v", i, err) } } el, err := attest.ParseEventLog(attestation.EventLog) if err != nil { return fmt.Errorf("failed to parse event log: %v", err) } if _, err := el.Verify(attestation.PCRs); err != nil { return fmt.Errorf("event log failed to verify: %v", err) } return nil } func selftest(tpm *attest.TPM) error { ak, err := tpm.NewAK(nil) if err != nil { return fmt.Errorf("NewAK() failed: %v", err) } defer ak.Close(tpm) if err := selftestCredentialActivation(tpm, ak); err != nil { return fmt.Errorf("credential activation failed: %v", err) } if err := selftestAttest(tpm, ak); err != nil { return fmt.Errorf("state attestation failed: %v", err) } return nil } func runCommand(tpm *attest.TPM) error { switch flag.Arg(0) { case "info": info, err := tpm.Info() if err != nil { return err } fmt.Printf("Version: %d\n", info.Version) fmt.Printf("Interface: %d\n", info.Interface) fmt.Printf("VendorInfo: %x\n", info.VendorInfo) fmt.Printf("Manufacturer: %v\n", info.Manufacturer) case "make-ak", "make-aik": k, err := tpm.NewAK(nil) if err != nil { return fmt.Errorf("failed to mint an AK: %v", err) } defer k.Close(tpm) b, err := k.Marshal() if err != nil { return err } return os.WriteFile(*keyPath, b, 0644) case "quote": b, err := os.ReadFile(*keyPath) if err != nil { return err } k, err := tpm.LoadAK(b) if err != nil { return fmt.Errorf("failed to load AK: %v", err) } defer k.Close(tpm) nonce, err := hex.DecodeString(*nonceHex) if err != nil { return err } alg := attest.HashSHA1 if *useSHA256 { alg = attest.HashSHA256 } q, err := k.Quote(tpm, nonce, alg) if err != nil { return fmt.Errorf("failed to generate quote: %v", err) } fmt.Printf("Quote: %x\n", q.Quote) fmt.Printf("Signature: %x\n", q.Signature) case "list-eks": eks, err := tpm.EKs() if err != nil { return fmt.Errorf("failed to read EKs: %v", err) } for _, ek := range eks { data, err := encodeEK(ek) if err != nil { return fmt.Errorf("encoding ek: %v", err) } fmt.Printf("%s\n", data) } case "list-pcrs": alg := attest.HashSHA1 if *useSHA256 { alg = attest.HashSHA256 } pcrs, err := tpm.PCRs(alg) if err != nil { return fmt.Errorf("failed to read PCRs: %v", err) } for _, pcr := range pcrs { fmt.Printf("PCR[%d]: %x\n", pcr.Index, pcr.Digest) } case "measurement-log": b, err := tpm.MeasurementLog() if err != nil { return fmt.Errorf("failed to read the measurement log: %v", err) } fmt.Printf("%x\n", b) case "dump": dumpData, err := runDump(tpm) if err != nil { return err } return json.NewEncoder(os.Stdout).Encode(dumpData) case "self-test": err := selftest(tpm) if err != nil { fmt.Println("FAIL") return err } else { fmt.Println("PASS") } default: return fmt.Errorf("no such command %q", flag.Arg(0)) } return nil } func encodeEK(ek attest.EK) ([]byte, error) { if ek.Certificate != nil { return pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE", Bytes: ek.Certificate.Raw, }), nil } switch pub := ek.Public.(type) { case *ecdsa.PublicKey: data, err := x509.MarshalPKIXPublicKey(pub) if err != nil { return nil, fmt.Errorf("marshaling ec public key: %v", err) } return pem.EncodeToMemory(&pem.Block{ Type: "EC PUBLIC KEY", Bytes: data, }), nil case *rsa.PublicKey: return pem.EncodeToMemory(&pem.Block{ Type: "RSA PUBLIC KEY", Bytes: x509.MarshalPKCS1PublicKey(pub), }), nil default: return nil, fmt.Errorf("unsupported public key type %T", pub) } } func runDump(tpm *attest.TPM) (*internal.Dump, error) { var ( out internal.Dump err error ) out.Static.TPMVersion = tpm.Version() if out.Static.EKPem, err = rsaEKPEM(tpm); err != nil { return nil, err } k, err := tpm.NewAK(nil) if err != nil { return nil, fmt.Errorf("failed to mint an AK: %v", err) } defer k.Close(tpm) out.AK = k.AttestationParameters() // Get a quote. if out.Quote.Nonce, err = hex.DecodeString(*nonceHex); err != nil { return nil, fmt.Errorf("failed decoding nonce hex: %v", err) } out.Quote.Alg = attest.HashSHA1 if *useSHA256 { out.Quote.Alg = attest.HashSHA256 } q, err := k.Quote(tpm, out.Quote.Nonce, out.Quote.Alg) if err != nil { return nil, fmt.Errorf("failed to generate quote: %v", err) } out.Quote.Quote = q.Quote out.Quote.Signature = q.Signature // Get log information. if out.Log.Raw, err = tpm.MeasurementLog(); err != nil { return nil, fmt.Errorf("failed to read measurement log: %v", err) } // Get PCR values. if out.Log.PCRs, err = tpm.PCRs(out.Quote.Alg); err != nil { return nil, fmt.Errorf("failed to read PCRs: %v", err) } return &out, nil } func rsaEKPEM(tpm *attest.TPM) ([]byte, error) { eks, err := tpm.EKs() if err != nil { return nil, fmt.Errorf("failed to read EKs: %v", err) } var ( pk *rsa.PublicKey buf bytes.Buffer ) for _, ek := range eks { if pub, ok := ek.Public.(*rsa.PublicKey); ok { pk = pub break } } if pk == nil { return nil, errors.New("no EK available") } if err := pem.Encode(&buf, &pem.Block{Type: "RSA PUBLIC KEY", Bytes: x509.MarshalPKCS1PublicKey(pk)}); err != nil { return nil, fmt.Errorf("failed to PEM encode: %v", err) } return buf.Bytes(), nil } go-attestation-0.5.1/attest/attest-tool/internal/000077500000000000000000000000001452320553600220635ustar00rootroot00000000000000go-attestation-0.5.1/attest/attest-tool/internal/eventlog/000077500000000000000000000000001452320553600237065ustar00rootroot00000000000000go-attestation-0.5.1/attest/attest-tool/internal/eventlog/eventlog.go000066400000000000000000000153411452320553600260640ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. // Package eventlog implements experimental logic for parsing the TCG event log format. package eventlog import "fmt" // eventType indicates what kind of data an event is reporting. type eventType uint32 func isReserved(t eventType) bool { if 0x00000013 <= t && t <= 0x0000FFFF { return true } if 0x800000E1 <= t && t <= 0x8000FFFF { return true } return false } // String returns the name as defined by the TCG specification. func (e eventType) String() string { if s, ok := eventTypeNames[e]; ok { return s } s := fmt.Sprintf("eventType(0x%08x)", int(e)) if isReserved(e) { s += " (reserved)" } return s } const ( // https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClient_Specific_Platform_Profile_for_TPM_2p0_1p04_PUBLIC.pdf#page=103 // Reserved for future use. evPrebootCert eventType = 0x00000000 // Host platform trust chain measurements. The event data can contain one of // the following, indicating different points of boot: "POST CODE", "SMM CODE", // "ACPI DATA", "BIS CODE", "Embedded UEFI Driver". // // PCR[0] MUST be extended with this event type. // // https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClient_Specific_Platform_Profile_for_TPM_2p0_1p04_PUBLIC.pdf#page=38 evPostCode eventType = 0x00000001 // The event type was never used and is considered reserved. evUnused eventType = 0x00000002 // Used for PCRs[0,6]. This event type doesn't extend the PCR, the digest MUST // be all zeros, and the data holds information intended for parsers such as // delimiting a switch to the agile crypto event format. // // This event MUST NOT extend any PCR evNoAction eventType = 0x00000003 // Delineates the point where the Platform Firmware relinquishes control of TPM // measurements to the operating system. // // Event data size MUST contain either 0x00000000 or 0xFFFFFFFF, the digest MUST // match the data. // // This event MUST extend the PCRs 0 through 7 inclusive. evSeparator eventType = 0x00000004 // An event indicating a particular action in the boot sequence, for example // "User Password Entered" or "Booting BCV Device s". // // The digests field contains the tagged hash of the event field for each PCR bank. // // Used for PCRs [1, 2, 3, 4, 5, and 6]. evAction eventType = 0x00000005 // Used for PCRs defined for OS and application usage. The digest field MUST // contain a hash of the data. The data contains a TCG_PCClientTaggedEvent // sructure. evEventTag eventType = 0x00000006 // Used for PCR[0] only. The digest contains the hash of the SRTM for each PCR // bank. The data is informative and not expected to match the digest. evSCRTMContents eventType = 0x00000007 evSCRTMVersion eventType = 0x00000008 // The digests field contains the tagged hash of the microcode patch applied for // each PCR bank. The data is informative and not expected to match the digest. evCUPMicrocode eventType = 0x00000009 // TODO(ericchiang): explain these events evPlatformConfigFiles eventType = 0x0000000A evTableOfDevices eventType = 0x0000000B // Can be used for any PCRs except 0, 1, 2, or 3. evCompactHash eventType = 0x0000000C // IPL events are deprecated evIPL eventType = 0x0000000D evIPLPartitionData eventType = 0x0000000E // Used for PCR[0] only. // // TODO(ericchiang): explain these events evNonhostCode eventType = 0x0000000F evNonhostConfig eventType = 0x00000010 evNonhostInfo eventType = 0x00000011 evOmitBootDeviceEvents eventType = 0x00000012 // The following events are UEFI specific. // Data contains a UEFI_VARIABLE_DATA structure. evEFIVariableDriverConfig eventType = 0x80000001 // PCR[1,3,5] evEFIVariableBoot eventType = 0x80000002 // PCR[1] // Data contains a UEFI_IMAGE_LOAD_EVENT structure. evEFIBootServicesApplication eventType = 0x80000003 // PCR[2,4] evEFIBootServicesDriver eventType = 0x80000004 // PCR[0,2] evEFIRuntimeServicesDriver eventType = 0x80000005 // PCR[2,4] // Data contains a UEFI_GPT_DATA structure. evEFIGPTEvent eventType = 0x80000006 // PCR[5] evEFIAction eventType = 0x80000007 // PCR[1,2,3,4,5,6,7] // Data contains a UEFI_PLATFORM_FIRMWARE_BLOB structure. evEFIPlatformFirmwareBlob eventType = 0x80000008 // PCR[0,2,4] // Data contains a UEFI_HANDOFF_TABLE_POINTERS structure. evEFIHandoffTables eventType = 0x80000009 // PCR[1] // The digests field contains the tagged hash of the H-CRTM event // data for each PCR bank. // // The Event Data MUST be the string: “HCRTMâ€. evEFIHCRTMEvent eventType = 0x80000010 // PCR[0] // Data contains a UEFI_VARIABLE_DATA structure. evEFIVariableAuthority eventType = 0x800000E0 // PCR[7] ) var eventTypeNames = map[eventType]string{ evPrebootCert: "EV_PREBOOT_CERT", evPostCode: "EV_POST_CODE", evUnused: "EV_UNUSED", evNoAction: "EV_NO_ACTION", evSeparator: "EV_SEPARATOR", evAction: "EV_ACTION", evEventTag: "EV_EVENT_TAG", evSCRTMContents: "EV_S_CRTM_CONTENTS", evSCRTMVersion: "EV_S_CRTM_VERSION", evCUPMicrocode: "EV_CPU_MICROCODE", evPlatformConfigFiles: "EV_PLATFORM_CONFIG_FLAGS", evTableOfDevices: "EV_TABLE_OF_DEVICES", evCompactHash: "EV_COMPACT_HASH", evIPL: "EV_IPL (deprecated)", evIPLPartitionData: "EV_IPL_PARTITION_DATA (deprecated)", evNonhostCode: "EV_NONHOST_CODE", evNonhostConfig: "EV_NONHOST_CONFIG", evNonhostInfo: "EV_NONHOST_INFO", evOmitBootDeviceEvents: "EV_OMIT_BOOT_DEVICE_EVENTS", // UEFI events evEFIVariableDriverConfig: "EV_EFI_VARIABLE_DRIVER_CONFIG", evEFIVariableBoot: "EV_EFI_VARIABLE_BOOT", evEFIBootServicesApplication: "EV_EFI_BOOT_SERVICES_APPLICATION", evEFIBootServicesDriver: "EV_EFI_BOOT_SERVICES_DRIVER", evEFIRuntimeServicesDriver: "EV_EFI_RUNTIME_SERVICES_DRIVER", evEFIGPTEvent: "EV_EFI_GPT_EVENT", evEFIAction: "EV_EFI_ACTION", evEFIPlatformFirmwareBlob: "EV_EFI_PLATFORM_FIRMWARE_BLOB", evEFIHandoffTables: "EV_EFI_HANDOFF_TABLES", evEFIHCRTMEvent: "EV_EFI_HCRTM_EVENT", evEFIVariableAuthority: "EV_EFI_VARIABLE_AUTHORITY", } go-attestation-0.5.1/attest/attest-tool/internal/eventlog/secureboot.go000066400000000000000000000150761452320553600264200ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package eventlog import ( "bytes" "crypto" "encoding/binary" "fmt" "io" "unicode/utf16" "github.com/google/go-attestation/attest" ) var ( // https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_final.pdf#page=153 efiGlobalVariable = efiGUID{ 0x8BE4DF61, 0x93CA, 0x11d2, [8]uint8{0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C}} efiGlobalVariableSecureBoot = "SecureBoot" efiGlobalVariablePlatformKey = "PK" efiGlobalVariableKeyExchangeKey = "KEK" // https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_final.pdf#page=1804 efiImageSecurityDatabaseGUID = efiGUID{ 0xd719b2cb, 0x3d3a, 0x4596, [8]uint8{0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f}} efiImageSecurityDatabase = "db" efiImageSecurityDatabase1 = "dbx" efiImageSecurityDatabase2 = "dbt" efiImageSecurityDatabase3 = "dbr" ) type efiGUID struct { Data1 uint32 Data2 uint16 Data3 uint16 Data4 [8]uint8 } func (e efiGUID) String() string { if s, ok := efiGUIDString[e]; ok { return s } return fmt.Sprintf("{0x%x,0x%x,0x%x,{%x}}", e.Data1, e.Data2, e.Data3, e.Data4) } var efiGUIDString = map[efiGUID]string{ efiGlobalVariable: "EFI_GLOBAL_VARIABLE", efiImageSecurityDatabaseGUID: "EFI_IMAGE_SECURITY_DATABASE_GUID", } type uefiVariableData struct { id efiGUID name string data []byte } func (d *uefiVariableData) String() string { return fmt.Sprintf("%s %s data length %d", d.id, d.name, len(d.data)) } // SecureBoot holds parsed PCR 7 values representing secure boot settings for // the device. type SecureBoot struct { Enabled bool // TODO(ericchiang): parse these as EFI_SIGNATURE_LIST // // https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_final.pdf#page=1788 PK []byte KEK []byte DB []byte DBX []byte DBT []byte DBR []byte // Authority is the set of certificate that were used during secure boot // validation. This will be a subset of the certifiates in DB. Authority []byte } // ParseSecureBoot parses UEFI secure boot variables (PCR[7) from a verified event log. // // See https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClient_Specific_Platform_Profile_for_TPM_2p0_1p04_PUBLIC.pdf#page=56 func ParseSecureBoot(events []attest.Event) (*SecureBoot, error) { var sb SecureBoot seenSep := false for i, e := range events { if e.Index != 7 { continue } t := eventType(e.Type) switch t { case evEFIVariableDriverConfig: if seenSep { return nil, fmt.Errorf("event %d %s after %s", i, t, evSeparator) } data, err := parseUEFIVariableData(e.Data, e.Digest) if err != nil { return nil, fmt.Errorf("parsing event %d, PCR[%02d] %s: %v", i, e.Index, t, err) } switch data.id { case efiGlobalVariable: switch data.name { case efiGlobalVariableSecureBoot: if len(data.data) != 1 { return nil, fmt.Errorf("%s/%s was %d bytes", data.id, data.name, len(data.data)) } switch data.data[0] { case 0x0: sb.Enabled = false case 0x1: sb.Enabled = true default: return nil, fmt.Errorf("invalid %s/%s value 0x%x", data.id, data.name, data.data) } case efiGlobalVariablePlatformKey: sb.PK = data.data case efiGlobalVariableKeyExchangeKey: sb.KEK = data.data } case efiImageSecurityDatabaseGUID: switch data.name { case efiImageSecurityDatabase: sb.DB = data.data case efiImageSecurityDatabase1: sb.DBX = data.data case efiImageSecurityDatabase2: sb.DBT = data.data case efiImageSecurityDatabase3: sb.DBR = data.data } } case evEFIVariableAuthority: if !seenSep { return nil, fmt.Errorf("event %d %s before %s", i, t, evSeparator) } data, err := parseUEFIVariableData(e.Data, e.Digest) if err != nil { return nil, fmt.Errorf("parsing event %d, PCR[%02d] %s: %v", i, e.Index, t, err) } switch data.id { case efiImageSecurityDatabaseGUID: switch data.name { case efiImageSecurityDatabase: if !sb.Enabled { return nil, fmt.Errorf("%s/%s present when secure boot wasn't enabled", t, data.name) } if len(sb.Authority) != 0 { // If a malicious value is appended to the eventlog, // ensure we only trust the first value written by // the UEFI firmware. return nil, fmt.Errorf("%s/%s was already present earlier in the event log", t, data.name) } sb.Authority = data.data } } case evSeparator: seenSep = true } } return &sb, nil } func binaryRead(r io.Reader, i interface{}) error { return binary.Read(r, binary.LittleEndian, i) } var hashBySize = map[int]crypto.Hash{ crypto.SHA1.Size(): crypto.SHA1, crypto.SHA256.Size(): crypto.SHA256, } func verifyDigest(digest, data []byte) bool { h, ok := hashBySize[len(digest)] if !ok { return false } hash := h.New() hash.Write(data) return bytes.Equal(digest, hash.Sum(nil)) } // parseUEFIVariableData parses a UEFI_VARIABLE_DATA struct and validates the // digest of an event entry. // // https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClient_Specific_Platform_Profile_for_TPM_2p0_1p04_PUBLIC.pdf#page=100 func parseUEFIVariableData(b, digest []byte) (*uefiVariableData, error) { r := bytes.NewBuffer(b) var hdr struct { ID efiGUID NameLength uint64 DataLength uint64 } if err := binaryRead(r, &hdr); err != nil { return nil, err } name := make([]uint16, hdr.NameLength) if err := binaryRead(r, &name); err != nil { return nil, fmt.Errorf("parsing name: %v", err) } if r.Len() != int(hdr.DataLength) { return nil, fmt.Errorf("remaining bytes %d doesn't match data length %d", r.Len(), hdr.DataLength) } data := r.Bytes() // TODO(ericchiang): older UEFI firmware (Lenovo Bios version 1.17) logs the // digest of the data, which doesn't encapsulate the ID or name. This lets // attackers alter keys and we should determine if this is an acceptable risk. if !verifyDigest(digest, b) && !verifyDigest(digest, data) { return nil, fmt.Errorf("digest didn't match data") } return &uefiVariableData{id: hdr.ID, name: string(utf16.Decode(name)), data: r.Bytes()}, nil } go-attestation-0.5.1/attest/attest-tool/internal/eventlog/secureboot_test.go000066400000000000000000000054461452320553600274570ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package eventlog import ( "encoding/json" "os" "testing" "github.com/google/go-attestation/attest" "github.com/google/go-attestation/attest/attest-tool/internal" ) func parseEvents(t *testing.T, testdata string) []attest.Event { data, err := os.ReadFile(testdata) if err != nil { t.Fatalf("reading test data: %v", err) } var dump internal.Dump if err := json.Unmarshal(data, &dump); err != nil { t.Fatalf("parsing test data: %v", err) } ak, err := attest.ParseAKPublic(dump.Static.TPMVersion, dump.AK.Public) if err != nil { t.Fatalf("parsing AK: %v", err) } if err := ak.Verify(attest.Quote{ Version: dump.Static.TPMVersion, Quote: dump.Quote.Quote, Signature: dump.Quote.Signature, }, dump.Log.PCRs, dump.Quote.Nonce); err != nil { t.Fatalf("verifying quote: %v", err) } el, err := attest.ParseEventLog(dump.Log.Raw) if err != nil { t.Fatalf("parsing event log: %v", err) } events, err := el.Verify(dump.Log.PCRs) if err != nil { t.Fatalf("validating event log: %v", err) } return events } func notEmpty(t *testing.T, name string, field []byte) { t.Helper() if len(field) == 0 { t.Errorf("field %s wasn't populated", name) } } func isEmpty(t *testing.T, name string, field []byte) { t.Helper() if len(field) != 0 { t.Errorf("expected field %s not to be populated", name) } } func TestParseSecureBootWindows(t *testing.T) { events := parseEvents(t, "../../../testdata/windows_gcp_shielded_vm.json") sb, err := ParseSecureBoot(events) if err != nil { t.Fatalf("parse secure boot: %v", err) } if !sb.Enabled { t.Errorf("expected secure boot to be enabled") } notEmpty(t, "db", sb.DB) notEmpty(t, "dbx", sb.DBX) notEmpty(t, "pk", sb.PK) notEmpty(t, "kek", sb.KEK) isEmpty(t, "dbt", sb.DBT) isEmpty(t, "dbr", sb.DBR) notEmpty(t, "Authority", sb.Authority) } func TestParseSecureBootLinux(t *testing.T) { events := parseEvents(t, "../../../testdata/linux_tpm12.json") sb, err := ParseSecureBoot(events) if err != nil { t.Errorf("parse secure boot: %v", err) } if sb.Enabled { t.Errorf("expected secure boot to be disabled") } notEmpty(t, "db", sb.DB) notEmpty(t, "dbx", sb.DBX) isEmpty(t, "dbt", sb.DBT) isEmpty(t, "dbr", sb.DBR) isEmpty(t, "Authority", sb.Authority) } go-attestation-0.5.1/attest/attest-tool/internal/internal.go000066400000000000000000000011551452320553600242300ustar00rootroot00000000000000// Package internal contains marshalling structures for attest-tool and tests. package internal import ( "github.com/google/go-attestation/attest" "github.com/google/go-tpm/legacy/tpm2" ) // Dump describes the layout of serialized information from the dump command. type Dump struct { Static struct { TPMVersion attest.TPMVersion EKPem []byte } AK attest.AttestationParameters Quote struct { Nonce []byte Alg attest.HashAlg Quote []byte Signature []byte } Log struct { PCRs []attest.PCR PCRAlg tpm2.Algorithm Raw []byte // The measured boot log in binary form. } } go-attestation-0.5.1/attest/attest.go000066400000000000000000000430021452320553600176220ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. // Package attest abstracts TPM attestation operations. package attest import ( "crypto" "crypto/x509" "errors" "fmt" "io" "strings" "github.com/google/go-tpm/legacy/tpm2" "github.com/google/go-tpm/tpm" "github.com/google/go-tpm/tpmutil" ) // TPMVersion is used to configure a preference in // which TPM to use, if multiple are available. type TPMVersion uint8 // TPM versions const ( TPMVersionAgnostic TPMVersion = iota TPMVersion12 TPMVersion20 ) // TPMInterface indicates how the client communicates // with the TPM. type TPMInterface uint8 // TPM interfaces const ( TPMInterfaceDirect TPMInterface = iota TPMInterfaceKernelManaged TPMInterfaceDaemonManaged TPMInterfaceCommandChannel ) // CommandChannelTPM20 represents a pipe along which TPM 2.0 commands // can be issued, and measurement logs read. type CommandChannelTPM20 interface { io.ReadWriteCloser MeasurementLog() ([]byte, error) } // OpenConfig encapsulates settings passed to OpenTPM(). type OpenConfig struct { // TPMVersion indicates which TPM version the library should // attempt to use. If the specified version is not available, // ErrTPMNotAvailable is returned. Defaults to TPMVersionAgnostic. TPMVersion TPMVersion // CommandChannel provides a TPM 2.0 command channel, which can be // used in-lieu of any TPM present on the platform. CommandChannel CommandChannelTPM20 } // keyEncoding indicates how an exported TPM key is represented. type keyEncoding uint8 func (e keyEncoding) String() string { switch e { case keyEncodingInvalid: return "invalid" case keyEncodingOSManaged: return "os-managed" case keyEncodingEncrypted: return "encrypted" case keyEncodingParameterized: return "parameterized" default: return fmt.Sprintf("keyEncoding<%d>", int(e)) } } // Key encodings const ( keyEncodingInvalid keyEncoding = iota // Managed by the OS but loadable by name. keyEncodingOSManaged // Key fully represented but in encrypted form. keyEncodingEncrypted // Parameters stored, but key must be regenerated before use. keyEncodingParameterized ) // ParentKeyConfig describes the Storage Root Key that is used // as a parent for new keys. type ParentKeyConfig struct { Algorithm Algorithm Handle tpmutil.Handle } var defaultParentConfig = ParentKeyConfig{ Algorithm: RSA, Handle: 0x81000001, } type ak interface { close(tpmBase) error marshal() ([]byte, error) activateCredential(tpm tpmBase, in EncryptedCredential, ek *EK) ([]byte, error) quote(t tpmBase, nonce []byte, alg HashAlg, selectedPCRs []int) (*Quote, error) attestationParameters() AttestationParameters certify(tb tpmBase, handle interface{}) (*CertificationParameters, error) } // AK represents a key which can be used for attestation. type AK struct { ak ak } // Close unloads the AK from the system. func (k *AK) Close(t *TPM) error { return k.ak.close(t.tpm) } // Marshal encodes the AK in a format that can be reloaded with tpm.LoadAK(). // This method exists to allow consumers to store the key persistently and load // it as a later time. Users SHOULD NOT attempt to interpret or extract values // from this blob. func (k *AK) Marshal() ([]byte, error) { return k.ak.marshal() } // ActivateCredential decrypts the secret using the key to prove that the AK // was generated on the same TPM as the EK. This method can be used with TPMs // that have the default EK, i.e. RSA EK with handle 0x81010001. // // This operation is synonymous with TPM2_ActivateCredential. func (k *AK) ActivateCredential(tpm *TPM, in EncryptedCredential) (secret []byte, err error) { return k.ak.activateCredential(tpm.tpm, in, nil) } // ActivateCredential decrypts the secret using the key to prove that the AK // was generated on the same TPM as the EK. This method can be used with TPMs // that have an ECC EK. The 'ek' argument must be one of EKs returned from // TPM.EKs() or TPM.EKCertificates(). // // This operation is synonymous with TPM2_ActivateCredential. func (k *AK) ActivateCredentialWithEK(tpm *TPM, in EncryptedCredential, ek EK) (secret []byte, err error) { return k.ak.activateCredential(tpm.tpm, in, &ek) } // Quote returns a quote over the platform state, signed by the AK. // // This is a low-level API. Consumers seeking to attest the state of the // platform should use tpm.AttestPlatform() instead. func (k *AK) Quote(tpm *TPM, nonce []byte, alg HashAlg) (*Quote, error) { pcrs := make([]int, 24) for pcr := range pcrs { pcrs[pcr] = pcr } return k.ak.quote(tpm.tpm, nonce, alg, pcrs) } // QuotePCRs is like Quote() but allows the caller to select a subset of the PCRs. func (k *AK) QuotePCRs(tpm *TPM, nonce []byte, alg HashAlg, pcrs []int) (*Quote, error) { return k.ak.quote(tpm.tpm, nonce, alg, pcrs) } // AttestationParameters returns information about the AK, typically used to // generate a credential activation challenge. func (k *AK) AttestationParameters() AttestationParameters { return k.ak.attestationParameters() } // Certify uses the attestation key to certify the key with `handle`. It returns // certification parameters which allow to verify the properties of the attested // key. Depending on the actual instantiation it can accept different handle // types (e.g., tpmutil.Handle on Linux or uintptr on Windows). func (k *AK) Certify(tpm *TPM, handle interface{}) (*CertificationParameters, error) { return k.ak.certify(tpm.tpm, handle) } // AKConfig encapsulates parameters for minting keys. type AKConfig struct { // Parent describes the Storage Root Key that will be used as a parent. // If nil, the default SRK (i.e. RSA with handle 0x81000001) is assumed. // Supported only by TPM 2.0 on Linux. Parent *ParentKeyConfig } // EncryptedCredential represents encrypted parameters which must be activated // against a key. type EncryptedCredential struct { Credential []byte Secret []byte } // Quote encapsulates the results of a Quote operation against the TPM, // using an attestation key. type Quote struct { Version TPMVersion Quote []byte Signature []byte } // PCR encapsulates the value of a PCR at a point in time. type PCR struct { Index int Digest []byte DigestAlg crypto.Hash // quoteVerified is true if the PCR was verified against a quote // in a call to AKPublic.Verify or AKPublic.VerifyAll. quoteVerified bool } // QuoteVerified returns true if the value of this PCR was previously // verified against a Quote, in a call to AKPublic.Verify or AKPublic.VerifyAll. func (p *PCR) QuoteVerified() bool { return p.quoteVerified } // EK is a burned-in endorcement key bound to a TPM. This optionally contains // a certificate that can chain to the TPM manufacturer. type EK struct { // Public key of the EK. Public crypto.PublicKey // Certificate is the EK certificate for TPMs that provide it. Certificate *x509.Certificate // For Intel TPMs, Intel hosts certificates at a public URL derived from the // Public key. Clients or servers can perform an HTTP GET to this URL, and // use ParseEKCertificate on the response body. CertificateURL string // The EK persistent handle. handle tpmutil.Handle } // AttestationParameters describes information about a key which is necessary // for verifying its properties remotely. type AttestationParameters struct { // Public represents the AK's canonical encoding. This blob includes the // public key, as well as signing parameters such as the hash algorithm // used to generate quotes. // // Use ParseAKPublic to access the key's data. Public []byte // For TPM 2.0 devices, Public is encoded as a TPMT_PUBLIC structure. // For TPM 1.2 devices, Public is a TPM_PUBKEY structure, as defined in // the TPM Part 2 Structures specification, available at // https://trustedcomputinggroup.org/wp-content/uploads/TPM-Main-Part-2-TPM-Structures_v1.2_rev116_01032011.pdf // UseTCSDActivationFormat is set when tcsd (trousers daemon) is operating // as an intermediary between this library and the TPM. A value of true // indicates that activation challenges should use the TCSD-specific format. UseTCSDActivationFormat bool // Subsequent fields are only populated for AKs generated on a TPM // implementing version 2.0 of the specification. The specific structures // referenced for each field are defined in the TPM Revision 2, Part 2 - // Structures specification, available here: // https://www.trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf // CreateData represents the properties of a TPM 2.0 key. It is encoded // as a TPMS_CREATION_DATA structure. CreateData []byte // CreateAttestation represents an assertion as to the details of the key. // It is encoded as a TPMS_ATTEST structure. CreateAttestation []byte // CreateSignature represents a signature of the CreateAttestation structure. // It is encoded as a TPMT_SIGNATURE structure. CreateSignature []byte } // AKPublic holds structured information about an AK's public key. type AKPublic struct { // Public is the public part of the AK. This can either be an *rsa.PublicKey or // and *ecdsa.PublicKey. Public crypto.PublicKey // Hash is the hashing algorithm the AK will use when signing quotes. Hash crypto.Hash } // ParseAKPublic parses the Public blob from the AttestationParameters, // returning the public key and signing parameters for the key. func ParseAKPublic(version TPMVersion, public []byte) (*AKPublic, error) { switch version { case TPMVersion12: rsaPub, err := tpm.UnmarshalPubRSAPublicKey(public) if err != nil { return nil, fmt.Errorf("parsing public key: %v", err) } return &AKPublic{Public: rsaPub, Hash: crypto.SHA1}, nil case TPMVersion20: pub, err := tpm2.DecodePublic(public) if err != nil { return nil, fmt.Errorf("parsing TPM public key structure: %v", err) } switch { case pub.RSAParameters == nil && pub.ECCParameters == nil: return nil, errors.New("parsing public key: missing asymmetric parameters") case pub.RSAParameters != nil && pub.RSAParameters.Sign == nil: return nil, errors.New("parsing public key: missing rsa signature scheme") case pub.ECCParameters != nil && pub.ECCParameters.Sign == nil: return nil, errors.New("parsing public key: missing ecc signature scheme") } pubKey, err := pub.Key() if err != nil { return nil, fmt.Errorf("parsing public key: %v", err) } var h crypto.Hash switch pub.Type { case tpm2.AlgRSA: h, err = pub.RSAParameters.Sign.Hash.Hash() case tpm2.AlgECC: h, err = pub.ECCParameters.Sign.Hash.Hash() default: return nil, fmt.Errorf("unsupported public key type 0x%x", pub.Type) } if err != nil { return nil, fmt.Errorf("invalid public key hash: %v", err) } return &AKPublic{Public: pubKey, Hash: h}, nil default: return nil, fmt.Errorf("unknown tpm version 0x%x", version) } } // Verify is used to prove authenticity of the PCR measurements. It ensures that // the quote was signed by the AK, and that its contents matches the PCR and // nonce combination. An error is returned if a provided PCR index was not part // of the quote. QuoteVerified() will return true on PCRs which were verified // by a quote. // // Do NOT use this method if you have multiple quotes to verify: Use VerifyAll // instead. // // The nonce is used to prevent replays of Quote and PCRs and is signed by the // quote. Some TPMs don't support nonces longer than 20 bytes, and if the // nonce is used to tie additional data to the quote, the additional data should be // hashed to construct the nonce. func (a *AKPublic) Verify(quote Quote, pcrs []PCR, nonce []byte) error { switch quote.Version { case TPMVersion12: return a.validate12Quote(quote, pcrs, nonce) case TPMVersion20: return a.validate20Quote(quote, pcrs, nonce) default: return fmt.Errorf("quote used unknown tpm version 0x%x", quote.Version) } } // VerifyAll uses multiple quotes to verify the authenticity of all PCR // measurements. See documentation on Verify() for semantics. // // An error is returned if any PCRs provided were not covered by a quote, // or if no quote/nonce was provided. func (a *AKPublic) VerifyAll(quotes []Quote, pcrs []PCR, nonce []byte) error { if len(quotes) == 0 { return errors.New("no quotes were provided") } if len(nonce) == 0 { return errors.New("no nonce was provided") } for i, quote := range quotes { if err := a.Verify(quote, pcrs, nonce); err != nil { return fmt.Errorf("quote %d: %v", i, err) } } var errPCRs []string for _, p := range pcrs { if !p.QuoteVerified() { errPCRs = append(errPCRs, fmt.Sprintf("%d (%s)", p.Index, p.DigestAlg)) } } if len(errPCRs) > 0 { return fmt.Errorf("some PCRs were not covered by a quote: %s", strings.Join(errPCRs, ", ")) } return nil } // HashAlg identifies a hashing Algorithm. type HashAlg uint8 // Valid hash algorithms. var ( HashSHA1 = HashAlg(tpm2.AlgSHA1) HashSHA256 = HashAlg(tpm2.AlgSHA256) ) func (a HashAlg) cryptoHash() crypto.Hash { switch a { case HashSHA1: return crypto.SHA1 case HashSHA256: return crypto.SHA256 } return 0 } func (a HashAlg) goTPMAlg() tpm2.Algorithm { switch a { case HashSHA1: return tpm2.AlgSHA1 case HashSHA256: return tpm2.AlgSHA256 } return 0 } // String returns a human-friendly representation of the hash algorithm. func (a HashAlg) String() string { switch a { case HashSHA1: return "SHA1" case HashSHA256: return "SHA256" } return fmt.Sprintf("HashAlg<%d>", int(a)) } // PlatformParameters encapsulates the set of information necessary to attest // the booted state of the machine the TPM is attached to. // // The digests contained in the event log can be considered authentic if: // - The AK public corresponds to the known AK for that platform. // - All quotes are verified with AKPublic.Verify(), and return no errors. // - The event log parsed successfully using ParseEventLog(), and a call // to EventLog.Verify() with the full set of PCRs returned no error. type PlatformParameters struct { // The version of the TPM which generated this attestation. TPMVersion TPMVersion // The public blob of the AK which endorsed the platform state. This can // be decoded to verify the adjacent quotes using ParseAKPublic(). Public []byte // The set of quotes which endorse the state of the PCRs. Quotes []Quote // The set of expected PCR values, which are used in replaying the event log // to verify digests were not tampered with. PCRs []PCR // The raw event log provided by the platform. This can be processed with // ParseEventLog(). EventLog []byte } var ( defaultOpenConfig = &OpenConfig{} // ErrTPMNotAvailable is returned in response to OpenTPM() when // either no TPM is available, or a TPM of the requested version // is not available (if TPMVersion was set in the provided config). ErrTPMNotAvailable = errors.New("TPM device not available") // ErrTPM12NotImplemented is returned in response to methods which // need to interact with the TPM1.2 device in ways that have not // yet been implemented. ErrTPM12NotImplemented = errors.New("TPM 1.2 support not yet implemented") ) // TPMInfo contains information about the version & interface // of an open TPM. type TPMInfo struct { Version TPMVersion Interface TPMInterface VendorInfo string Manufacturer TCGVendorID // FirmwareVersionMajor and FirmwareVersionMinor describe // the firmware version of the TPM, but are only available // for TPM 2.0 devices. FirmwareVersionMajor int FirmwareVersionMinor int } // probedTPM identifies a TPM device on the system, which // is a candidate for being used. type probedTPM struct { Version TPMVersion Path string } // MatchesConfig returns true if the TPM satisfies the constraints // specified by the given config. func (t *probedTPM) MatchesConfig(config OpenConfig) bool { return config.TPMVersion == TPMVersionAgnostic || t.Version == config.TPMVersion } // OpenTPM initializes access to the TPM based on the // config provided. func OpenTPM(config *OpenConfig) (*TPM, error) { if config == nil { config = defaultOpenConfig } // As a special case, if the user provided us with a command channel, // we should use that. if config.CommandChannel != nil { if config.TPMVersion > TPMVersionAgnostic && config.TPMVersion != TPMVersion20 { return nil, errors.New("command channel can only be used as a TPM 2.0 device") } return &TPM{&wrappedTPM20{ interf: TPMInterfaceCommandChannel, rwc: config.CommandChannel, }}, nil } candidateTPMs, err := probeSystemTPMs() if err != nil { return nil, err } for _, tpm := range candidateTPMs { if tpm.MatchesConfig(*config) { return openTPM(tpm) } } return nil, ErrTPMNotAvailable } // AvailableTPMs returns information about available TPMs matching // the given config, without opening the devices. func AvailableTPMs(config *OpenConfig) ([]TPMInfo, error) { if config == nil { config = defaultOpenConfig } candidateTPMs, err := probeSystemTPMs() if err != nil { return nil, err } var out []TPMInfo for _, tpm := range candidateTPMs { if tpm.MatchesConfig(*config) { t, err := openTPM(tpm) if err != nil { return nil, err } defer t.Close() i, err := t.Info() if err != nil { return nil, err } out = append(out, *i) } } return out, nil } go-attestation-0.5.1/attest/attest_fuzz.go000066400000000000000000000027321452320553600207050ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. //go:build gofuzz // +build gofuzz package attest // FuzzParseAKPublic12 is an exported entrypoint for fuzzers to test // ParseAKPublic TPM 1.2 blobs. This method should not be used for any // other purpose. func FuzzParseAKPublic12(data []byte) int { _, err := ParseAKPublic(TPMVersion12, data) if err != nil { return 0 } return 1 } // FuzzParseAKPublic20 is an exported entrypoint for fuzzers to test // ParseAKPublic TPM 2.0 blobs. This method should not be used for any // other purpose. func FuzzParseAKPublic20(data []byte) int { _, err := ParseAKPublic(TPMVersion20, data) if err != nil { return 0 } return 1 } // FuzzParseEKCertificate is an exported entrypoint for fuzzers to test // ParseEKCertificate. This method should not be used for any other purpose. func FuzzParseEKCertificate(data []byte) int { _, err := ParseEKCertificate(data) if err != nil { return 0 } return 1 } go-attestation-0.5.1/attest/attest_simulated_tpm20_test.go000066400000000000000000000205731452320553600237620ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. //go:build (!localtest || !tpm12) && cgo && !gofuzz // +build !localtest !tpm12 // +build cgo // +build !gofuzz // NOTE: simulator requires cgo, hence the build tag. package attest import ( "bytes" "crypto" "testing" "github.com/google/go-tpm-tools/simulator" ) func setupSimulatedTPM(t *testing.T) (*simulator.Simulator, *TPM) { t.Helper() tpm, err := simulator.Get() if err != nil { t.Fatal(err) } attestTPM, err := OpenTPM(&OpenConfig{CommandChannel: &fakeCmdChannel{tpm}}) if err != nil { t.Fatal(err) } return tpm, attestTPM } func TestSimTPM20EK(t *testing.T) { sim, tpm := setupSimulatedTPM(t) defer sim.Close() eks, err := tpm.EKs() if err != nil { t.Errorf("EKs() failed: %v", err) } if len(eks) == 0 || (eks[0].Public == nil) { t.Errorf("EKs() = %v, want at least 1 EK with populated fields", eks) } } func TestSimTPM20Info(t *testing.T) { sim, tpm := setupSimulatedTPM(t) defer sim.Close() if _, err := tpm.Info(); err != nil { t.Errorf("tpm.Info() failed: %v", err) } } func TestSimTPM20AKCreateAndLoad(t *testing.T) { sim, tpm := setupSimulatedTPM(t) defer sim.Close() ak, err := tpm.NewAK(nil) if err != nil { t.Fatalf("NewAK() failed: %v", err) } enc, err := ak.Marshal() if err != nil { ak.Close(tpm) t.Fatalf("ak.Marshal() failed: %v", err) } if err := ak.Close(tpm); err != nil { t.Fatalf("ak.Close() failed: %v", err) } loaded, err := tpm.LoadAK(enc) if err != nil { t.Fatalf("LoadKey() failed: %v", err) } defer loaded.Close(tpm) k1, k2 := ak.ak.(*wrappedKey20), loaded.ak.(*wrappedKey20) if !bytes.Equal(k1.public, k2.public) { t.Error("Original & loaded AK public blobs did not match.") t.Logf("Original = %v", k1.public) t.Logf("Loaded = %v", k2.public) } } func TestSimTPM20ActivateCredential(t *testing.T) { testActivateCredential(t, false) } func TestSimTPM20ActivateCredentialWithEK(t *testing.T) { testActivateCredential(t, true) } func testActivateCredential(t *testing.T, useEK bool) { sim, tpm := setupSimulatedTPM(t) defer sim.Close() EKs, err := tpm.EKs() if err != nil { t.Fatalf("EKs() failed: %v", err) } ek := chooseEK(t, EKs) ak, err := tpm.NewAK(nil) if err != nil { t.Fatalf("NewAK() failed: %v", err) } defer ak.Close(tpm) ap := ActivationParameters{ TPMVersion: TPMVersion20, AK: ak.AttestationParameters(), EK: ek.Public, } secret, challenge, err := ap.Generate() if err != nil { t.Fatalf("Generate() failed: %v", err) } var decryptedSecret []byte if useEK { decryptedSecret, err = ak.ActivateCredentialWithEK(tpm, *challenge, ek) } else { decryptedSecret, err = ak.ActivateCredential(tpm, *challenge) } if err != nil { t.Errorf("ak.ActivateCredential() failed: %v", err) } if !bytes.Equal(secret, decryptedSecret) { t.Error("secret does not match decrypted secret") t.Logf("Secret = %v", secret) t.Logf("Decrypted secret = %v", decryptedSecret) } } func TestParseAKPublic20(t *testing.T) { sim, tpm := setupSimulatedTPM(t) defer sim.Close() ak, err := tpm.NewAK(nil) if err != nil { t.Fatalf("NewAK() failed: %v", err) } defer ak.Close(tpm) params := ak.AttestationParameters() if _, err := ParseAKPublic(TPMVersion20, params.Public); err != nil { t.Errorf("parsing AK public blob: %v", err) } } func TestSimTPM20QuoteAndVerifyAll(t *testing.T) { sim, tpm := setupSimulatedTPM(t) defer sim.Close() ak, err := tpm.NewAK(nil) if err != nil { t.Fatalf("NewAK() failed: %v", err) } defer ak.Close(tpm) nonce := []byte{1, 2, 3, 4, 5, 6, 7, 8} quote256, err := ak.Quote(tpm, nonce, HashSHA256) if err != nil { t.Fatalf("ak.Quote(SHA256) failed: %v", err) } quote1, err := ak.Quote(tpm, nonce, HashSHA1) if err != nil { t.Fatalf("ak.Quote(SHA1) failed: %v", err) } // Providing both PCR banks to AKPublic.Verify() ensures we can handle // the case where extra PCRs of a different digest algorithm are provided. var pcrs []PCR for _, alg := range []HashAlg{HashSHA256, HashSHA1} { p, err := tpm.PCRs(alg) if err != nil { t.Fatalf("tpm.PCRs(%v) failed: %v", alg, err) } pcrs = append(pcrs, p...) } pub, err := ParseAKPublic(tpm.Version(), ak.AttestationParameters().Public) if err != nil { t.Fatalf("ParseAKPublic() failed: %v", err) } // Ensure VerifyAll fails if a quote is missing and hence not all PCR // banks are covered. if err := pub.VerifyAll([]Quote{*quote256}, pcrs, nonce); err == nil { t.Error("VerifyAll().err returned nil, expected failure") } if err := pub.VerifyAll([]Quote{*quote256, *quote1}, pcrs, nonce); err != nil { t.Errorf("quote verification failed: %v", err) } } func TestSimTPM20AttestPlatform(t *testing.T) { sim, tpm := setupSimulatedTPM(t) defer sim.Close() ak, err := tpm.NewAK(nil) if err != nil { t.Fatalf("NewAK() failed: %v", err) } defer ak.Close(tpm) nonce := []byte{1, 2, 3, 4, 5, 6, 7, 8} attestation, err := tpm.attestPlatform(ak, nonce, nil) if err != nil { t.Fatalf("AttestPlatform() failed: %v", err) } pub, err := ParseAKPublic(attestation.TPMVersion, attestation.Public) if err != nil { t.Fatalf("ParseAKPublic() failed: %v", err) } if err := pub.VerifyAll(attestation.Quotes, attestation.PCRs, nonce); err != nil { t.Errorf("quote verification failed: %v", err) } } func TestSimTPM20PCRs(t *testing.T) { sim, tpm := setupSimulatedTPM(t) defer sim.Close() PCRs, err := tpm.PCRs(HashSHA256) if err != nil { t.Fatalf("PCRs() failed: %v", err) } if len(PCRs) != 24 { t.Errorf("len(PCRs) = %d, want %d", len(PCRs), 24) } for i, pcr := range PCRs { if len(pcr.Digest) != pcr.DigestAlg.Size() { t.Errorf("PCR %d len(digest) = %d, expected match with digest algorithm size (%d)", pcr.Index, len(pcr.Digest), pcr.DigestAlg.Size()) } if pcr.Index != i { t.Errorf("PCR index %d does not match map index %d", pcr.Index, i) } if pcr.DigestAlg != crypto.SHA256 { t.Errorf("pcr.DigestAlg = %v, expected crypto.SHA256", pcr.DigestAlg) } } } func TestSimTPM20PersistenceSRK(t *testing.T) { testPersistenceSRK(t, defaultParentConfig) } func TestSimTPM20PersistenceECCSRK(t *testing.T) { parentConfig := ParentKeyConfig{ Algorithm: ECDSA, Handle: 0x81000002, } testPersistenceSRK(t, parentConfig) } func testPersistenceSRK(t *testing.T, parentConfig ParentKeyConfig) { sim, tpm := setupSimulatedTPM(t) defer sim.Close() srkHnd, _, err := tpm.tpm.(*wrappedTPM20).getStorageRootKeyHandle(parentConfig) if err != nil { t.Fatalf("getStorageRootKeyHandle() failed: %v", err) } if srkHnd != parentConfig.Handle { t.Fatalf("bad SRK-equivalent handle: got 0x%x, wanted 0x%x", srkHnd, parentConfig.Handle) } srkHnd, p, err := tpm.tpm.(*wrappedTPM20).getStorageRootKeyHandle(parentConfig) if err != nil { t.Fatalf("second getStorageRootKeyHandle() failed: %v", err) } if srkHnd != parentConfig.Handle { t.Fatalf("bad SRK-equivalent handle: got 0x%x, wanted 0x%x", srkHnd, parentConfig.Handle) } if p { t.Fatalf("generated a new key the second time; that shouldn't happen") } } func TestSimTPM20PersistenceEK(t *testing.T) { sim, tpm := setupSimulatedTPM(t) defer sim.Close() eks, err := tpm.EKs() if err != nil { t.Errorf("EKs() failed: %v", err) } if len(eks) == 0 || (eks[0].Public == nil) { t.Errorf("EKs() = %v, want at least 1 EK with populated fields", eks) } ek := eks[0] ekHnd, _, err := tpm.tpm.(*wrappedTPM20).getEndorsementKeyHandle(&ek) if err != nil { t.Fatalf("getStorageRootKeyHandle() failed: %v", err) } if ekHnd != ek.handle { t.Fatalf("bad EK-equivalent handle: got 0x%x, wanted 0x%x", ekHnd, ek.handle) } ekHnd, p, err := tpm.tpm.(*wrappedTPM20).getEndorsementKeyHandle(&ek) if err != nil { t.Fatalf("second getEndorsementKeyHandle() failed: %v", err) } if ekHnd != ek.handle { t.Fatalf("bad EK-equivalent handle: got 0x%x, wanted 0x%x", ekHnd, ek.handle) } if p { t.Fatalf("generated a new key the second time; that shouldn't happen") } } go-attestation-0.5.1/attest/attest_test.go000066400000000000000000000102611452320553600206620ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package attest import ( "bytes" "flag" "fmt" "reflect" "testing" ) var ( testLocal = flag.Bool("testLocal", false, "run tests against local hardware") ) func TestOpen(t *testing.T) { if !*testLocal { t.SkipNow() } tpm, err := OpenTPM(nil) if err != nil { t.Fatalf("OpenTPM() failed: %v", err) } if tpm == nil { t.Fatalf("Expected non-nil tpm struct") } defer tpm.Close() } func TestInfo(t *testing.T) { if !*testLocal { t.SkipNow() } tpm, err := OpenTPM(nil) if err != nil { t.Fatalf("OpenTPM() failed: %v", err) } defer tpm.Close() info, err := tpm.Info() if err != nil { t.Errorf("tpm.Info() failed: %v", err) } if info.Manufacturer.String() == "" { t.Error("Expected info.Manufacturer.String() != ''") } t.Logf("TPM Info = %+v", info) } func TestEKs(t *testing.T) { if !*testLocal { t.SkipNow() } tpm, err := OpenTPM(nil) if err != nil { t.Fatalf("OpenTPM() failed: %v", err) } defer tpm.Close() eks, err := tpm.EKs() if err != nil { t.Errorf("EKs() failed: %v", err) } if len(eks) == 0 { t.Log("EKs() did not return anything. This could be an issue if an EK is present.") } } func TestAKCreateAndLoad(t *testing.T) { if !*testLocal { t.SkipNow() } tpm, err := OpenTPM(nil) if err != nil { t.Fatalf("OpenTPM() failed: %v", err) } defer tpm.Close() ak, err := tpm.NewAK(nil) if err != nil { t.Fatalf("NewAK() failed: %v", err) } enc, err := ak.Marshal() if err != nil { ak.Close(tpm) t.Fatalf("ak.Marshal() failed: %v", err) } if err := ak.Close(tpm); err != nil { t.Fatalf("ak.Close() failed: %v", err) } loaded, err := tpm.LoadAK(enc) if err != nil { t.Fatalf("LoadKey() failed: %v", err) } defer loaded.Close(tpm) k1, k2 := ak.ak.(*wrappedKey20), loaded.ak.(*wrappedKey20) if !bytes.Equal(k1.public, k2.public) { t.Error("Original & loaded AK public blobs did not match.") t.Logf("Original = %v", k1.public) t.Logf("Loaded = %v", k2.public) } } // chooseEK selects the EK which will be activated against. func chooseEK(t *testing.T, eks []EK) EK { t.Helper() for _, ek := range eks { return ek } t.Fatalf("No suitable EK found") return EK{} } func TestPCRs(t *testing.T) { if !*testLocal { t.SkipNow() } tpm, err := OpenTPM(nil) if err != nil { t.Fatalf("OpenTPM() failed: %v", err) } defer tpm.Close() PCRs, err := tpm.PCRs(HashSHA1) if err != nil { t.Fatalf("PCRs() failed: %v", err) } if len(PCRs) != 24 { t.Errorf("len(PCRs) = %d, want %d", len(PCRs), 24) } for i, pcr := range PCRs { if pcr.Index != i { t.Errorf("PCR index %d does not match map index %d", pcr.Index, i) } } } func TestBug139(t *testing.T) { // Tests ParseAKPublic() with known parseable but non-spec-compliant blobs, and ensure // an error is returned rather than a segfault. // https://github.com/google/go-attestation/issues/139 badBlob := []byte{0, 1, 0, 4, 0, 1, 0, 0, 0, 0, 0, 6, 0, 128, 0, 67, 0, 16, 8, 0, 0, 1, 0, 1, 0, 0} msg := "parsing public key: missing rsa signature scheme" if _, err := ParseAKPublic(TPMVersion20, badBlob); err == nil || err.Error() != msg { t.Errorf("ParseAKPublic() err = %v, want %v", err, msg) } } func TestBug142(t *testing.T) { // Tests ParseEKCertificate() with a malformed size prefix which would overflow // an int16, ensuring an error is returned rather than a panic occurring. input := []byte{0x10, 0x01, 0x00, 0xff, 0xff, 0x20} wantErr := fmt.Errorf("parsing nvram header: ekCert size %d smaller than specified cert length %d", len(input), 65535) if _, err := ParseEKCertificate(input); !reflect.DeepEqual(err, wantErr) { t.Errorf("ParseEKCertificate() = %v, want %v", err, wantErr) } } go-attestation-0.5.1/attest/attest_tpm12_test.go000066400000000000000000000072631452320553600217150ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package attest import ( "bytes" "crypto/rand" "flag" "sort" "testing" ) var ( testTPM12 = flag.Bool("testTPM12", false, "run tests for TPM1.2") tpm12config = &OpenConfig{TPMVersion: TPMVersion12} ) func openTPM12(t *testing.T) *TPM { if !*testTPM12 { t.SkipNow() } tpm, err := OpenTPM(tpm12config) if err != nil { t.Fatalf("Failed to open tpm 1.2: %v", err) } return tpm } func TestTPM12Info(t *testing.T) { tpm := openTPM12(t) defer tpm.Close() Info, err := tpm.Info() if err != nil { t.Fatalf("Failed to get Vendor info: %v", err) } t.Logf("Vendor info: %s\n", Info.VendorInfo) } func TestTPM12PCRs(t *testing.T) { tpm := openTPM12(t) defer tpm.Close() PCRs, err := tpm.PCRs(HashSHA1) if err != nil { t.Fatalf("Failed to get PCR values: %v", err) } var indices []int for i, PCR := range PCRs { if i != PCR.Index { t.Errorf("Index %d does not match the PCRindex %d\n", i, PCR.Index) } indices = append(indices, i) } sort.Ints(indices) for i := range indices { PCR := PCRs[i] t.Logf("PCR %v contains value 0x%x, which was caculated using alg %v\n", PCR.Index, bytes.NewBuffer(PCR.Digest), PCR.DigestAlg) } } func TestTPM12EKs(t *testing.T) { tpm := openTPM12(t) defer tpm.Close() eks, err := tpm.EKs() if err != nil { t.Fatalf("Failed to get EKs: %v", err) } if len(eks) == 0 { t.Fatalf("EKs returned nothing") } } func TestNewAK(t *testing.T) { tpm := openTPM12(t) defer tpm.Close() if _, err := tpm.NewAK(nil); err != nil { t.Fatalf("NewAK failed: %v", err) } } func TestTPMQuote(t *testing.T) { tpm := openTPM12(t) defer tpm.Close() nonce := make([]byte, 20) if _, err := rand.Read(nonce); err != nil { t.Fatalf("reading nonce: %v", err) } ak, err := tpm.NewAK(nil) if err != nil { t.Fatalf("NewAK failed: %v", err) } quote, err := ak.Quote(tpm, nonce, HashSHA1) if err != nil { t.Fatalf("Quote failed: %v", err) } t.Logf("Quote{version: %v, quote: %x, signature: %x}\n", quote.Version, quote.Quote, quote.Signature) } func TestParseAKPublic12(t *testing.T) { tpm := openTPM12(t) defer tpm.Close() ak, err := tpm.NewAK(nil) if err != nil { t.Fatalf("NewAK() failed: %v", err) } defer ak.Close(tpm) params := ak.AttestationParameters() if _, err := ParseAKPublic(TPMVersion12, params.Public); err != nil { t.Errorf("parsing AK public blob: %v", err) } } func TestTPMActivateCredential(t *testing.T) { tpm := openTPM12(t) defer tpm.Close() ak, err := tpm.NewAK(nil) if err != nil { t.Fatalf("NewAK failed: %v", err) } EKs, err := tpm.EKs() if err != nil { t.Fatalf("failed to read EKs: %v", err) } ek := chooseEK(t, EKs) ap := ActivationParameters{ TPMVersion: TPMVersion12, AK: ak.AttestationParameters(), EK: ek.Public, } secret, challenge, err := ap.Generate() if err != nil { t.Fatalf("Generate() failed: %v", err) } validation, err := ak.ActivateCredential(tpm, *challenge) if err != nil { t.Fatalf("ActivateCredential failed: %v", err) } if !bytes.Equal(validation, secret) { t.Errorf("secret mismatch: expected %x, got %x", secret, validation) } t.Logf("validation: %x", validation) } go-attestation-0.5.1/attest/certification.go000066400000000000000000000221431452320553600211440ustar00rootroot00000000000000// Copyright 2021 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package attest import ( "bytes" "crypto" "crypto/rand" "crypto/rsa" "errors" "fmt" "io" "github.com/google/go-tpm/legacy/tpm2" "github.com/google/go-tpm/legacy/tpm2/credactivation" "github.com/google/go-tpm/tpmutil" ) // secureCurves represents a set of secure elliptic curves. For now, // the selection is based on the key size only. var secureCurves = map[tpm2.EllipticCurve]bool{ tpm2.CurveNISTP256: true, tpm2.CurveNISTP384: true, tpm2.CurveNISTP521: true, tpm2.CurveBNP256: true, tpm2.CurveBNP638: true, } // CertificationParameters encapsulates the inputs for certifying an application key. // Only TPM 2.0 is supported at this point. type CertificationParameters struct { // Public represents the key's canonical encoding (a TPMT_PUBLIC structure). // It includes the public key and signing parameters. Public []byte // CreateData represents the properties of a TPM 2.0 key. It is encoded // as a TPMS_CREATION_DATA structure. CreateData []byte // CreateAttestation represents an assertion as to the details of the key. // It is encoded as a TPMS_ATTEST structure. CreateAttestation []byte // CreateSignature represents a signature of the CreateAttestation structure. // It is encoded as a TPMT_SIGNATURE structure. CreateSignature []byte } // VerifyOpts specifies options for the key certification's verification. type VerifyOpts struct { // Public is the public key used to verify key ceritification. Public crypto.PublicKey // Hash is the hash function used for signature verification. It can be // extracted from the properties of the certifying key. Hash crypto.Hash } // ActivateOpts specifies options for the key certification's challenge generation. type ActivateOpts struct { // EK, the endorsement key, describes an asymmetric key whose // private key is permanently bound to the TPM. // // Activation will verify that the provided EK is held on the same // TPM as the key we're certifying. However, it is the caller's responsibility to // ensure the EK they provide corresponds to the the device which // they are trying to associate the certified key with. EK crypto.PublicKey // VerifierKeyNameDigest is the name digest of the public key we're using to // verify the certification of the tpm-generated key being activated. // The verifier key (usually the AK) that owns this digest should be the same // key used in VerifyOpts.Public. // Use tpm2.Public.Name() to produce the digest for a provided key. VerifierKeyNameDigest *tpm2.HashValue } // NewActivateOpts creates options for use in generating an activation challenge for a certified key. // The computed hash is the name digest of the public key used to verify the certification of our key. func NewActivateOpts(verifierPubKey tpm2.Public, ek crypto.PublicKey) (*ActivateOpts, error) { pubName, err := verifierPubKey.Name() if err != nil { return nil, fmt.Errorf("unable to resolve a tpm2.Public Name struct from the given public key struct: %v", err) } return &ActivateOpts{ EK: ek, VerifierKeyNameDigest: pubName.Digest, }, nil } // Verify verifies the TPM2-produced certification parameters checking whether: // - the key length is secure // - the attestation parameters matched the attested key // - the key was TPM-generated and resides within TPM // - the key can sign/decrypt outside-TPM objects // - the signature is successfuly verified against the passed public key // For now, it accepts only RSA verification keys. func (p *CertificationParameters) Verify(opts VerifyOpts) error { pub, err := tpm2.DecodePublic(p.Public) if err != nil { return fmt.Errorf("DecodePublic() failed: %v", err) } att, err := tpm2.DecodeAttestationData(p.CreateAttestation) if err != nil { return fmt.Errorf("DecodeAttestationData() failed: %v", err) } if att.Type != tpm2.TagAttestCertify { return fmt.Errorf("attestation does not apply to certification data, got tag %x", att.Type) } switch pub.Type { case tpm2.AlgRSA: if pub.RSAParameters.KeyBits < minRSABits { return fmt.Errorf("attested key too small: must be at least %d bits but was %d bits", minRSABits, pub.RSAParameters.KeyBits) } case tpm2.AlgECC: if !secureCurves[pub.ECCParameters.CurveID] { return fmt.Errorf("attested key uses insecure curve") } default: return fmt.Errorf("public key of alg 0x%x not supported", pub.Type) } // Make sure the key has sane parameters (e.g., attestation can be faked if an AK // can be used for arbitrary signatures). // We verify the following: // - Key is TPM backed. // - Key is TPM generated. // - Key is not restricted (means it can do arbitrary signing/decrypt ops). // - Key cannot be duplicated. // - Key was generated by a call to TPM_Create*. if att.Magic != tpm20GeneratedMagic { return errors.New("creation attestation was not produced by a TPM") } if (pub.Attributes & tpm2.FlagFixedTPM) == 0 { return errors.New("provided key is exportable") } if (pub.Attributes & tpm2.FlagRestricted) != 0 { return errors.New("provided key is restricted") } if (pub.Attributes & tpm2.FlagFixedParent) == 0 { return errors.New("provided key can be duplicated to a different parent") } if (pub.Attributes & tpm2.FlagSensitiveDataOrigin) == 0 { return errors.New("provided key is not created by TPM") } // Verify the attested creation name matches what is computed from // the public key. match, err := att.AttestedCertifyInfo.Name.MatchesPublic(pub) if err != nil { return err } if !match { return errors.New("certification refers to a different key") } // Check the signature over the attestation data verifies correctly. // TODO: Support ECC certifying keys pk, ok := opts.Public.(*rsa.PublicKey) if !ok { return fmt.Errorf("only RSA verification keys are supported") } if !opts.Hash.Available() { return fmt.Errorf("hash function is unavailable") } hsh := opts.Hash.New() hsh.Write(p.CreateAttestation) if len(p.CreateSignature) < 8 { return fmt.Errorf("signature invalid: length of %d is shorter than 8", len(p.CreateSignature)) } sig, err := tpm2.DecodeSignature(bytes.NewBuffer(p.CreateSignature)) if err != nil { return fmt.Errorf("DecodeSignature() failed: %v", err) } if err := rsa.VerifyPKCS1v15(pk, opts.Hash, hsh.Sum(nil), sig.RSA.Signature); err != nil { return fmt.Errorf("could not verify attestation: %v", err) } return nil } // Generate returns a credential activation challenge, which can be provided // to the TPM to verify the AK parameters given are authentic & the AK // is present on the same TPM as the EK. // // The caller is expected to verify the secret returned from the TPM as // as result of calling ActivateCredential() matches the secret returned here. // The caller should use subtle.ConstantTimeCompare to avoid potential // timing attack vectors. func (p *CertificationParameters) Generate(rnd io.Reader, verifyOpts VerifyOpts, activateOpts ActivateOpts) (secret []byte, ec *EncryptedCredential, err error) { if err := p.Verify(verifyOpts); err != nil { return nil, nil, err } if activateOpts.EK == nil { return nil, nil, errors.New("no EK provided") } secret = make([]byte, activationSecretLen) if rnd == nil { rnd = rand.Reader } if _, err = io.ReadFull(rnd, secret); err != nil { return nil, nil, fmt.Errorf("error generating activation secret: %v", err) } att, err := tpm2.DecodeAttestationData(p.CreateAttestation) if err != nil { return nil, nil, fmt.Errorf("DecodeAttestationData() failed: %v", err) } if att.Type != tpm2.TagAttestCertify { return nil, nil, fmt.Errorf("attestation does not apply to certify data, got %x", att.Type) } cred, encSecret, err := credactivation.Generate(activateOpts.VerifierKeyNameDigest, activateOpts.EK, symBlockSize, secret) if err != nil { return nil, nil, fmt.Errorf("credactivation.Generate() failed: %v", err) } return secret, &EncryptedCredential{ Credential: cred, Secret: encSecret, }, nil } // certify uses AK's handle and the passed signature scheme to certify the key // with the `hnd` handle. func certify(tpm io.ReadWriteCloser, hnd, akHnd tpmutil.Handle, scheme tpm2.SigScheme) (*CertificationParameters, error) { pub, _, _, err := tpm2.ReadPublic(tpm, hnd) if err != nil { return nil, fmt.Errorf("tpm2.ReadPublic() failed: %v", err) } public, err := pub.Encode() if err != nil { return nil, fmt.Errorf("could not encode public key: %v", err) } att, sig, err := tpm2.CertifyEx(tpm, "", "", hnd, akHnd, nil, scheme) if err != nil { return nil, fmt.Errorf("tpm2.Certify() failed: %v", err) } return &CertificationParameters{ Public: public, CreateAttestation: att, CreateSignature: sig, }, nil } go-attestation-0.5.1/attest/certification_test.go000066400000000000000000000225141452320553600222050ustar00rootroot00000000000000// Copyright 2021 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. //go:build (!localtest || !tpm12) && cgo && !gofuzz // +build !localtest !tpm12 // +build cgo // +build !gofuzz package attest import ( "bytes" "crypto" "crypto/rand" "crypto/rsa" "testing" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/go-tpm/legacy/tpm2" ) func TestSimTPM20CertificationParameters(t *testing.T) { sim, tpm := setupSimulatedTPM(t) defer sim.Close() testCertificationParameters(t, tpm) } func TestTPM20CertificationParameters(t *testing.T) { if !*testLocal { t.SkipNow() } tpm, err := OpenTPM(nil) if err != nil { t.Fatalf("OpenTPM() failed: %v", err) } defer tpm.Close() testCertificationParameters(t, tpm) } func testCertificationParameters(t *testing.T, tpm *TPM) { ak, err := tpm.NewAK(nil) if err != nil { t.Fatal(err) } akAttestParams := ak.AttestationParameters() pub, err := tpm2.DecodePublic(akAttestParams.Public) if err != nil { t.Fatal(err) } if pub.Type != tpm2.AlgRSA { t.Fatal("non-RSA verifying key") } pk := &rsa.PublicKey{E: int(pub.RSAParameters.Exponent()), N: pub.RSAParameters.Modulus()} hash, err := pub.RSAParameters.Sign.Hash.Hash() if err != nil { t.Fatal(err) } correctOpts := VerifyOpts{ Public: pk, Hash: hash, } wrongKey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { t.Fatal(err) } wrongHash := crypto.SHA512_256 if wrongHash == correctOpts.Hash { wrongHash = crypto.SHA256 } sk, err := tpm.NewKey(ak, nil) if err != nil { t.Fatal(err) } skCertParams := sk.CertificationParameters() for _, test := range []struct { name string p *CertificationParameters opts VerifyOpts err error }{ { name: "OK", p: &skCertParams, opts: correctOpts, err: nil, }, { name: "wrong public key", p: &skCertParams, opts: VerifyOpts{ Public: wrongKey.Public, Hash: correctOpts.Hash, }, err: cmpopts.AnyError, }, { name: "wrong hash function", p: &skCertParams, opts: VerifyOpts{ Public: correctOpts.Public, Hash: wrongHash, }, err: cmpopts.AnyError, }, { name: "unavailable hash function", p: &skCertParams, opts: VerifyOpts{ Public: correctOpts.Public, Hash: crypto.BLAKE2b_384, }, err: cmpopts.AnyError, }, { name: "modified Public", p: &CertificationParameters{ Public: akAttestParams.Public, CreateAttestation: skCertParams.CreateAttestation, CreateSignature: skCertParams.CreateSignature, }, opts: correctOpts, err: cmpopts.AnyError, }, { name: "modified CreateAttestation", p: &CertificationParameters{ Public: skCertParams.Public, CreateAttestation: akAttestParams.CreateAttestation, CreateSignature: skCertParams.CreateSignature, }, opts: correctOpts, err: cmpopts.AnyError, }, { name: "modified CreateSignature", p: &CertificationParameters{ Public: skCertParams.Public, CreateAttestation: skCertParams.CreateAttestation, CreateSignature: akAttestParams.CreateSignature, }, opts: correctOpts, err: cmpopts.AnyError, }, } { t.Run(test.name, func(t *testing.T) { err := test.p.Verify(test.opts) if test.err == nil && err == nil { return } if got, want := err, test.err; !cmp.Equal(got, want, cmpopts.EquateErrors()) { t.Errorf("p.Verify() err = %v, want = %v", got, want) } }) } } func TestSimTPM20KeyCertification(t *testing.T) { sim, tpm := setupSimulatedTPM(t) defer sim.Close() testKeyCertification(t, tpm) } func TestTPM20KeyCertification(t *testing.T) { if !*testLocal { t.SkipNow() } tpm, err := OpenTPM(nil) if err != nil { t.Fatalf("OpenTPM() failed: %v", err) } defer tpm.Close() testKeyCertification(t, tpm) } func testKeyCertification(t *testing.T, tpm *TPM) { ak, err := tpm.NewAK(nil) if err != nil { t.Fatalf("NewAK() failed: %v", err) } akAttestParams := ak.AttestationParameters() pub, err := tpm2.DecodePublic(akAttestParams.Public) if err != nil { t.Fatalf("DecodePublic() failed: %v", err) } pk := &rsa.PublicKey{E: int(pub.RSAParameters.Exponent()), N: pub.RSAParameters.Modulus()} hash, err := pub.RSAParameters.Sign.Hash.Hash() if err != nil { t.Fatalf("cannot access AK's hash function: %v", err) } verifyOpts := VerifyOpts{ Public: pk, Hash: hash, } for _, test := range []struct { name string opts *KeyConfig err error }{ { name: "default", opts: nil, err: nil, }, { name: "ECDSAP256-SHA256", opts: &KeyConfig{ Algorithm: ECDSA, Size: 256, }, err: nil, }, { name: "ECDSAP384-SHA384", opts: &KeyConfig{ Algorithm: ECDSA, Size: 384, }, err: nil, }, { name: "ECDSAP521-SHA512", opts: &KeyConfig{ Algorithm: ECDSA, Size: 521, }, err: nil, }, { name: "RSA-1024, key too short", opts: &KeyConfig{ Algorithm: RSA, Size: 1024, }, err: cmpopts.AnyError, }, { name: "RSA-2048", opts: &KeyConfig{ Algorithm: RSA, Size: 2048, }, err: nil, }, } { t.Run(test.name, func(t *testing.T) { sk, err := tpm.NewKey(ak, test.opts) if err != nil { t.Fatalf("NewKey() failed: %v", err) } defer sk.Close() p := sk.CertificationParameters() err = p.Verify(verifyOpts) if test.err == nil && err == nil { return } if got, want := err, test.err; !cmp.Equal(got, want, cmpopts.EquateErrors()) { t.Errorf("p.Verify() err = %v, want = %v", got, want) } }) } } func TestKeyActivationTPM20(t *testing.T) { sim, tpm := setupSimulatedTPM(t) defer sim.Close() ak, err := tpm.NewAK(nil) if err != nil { t.Fatalf("error creating a new AK using simulated TPM: %v", err) } akAttestParams := ak.AttestationParameters() pub, err := tpm2.DecodePublic(akAttestParams.Public) if err != nil { t.Fatalf("unable to decode public struct from AK attestation params: %v", err) } if pub.Type != tpm2.AlgRSA { t.Fatal("non-RSA verifying key") } eks, err := tpm.EKs() if err != nil { t.Fatalf("unexpected error retrieving EK from tpm: %v", err) } if len(eks) == 0 { t.Fatal("expected at least one EK from the simulated TPM") } pk := &rsa.PublicKey{E: int(pub.RSAParameters.Exponent()), N: pub.RSAParameters.Modulus()} hash, err := pub.RSAParameters.Sign.Hash.Hash() if err != nil { t.Fatalf("unable to compute hash signature from verifying key's RSA parameters: %v", err) } verifyOpts := VerifyOpts{ Public: pk, Hash: hash, } sk, err := tpm.NewKey(ak, nil) if err != nil { t.Fatalf("unable to create a new TPM-backed key to certify: %v", err) } skCertParams := sk.CertificationParameters() activateOpts, err := NewActivateOpts(pub, eks[0].Public) if err != nil { t.Fatalf("unable to create new ActivateOpts: %v", err) } wrongPub, err := tpm2.DecodePublic(skCertParams.Public) if err != nil { t.Fatalf("unable to decode public struct from CertificationParameters: %v", err) } wrongActivateOpts, err := NewActivateOpts(wrongPub, eks[0].Public) if err != nil { t.Fatalf("unable to create wrong ActivateOpts: %v", err) } for _, test := range []struct { name string p *CertificationParameters verifyOpts VerifyOpts activateOpts ActivateOpts generateErr error activateErr error }{ { name: "OK", p: &skCertParams, verifyOpts: verifyOpts, activateOpts: *activateOpts, generateErr: nil, activateErr: nil, }, { name: "invalid verify opts", p: &skCertParams, verifyOpts: VerifyOpts{}, activateOpts: *activateOpts, generateErr: cmpopts.AnyError, activateErr: nil, }, { name: "invalid activate opts", p: &skCertParams, verifyOpts: verifyOpts, activateOpts: *wrongActivateOpts, generateErr: nil, activateErr: cmpopts.AnyError, }, } { t.Run(test.name, func(t *testing.T) { expectedSecret, encryptedCredentials, err := test.p.Generate(rand.Reader, test.verifyOpts, test.activateOpts) if test.generateErr != nil { if got, want := err, test.generateErr; !cmp.Equal(got, want, cmpopts.EquateErrors()) { t.Errorf("p.Generate() err = %v, want = %v", got, want) } return } else if err != nil { t.Errorf("unexpected p.Generate() error: %v", err) return } actualSecret, err := ak.ActivateCredential(tpm, *encryptedCredentials) if test.activateErr != nil { if got, want := err, test.activateErr; !cmp.Equal(got, want, cmpopts.EquateErrors()) { t.Errorf("p.ActivateCredential() err = %v, want = %v", got, want) } return } else if err != nil { t.Errorf("unexpected p.ActivateCredential() error: %v", err) return } if !bytes.Equal(expectedSecret, actualSecret) { t.Fatalf("Unexpected bytes decoded, expected %x, but got %x", expectedSecret, actualSecret) } }) } } go-attestation-0.5.1/attest/challenge.go000066400000000000000000000071001452320553600202370ustar00rootroot00000000000000package attest import ( "bytes" "crypto/aes" "crypto/cipher" "crypto/rsa" "crypto/sha1" "encoding/binary" "fmt" "io" ) const ( ekBlobTag = 0x000c ekBlobActivateTag = 0x002b ekTypeActivate = 0x0001 algXOR = 0x0000000a schemeESNone = 0x0001 ) type symKeyHeader struct { Alg uint32 Scheme uint16 KeySize uint16 } type activationBlobHeader struct { Tag uint16 KeyHeader symKeyHeader } func makeEmptyPCRInfo() []byte { var b bytes.Buffer binary.Write(&b, binary.BigEndian, uint16(3)) // SIZE_OF_SELECT b.Write([]byte{0x00, 0x00, 0x00}) // empty bitfield for 3 PCRs b.Write([]byte{0x01}) // TPM_LOCALITY_SELECTION = TPM_LOC_ZERO b.Write(bytes.Repeat([]byte{0}, sha1.Size)) // TPM_COMPOSITE_HASH return b.Bytes() } func makeActivationBlob(symKey, akpub []byte) (blob []byte, err error) { akHash := sha1.Sum(akpub) var out bytes.Buffer if err := binary.Write(&out, binary.BigEndian, activationBlobHeader{ Tag: ekBlobActivateTag, KeyHeader: symKeyHeader{ Alg: algXOR, Scheme: schemeESNone, KeySize: uint16(len(symKey)), }, }); err != nil { return nil, err } out.Write(symKey) out.Write(akHash[:]) out.Write(makeEmptyPCRInfo()) return out.Bytes(), nil } type ekBlobHeader struct { Tag uint16 EkType uint16 BlobLen uint32 } func makeEkBlob(activationBlob []byte) []byte { var out bytes.Buffer binary.Write(&out, binary.BigEndian, ekBlobHeader{ Tag: ekBlobTag, EkType: ekTypeActivate, BlobLen: uint32(len(activationBlob)), }) out.Write(activationBlob) return out.Bytes() } func pad(plaintext []byte, bsize int) []byte { pad := bsize - (len(plaintext) % bsize) if pad == 0 { pad = bsize } for i := 0; i < pad; i++ { plaintext = append(plaintext, byte(pad)) } return plaintext } // generateChallenge12 generates a TPM_EK_BLOB challenge for a TPM 1.2 device. // This process is defined in section 15.1 of the TPM 1.2 commands spec, // available at: https://trustedcomputinggroup.org/wp-content/uploads/TPM-Main-Part-3-Commands_v1.2_rev116_01032011.pdf // // asymenc is a TPM_EK_BLOB structure containing a TPM_EK_BLOB_ACTIVATE structure, // encrypted with the EK of the TPM. The contained credential is the aes key // for symenc. // symenc is a structure with TPM_SYM_MODE_CBC leading, then the IV, and then // the secret encrypted with the session key credential contained in asymenc. // To use this, pass asymenc as the input to the TPM_ActivateIdentity command. // Use the returned credential as the aes key to decode the secret in symenc. func generateChallenge12(rand io.Reader, pubkey *rsa.PublicKey, akpub, secret []byte) (asymenc []byte, symenc []byte, err error) { aeskey := make([]byte, 16) iv := make([]byte, 16) if _, err = io.ReadFull(rand, aeskey); err != nil { return nil, nil, err } if _, err = io.ReadFull(rand, iv); err != nil { return nil, nil, err } activationBlob, err := makeActivationBlob(aeskey, akpub) if err != nil { return nil, nil, err } label := []byte{'T', 'C', 'P', 'A'} asymenc, err = rsa.EncryptOAEP(sha1.New(), rand, pubkey, makeEkBlob(activationBlob), label) if err != nil { return nil, nil, fmt.Errorf("EncryptOAEP() failed: %v", err) } block, err := aes.NewCipher(aeskey) if err != nil { return nil, nil, err } cbc := cipher.NewCBCEncrypter(block, iv) secret = pad(secret, len(iv)) symenc = make([]byte, len(secret)) cbc.CryptBlocks(symenc, secret) var symOut bytes.Buffer binary.Write(&symOut, binary.BigEndian, uint32(0x02)) // TPM_SYM_MODE_CBC symOut.Write(iv) symOut.Write(symenc) return asymenc, symOut.Bytes(), nil } go-attestation-0.5.1/attest/challenge_test.go000066400000000000000000000065451452320553600213120ustar00rootroot00000000000000package attest import ( "bytes" "crypto/rand" "crypto/rsa" "crypto/x509" "testing" ) func TestMakeActivationBlob(t *testing.T) { blob, err := makeActivationBlob([]byte{1, 2, 3, 4, 5}, []byte{5, 6, 7, 8}) if err != nil { t.Fatal(err) } if got, want := blob[0:2], []byte{0, 0x2b}; !bytes.Equal(got, want) { t.Errorf("tag = %v, want %v", got, want) } if got, want := blob[2:6], []byte{0, 0, 0, 0x0a}; !bytes.Equal(got, want) { t.Errorf("alg = %v, want %v", got, want) } if got, want := blob[6:8], []byte{0, 1}; !bytes.Equal(got, want) { t.Errorf("scheme = %v, want %v", got, want) } if got, want := blob[8:10], []byte{0, 5}; !bytes.Equal(got, want) { t.Errorf("len = %v, want %v", got, want) } if got, want := blob[10:15], []byte{1, 2, 3, 4, 5}; !bytes.Equal(got, want) { t.Errorf("symKey = %v, want %v", got, want) } if got, want := blob[15:35], []byte{133, 217, 101, 29, 154, 57, 154, 103, 224, 21, 208, 71, 253, 158, 106, 148, 30, 107, 32, 187}; !bytes.Equal(got, want) { t.Errorf("ak digest = %v, want %v", got, want) } if got, want := blob[35:37], []byte{0, 3}; !bytes.Equal(got, want) { t.Errorf("size of select = %v, want %v", got, want) } if got, want := blob[37:40], []byte{0, 0, 0}; !bytes.Equal(got, want) { t.Errorf("select bitfield = %v, want %v", got, want) } if got, want := blob[40:41], []byte{1}; !bytes.Equal(got, want) { t.Errorf("locality = %v, want %v", got, want) } if got, want := blob[41:61], bytes.Repeat([]byte{0}, 20); !bytes.Equal(got, want) { t.Errorf("select digest = %v, want %v", got, want) } } func TestGenerateChallengeSymHeader(t *testing.T) { cert, err := x509.ParseCertificate(decodeBase64("MIID2jCCA4CgAwIBAgIKFsBPsR6KEUuzHjAKBggqhkjOPQQDAjBVMVMwHwYDVQQDExhOdXZvdG9uIFRQTSBSb290IENBIDIxMTAwJQYDVQQKEx5OdXZvdG9uIFRlY2hub2xvZ3kgQ29ycG9yYXRpb24wCQYDVQQGEwJUVzAeFw0xNzEwMTgyMzQ5MjBaFw0zNzEwMTQyMzQ5MjBaMAAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsiqa4C+4hxqQgQ93aFmVq+hvbV6FDvNod24lA1s24pVJzUdOW/D0ORY3TdvRKS1xEh+yPD+iao+XrRGELHSOrGxid/kaTiOF8KdR5BWJwCoedQasqMyQsgZNlU6nKoERcex2G6DDozkdUgrJ/A04qG8tkpEfwmS+0SVWEtDoTb4fzdehKmS32gKcY/I3ZnmpE/5+FCJHKUwIPxHPwAGdhWoYEGsb7ZwG3/S4UuPEfHaab/iwj/WxwbnGtysMu9r1ZkHjQx6FblWVLoXCqrTl0q0samTuW52MffybbOEzn9R0pnfiyQlpL8CLKP4/kBPUGkkvZm2MJsF2cwNRJtEXVAgMBAAGjggHAMIIBvDBKBgNVHREBAf8EQDA+pDwwOjE4MBQGBWeBBQIBEwtpZDo0RTU0NDMwMDAQBgVngQUCAhMHTlBDVDZ4eDAOBgVngQUCAxMFaWQ6MTMwDAYDVR0TAQH/BAIwADAQBgNVHSUECTAHBgVngQUIATAfBgNVHSMEGDAWgBSfu3mqD1JieL7RUJKacXHpajW+9zAOBgNVHQ8BAf8EBAMCBSAwcAYDVR0JBGkwZzAWBgVngQUCEDENMAsMAzIuMAIBAAIBdDBNBgVngQUCEjFEMEICAQABAf+gAwoBAaEDCgEAogMKAQCjFTATFgMzLjEKAQQKAQEBAf+gAwoBAqQPMA0WBTE0MC0yCgECAQEApQMBAQAwQQYDVR0gBDowODA2BgRVHSAAMC4wLAYIKwYBBQUHAgEWIGh0dHA6Ly93d3cubnV2b3Rvbi5jb20vc2VjdXJpdHkvMGgGCCsGAQUFBwEBBFwwWjBYBggrBgEFBQcwAoZMaHR0cDovL3d3dy5udXZvdG9uLmNvbS9zZWN1cml0eS9OVEMtVFBNLUVLLUNlcnQvTnV2b3RvbiBUUE0gUm9vdCBDQSAyMTEwLmNlcjAKBggqhkjOPQQDAgNIADBFAiEAtct+vD/l1Vv9TJOl6oRSI+IZk+k31YIqcscDZEGpZI0CIFFAsVKlFnQnXKTxo7sx9dGOio92Bschl0TQLQhVv0K7", t)) if err != nil { t.Fatal(err) } _, sym, err := generateChallenge12(rand.Reader, cert.PublicKey.(*rsa.PublicKey), []byte("pubkey yo"), []byte("secretz")) if err != nil { t.Fatal(err) } if got, want := len(sym), 36; got != want { t.Errorf("len(sym) = %v, want %v", got, want) } if got, want := sym[0:4], []byte{0, 0, 0, 2}; !bytes.Equal(got, want) { t.Errorf("symmetric mode = %v, want %v", got, want) } } go-attestation-0.5.1/attest/eventlog.go000066400000000000000000000576771452320553600201700ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package attest import ( "bytes" "crypto" "crypto/rsa" "crypto/sha1" "crypto/sha256" "encoding/binary" "errors" "fmt" "io" "sort" "strings" // Ensure hashes are available. _ "crypto/sha256" "github.com/google/go-tpm/legacy/tpm2" "github.com/google/go-tpm/tpmutil" ) // ReplayError describes the parsed events that failed to verify against // a particular PCR. type ReplayError struct { Events []Event // InvalidPCRs reports the set of PCRs where the event log replay failed. InvalidPCRs []int } func (e ReplayError) affected(pcr int) bool { for _, p := range e.InvalidPCRs { if p == pcr { return true } } return false } // Error returns a human-friendly description of replay failures. func (e ReplayError) Error() string { return fmt.Sprintf("event log failed to verify: the following registers failed to replay: %v", e.InvalidPCRs) } // EventType indicates what kind of data an event is reporting. // // https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClientSpecPlat_TPM_2p0_1p04_pub.pdf#page=103 type EventType uint32 var eventTypeStrings = map[uint32]string{ 0x00000000: "EV_PREBOOT_CERT", 0x00000001: "EV_POST_CODE", 0x00000002: "EV_UNUSED", 0x00000003: "EV_NO_ACTION", 0x00000004: "EV_SEPARATOR", 0x00000005: "EV_ACTION", 0x00000006: "EV_EVENT_TAG", 0x00000007: "EV_S_CRTM_CONTENTS", 0x00000008: "EV_S_CRTM_VERSION", 0x00000009: "EV_CPU_MICROCODE", 0x0000000A: "EV_PLATFORM_CONFIG_FLAGS", 0x0000000B: "EV_TABLE_OF_DEVICES", 0x0000000C: "EV_COMPACT_HASH", 0x0000000D: "EV_IPL", 0x0000000E: "EV_IPL_PARTITION_DATA", 0x0000000F: "EV_NONHOST_CODE", 0x00000010: "EV_NONHOST_CONFIG", 0x00000011: "EV_NONHOST_INFO", 0x00000012: "EV_OMIT_BOOT_DEVICE_EVENTS", 0x80000000: "EV_EFI_EVENT_BASE", 0x80000001: "EV_EFI_VARIABLE_DRIVER_CONFIG", 0x80000002: "EV_EFI_VARIABLE_BOOT", 0x80000003: "EV_EFI_BOOT_SERVICES_APPLICATION", 0x80000004: "EV_EFI_BOOT_SERVICES_DRIVER", 0x80000005: "EV_EFI_RUNTIME_SERVICES_DRIVER", 0x80000006: "EV_EFI_GPT_EVENT", 0x80000007: "EV_EFI_ACTION", 0x80000008: "EV_EFI_PLATFORM_FIRMWARE_BLOB", 0x80000009: "EV_EFI_HANDOFF_TABLES", 0x80000010: "EV_EFI_HCRTM_EVENT", 0x800000E0: "EV_EFI_VARIABLE_AUTHORITY", } // String returns the Spec name of the EventType, for example "EV_ACTION". If // unknown, it returns a formatted string of the EventType value. func (e EventType) String() string { if s, ok := eventTypeStrings[uint32(e)]; ok { return s } // NOTE: 0x00000013-0x0000FFFF are reserverd. Should we include that // information in the formatting? return fmt.Sprintf("EventType(0x%08x)", uint32(e)) } // Event is a single event from a TCG event log. This reports descrete items such // as BIOS measurements or EFI states. // // There are many pitfalls for using event log events correctly to determine the // state of a machine[1]. In general it's much safer to only rely on the raw PCR // values and use the event log for debugging. // // [1] https://github.com/google/go-attestation/blob/master/docs/event-log-disclosure.md type Event struct { // order of the event in the event log. sequence int // Index of the PCR that this event was replayed against. Index int // Untrusted type of the event. This value is not verified by event log replays // and can be tampered with. It should NOT be used without additional context, // and unrecognized event types should result in errors. Type EventType // Data of the event. For certain kinds of events, this must match the event // digest to be valid. Data []byte // Digest is the verified digest of the event data. While an event can have // multiple for different hash values, this is the one that was matched to the // PCR value. Digest []byte // TODO(ericchiang): Provide examples or links for which event types must // match their data to their digest. } func (e *Event) digestEquals(b []byte) error { if len(e.Digest) == 0 { return errors.New("no digests present") } switch len(e.Digest) { case crypto.SHA256.Size(): s := sha256.Sum256(b) if bytes.Equal(s[:], e.Digest) { return nil } case crypto.SHA1.Size(): s := sha1.Sum(b) if bytes.Equal(s[:], e.Digest) { return nil } default: return fmt.Errorf("cannot compare hash of length %d", len(e.Digest)) } return fmt.Errorf("digest (len %d) does not match", len(e.Digest)) } // EventLog is a parsed measurement log. This contains unverified data representing // boot events that must be replayed against PCR values to determine authenticity. type EventLog struct { // Algs holds the set of algorithms that the event log uses. Algs []HashAlg rawEvents []rawEvent specIDEvent *specIDEvent } func (e *EventLog) clone() *EventLog { out := EventLog{ Algs: make([]HashAlg, len(e.Algs)), rawEvents: make([]rawEvent, len(e.rawEvents)), } copy(out.Algs, e.Algs) copy(out.rawEvents, e.rawEvents) if e.specIDEvent != nil { dupe := *e.specIDEvent out.specIDEvent = &dupe } return &out } // Events returns events that have not been replayed against the PCR values and // are therefore unverified. The returned events contain the digest that matches // the provided hash algorithm, or are empty if that event didn't contain a // digest for that hash. // // This method is insecure and should only be used for debugging. func (e *EventLog) Events(hash HashAlg) []Event { var events []Event for _, re := range e.rawEvents { ev := Event{ Index: re.index, Type: re.typ, Data: re.data, } for _, digest := range re.digests { if hash.cryptoHash() != digest.hash { continue } ev.Digest = digest.data break } events = append(events, ev) } return events } // Verify replays the event log against a TPM's PCR values, returning the // events which could be matched to a provided PCR value. // // PCRs provide no security guarantees unless they're attested to have been // generated by a TPM. Verify does not perform these checks. // // An error is returned if the replayed digest for events with a given PCR // index do not match any provided value for that PCR index. func (e *EventLog) Verify(pcrs []PCR) ([]Event, error) { events, err := e.verify(pcrs) // If there were any issues replaying the PCRs, try each of the workarounds // in turn. // TODO(jsonp): Allow workarounds to be combined. if rErr, isReplayErr := err.(ReplayError); isReplayErr { for _, wkrd := range eventlogWorkarounds { if !rErr.affected(wkrd.affectedPCR) { continue } el := e.clone() if err := wkrd.apply(el); err != nil { return nil, fmt.Errorf("failed applying workaround %q: %v", wkrd.id, err) } if events, err := el.verify(pcrs); err == nil { return events, nil } } } return events, err } func (e *EventLog) verify(pcrs []PCR) ([]Event, error) { events, err := replayEvents(e.rawEvents, pcrs) if err != nil { if _, isReplayErr := err.(ReplayError); isReplayErr { return nil, err } return nil, fmt.Errorf("pcrs failed to replay: %v", err) } return events, nil } type rawAttestationData struct { Version [4]byte // This MUST be 1.1.0.0 Fixed [4]byte // This SHALL always be the string ‘QUOT’ Digest [20]byte // PCR Composite Hash Nonce [20]byte // Nonce Hash } var ( fixedQuote = [4]byte{'Q', 'U', 'O', 'T'} ) type rawPCRComposite struct { Size uint16 // always 3 PCRMask [3]byte Values tpmutil.U32Bytes } func (a *AKPublic) validate12Quote(quote Quote, pcrs []PCR, nonce []byte) error { pub, ok := a.Public.(*rsa.PublicKey) if !ok { return fmt.Errorf("unsupported public key type: %T", a.Public) } qHash := sha1.Sum(quote.Quote) if err := rsa.VerifyPKCS1v15(pub, crypto.SHA1, qHash[:], quote.Signature); err != nil { return fmt.Errorf("invalid quote signature: %v", err) } var att rawAttestationData if _, err := tpmutil.Unpack(quote.Quote, &att); err != nil { return fmt.Errorf("parsing quote: %v", err) } // TODO(ericchiang): validate Version field. if att.Nonce != sha1.Sum(nonce) { return fmt.Errorf("invalid nonce") } if att.Fixed != fixedQuote { return fmt.Errorf("quote wasn't a QUOT object: %x", att.Fixed) } // See 5.4.1 Creating a PCR composite hash sort.Slice(pcrs, func(i, j int) bool { return pcrs[i].Index < pcrs[j].Index }) var ( pcrMask [3]byte // bitmap indicating which PCRs are active values []byte // appended values of all PCRs ) for _, pcr := range pcrs { if pcr.Index < 0 || pcr.Index >= 24 { return fmt.Errorf("invalid PCR index: %d", pcr.Index) } pcrMask[pcr.Index/8] |= 1 << uint(pcr.Index%8) values = append(values, pcr.Digest...) } composite, err := tpmutil.Pack(rawPCRComposite{3, pcrMask, values}) if err != nil { return fmt.Errorf("marshaling PCRs: %v", err) } if att.Digest != sha1.Sum(composite) { return fmt.Errorf("PCRs passed didn't match quote: %v", err) } // All provided PCRs are used to construct the composite hash which // is verified against the quote (for TPM 1.2), so if we got this far, // all PCR values are verified. for i := range pcrs { pcrs[i].quoteVerified = true } return nil } func (a *AKPublic) validate20Quote(quote Quote, pcrs []PCR, nonce []byte) error { sig, err := tpm2.DecodeSignature(bytes.NewBuffer(quote.Signature)) if err != nil { return fmt.Errorf("parse quote signature: %v", err) } sigHash := a.Hash.New() sigHash.Write(quote.Quote) switch pub := a.Public.(type) { case *rsa.PublicKey: if sig.RSA == nil { return fmt.Errorf("rsa public key provided for ec signature") } sigBytes := []byte(sig.RSA.Signature) if err := rsa.VerifyPKCS1v15(pub, a.Hash, sigHash.Sum(nil), sigBytes); err != nil { return fmt.Errorf("invalid quote signature: %v", err) } default: // TODO(ericchiang): support ecdsa return fmt.Errorf("unsupported public key type %T", pub) } att, err := tpm2.DecodeAttestationData(quote.Quote) if err != nil { return fmt.Errorf("parsing quote signature: %v", err) } if att.Type != tpm2.TagAttestQuote { return fmt.Errorf("attestation isn't a quote, tag of type 0x%x", att.Type) } if !bytes.Equal([]byte(att.ExtraData), nonce) { return fmt.Errorf("nonce = %#v, want %#v", []byte(att.ExtraData), nonce) } pcrByIndex := map[int][]byte{} pcrDigestAlg := HashAlg(att.AttestedQuoteInfo.PCRSelection.Hash).cryptoHash() for _, pcr := range pcrs { if pcr.DigestAlg == pcrDigestAlg { pcrByIndex[pcr.Index] = pcr.Digest } } sigHash.Reset() quotePCRs := make(map[int]struct{}, len(att.AttestedQuoteInfo.PCRSelection.PCRs)) for _, index := range att.AttestedQuoteInfo.PCRSelection.PCRs { digest, ok := pcrByIndex[index] if !ok { return fmt.Errorf("quote was over PCR %d which wasn't provided", index) } quotePCRs[index] = struct{}{} sigHash.Write(digest) } for index := range pcrByIndex { if _, exists := quotePCRs[index]; !exists { return fmt.Errorf("provided PCR %d was not included in quote", index) } } if !bytes.Equal(sigHash.Sum(nil), att.AttestedQuoteInfo.PCRDigest) { return fmt.Errorf("quote digest didn't match pcrs provided") } // If we got this far, all included PCRs with a digest algorithm matching that // of the quote are verified. As such, we set their quoteVerified bit. for i, pcr := range pcrs { if _, exists := quotePCRs[pcr.Index]; exists && pcr.DigestAlg == pcrDigestAlg { pcrs[i].quoteVerified = true } } return nil } func extend(pcr PCR, replay []byte, e rawEvent, locality byte) (pcrDigest []byte, eventDigest []byte, err error) { h := pcr.DigestAlg for _, digest := range e.digests { if digest.hash != pcr.DigestAlg { continue } if len(digest.data) != len(pcr.Digest) { return nil, nil, fmt.Errorf("digest data length (%d) doesn't match PCR digest length (%d)", len(digest.data), len(pcr.Digest)) } hash := h.New() if len(replay) != 0 { hash.Write(replay) } else { b := make([]byte, h.Size()) b[h.Size()-1] = locality hash.Write(b) } hash.Write(digest.data) return hash.Sum(nil), digest.data, nil } return nil, nil, fmt.Errorf("no event digest matches pcr algorithm: %v", pcr.DigestAlg) } // replayPCR replays the event log for a specific PCR, using pcr and // event digests with the algorithm in pcr. An error is returned if the // replayed values do not match the final PCR digest, or any event tagged // with that PCR does not possess an event digest with the specified algorithm. func replayPCR(rawEvents []rawEvent, pcr PCR) ([]Event, bool) { var ( replay []byte outEvents []Event locality byte ) for _, e := range rawEvents { if e.index != pcr.Index { continue } // If TXT is enabled then the first event for PCR0 // should be a StartupLocality event. The final byte // of this event indicates the locality from which // TPM2_Startup() was issued. The initial value of // PCR0 is equal to the locality. if e.typ == eventTypeNoAction { if pcr.Index == 0 && len(e.data) == 17 && strings.HasPrefix(string(e.data), "StartupLocality") { locality = e.data[len(e.data)-1] } continue } replayValue, digest, err := extend(pcr, replay, e, locality) if err != nil { return nil, false } replay = replayValue outEvents = append(outEvents, Event{sequence: e.sequence, Data: e.data, Digest: digest, Index: pcr.Index, Type: e.typ}) } if len(outEvents) > 0 && !bytes.Equal(replay, pcr.Digest) { return nil, false } return outEvents, true } type pcrReplayResult struct { events []Event successful bool } func replayEvents(rawEvents []rawEvent, pcrs []PCR) ([]Event, error) { var ( invalidReplays []int verifiedEvents []Event allPCRReplays = map[int][]pcrReplayResult{} ) // Replay the event log for every PCR and digest algorithm combination. for _, pcr := range pcrs { events, ok := replayPCR(rawEvents, pcr) allPCRReplays[pcr.Index] = append(allPCRReplays[pcr.Index], pcrReplayResult{events, ok}) } // Record PCR indices which do not have any successful replay. Record the // events for a successful replay. pcrLoop: for i, replaysForPCR := range allPCRReplays { for _, replay := range replaysForPCR { if replay.successful { // We consider the PCR verified at this stage: The replay of values with // one digest algorithm matched a provided value. // As such, we save the PCR's events, and proceed to the next PCR. verifiedEvents = append(verifiedEvents, replay.events...) continue pcrLoop } } invalidReplays = append(invalidReplays, i) } if len(invalidReplays) > 0 { events := make([]Event, 0, len(rawEvents)) for _, e := range rawEvents { events = append(events, Event{e.sequence, e.index, e.typ, e.data, nil}) } return nil, ReplayError{ Events: events, InvalidPCRs: invalidReplays, } } sort.Slice(verifiedEvents, func(i int, j int) bool { return verifiedEvents[i].sequence < verifiedEvents[j].sequence }) return verifiedEvents, nil } // EV_NO_ACTION is a special event type that indicates information to the parser // instead of holding a measurement. For TPM 2.0, this event type is used to signal // switching from SHA1 format to a variable length digest. // // https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClientSpecPlat_TPM_2p0_1p04_pub.pdf#page=110 const eventTypeNoAction = 0x03 // ParseEventLog parses an unverified measurement log. func ParseEventLog(measurementLog []byte) (*EventLog, error) { var specID *specIDEvent r := bytes.NewBuffer(measurementLog) parseFn := parseRawEvent var el EventLog e, err := parseFn(r, specID) if err != nil { return nil, fmt.Errorf("parse first event: %v", err) } if e.typ == eventTypeNoAction && len(e.data) >= binary.Size(specIDEventHeader{}) { specID, err = parseSpecIDEvent(e.data) if err != nil { return nil, fmt.Errorf("failed to parse spec ID event: %v", err) } for _, alg := range specID.algs { switch tpm2.Algorithm(alg.ID) { case tpm2.AlgSHA1: el.Algs = append(el.Algs, HashSHA1) case tpm2.AlgSHA256: el.Algs = append(el.Algs, HashSHA256) } } if len(el.Algs) == 0 { return nil, fmt.Errorf("measurement log didn't use sha1 or sha256 digests") } // Switch to parsing crypto agile events. Don't include this in the // replayed events since it intentionally doesn't extend the PCRs. // // Note that this doesn't actually guarantee that events have SHA256 // digests. parseFn = parseRawEvent2 el.specIDEvent = specID } else { el.Algs = []HashAlg{HashSHA1} el.rawEvents = append(el.rawEvents, e) } sequence := 1 for r.Len() != 0 { e, err := parseFn(r, specID) if err != nil { return nil, err } e.sequence = sequence sequence++ el.rawEvents = append(el.rawEvents, e) } return &el, nil } type specIDEvent struct { algs []specAlgSize } type specAlgSize struct { ID uint16 Size uint16 } // Expected values for various Spec ID Event fields. // https://trustedcomputinggroup.org/wp-content/uploads/EFI-Protocol-Specification-rev13-160330final.pdf#page=19 var wantSignature = [16]byte{0x53, 0x70, 0x65, 0x63, 0x20, 0x49, 0x44, 0x20, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x33, 0x00} // "Spec ID Event03\0" const ( wantMajor = 2 wantMinor = 0 wantErrata = 0 ) type specIDEventHeader struct { Signature [16]byte PlatformClass uint32 VersionMinor uint8 VersionMajor uint8 Errata uint8 UintnSize uint8 NumAlgs uint32 } // parseSpecIDEvent parses a TCG_EfiSpecIDEventStruct structure from the reader. // // https://trustedcomputinggroup.org/wp-content/uploads/EFI-Protocol-Specification-rev13-160330final.pdf#page=18 func parseSpecIDEvent(b []byte) (*specIDEvent, error) { r := bytes.NewReader(b) var header specIDEventHeader if err := binary.Read(r, binary.LittleEndian, &header); err != nil { return nil, fmt.Errorf("reading event header: %w: %X", err, b) } if header.Signature != wantSignature { return nil, fmt.Errorf("invalid spec id signature: %x", header.Signature) } if header.VersionMajor != wantMajor { return nil, fmt.Errorf("invalid spec major version, got %02x, wanted %02x", header.VersionMajor, wantMajor) } if header.VersionMinor != wantMinor { return nil, fmt.Errorf("invalid spec minor version, got %02x, wanted %02x", header.VersionMajor, wantMinor) } // TODO(ericchiang): Check errata? Or do we expect that to change in ways // we're okay with? specAlg := specAlgSize{} e := specIDEvent{} for i := 0; i < int(header.NumAlgs); i++ { if err := binary.Read(r, binary.LittleEndian, &specAlg); err != nil { return nil, fmt.Errorf("reading algorithm: %v", err) } e.algs = append(e.algs, specAlg) } var vendorInfoSize uint8 if err := binary.Read(r, binary.LittleEndian, &vendorInfoSize); err != nil { return nil, fmt.Errorf("reading vender info size: %v", err) } if r.Len() != int(vendorInfoSize) { return nil, fmt.Errorf("reading vendor info, expected %d remaining bytes, got %d", vendorInfoSize, r.Len()) } return &e, nil } type digest struct { hash crypto.Hash data []byte } type rawEvent struct { sequence int index int typ EventType data []byte digests []digest } // TPM 1.2 event log format. See "5.1 SHA1 Event Log Entry Format" // https://trustedcomputinggroup.org/wp-content/uploads/EFI-Protocol-Specification-rev13-160330final.pdf#page=15 type rawEventHeader struct { PCRIndex uint32 Type uint32 Digest [20]byte EventSize uint32 } type eventSizeErr struct { eventSize uint32 logSize int } func (e *eventSizeErr) Error() string { return fmt.Sprintf("event data size (%d bytes) is greater than remaining measurement log (%d bytes)", e.eventSize, e.logSize) } func parseRawEvent(r *bytes.Buffer, specID *specIDEvent) (event rawEvent, err error) { var h rawEventHeader if err = binary.Read(r, binary.LittleEndian, &h); err != nil { return event, fmt.Errorf("header deserialization error: %w", err) } if h.EventSize > uint32(r.Len()) { return event, &eventSizeErr{h.EventSize, r.Len()} } data := make([]byte, int(h.EventSize)) if _, err := io.ReadFull(r, data); err != nil { return event, fmt.Errorf("reading data error: %w", err) } digests := []digest{{hash: crypto.SHA1, data: h.Digest[:]}} return rawEvent{ typ: EventType(h.Type), data: data, index: int(h.PCRIndex), digests: digests, }, nil } // TPM 2.0 event log format. See "5.2 Crypto Agile Log Entry Format" // https://trustedcomputinggroup.org/wp-content/uploads/EFI-Protocol-Specification-rev13-160330final.pdf#page=15 type rawEvent2Header struct { PCRIndex uint32 Type uint32 } func parseRawEvent2(r *bytes.Buffer, specID *specIDEvent) (event rawEvent, err error) { var h rawEvent2Header if err = binary.Read(r, binary.LittleEndian, &h); err != nil { return event, err } event.typ = EventType(h.Type) event.index = int(h.PCRIndex) // parse the event digests var numDigests uint32 if err := binary.Read(r, binary.LittleEndian, &numDigests); err != nil { return event, err } for i := 0; i < int(numDigests); i++ { var algID uint16 if err := binary.Read(r, binary.LittleEndian, &algID); err != nil { return event, err } var digest digest for _, alg := range specID.algs { if alg.ID != algID { continue } if r.Len() < int(alg.Size) { return event, fmt.Errorf("reading digest: %v", io.ErrUnexpectedEOF) } digest.data = make([]byte, alg.Size) digest.hash = HashAlg(alg.ID).cryptoHash() } if len(digest.data) == 0 { return event, fmt.Errorf("unknown algorithm ID %x", algID) } if _, err := io.ReadFull(r, digest.data); err != nil { return event, err } event.digests = append(event.digests, digest) } // parse event data var eventSize uint32 if err = binary.Read(r, binary.LittleEndian, &eventSize); err != nil { return event, err } if eventSize > uint32(r.Len()) { return event, &eventSizeErr{eventSize, r.Len()} } event.data = make([]byte, int(eventSize)) if _, err := io.ReadFull(r, event.data); err != nil { return event, err } return event, err } // AppendEvents takes a series of TPM 2.0 event logs and combines // them into a single sequence of events with a single header. // // Additional logs must not use a digest algorithm which was not // present in the original log. func AppendEvents(base []byte, additional ...[]byte) ([]byte, error) { baseLog, err := ParseEventLog(base) if err != nil { return nil, fmt.Errorf("base: %v", err) } if baseLog.specIDEvent == nil { return nil, errors.New("tpm 1.2 event logs cannot be combined") } outBuff := make([]byte, len(base)) copy(outBuff, base) out := bytes.NewBuffer(outBuff) for i, l := range additional { log, err := ParseEventLog(l) if err != nil { return nil, fmt.Errorf("log %d: %v", i, err) } if log.specIDEvent == nil { return nil, fmt.Errorf("log %d: cannot use tpm 1.2 event log as a source", i) } algCheck: for _, alg := range log.specIDEvent.algs { for _, baseAlg := range baseLog.specIDEvent.algs { if baseAlg == alg { continue algCheck } } return nil, fmt.Errorf("log %d: cannot use digest (%+v) not present in base log", i, alg) } for x, e := range log.rawEvents { // Serialize header (PCR index, event type, number of digests) binary.Write(out, binary.LittleEndian, rawEvent2Header{ PCRIndex: uint32(e.index), Type: uint32(e.typ), }) binary.Write(out, binary.LittleEndian, uint32(len(e.digests))) // Serialize digests for _, d := range e.digests { var algID uint16 switch d.hash { case crypto.SHA256: algID = uint16(HashSHA256) case crypto.SHA1: algID = uint16(HashSHA1) default: return nil, fmt.Errorf("log %d: event %d: unhandled hash function %v", i, x, d.hash) } binary.Write(out, binary.LittleEndian, algID) out.Write(d.data) } // Serialize event data binary.Write(out, binary.LittleEndian, uint32(len(e.data))) out.Write(e.data) } } return out.Bytes(), nil } go-attestation-0.5.1/attest/eventlog_fuzz.go000066400000000000000000000016061452320553600212230ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. //go:build gofuzz // +build gofuzz package attest // FuzzParseEventLog is an exported entrypoint for fuzzers to test the eventlog // parser. This method should not be used for any other purpose. func FuzzParseEventLog(data []byte) int { _, err := ParseEventLog(data) if err != nil { return 0 } return 1 } go-attestation-0.5.1/attest/eventlog_test.go000066400000000000000000000247071452320553600212130ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package attest import ( "bytes" "encoding/base64" "encoding/json" "os" "testing" "github.com/google/go-tpm/legacy/tpm2" ) // Dump describes the layout of serialized information from the dump command. type Dump struct { Static struct { TPMVersion TPMVersion EKPem []byte } AK AttestationParameters Quote struct { Nonce []byte Alg HashAlg Quote []byte Signature []byte } Log struct { PCRs []PCR PCRAlg tpm2.Algorithm Raw []byte // The measured boot log in binary form. } } func TestParseEventLogWindows(t *testing.T) { testParseEventLog(t, "testdata/windows_gcp_shielded_vm.json") } func TestParseEventLogLinux(t *testing.T) { testParseEventLog(t, "testdata/linux_tpm12.json") } func testParseEventLog(t *testing.T, testdata string) { data, err := os.ReadFile(testdata) if err != nil { t.Fatalf("reading test data: %v", err) } var dump Dump if err := json.Unmarshal(data, &dump); err != nil { t.Fatalf("parsing test data: %v", err) } if _, err := ParseEventLog(dump.Log.Raw); err != nil { t.Fatalf("parsing event log: %v", err) } } func TestParseCryptoAgileEventLog(t *testing.T) { data, err := os.ReadFile("testdata/crypto_agile_eventlog") if err != nil { t.Fatalf("reading test data: %v", err) } if _, err := ParseEventLog(data); err != nil { t.Fatalf("parsing event log: %v", err) } } func TestEventLogLinux(t *testing.T) { testEventLog(t, "testdata/linux_tpm12.json") } func TestEventLog(t *testing.T) { testEventLog(t, "testdata/windows_gcp_shielded_vm.json") } func testEventLog(t *testing.T, testdata string) { data, err := os.ReadFile(testdata) if err != nil { t.Fatalf("reading test data: %v", err) } var dump Dump if err := json.Unmarshal(data, &dump); err != nil { t.Fatalf("parsing test data: %v", err) } ak, err := ParseAKPublic(dump.Static.TPMVersion, dump.AK.Public) if err != nil { t.Fatalf("parsing AK: %v", err) } if err := ak.Verify(Quote{ Version: dump.Static.TPMVersion, Quote: dump.Quote.Quote, Signature: dump.Quote.Signature, }, dump.Log.PCRs, dump.Quote.Nonce); err != nil { t.Fatalf("verifying quote: %v", err) } el, err := ParseEventLog(dump.Log.Raw) if err != nil { t.Fatalf("parsing event log: %v", err) } events, err := el.Verify(dump.Log.PCRs) if err != nil { t.Fatalf("validating event log: %v", err) } for i, e := range events { if e.sequence != i { t.Errorf("event out of order: events[%d].sequence = %d, want %d", i, e.sequence, i) } } } func TestParseEventLogEventSizeTooLarge(t *testing.T) { data := []byte{ // PCR index 0x30, 0x34, 0x39, 0x33, // type 0x36, 0x30, 0x30, 0x32, // Digest 0x31, 0x39, 0x36, 0x33, 0x39, 0x34, 0x34, 0x37, 0x39, 0x32, 0x31, 0x32, 0x32, 0x37, 0x39, 0x30, 0x34, 0x30, 0x31, 0x6d, // Event size (3.183 GB) 0xbd, 0xbf, 0xef, 0x47, // "event data" 0x00, 0x00, 0x00, 0x00, } // If this doesn't panic, the test passed // TODO(ericchiang): use errors.As once go-attestation switches to Go 1.13. _, err := ParseEventLog(data) if err == nil { t.Fatalf("expected parsing invalid event log to fail") } } func TestParseEventLogEventSizeZero(t *testing.T) { data := []byte{ // PCR index 0x4, 0x0, 0x0, 0x0, // type 0xd, 0x0, 0x0, 0x0, // Digest 0x94, 0x2d, 0xb7, 0x4a, 0xa7, 0x37, 0x5b, 0x23, 0xea, 0x23, 0x58, 0xeb, 0x3b, 0x31, 0x59, 0x88, 0x60, 0xf6, 0x90, 0x59, // Event size (0 B) 0x0, 0x0, 0x0, 0x0, // no "event data" } if _, err := parseRawEvent(bytes.NewBuffer(data), nil); err != nil { t.Fatalf("parsing event log: %v", err) } } func TestParseEventLog2EventSizeZero(t *testing.T) { data := []byte{ // PCR index 0x0, 0x0, 0x0, 0x0, // type 0x7, 0x0, 0x0, 0x0, // number of digests 0x1, 0x0, 0x0, 0x0, // algorithm 0xb, 0x0, // Digest 0xc8, 0xe3, 0x88, 0xb4, 0x79, 0x12, 0x86, 0x0c, 0x66, 0xa1, 0x5d, 0xad, 0xc4, 0x34, 0xf5, 0xdf, 0x73, 0x6c, 0x3a, 0xb4, 0xbe, 0x52, 0x07, 0x08, 0xdf, 0xac, 0x48, 0x2d, 0x71, 0xce, 0xa0, 0x73, // Event size (0 B) 0x0, 0x0, 0x0, 0x0, // no "event data" } specID := &specIDEvent{ algs: []specAlgSize{ {ID: uint16(tpm2.AlgSHA256), Size: 32}, }, } if _, err := parseRawEvent2(bytes.NewBuffer(data), specID); err != nil { t.Fatalf("parsing event log: %v", err) } } func TestParseShortNoAction(t *testing.T) { // https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClientSpecPlat_TPM_2p0_1p04_pub.pdf#page=110 // says: "For EV_NO_ACTION events other than the EFI Specification ID event // (Section 9.4.5.1) the log will ...". Thus it is concluded other // than "EFI Specification ID" events are also valid as NO_ACTION events. // // Currently we just assume that such events will have Data shorter than // "EFI Specification ID" field. data, err := os.ReadFile("testdata/short_no_action_eventlog") if err != nil { t.Fatalf("reading test data: %v", err) } if _, err := ParseEventLog(data); err != nil { t.Fatalf("parsing event log: %v", err) } } func TestParseSpecIDEvent(t *testing.T) { tests := []struct { name string data []byte want []uint16 wantErr bool }{ { name: "sha1", data: append( []byte("Spec ID Event03"), 0x0, 0x0, 0x0, 0x0, 0x0, // platform class 0x0, // version minor 0x2, // version major 0x0, // errata 0x8, // uintn size 0x1, 0x0, 0x0, 0x0, // num algs 0x04, 0x0, // SHA1 0x14, 0x0, // size 0x2, // vendor info size 0x0, 0x0, ), want: []uint16{0x0004}, }, { name: "sha1_and_sha256", data: append( []byte("Spec ID Event03"), 0x0, 0x0, 0x0, 0x0, 0x0, // platform class 0x0, // version minor 0x2, // version major 0x0, // errata 0x8, // uintn size 0x2, 0x0, 0x0, 0x0, // num algs 0x04, 0x0, // SHA1 0x14, 0x0, // size 0x0B, 0x0, // SHA256 0x20, 0x0, // size 0x2, // vendor info size 0x0, 0x0, ), want: []uint16{0x0004, 0x000B}, }, { name: "invalid_version", data: append( []byte("Spec ID Event03"), 0x0, 0x0, 0x0, 0x0, 0x0, // platform class 0x2, // version minor 0x1, // version major 0x0, // errata 0x8, // uintn size 0x2, 0x0, 0x0, 0x0, // num algs 0x04, 0x0, // SHA1 0x14, 0x0, // size 0x0B, 0x0, // SHA256 0x20, 0x0, // size 0x2, // vendor info size 0x0, 0x0, ), wantErr: true, }, { name: "malicious_number_of_algs", data: append( []byte("Spec ID Event03"), 0x0, 0x0, 0x0, 0x0, 0x0, // platform class 0x0, // version minor 0x2, // version major 0x0, // errata 0x8, // uintn size 0xff, 0xff, 0xff, 0xff, // num algs 0x04, 0x0, // SHA1 0x14, 0x0, // size 0x2, // vendor info size 0x0, 0x0, ), wantErr: true, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { spec, err := parseSpecIDEvent(test.data) var algs []uint16 if (err != nil) != test.wantErr { t.Fatalf("parsing spec, wantErr=%t, got=%v", test.wantErr, err) } if err != nil { return } algsEq := func(want, got []uint16) bool { if len(got) != len(want) { return false } for i, alg := range got { if want[i] != alg { return false } } return true } for _, alg := range spec.algs { algs = append(algs, alg.ID) } if !algsEq(test.want, algs) { t.Errorf("algorithms, got=%x, want=%x", spec.algs, test.want) } }) } } func TestEBSVerifyWorkaround(t *testing.T) { pcr5 := []PCR{ { Index: 5, Digest: []byte{ 0x31, 0x24, 0x58, 0x08, 0xd6, 0xd3, 0x58, 0x49, 0xbc, 0x39, 0x4f, 0x63, 0x43, 0xf2, 0xb3, 0xff, 0x90, 0x8e, 0xd5, 0xe3, }, DigestAlg: HashSHA1.cryptoHash(), }, { Index: 5, Digest: []byte{ 0x6c, 0xae, 0xa1, 0x23, 0xfa, 0x61, 0x11, 0x30, 0x5e, 0xe6, 0x24, 0xe4, 0x52, 0xe2, 0x69, 0xad, 0x14, 0xac, 0x52, 0x2a, 0xb8, 0xbf, 0x0c, 0x88, 0xe1, 0x16, 0x16, 0xde, 0x4c, 0x22, 0x2f, 0x7d, }, DigestAlg: HashSHA256.cryptoHash(), }, } elr, err := os.ReadFile("testdata/ebs_event_missing_eventlog") if err != nil { t.Fatal(err) } el, err := ParseEventLog(elr) if err != nil { t.Fatalf("ParseEventLog() failed: %v", err) } if _, err := el.Verify(pcr5); err != nil { t.Errorf("Verify() failed: %v", err) } } func TestAppendEvents(t *testing.T) { base, err := os.ReadFile("testdata/ubuntu_2104_shielded_vm_no_secure_boot_eventlog") if err != nil { t.Fatalf("reading test data: %v", err) } extraLog, err := base64.StdEncoding.DecodeString(`AAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACUAAABTcGVjIElEIEV2ZW50MDMAAAAAAAACAAEC AAAABAAUAAsAIAAACAAAAAYAAAACAAAABACX3UqVWDMNeg2Hkxyy6Q35wO4yBwsAVXbW4fKD8+xm Kv75L4ecBpvSR4d6bz+A7z1prUcKPuMrAQAACAISpgJpbWFfaGFzaD1zaGEyNTYgYXBwYXJtb3I9 MSBwY2k9bm9hZXIsbm9hdHMgcHJpbnRrLmRldmttc2c9b24gc2xhYl9ub21lcmdlIGNvbnNvbGU9 dHR5UzAsMTE1MjAwbjggY29uc29sZT10dHkwIGdsaW51eC1ib290LWltYWdlPTIwMjExMDI3LjAy LjAzIHF1aWV0IHNwbGFzaCBwbHltb3V0aC5pZ25vcmUtc2VyaWFsLWNvbnNvbGVzIGxzbT1sb2Nr ZG93bix5YW1hLGxvYWRwaW4sc2FmZXNldGlkLGludGVncml0eSxhcHBhcm1vcixzZWxpbnV4LHNt YWNrLHRvbW95byxicGYgcGFuaWM9MzAgaTkxNS5lbmFibGVfcHNyPTA=`) if err != nil { t.Fatal(err) } combined, err := AppendEvents(base, extraLog) if err != nil { t.Fatalf("CombineEventLogs() failed: %v", err) } // Make sure the combined log parses successfully and has one more // event than the base log. parsedBase, err := ParseEventLog(base) if err != nil { t.Fatal(err) } parsed, err := ParseEventLog(combined) if err != nil { t.Fatalf("ParseEventLog(combined_log) failed: %v", err) } if got, want := len(parsed.rawEvents), len(parsedBase.rawEvents)+1; got != want { t.Errorf("unexpected number of events in combined log: got %d, want %d", got, want) for i, e := range parsed.rawEvents { t.Logf("logs[%d] = %+v", i, e) } } } go-attestation-0.5.1/attest/eventlog_workarounds.go000066400000000000000000000045211452320553600226020ustar00rootroot00000000000000// Copyright 2020 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package attest type elWorkaround struct { id string affectedPCR int apply func(e *EventLog) error } // inject3 appends two new events into the event log. func inject3(e *EventLog, pcr int, data1, data2, data3 string) error { if err := inject(e, pcr, data1); err != nil { return err } if err := inject(e, pcr, data2); err != nil { return err } return inject(e, pcr, data3) } // inject2 appends two new events into the event log. func inject2(e *EventLog, pcr int, data1, data2 string) error { if err := inject(e, pcr, data1); err != nil { return err } return inject(e, pcr, data2) } // inject appends a new event into the event log. func inject(e *EventLog, pcr int, data string) error { evt := rawEvent{ data: []byte(data), index: pcr, sequence: e.rawEvents[len(e.rawEvents)-1].sequence + 1, } for _, alg := range e.Algs { h := alg.cryptoHash().New() h.Write([]byte(data)) evt.digests = append(evt.digests, digest{hash: alg.cryptoHash(), data: h.Sum(nil)}) } e.rawEvents = append(e.rawEvents, evt) return nil } const ( ebsInvocation = "Exit Boot Services Invocation" ebsSuccess = "Exit Boot Services Returned with Success" ebsFailure = "Exit Boot Services Returned with Failure" ) var eventlogWorkarounds = []elWorkaround{ { id: "EBS Invocation + Success", affectedPCR: 5, apply: func(e *EventLog) error { return inject2(e, 5, ebsInvocation, ebsSuccess) }, }, { id: "EBS Invocation + Failure", affectedPCR: 5, apply: func(e *EventLog) error { return inject2(e, 5, ebsInvocation, ebsFailure) }, }, { id: "EBS Invocation + Failure + Success", affectedPCR: 5, apply: func(e *EventLog) error { return inject3(e, 5, ebsInvocation, ebsFailure, ebsSuccess) }, }, } go-attestation-0.5.1/attest/example_test.go000066400000000000000000000116761452320553600210240ustar00rootroot00000000000000package attest_test import ( "crypto/subtle" "flag" "log" "testing" "github.com/google/go-attestation/attest" ) var ( testExamples = flag.Bool("test-examples", false, "Enable tests for examples.") ) func ExampleAK() { tpm, err := attest.OpenTPM(nil) if err != nil { log.Fatalf("Failed to open the TPM: %v", err) } defer tpm.Close() // Create a new AK. ak, err := tpm.NewAK(nil) if err != nil { log.Fatalf("Failed to create AK: %v", err) } // Save a re-loadable representation to blob. blob, err := ak.Marshal() if err != nil { log.Fatalf("Failed to marshal AK: %v", err) } // Close our handle to the AK. if err := ak.Close(tpm); err != nil { log.Fatalf("Failed to close AK: %v", err) } // Re-load the created AK from the blob. ak, err = tpm.LoadAK(blob) if err != nil { log.Fatalf("Failed to load AK: %v", err) } if err := ak.Close(tpm); err != nil { log.Fatalf("Failed to close AK: %v", err) } } func ExampleAK_credentialActivation() { tpm, err := attest.OpenTPM(nil) if err != nil { log.Fatalf("Failed to open TPM: %v", err) } defer tpm.Close() // Create a new AK. ak, err := tpm.NewAK(nil) if err != nil { log.Fatalf("Failed to create AK: %v", err) } defer ak.Close(tpm) // Read the EK. ek, err := tpm.EKs() if err != nil { log.Fatalf("Failed to enumerate EKs: %v", err) } // Read parameters necessary to generate a challenge. ap := ak.AttestationParameters() // Generate a credential activation challenge (usually done on the server). activation := attest.ActivationParameters{ TPMVersion: tpm.Version(), EK: ek[0].Public, AK: ap, } secret, challenge, err := activation.Generate() if err != nil { log.Fatalf("Failed to generate activation challenge: %v", err) } // Challenge the AK & EK properties to recieve the decrypted secret. decrypted, err := ak.ActivateCredential(tpm, *challenge) if err != nil { log.Fatalf("Failed to activate credential: %v", err) } // Check that the AK completed the challenge (usually done on the server). if subtle.ConstantTimeCompare(secret, decrypted) == 0 { log.Fatal("Activation response did not match secret") } } func ExampleAK_credentialActivationWithEK() { tpm, err := attest.OpenTPM(nil) if err != nil { log.Fatalf("Failed to open TPM: %v", err) } defer tpm.Close() // Create a new AK. ak, err := tpm.NewAK(nil) if err != nil { log.Fatalf("Failed to create AK: %v", err) } defer ak.Close(tpm) // Read the EK certificates. ekCerts, err := tpm.EKCertificates() if err != nil { log.Fatalf("Failed to enumerate EKs: %v", err) } // Read parameters necessary to generate a challenge. ap := ak.AttestationParameters() // Try activating with each EK certificate. for _, ek := range ekCerts { // Generate a credential activation challenge (usually done on the server). activation := attest.ActivationParameters{ TPMVersion: tpm.Version(), EK: ek.Public, AK: ap, } secret, challenge, err := activation.Generate() if err != nil { log.Fatalf("Failed to generate activation challenge: %v", err) } // Challenge the AK & EK properties to recieve the decrypted secret. decrypted, err := ak.ActivateCredentialWithEK(tpm, *challenge, ek) if err != nil { log.Fatalf("Failed to activate credential: %v", err) } // Check that the AK completed the challenge (usually done on the server). if subtle.ConstantTimeCompare(secret, decrypted) == 0 { log.Fatal("Activation response did not match secret") } } } func TestExampleAK(t *testing.T) { if !*testExamples { t.SkipNow() } ExampleAK() ExampleAK_credentialActivation() ExampleAK_credentialActivationWithEK() } func TestExampleTPM(t *testing.T) { if !*testExamples { t.SkipNow() } ExampleTPM_AttestPlatform() } func ExampleTPM_AttestPlatform() { tpm, err := attest.OpenTPM(nil) if err != nil { log.Fatalf("Failed to open TPM: %v", err) } defer tpm.Close() // Create a new AK. ak, err := tpm.NewAK(nil) if err != nil { log.Fatalf("Failed to create AK: %v", err) } defer ak.Close(tpm) // The nonce would typically be provided by the server. nonce := []byte{1, 2, 3, 4, 5, 6, 7, 8} // Perform an attestation against the state of the plaform. Usually, you // would pass a nil config, and the event log would be read from the // platform. To ensure this example runs on platforms without event logs, // we pass a fake EventLog value. att, err := tpm.AttestPlatform(ak, nonce, &attest.PlatformAttestConfig{ EventLog: []byte{0}, }) if err != nil { log.Fatalf("Failed to attest the platform state: %v", err) } // Construct an AKPublic struct from the parameters of the key. This // will be used to verify the quote signatures. pub, err := attest.ParseAKPublic(tpm.Version(), ak.AttestationParameters().Public) if err != nil { log.Fatalf("Failed to parse AK public: %v", err) } for i, q := range att.Quotes { if err := pub.Verify(q, att.PCRs, nonce); err != nil { log.Fatalf("quote[%d] verification failed: %v", i, err) } } } go-attestation-0.5.1/attest/internal/000077500000000000000000000000001452320553600176045ustar00rootroot00000000000000go-attestation-0.5.1/attest/internal/events.go000066400000000000000000000457401452320553600214510ustar00rootroot00000000000000package internal import ( "bytes" "crypto/x509" "encoding/binary" "errors" "fmt" "io" "unicode/utf16" ) const ( // maxNameLen is the maximum accepted byte length for a name field. // This value should be larger than any reasonable value. maxNameLen = 2048 // maxDataLen is the maximum size in bytes of a variable data field. // This value should be larger than any reasonable value. maxDataLen = 1024 * 1024 // 1 Megabyte. ) // GUIDs representing the contents of an UEFI_SIGNATURE_LIST. var ( hashSHA256SigGUID = efiGUID{0xc1c41626, 0x504c, 0x4092, [8]byte{0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28}} hashSHA1SigGUID = efiGUID{0x826ca512, 0xcf10, 0x4ac9, [8]byte{0xb1, 0x87, 0xbe, 0x01, 0x49, 0x66, 0x31, 0xbd}} hashSHA224SigGUID = efiGUID{0x0b6e5233, 0xa65c, 0x44c9, [8]byte{0x94, 0x07, 0xd9, 0xab, 0x83, 0xbf, 0xc8, 0xbd}} hashSHA384SigGUID = efiGUID{0xff3e5307, 0x9fd0, 0x48c9, [8]byte{0x85, 0xf1, 0x8a, 0xd5, 0x6c, 0x70, 0x1e, 0x01}} hashSHA512SigGUID = efiGUID{0x093e0fae, 0xa6c4, 0x4f50, [8]byte{0x9f, 0x1b, 0xd4, 0x1e, 0x2b, 0x89, 0xc1, 0x9a}} keyRSA2048SigGUID = efiGUID{0x3c5766e8, 0x269c, 0x4e34, [8]byte{0xaa, 0x14, 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6}} certRSA2048SHA256SigGUID = efiGUID{0xe2b36190, 0x879b, 0x4a3d, [8]byte{0xad, 0x8d, 0xf2, 0xe7, 0xbb, 0xa3, 0x27, 0x84}} certRSA2048SHA1SigGUID = efiGUID{0x67f8444f, 0x8743, 0x48f1, [8]byte{0xa3, 0x28, 0x1e, 0xaa, 0xb8, 0x73, 0x60, 0x80}} certX509SigGUID = efiGUID{0xa5c059a1, 0x94e4, 0x4aa7, [8]byte{0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72}} certHashSHA256SigGUID = efiGUID{0x3bd2a492, 0x96c0, 0x4079, [8]byte{0xb4, 0x20, 0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed}} certHashSHA384SigGUID = efiGUID{0x7076876e, 0x80c2, 0x4ee6, [8]byte{0xaa, 0xd2, 0x28, 0xb3, 0x49, 0xa6, 0x86, 0x5b}} certHashSHA512SigGUID = efiGUID{0x446dbf63, 0x2502, 0x4cda, [8]byte{0xbc, 0xfa, 0x24, 0x65, 0xd2, 0xb0, 0xfe, 0x9d}} ) var ( // https://github.com/rhboot/shim/blob/20e4d9486fcae54ee44d2323ae342ffe68c920e6/lib/guid.c#L36 // GUID used by the shim. shimLockGUID = efiGUID{0x605dab50, 0xe046, 0x4300, [8]byte{0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23}} // "SbatLevel" encoded as UCS-2. shimSbatVarName = []uint16{0x53, 0x62, 0x61, 0x74, 0x4c, 0x65, 0x76, 0x65, 0x6c} // "MokListTrusted" encoded as UCS-2. shimMokListTrustedVarName = []uint16{0x4d, 0x6f, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64} ) // EventType describes the type of event signalled in the event log. type EventType uint32 // BIOS Events (TCG PC Client Specific Implementation Specification for Conventional BIOS 1.21) const ( PrebootCert EventType = 0x00000000 PostCode EventType = 0x00000001 unused EventType = 0x00000002 NoAction EventType = 0x00000003 Separator EventType = 0x00000004 Action EventType = 0x00000005 EventTag EventType = 0x00000006 SCRTMContents EventType = 0x00000007 SCRTMVersion EventType = 0x00000008 CpuMicrocode EventType = 0x00000009 PlatformConfigFlags EventType = 0x0000000A TableOfDevices EventType = 0x0000000B CompactHash EventType = 0x0000000C Ipl EventType = 0x0000000D IplPartitionData EventType = 0x0000000E NonhostCode EventType = 0x0000000F NonhostConfig EventType = 0x00000010 NonhostInfo EventType = 0x00000011 OmitBootDeviceEvents EventType = 0x00000012 ) // EFI Events (TCG EFI Platform Specification Version 1.22) const ( EFIEventBase EventType = 0x80000000 EFIVariableDriverConfig EventType = 0x80000001 EFIVariableBoot EventType = 0x80000002 EFIBootServicesApplication EventType = 0x80000003 EFIBootServicesDriver EventType = 0x80000004 EFIRuntimeServicesDriver EventType = 0x80000005 EFIGPTEvent EventType = 0x80000006 EFIAction EventType = 0x80000007 EFIPlatformFirmwareBlob EventType = 0x80000008 EFIHandoffTables EventType = 0x80000009 EFIHCRTMEvent EventType = 0x80000010 EFIVariableAuthority EventType = 0x800000e0 ) // EFIDeviceType describes the type of a device specified by a device path. type EFIDeviceType uint8 // "Device Path Protocol" type values. // // Section 9.3.2 of the UEFI specification, accessible at: // https://uefi.org/sites/default/files/resources/UEFI%20Spec%202_6.pdf const ( HardwareDevice EFIDeviceType = 0x01 ACPIDevice EFIDeviceType = 0x02 MessagingDevice EFIDeviceType = 0x03 MediaDevice EFIDeviceType = 0x04 BBSDevice EFIDeviceType = 0x05 EndDeviceArrayMarker EFIDeviceType = 0x7f ) // ErrSigMissingGUID is returned if an EFI_SIGNATURE_DATA structure was parsed // successfully, however was missing the SignatureOwner GUID. This case is // handled specially as a workaround for a bug relating to authority events. var ErrSigMissingGUID = errors.New("signature data was missing owner GUID") var eventTypeNames = map[EventType]string{ PrebootCert: "Preboot Cert", PostCode: "POST Code", unused: "Unused", NoAction: "No Action", Separator: "Separator", Action: "Action", EventTag: "Event Tag", SCRTMContents: "S-CRTM Contents", SCRTMVersion: "S-CRTM Version", CpuMicrocode: "CPU Microcode", PlatformConfigFlags: "Platform Config Flags", TableOfDevices: "Table of Devices", CompactHash: "Compact Hash", Ipl: "IPL", IplPartitionData: "IPL Partition Data", NonhostCode: "Non-Host Code", NonhostConfig: "Non-HostConfig", NonhostInfo: "Non-Host Info", OmitBootDeviceEvents: "Omit Boot Device Events", EFIEventBase: "EFI Event Base", EFIVariableDriverConfig: "EFI Variable Driver Config", EFIVariableBoot: "EFI Variable Boot", EFIBootServicesApplication: "EFI Boot Services Application", EFIBootServicesDriver: "EFI Boot Services Driver", EFIRuntimeServicesDriver: "EFI Runtime Services Driver", EFIGPTEvent: "EFI GPT Event", EFIAction: "EFI Action", EFIPlatformFirmwareBlob: "EFI Platform Firmware Blob", EFIVariableAuthority: "EFI Variable Authority", EFIHandoffTables: "EFI Handoff Tables", EFIHCRTMEvent: "EFI H-CRTM Event", } // TaggedEventData represents the TCG_PCClientTaggedEventStruct structure, // as defined by 11.3.2.1 in the "TCG PC Client Specific Implementation // Specification for Conventional BIOS", version 1.21. type TaggedEventData struct { ID uint32 Data []byte } // ParseTaggedEventData parses a TCG_PCClientTaggedEventStruct structure. func ParseTaggedEventData(d []byte) (*TaggedEventData, error) { var ( r = bytes.NewReader(d) header struct { ID uint32 DataLen uint32 } ) if err := binary.Read(r, binary.LittleEndian, &header); err != nil { return nil, fmt.Errorf("reading header: %w", err) } if int(header.DataLen) > len(d) { return nil, fmt.Errorf("tagged event len (%d bytes) larger than data length (%d bytes)", header.DataLen, len(d)) } out := TaggedEventData{ ID: header.ID, Data: make([]byte, header.DataLen), } return &out, binary.Read(r, binary.LittleEndian, &out.Data) } func (e EventType) String() string { if s, ok := eventTypeNames[e]; ok { return s } return fmt.Sprintf("EventType(0x%x)", uint32(e)) } // UntrustedParseEventType returns the event type indicated by // the provided value. func UntrustedParseEventType(et uint32) (EventType, error) { // "The value associated with a UEFI specific platform event type MUST be in // the range between 0x80000000 and 0x800000FF, inclusive." if (et < 0x80000000 && et > 0x800000FF) || (et <= 0x0 && et > 0x12) { return EventType(0), fmt.Errorf("event type not between [0x0, 0x12] or [0x80000000, 0x800000FF]: got %#x", et) } if _, ok := eventTypeNames[EventType(et)]; !ok { return EventType(0), fmt.Errorf("unknown event type %#x", et) } return EventType(et), nil } // efiGUID represents the EFI_GUID type. // See section "2.3.1 Data Types" in the specification for more information. // type efiGUID [16]byte type efiGUID struct { Data1 uint32 Data2 uint16 Data3 uint16 Data4 [8]byte } func (d efiGUID) String() string { var u [8]byte binary.BigEndian.PutUint32(u[:4], d.Data1) binary.BigEndian.PutUint16(u[4:6], d.Data2) binary.BigEndian.PutUint16(u[6:8], d.Data3) return fmt.Sprintf("%x-%x-%x-%x-%x", u[:4], u[4:6], u[6:8], d.Data4[:2], d.Data4[2:]) } // UEFIVariableDataHeader represents the leading fixed-size fields // within UEFI_VARIABLE_DATA. type UEFIVariableDataHeader struct { VariableName efiGUID UnicodeNameLength uint64 // uintN VariableDataLength uint64 // uintN } // UEFIVariableData represents the UEFI_VARIABLE_DATA structure. type UEFIVariableData struct { Header UEFIVariableDataHeader UnicodeName []uint16 VariableData []byte // []int8 } // ParseUEFIVariableData parses the data section of an event structured as // a UEFI variable. // // https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClient_Specific_Platform_Profile_for_TPM_2p0_1p04_PUBLIC.pdf#page=100 func ParseUEFIVariableData(r io.Reader) (ret UEFIVariableData, err error) { err = binary.Read(r, binary.LittleEndian, &ret.Header) if err != nil { return } if ret.Header.UnicodeNameLength > maxNameLen { return UEFIVariableData{}, fmt.Errorf("unicode name too long: %d > %d", ret.Header.UnicodeNameLength, maxNameLen) } ret.UnicodeName = make([]uint16, ret.Header.UnicodeNameLength) for i := 0; uint64(i) < ret.Header.UnicodeNameLength; i++ { err = binary.Read(r, binary.LittleEndian, &ret.UnicodeName[i]) if err != nil { return } } if ret.Header.VariableDataLength > maxDataLen { return UEFIVariableData{}, fmt.Errorf("variable data too long: %d > %d", ret.Header.VariableDataLength, maxDataLen) } ret.VariableData = make([]byte, ret.Header.VariableDataLength) _, err = io.ReadFull(r, ret.VariableData) return } func (v *UEFIVariableData) VarName() string { return string(utf16.Decode(v.UnicodeName)) } func (v *UEFIVariableData) SignatureData() (certs []x509.Certificate, hashes [][]byte, err error) { return parseEfiSignatureList(v.VariableData) } // UEFIVariableAuthority describes the contents of a UEFI variable authority // event. type UEFIVariableAuthority struct { Certs []x509.Certificate } // ParseUEFIVariableAuthority parses the data section of an event structured as // a UEFI variable authority. // // https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_final.pdf#page=1789 func ParseUEFIVariableAuthority(v UEFIVariableData) (UEFIVariableAuthority, error) { if v.Header.VariableName == shimLockGUID && ( // Skip parsing new SBAT section logged by shim. // See https://github.com/rhboot/shim/blob/main/SBAT.md for more. unicodeNameEquals(v, shimSbatVarName) || //https://github.com/rhboot/shim/blob/20e4d9486fcae54ee44d2323ae342ffe68c920e6/include/sbat.h#L9-L12 // Skip parsing new MokListTrusted section logged by shim. // See https://github.com/rhboot/shim/blob/main/MokVars.txt for more. unicodeNameEquals(v, shimMokListTrustedVarName)) { //https://github.com/rhboot/shim/blob/4e513405b4f1641710115780d19dcec130c5208f/mok.c#L169-L182 return UEFIVariableAuthority{}, nil } certs, err := parseEfiSignature(v.VariableData) return UEFIVariableAuthority{Certs: certs}, err } func unicodeNameEquals(v UEFIVariableData, comp []uint16) bool { if len(v.UnicodeName) != len(comp) { return false } for i, v := range v.UnicodeName { if v != comp[i] { return false } } return true } // efiSignatureData represents the EFI_SIGNATURE_DATA type. // See section "31.4.1 Signature Database" in the specification for more information. type efiSignatureData struct { SignatureOwner efiGUID SignatureData []byte // []int8 } // efiSignatureList represents the EFI_SIGNATURE_LIST type. // See section "31.4.1 Signature Database" in the specification for more information. type efiSignatureListHeader struct { SignatureType efiGUID SignatureListSize uint32 SignatureHeaderSize uint32 SignatureSize uint32 } type efiSignatureList struct { Header efiSignatureListHeader SignatureData []byte Signatures []byte } // parseEfiSignatureList parses a EFI_SIGNATURE_LIST structure. // The structure and related GUIDs are defined at: // https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_final.pdf#page=1790 func parseEfiSignatureList(b []byte) ([]x509.Certificate, [][]byte, error) { if len(b) < 28 { // Being passed an empty signature list here appears to be valid return nil, nil, nil } signatures := efiSignatureList{} buf := bytes.NewReader(b) certificates := []x509.Certificate{} hashes := [][]byte{} for buf.Len() > 0 { err := binary.Read(buf, binary.LittleEndian, &signatures.Header) if err != nil { return nil, nil, err } if signatures.Header.SignatureHeaderSize > maxDataLen { return nil, nil, fmt.Errorf("signature header too large: %d > %d", signatures.Header.SignatureHeaderSize, maxDataLen) } if signatures.Header.SignatureListSize > maxDataLen { return nil, nil, fmt.Errorf("signature list too large: %d > %d", signatures.Header.SignatureListSize, maxDataLen) } signatureType := signatures.Header.SignatureType switch signatureType { case certX509SigGUID: // X509 certificate for sigOffset := 0; uint32(sigOffset) < signatures.Header.SignatureListSize-28; { signature := efiSignatureData{} signature.SignatureData = make([]byte, signatures.Header.SignatureSize-16) err := binary.Read(buf, binary.LittleEndian, &signature.SignatureOwner) if err != nil { return nil, nil, err } err = binary.Read(buf, binary.LittleEndian, &signature.SignatureData) if err != nil { return nil, nil, err } cert, err := x509.ParseCertificate(signature.SignatureData) if err != nil { return nil, nil, err } sigOffset += int(signatures.Header.SignatureSize) certificates = append(certificates, *cert) } case hashSHA256SigGUID: // SHA256 for sigOffset := 0; uint32(sigOffset) < signatures.Header.SignatureListSize-28; { signature := efiSignatureData{} signature.SignatureData = make([]byte, signatures.Header.SignatureSize-16) err := binary.Read(buf, binary.LittleEndian, &signature.SignatureOwner) if err != nil { return nil, nil, err } err = binary.Read(buf, binary.LittleEndian, &signature.SignatureData) if err != nil { return nil, nil, err } hashes = append(hashes, signature.SignatureData) sigOffset += int(signatures.Header.SignatureSize) } case keyRSA2048SigGUID: err = errors.New("unhandled RSA2048 key") case certRSA2048SHA256SigGUID: err = errors.New("unhandled RSA2048-SHA256 key") case hashSHA1SigGUID: err = errors.New("unhandled SHA1 hash") case certRSA2048SHA1SigGUID: err = errors.New("unhandled RSA2048-SHA1 key") case hashSHA224SigGUID: err = errors.New("unhandled SHA224 hash") case hashSHA384SigGUID: err = errors.New("unhandled SHA384 hash") case hashSHA512SigGUID: err = errors.New("unhandled SHA512 hash") case certHashSHA256SigGUID: err = errors.New("unhandled X509-SHA256 hash metadata") case certHashSHA384SigGUID: err = errors.New("unhandled X509-SHA384 hash metadata") case certHashSHA512SigGUID: err = errors.New("unhandled X509-SHA512 hash metadata") default: err = fmt.Errorf("unhandled signature type %s", signatureType) } if err != nil { return nil, nil, err } } return certificates, hashes, nil } // EFISignatureData represents the EFI_SIGNATURE_DATA type. // See section "31.4.1 Signature Database" in the specification // for more information. type EFISignatureData struct { SignatureOwner efiGUID SignatureData []byte // []int8 } func parseEfiSignature(b []byte) ([]x509.Certificate, error) { certificates := []x509.Certificate{} if len(b) < 16 { return nil, fmt.Errorf("invalid signature: buffer smaller than header (%d < %d)", len(b), 16) } buf := bytes.NewReader(b) signature := EFISignatureData{} signature.SignatureData = make([]byte, len(b)-16) if err := binary.Read(buf, binary.LittleEndian, &signature.SignatureOwner); err != nil { return certificates, err } if err := binary.Read(buf, binary.LittleEndian, &signature.SignatureData); err != nil { return certificates, err } cert, err := x509.ParseCertificate(signature.SignatureData) if err == nil { certificates = append(certificates, *cert) } else { // A bug in shim may cause an event to be missing the SignatureOwner GUID. // We handle this, but signal back to the caller using ErrSigMissingGUID. var err2 error cert, err2 = x509.ParseCertificate(b) if err2 == nil { certificates = append(certificates, *cert) err = ErrSigMissingGUID } } return certificates, err } type EFIDevicePathElement struct { Type EFIDeviceType Subtype uint8 Data []byte } // EFIImageLoad describes an EFI_IMAGE_LOAD_EVENT structure. type EFIImageLoad struct { Header EFIImageLoadHeader DevPathData []byte } type EFIImageLoadHeader struct { LoadAddr uint64 Length uint64 LinkAddr uint64 DevicePathLen uint64 } func parseDevicePathElement(r io.Reader) (EFIDevicePathElement, error) { var ( out EFIDevicePathElement dataLen uint16 ) if err := binary.Read(r, binary.LittleEndian, &out.Type); err != nil { return EFIDevicePathElement{}, fmt.Errorf("reading type: %v", err) } if err := binary.Read(r, binary.LittleEndian, &out.Subtype); err != nil { return EFIDevicePathElement{}, fmt.Errorf("reading subtype: %v", err) } if err := binary.Read(r, binary.LittleEndian, &dataLen); err != nil { return EFIDevicePathElement{}, fmt.Errorf("reading data len: %v", err) } if dataLen > maxNameLen { return EFIDevicePathElement{}, fmt.Errorf("device path data too long: %d > %d", dataLen, maxNameLen) } if dataLen < 4 { return EFIDevicePathElement{}, fmt.Errorf("device path data too short: %d < %d", dataLen, 4) } out.Data = make([]byte, dataLen-4) if err := binary.Read(r, binary.LittleEndian, &out.Data); err != nil { return EFIDevicePathElement{}, fmt.Errorf("reading data: %v", err) } return out, nil } func (h *EFIImageLoad) DevicePath() ([]EFIDevicePathElement, error) { var ( r = bytes.NewReader(h.DevPathData) out []EFIDevicePathElement ) for r.Len() > 0 { e, err := parseDevicePathElement(r) if err != nil { return nil, err } if e.Type == EndDeviceArrayMarker { return out, nil } out = append(out, e) } return out, nil } // ParseEFIImageLoad parses an EFI_IMAGE_LOAD_EVENT structure. // // https://trustedcomputinggroup.org/wp-content/uploads/TCG_EFI_Platform_1_22_Final_-v15.pdf#page=17 func ParseEFIImageLoad(r io.Reader) (ret EFIImageLoad, err error) { err = binary.Read(r, binary.LittleEndian, &ret.Header) if err != nil { return } if ret.Header.DevicePathLen > maxNameLen { return EFIImageLoad{}, fmt.Errorf("device path structure too long: %d > %d", ret.Header.DevicePathLen, maxNameLen) } ret.DevPathData = make([]byte, ret.Header.DevicePathLen) err = binary.Read(r, binary.LittleEndian, &ret.DevPathData) return } go-attestation-0.5.1/attest/internal/events_test.go000066400000000000000000000020661452320553600225020ustar00rootroot00000000000000package internal import ( "bytes" "testing" "github.com/google/go-cmp/cmp" ) func TestParseUEFIVariableData(t *testing.T) { data := []byte{0x61, 0xdf, 0xe4, 0x8b, 0xca, 0x93, 0xd2, 0x11, 0xaa, 0xd, 0x0, 0xe0, 0x98, 0x3, 0x2b, 0x8c, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x53, 0x0, 0x65, 0x0, 0x63, 0x0, 0x75, 0x0, 0x72, 0x0, 0x65, 0x0, 0x42, 0x0, 0x6f, 0x0, 0x6f, 0x0, 0x74, 0x0, 0x1} want := UEFIVariableData{ Header: UEFIVariableDataHeader{ VariableName: efiGUID{Data1: 0x8be4df61, Data2: 0x93ca, Data3: 0x11d2, Data4: [8]uint8{0xaa, 0xd, 0x0, 0xe0, 0x98, 0x3, 0x2b, 0x8c}}, UnicodeNameLength: 0xa, VariableDataLength: 0x1, }, UnicodeName: []uint16{0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x42, 0x6f, 0x6f, 0x74}, VariableData: []uint8{0x1}, } got, err := ParseUEFIVariableData(bytes.NewReader(data)) if err != nil { t.Fatalf("ParseEFIVariableData() failed: %v", err) } if diff := cmp.Diff(want, got); diff != "" { t.Errorf("ParseUEFIVariableData() mismatch (-want +got):\n%s", diff) } } go-attestation-0.5.1/attest/key_linux.go000066400000000000000000000053521452320553600203330ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. //go:build linux && !gofuzz && cgo && tspi // +build linux,!gofuzz,cgo,tspi package attest import ( "fmt" "github.com/google/go-tspi/attestation" ) // trousersKey12 represents a key bound to a TPM 1.2 device via tcsd. type trousersKey12 struct { blob []byte public []byte } func newTrousersKey12(blob, public []byte) ak { return &trousersKey12{ blob: blob, public: public, } } // Marshal represents the key in a persistent format which may be // loaded at a later time using tpm.LoadKey(). func (k *trousersKey12) marshal() ([]byte, error) { out := serializedKey{ Encoding: keyEncodingEncrypted, TPMVersion: TPMVersion12, Blob: k.blob, Public: k.public, } return out.Serialize() } func (k *trousersKey12) close(tpm tpmBase) error { return nil // No state for tpm 1.2. } func (k *trousersKey12) activateCredential(tb tpmBase, in EncryptedCredential, ek *EK) ([]byte, error) { t, ok := tb.(*trousersTPM) if !ok { return nil, fmt.Errorf("expected *linuxTPM, got %T", tb) } cred, err := attestation.AIKChallengeResponse(t.ctx, k.blob, in.Credential, in.Secret) if err != nil { return nil, fmt.Errorf("failed to activate ak: %v", err) } return cred, nil } func (k *trousersKey12) quote(tb tpmBase, nonce []byte, alg HashAlg, selectedPCRs []int) (*Quote, error) { t, ok := tb.(*trousersTPM) if !ok { return nil, fmt.Errorf("expected *linuxTPM, got %T", tb) } if alg != HashSHA1 { return nil, fmt.Errorf("only SHA1 algorithms supported on TPM 1.2, not %v", alg) } if selectedPCRs != nil { return nil, fmt.Errorf("selecting PCRs not supported on TPM 1.2 (parameter must be nil)") } quote, rawSig, err := attestation.GetQuote(t.ctx, k.blob, nonce) if err != nil { return nil, fmt.Errorf("Quote() failed: %v", err) } return &Quote{ Version: TPMVersion12, Quote: quote, Signature: rawSig, }, nil } func (k *trousersKey12) attestationParameters() AttestationParameters { return AttestationParameters{ Public: k.public, UseTCSDActivationFormat: true, } } func (k *trousersKey12) certify(tb tpmBase, handle interface{}) (*CertificationParameters, error) { return nil, fmt.Errorf("not implemented") } go-attestation-0.5.1/attest/key_windows.go000066400000000000000000000135601452320553600206660ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. //go:build windows // +build windows package attest import ( "fmt" "github.com/google/go-tpm/legacy/tpm2" tpm1 "github.com/google/go-tpm/tpm" ) // windowsKey12 represents a Windows-managed key on a TPM1.2 TPM. type windowsKey12 struct { hnd uintptr pcpKeyName string public []byte } func newWindowsKey12(hnd uintptr, pcpKeyName string, public []byte) ak { return &windowsKey12{ hnd: hnd, pcpKeyName: pcpKeyName, public: public, } } func (k *windowsKey12) marshal() ([]byte, error) { out := serializedKey{ Encoding: keyEncodingOSManaged, TPMVersion: TPMVersion12, Name: k.pcpKeyName, Public: k.public, } return out.Serialize() } func (k *windowsKey12) activateCredential(t tpmBase, in EncryptedCredential, ek *EK) ([]byte, error) { tpm, ok := t.(*windowsTPM) if !ok { return nil, fmt.Errorf("expected *windowsTPM, got %T", t) } secretKey, err := tpm.pcp.ActivateCredential(k.hnd, in.Credential) if err != nil { return nil, err } return decryptCredential(secretKey, in.Secret) } func (k *windowsKey12) quote(tb tpmBase, nonce []byte, alg HashAlg, selectedPCRs []int) (*Quote, error) { if alg != HashSHA1 { return nil, fmt.Errorf("only SHA1 algorithms supported on TPM 1.2, not %v", alg) } t, ok := tb.(*windowsTPM) if !ok { return nil, fmt.Errorf("expected *windowsTPM, got %T", tb) } tpmKeyHnd, err := t.pcp.TPMKeyHandle(k.hnd) if err != nil { return nil, fmt.Errorf("TPMKeyHandle() failed: %v", err) } tpm, err := t.pcp.TPMCommandInterface() if err != nil { return nil, fmt.Errorf("TPMCommandInterface() failed: %v", err) } sig, pcrc, err := tpm1.Quote(tpm, tpmKeyHnd, nonce, selectedPCRs[:], wellKnownAuth[:]) if err != nil { return nil, fmt.Errorf("Quote() failed: %v", err) } // Construct and return TPM_QUOTE_INFO // Returning TPM_QUOTE_INFO allows us to verify the Quote at a higher resolution // and matches what go-tspi returns. quote, err := tpm1.NewQuoteInfo(nonce, selectedPCRs[:], pcrc) if err != nil { return nil, fmt.Errorf("failed to construct Quote Info: %v", err) } return &Quote{ Version: TPMVersion12, Quote: quote, Signature: sig, }, nil } func (k *windowsKey12) close(tpm tpmBase) error { return closeNCryptObject(k.hnd) } func (k *windowsKey12) attestationParameters() AttestationParameters { return AttestationParameters{ Public: k.public, } } func (k *windowsKey12) certify(tb tpmBase, handle interface{}) (*CertificationParameters, error) { return nil, fmt.Errorf("not implemented") } // windowsKey20 represents a key bound to a TPM 2.0. type windowsKey20 struct { hnd uintptr pcpKeyName string public []byte createData []byte createAttestation []byte createSignature []byte } func newWindowsKey20(hnd uintptr, pcpKeyName string, public, createData, createAttest, createSig []byte) ak { return &windowsKey20{ hnd: hnd, pcpKeyName: pcpKeyName, public: public, createData: createData, createAttestation: createAttest, createSignature: createSig, } } func (k *windowsKey20) marshal() ([]byte, error) { out := serializedKey{ Encoding: keyEncodingOSManaged, TPMVersion: TPMVersion20, Name: k.pcpKeyName, Public: k.public, CreateData: k.createData, CreateAttestation: k.createAttestation, CreateSignature: k.createSignature, } return out.Serialize() } func (k *windowsKey20) activateCredential(t tpmBase, in EncryptedCredential, ek *EK) ([]byte, error) { tpm, ok := t.(*windowsTPM) if !ok { return nil, fmt.Errorf("expected *windowsTPM, got %T", t) } return tpm.pcp.ActivateCredential(k.hnd, append(in.Credential, in.Secret...)) } func (k *windowsKey20) quote(tb tpmBase, nonce []byte, alg HashAlg, selectedPCRs []int) (*Quote, error) { t, ok := tb.(*windowsTPM) if !ok { return nil, fmt.Errorf("expected *windowsTPM, got %T", tb) } tpmKeyHnd, err := t.pcp.TPMKeyHandle(k.hnd) if err != nil { return nil, fmt.Errorf("TPMKeyHandle() failed: %v", err) } tpm, err := t.pcp.TPMCommandInterface() if err != nil { return nil, fmt.Errorf("TPMCommandInterface() failed: %v", err) } return quote20(tpm, tpmKeyHnd, alg.goTPMAlg(), nonce, selectedPCRs) } func (k *windowsKey20) close(tpm tpmBase) error { return closeNCryptObject(k.hnd) } func (k *windowsKey20) attestationParameters() AttestationParameters { return AttestationParameters{ Public: k.public, CreateData: k.createData, CreateAttestation: k.createAttestation, CreateSignature: k.createSignature, } } func (k *windowsKey20) certify(tb tpmBase, handle interface{}) (*CertificationParameters, error) { t, ok := tb.(*windowsTPM) if !ok { return nil, fmt.Errorf("expected *windowsTPM, got %T", tb) } h, ok := handle.(uintptr) if !ok { return nil, fmt.Errorf("expected uinptr, got %T", handle) } hnd, err := t.pcp.TPMKeyHandle(h) if err != nil { return nil, fmt.Errorf("TPMKeyHandle() failed: %v", err) } akHnd, err := t.pcp.TPMKeyHandle(k.hnd) if err != nil { return nil, fmt.Errorf("TPMKeyHandle() failed: %v", err) } tpm, err := t.pcp.TPMCommandInterface() if err != nil { return nil, fmt.Errorf("TPMCommandInterface() failed: %v", err) } scheme := tpm2.SigScheme{ Alg: tpm2.AlgRSASSA, Hash: tpm2.AlgSHA1, // PCP-created AK uses SHA1 } return certify(tpm, hnd, akHnd, scheme) } go-attestation-0.5.1/attest/pcp_windows.go000066400000000000000000000604621452320553600206630ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. //go:build windows // +build windows package attest import ( "bytes" "crypto/x509" "encoding/binary" "fmt" "io" "syscall" "unsafe" "github.com/google/go-tpm/tpmutil" tpmtbs "github.com/google/go-tpm/tpmutil/tbs" "golang.org/x/sys/windows" ) const ( pcpProviderName = "Microsoft Platform Crypto Provider" cryptENotFound = 0x80092004 // From winerror.h. // The below is documented in this Microsoft whitepaper: // https://github.com/Microsoft/TSS.MSR/blob/master/PCPTool.v11/Using%20the%20Windows%208%20Platform%20Crypto%20Provider%20and%20Associated%20TPM%20Functionality.pdf ncryptOverwriteKeyFlag = 0x80 // Key usage value for AKs. nCryptPropertyPCPKeyUsagePolicyIdentity = 0x8 ) // DLL references. var ( nCrypt = windows.MustLoadDLL("ncrypt.dll") nCryptOpenStorageProvider = nCrypt.MustFindProc("NCryptOpenStorageProvider") nCryptFreeObject = nCrypt.MustFindProc("NCryptFreeObject") nCryptGetProperty = nCrypt.MustFindProc("NCryptGetProperty") nCryptSetProperty = nCrypt.MustFindProc("NCryptSetProperty") nCryptOpenKey = nCrypt.MustFindProc("NCryptOpenKey") nCryptCreatePersistedKey = nCrypt.MustFindProc("NCryptCreatePersistedKey") nCryptFinalizeKey = nCrypt.MustFindProc("NCryptFinalizeKey") nCryptDeleteKey = nCrypt.MustFindProc("NCryptDeleteKey") crypt32 = windows.MustLoadDLL("crypt32.dll") crypt32CertEnumCertificatesInStore = crypt32.MustFindProc("CertEnumCertificatesInStore") crypt32CertCloseStore = crypt32.MustFindProc("CertCloseStore") tbs *windows.DLL tbsGetDeviceInfo *windows.Proc ) // Error codes. var ( isReadyErrors = map[uint32]string{ 0x00000002: "Platform restart is required (shutdown).", 0x00000004: "Platform restart is required (reboot).", 0x00000008: "The TPM is already owned.", 0x00000010: "Physical presence is required to provision the TPM.", 0x00000020: "The TPM is disabled or deactivated.", 0x00000040: "TPM ownership was taken.", 0x00000080: "An endorsement key exists in the TPM.", 0x00000100: "The TPM owner authorization is not properly stored in the registry.", 0x00000200: "The Storage Root Key (SRK) authorization value is not all zeros.", 0x00000800: "The operating system's registry information about the TPM’s Storage Root Key does not match the TPM Storage Root Key.", 0x00001000: "The TPM permanent flag to allow reading of the Storage Root Key public value is not set.", 0x00002000: "The monotonic counter incremented during boot has not been created.", 0x00020000: "Windows Group Policy is configured to not store any TPM owner authorization so the TPM cannot be fully ready.", 0x00040000: "The EK Certificate was not read from the TPM NV Ram and stored in the registry.", 0x00080000: "The TCG event log is empty or cannot be read.", 0x00100000: "The TPM is not owned.", 0x00200000: "An error occurred, but not specific to a particular task.", 0x00400000: "The device lock counter has not been created.", 0x00800000: "The device identifier has not been created.", } tpmErrNums = map[uint32]string{ 0x80280001: "TPM_E_AUTHFAIL", 0x80280002: "TPM_E_BADINDEX", 0x80280003: "TPM_E_BAD_PARAMETER", 0x80280004: "TPM_E_AUDITFAILURE", 0x80280005: "TPM_E_CLEAR_DISABLED", 0x80280006: "TPM_E_DEACTIVATED", 0x80280007: "TPM_E_DISABLED", 0x80280008: "TPM_E_DISABLED_CMD", 0x80280009: "TPM_E_FAIL", 0x8028000A: "TPM_E_BAD_ORDINAL", 0x8028000B: "TPM_E_INSTALL_DISABLED", 0x8028000C: "TPM_E_INVALID_KEYHANDLE", 0x8028000D: "TPM_E_KEYNOTFOUND", 0x8028000E: "TPM_E_INAPPROPRIATE_ENC", 0x8028000F: "TPM_E_MIGRATEFAIL", 0x80280010: "TPM_E_INVALID_PCR_INFO", 0x80280011: "TPM_E_NOSPACE", 0x80280012: "TPM_E_NOSRK", 0x80280013: "TPM_E_NOTSEALED_BLOB", 0x80280014: "TPM_E_OWNER_SET", 0x80280015: "TPM_E_RESOURCES", 0x80280016: "TPM_E_SHORTRANDOM", 0x80280017: "TPM_E_SIZE", 0x80280018: "TPM_E_WRONGPCRVAL", 0x80280019: "TPM_E_BAD_PARAM_SIZE", 0x8028001A: "TPM_E_SHA_THREAD", 0x8028001B: "TPM_E_SHA_ERROR", 0x8028001C: "TPM_E_FAILEDSELFTEST", 0x8028001D: "TPM_E_AUTH2FAIL", 0x8028001E: "TPM_E_BADTAG", 0x8028001F: "TPM_E_IOERROR", 0x80280020: "TPM_E_ENCRYPT_ERROR", 0x80280021: "TPM_E_DECRYPT_ERROR", 0x80280022: "TPM_E_INVALID_AUTHHANDLE", 0x80280023: "TPM_E_NO_ENDORSEMENT", 0x80280024: "TPM_E_INVALID_KEYUSAGE", 0x80280025: "TPM_E_WRONG_ENTITYTYPE", 0x80280026: "TPM_E_INVALID_POSTINIT", 0x80280027: "TPM_E_INAPPROPRIATE_SIG", 0x80280028: "TPM_E_BAD_KEY_PROPERTY", 0x80280029: "TPM_E_BAD_MIGRATION", 0x8028002A: "TPM_E_BAD_SCHEME", 0x8028002B: "TPM_E_BAD_DATASIZE", 0x8028002C: "TPM_E_BAD_MODE", 0x8028002D: "TPM_E_BAD_PRESENCE", 0x8028002E: "TPM_E_BAD_VERSION", 0x8028002F: "TPM_E_NO_WRAP_TRANSPORT", 0x80280030: "TPM_E_AUDITFAIL_UNSUCCESSFUL", 0x80280031: "TPM_E_AUDITFAIL_SUCCESSFUL", 0x80280032: "TPM_E_NOTRESETABLE", 0x80280033: "TPM_E_NOTLOCAL", 0x80280034: "TPM_E_BAD_TYPE", 0x80280035: "TPM_E_INVALID_RESOURCE", 0x80280036: "TPM_E_NOTFIPS", 0x80280037: "TPM_E_INVALID_FAMILY", 0x80280038: "TPM_E_NO_NV_PERMISSION", 0x80280039: "TPM_E_REQUIRES_SIGN", 0x8028003A: "TPM_E_KEY_NOTSUPPORTED", 0x8028003B: "TPM_E_AUTH_CONFLICT", 0x8028003C: "TPM_E_AREA_LOCKED", // TODO: Finish NVRAM error codes. 0x80280049: "TPM_E_NOOPERATOR", 0x8028004A: "TPM_E_RESOURCEMISSING", 0x8028004B: "TPM_E_DELEGATE_LOCK", 0x8028004C: "TPM_E_DELEGATE_FAMILY", 0x8028004D: "TPM_E_DELEGATE_ADMIN", 0x8028004E: "TPM_E_TRANSPORT_NOTEXCLUSIVE", 0x8028004F: "TPM_E_OWNER_CONTROL", 0x80280050: "TPM_E_DAA_RESOURCES", // TODO: Finish DAA error codes. 0x80280058: "TPM_E_BAD_HANDLE", 0x80280059: "TPM_E_BAD_DELEGATE", 0x8028005A: "TPM_E_BADCONTEXT", 0x8028005B: "TPM_E_TOOMANYCONTEXTS", 0x8028005C: "TPM_E_MA_TICKET_SIGNATURE", 0x8028005D: "TPM_E_MA_DESTINATION", 0x8028005E: "TPM_E_MA_SOURCE", 0x8028005F: "TPM_E_MA_AUTHORITY", 0x80280061: "TPM_E_PERMANENTEK", 0x80280062: "TPM_E_BAD_SIGNATURE", 0x80280063: "TPM_E_NOCONTEXTSPACE", 0x80280400: "TPM_E_COMMAND_BLOCKED", 0x80280401: "TPM_E_INVALID_HANDLE", 0x80280402: "TPM_E_DUPLICATE_VHANDLE", 0x80280403: "TPM_E_EMBEDDED_COMMAND_BLOCKED", 0x80280404: "TPM_E_EMBEDDED_COMMAND_UNSUPPORTED", 0x80280800: "TPM_E_RETRY", 0x80280801: "TPM_E_NEEDS_SELFTEST", 0x80280802: "TPM_E_DOING_SELFTEST", 0x80280803: "TPM_E_DEFEND_LOCK_RUNNING", 0x80284001: "TBS_E_INTERNAL_ERROR", 0x80284002: "TBS_E_BAD_PARAMETER", 0x80284003: "TBS_E_INVALID_OUTPUT_POINTER", 0x80284004: "TBS_E_INVALID_CONTEXT", 0x80284005: "TBS_E_INSUFFICIENT_BUFFER", 0x80284006: "TBS_E_IOERROR", 0x80284007: "TBS_E_INVALID_CONTEXT_PARAM", 0x80284008: "TBS_E_SERVICE_NOT_RUNNING", 0x80284009: "TBS_E_TOO_MANY_TBS_CONTEXTS", 0x8028400A: "TBS_E_TOO_MANY_RESOURCES", 0x8028400B: "TBS_E_SERVICE_START_PENDING", 0x8028400C: "TBS_E_PPI_NOT_SUPPORTED", 0x8028400D: "TBS_E_COMMAND_CANCELED", 0x8028400E: "TBS_E_BUFFER_TOO_LARGE", 0x8028400F: "TBS_E_TPM_NOT_FOUND", 0x80284010: "TBS_E_SERVICE_DISABLED", 0x80284011: "TBS_E_NO_EVENT_LOG", 0x80284012: "TBS_E_ACCESS_DENIED", 0x80284013: "TBS_E_PROVISIONING_NOT_ALLOWED", 0x80284014: "TBS_E_PPI_FUNCTION_UNSUPPORTED", 0x80284015: "TBS_E_OWNERAUTH_NOT_FOUND", 0x80284016: "TBS_E_PROVISIONING_INCOMPLETE", // TODO: TPMAPI & TPMSIMP error codes. 0x80290401: "TPM_E_PCP_DEVICE_NOT_READY", 0x80290402: "TPM_E_PCP_INVALID_HANDLE", 0x80290403: "TPM_E_PCP_INVALID_PARAMETER", 0x80290404: "TPM_E_PCP_FLAG_NOT_SUPPORTED", 0x80290405: "TPM_E_PCP_NOT_SUPPORTED", 0x80290406: "TPM_E_PCP_BUFFER_TOO_SMALL", 0x80290407: "TPM_E_PCP_INTERNAL_ERROR", 0x80290408: "TPM_E_PCP_AUTHENTICATION_FAILED", 0x80290409: "TPM_E_PCP_AUTHENTICATION_IGNORED", 0x8029040A: "TPM_E_PCP_POLICY_NOT_FOUND", 0x8029040B: "TPM_E_PCP_PROFILE_NOT_FOUND", 0x8029040C: "TPM_E_PCP_VALIDATION_FAILED", 0x80090009: "NTE_BAD_FLAGS", 0x80090026: "NTE_INVALID_HANDLE", 0x80090027: "NTE_INVALID_PARAMETER", 0x80090029: "NTE_NOT_SUPPORTED", } ) func maybeWinErr(errNo uintptr) error { if code, known := tpmErrNums[uint32(errNo)]; known { return fmt.Errorf("tpm or subsystem failure: %s", code) } return nil } func utf16ToString(buf []byte) (string, error) { b := make([]uint16, len(buf)/2) // LPCSTR (Windows' representation of utf16) is always little endian. if err := binary.Read(bytes.NewReader(buf), binary.LittleEndian, &b); err != nil { return "", err } return windows.UTF16ToString(b), nil } // closeNCryptoObject is a helper to call NCryptFreeObject on a given handle. func closeNCryptObject(hnd uintptr) error { r, _, msg := nCryptFreeObject.Call(hnd) if r != 0 { if tpmErr := maybeWinErr(r); tpmErr != nil { return tpmErr } return fmt.Errorf("NCryptFreeObject returned %X: %v", r, msg) } return nil } // getNCryptBufferProperty is a helper to read a byte slice from a NCrypt handle property // using NCryptGetProperty. func getNCryptBufferProperty(hnd uintptr, field string) ([]byte, error) { var size uint32 wideField, err := windows.UTF16FromString(field) if err != nil { return nil, err } r, _, msg := nCryptGetProperty.Call(hnd, uintptr(unsafe.Pointer(&wideField[0])), 0, 0, uintptr(unsafe.Pointer(&size)), 0) if r != 0 { if tpmErr := maybeWinErr(r); tpmErr != nil { msg = tpmErr } return nil, fmt.Errorf("NCryptGetProperty returned %d,%X (%v) for key %q on size read", size, r, msg, field) } buff := make([]byte, size) r, _, msg = nCryptGetProperty.Call(hnd, uintptr(unsafe.Pointer(&wideField[0])), uintptr(unsafe.Pointer(&buff[0])), uintptr(size), uintptr(unsafe.Pointer(&size)), 0) if r != 0 { if tpmErr := maybeWinErr(r); tpmErr != nil { msg = tpmErr } return nil, fmt.Errorf("NCryptGetProperty returned %X (%v) for key %q on data read", r, msg, field) } return buff, nil } // winPCP represents a reference to the Platform Crypto Provider. type winPCP struct { hProv uintptr } // tbsDeviceInfo represents TPM device information from the TBS // API. This structure is identical to _TBS_DEVICE_INFO in tbs.h. type tbsDeviceInfo struct { TBSVersion uint32 TPMVersion uint32 TPMInterfaceType uint32 TPMImplementationRevision uint32 } // windowsTPMInfo describes the versions of the TPM and OS interface code. type windowsTPMInfo struct { Manufacturer string PCPVersion string TBSInfo tbsDeviceInfo } // TPMInfo returns version information about the TPM & OS interface code. func (h *winPCP) TPMInfo() (*windowsTPMInfo, error) { var err error out := &windowsTPMInfo{} buf, err := getNCryptBufferProperty(h.hProv, "PCP_PLATFORM_TYPE") if err != nil { return nil, fmt.Errorf("Failed to read PCP_PLATFORM_TYPE: %v", err) } out.Manufacturer, err = utf16ToString(buf) if err != nil { return nil, err } buf, err = getNCryptBufferProperty(h.hProv, "PCP_PROVIDER_VERSION") if err != nil { return nil, fmt.Errorf("Failed to read PCP_PROVIDER_VERSION: %v", err) } out.PCPVersion, err = utf16ToString(buf) if err != nil { return nil, err } r, _, msg := tbsGetDeviceInfo.Call(unsafe.Sizeof(out.TBSInfo), uintptr(unsafe.Pointer(&out.TBSInfo))) if r != 0 { return nil, fmt.Errorf("Failed to call Tbsi_GetDeviceInfo: %v", msg) } return out, nil } // TPMCommandInterface returns an interface where TPM commands can issued directly. func (h *winPCP) TPMCommandInterface() (io.ReadWriteCloser, error) { var provTBS tpmtbs.Context var sz uint32 platformHndField, err := windows.UTF16FromString("PCP_PLATFORMHANDLE") if err != nil { return nil, err } r, _, err := nCryptGetProperty.Call(h.hProv, uintptr(unsafe.Pointer(&platformHndField[0])), uintptr(unsafe.Pointer(&provTBS)), unsafe.Sizeof(provTBS), uintptr(unsafe.Pointer(&sz)), 0) if r != 0 { if tpmErr := maybeWinErr(r); tpmErr != nil { err = tpmErr } return nil, fmt.Errorf("NCryptGetProperty for platform handle returned %X (%v)", r, err) } return tpmutil.FromContext(provTBS), nil } // TPMKeyHandle returns a transient handle to the given key on the TPM. func (h *winPCP) TPMKeyHandle(hnd uintptr) (tpmutil.Handle, error) { var keyHndTBS tpmutil.Handle var sz uint32 platformHndField, err := windows.UTF16FromString("PCP_PLATFORMHANDLE") if err != nil { return 0, err } if r, _, err := nCryptGetProperty.Call(hnd, uintptr(unsafe.Pointer(&platformHndField[0])), uintptr(unsafe.Pointer(&keyHndTBS)), unsafe.Sizeof(keyHndTBS), uintptr(unsafe.Pointer(&sz)), 0); r != 0 { if tpmErr := maybeWinErr(r); tpmErr != nil { err = tpmErr } return 0, fmt.Errorf("NCryptGetProperty for hKey platform handle returned %X (%v)", r, err) } return keyHndTBS, nil } // Close releases all resources managed by the Handle. func (h *winPCP) Close() error { return closeNCryptObject(h.hProv) } // DeleteKey permanently removes the key with the given handle from the system, // and frees its handle. func (h *winPCP) DeleteKey(kh uintptr) error { r, _, msg := nCryptDeleteKey.Call(kh, 0) if r != 0 { return fmt.Errorf("nCryptDeleteKey returned %X: %v", r, msg) } return nil } // EKCerts returns the Endorsement Certificates. // Failure to fetch an ECC certificate is not considered // an error as they do not exist on all platforms. func (h *winPCP) EKCerts() ([]*x509.Certificate, error) { c, err := getPCPCerts(h.hProv, "PCP_RSA_EKNVCERT") if err != nil { return nil, err } eccCerts, err := getPCPCerts(h.hProv, "PCP_ECC_EKNVCERT") if err == nil { // ECC certs are not present on all platforms c = append(c, eccCerts...) } // Reading the certificate from the system store has failed. // Lets try reading the raw bytes directly from NVRAM instead. if len(c) == 0 { certs, err := getPCPCerts(h.hProv, "PCP_EKNVCERT") if err != nil { return nil, fmt.Errorf("Failed to read PCP_EKNVCERT: %v", err) } c = append(c, certs...) } var out []*x509.Certificate for _, der := range c { cert, err := ParseEKCertificate(der) if err != nil { return nil, err } out = append(out, cert) } return out, nil } // getPCPCerts is a helper to iterate over a certificates in a cert store, // whose handle was obtained by reading a specific property on a PCP handle. func getPCPCerts(hProv uintptr, propertyName string) ([][]byte, error) { var size, cryptCertHnd uintptr utf16PropName, err := windows.UTF16FromString(propertyName) if err != nil { return nil, err } r, _, msg := nCryptGetProperty.Call(hProv, uintptr(unsafe.Pointer(&utf16PropName[0])), uintptr(unsafe.Pointer(&cryptCertHnd)), 8, uintptr(unsafe.Pointer(&size)), 0) if r != 0 { return nil, fmt.Errorf("NCryptGetProperty returned %X, %v", r, msg) } defer crypt32CertCloseStore.Call(uintptr(unsafe.Pointer(cryptCertHnd)), 0) var out [][]byte var certContext uintptr for { certContext, _, msg = crypt32CertEnumCertificatesInStore.Call(uintptr(unsafe.Pointer(cryptCertHnd)), certContext) if certContext == 0 && msg != nil { if errno, ok := msg.(syscall.Errno); ok { // cryptENotFound is returned when there are no more certificates to iterate through. if errno == cryptENotFound { break } } return nil, msg } cert := (*syscall.CertContext)(unsafe.Pointer(certContext)) // Copy the buffer. This was taken straight from the Go source: src/crypto/x509/root_windows.go#L70 buf := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:] buf2 := make([]byte, cert.Length) copy(buf2, buf) out = append(out, buf2) } return out, nil } // NewAK creates a persistent attestation key of the specified name. func (h *winPCP) NewAK(name string) (uintptr, error) { var kh uintptr utf16Name, err := windows.UTF16FromString(name) if err != nil { return 0, err } utf16RSA, err := windows.UTF16FromString("RSA") if err != nil { return 0, err } // Create a persistent RSA key of the specified name. r, _, msg := nCryptCreatePersistedKey.Call(h.hProv, uintptr(unsafe.Pointer(&kh)), uintptr(unsafe.Pointer(&utf16RSA[0])), uintptr(unsafe.Pointer(&utf16Name[0])), 0, 0) if r != 0 { if tpmErr := maybeWinErr(r); tpmErr != nil { msg = tpmErr } return 0, fmt.Errorf("NCryptCreatePersistedKey returned %X: %v", r, msg) } // Specify generated key length to be 2048 bits. utf16Length, err := windows.UTF16FromString("Length") if err != nil { return 0, err } var length uint32 = 2048 r, _, msg = nCryptSetProperty.Call(kh, uintptr(unsafe.Pointer(&utf16Length[0])), uintptr(unsafe.Pointer(&length)), unsafe.Sizeof(length), 0) if r != 0 { if tpmErr := maybeWinErr(r); tpmErr != nil { msg = tpmErr } return 0, fmt.Errorf("NCryptSetProperty (Length) returned %X: %v", r, msg) } // Specify the generated key can only be used for identity attestation. utf16KeyPolicy, err := windows.UTF16FromString("PCP_KEY_USAGE_POLICY") if err != nil { return 0, err } var policy uint32 = nCryptPropertyPCPKeyUsagePolicyIdentity r, _, msg = nCryptSetProperty.Call(kh, uintptr(unsafe.Pointer(&utf16KeyPolicy[0])), uintptr(unsafe.Pointer(&policy)), unsafe.Sizeof(policy), 0) if r != 0 { if tpmErr := maybeWinErr(r); tpmErr != nil { msg = tpmErr } return 0, fmt.Errorf("NCryptSetProperty (PCP KeyUsage Policy) returned %X: %v", r, msg) } // Finalize (create) the key. r, _, msg = nCryptFinalizeKey.Call(kh, 0) if r != 0 { if tpmErr := maybeWinErr(r); tpmErr != nil { msg = tpmErr } return 0, fmt.Errorf("NCryptFinalizeKey returned %X: %v", r, msg) } return kh, nil } // EKPub returns a BCRYPT_RSA_BLOB structure representing the EK. func (h *winPCP) EKPub() ([]byte, error) { return getNCryptBufferProperty(h.hProv, "PCP_EKPUB") } type akProps struct { RawPublic []byte RawCreationData []byte RawAttest []byte RawSignature []byte } // AKProperties returns the binding properties of the given attestation // key. Note that it is only valid to call this function with the same // winPCP handle within which the AK was created. func (h *winPCP) AKProperties(kh uintptr) (*akProps, error) { idBlob, err := getNCryptBufferProperty(kh, "PCP_TPM12_IDBINDING") if err != nil { return nil, err } r := bytes.NewReader(idBlob) // Because the TPM 1.2 blob leads with a version tag, // we can switch decoding logic based on it. if bytes.Equal(idBlob[0:4], []byte{1, 1, 0, 0}) { return decodeAKProps12(r) } return decodeAKProps20(r) } // decodeAKProps12 separates the single TPM 1.2 blob from the PCP property // into its constituents, returning information about the public key // of the AK. func decodeAKProps12(r *bytes.Reader) (*akProps, error) { var out akProps // Skip over fixed-size fields in TPM_IDENTITY_CONTENTS which // we don't need to read. // Specifically: ver, ordinal, & labelPrivCADigest. r.Seek(4+4+20, io.SeekCurrent) pubKeyStartIdx := int(r.Size()) - r.Len() // Skip over fixed-size key parameters in TPM_PUBKEY, so // we can read the length of the exponent & // determine where the pubkey structure ends. // Specifically: algID, encScheme, sigScheme, paramSize, keyLength, // and numPrimes. r.Seek(4+2+2+4+4+4, io.SeekCurrent) // Read the size of the exponent section. var exponentSize uint32 if err := binary.Read(r, binary.BigEndian, &exponentSize); err != nil { return nil, fmt.Errorf("failed to decode exponentSize: %v", err) } // Consume the bytes representing the exponent. exp := make([]byte, int(exponentSize)) if err := binary.Read(r, binary.BigEndian, &exp); err != nil { return nil, fmt.Errorf("failed to decode exp: %v", err) } // Read the size of the key data. var keyDataSize uint32 if err := binary.Read(r, binary.BigEndian, &keyDataSize); err != nil { return nil, fmt.Errorf("failed to decode keyDataSize: %v", err) } // Seek to the end of the key data. r.Seek(int64(keyDataSize), io.SeekCurrent) // Read the trailing signature. out.RawSignature = make([]byte, r.Len()) if err := binary.Read(r, binary.BigEndian, &out.RawSignature); err != nil { return nil, fmt.Errorf("failed to decode signature: %v", err) } // Seek back to the location of the public key, and consume it. r.Seek(int64(pubKeyStartIdx), io.SeekStart) out.RawPublic = make([]byte, 24+int(exponentSize)+4+int(keyDataSize)) if err := binary.Read(r, binary.BigEndian, &out.RawPublic); err != nil { return nil, fmt.Errorf("failed to decode public: %v", err) } return &out, nil } // decodeAKProps20 separates the single TPM 2.0 blob from the PCP property // into its constituents. For TPM 2.0 devices, these are bytes representing // the following structures: TPM2B_PUBLIC, TPM2B_CREATION_DATA, TPM2B_ATTEST, // and TPMT_SIGNATURE. func decodeAKProps20(r *bytes.Reader) (*akProps, error) { var out akProps var publicSize uint16 if err := binary.Read(r, binary.BigEndian, &publicSize); err != nil { return nil, fmt.Errorf("failed to decode TPM2B_PUBLIC.size: %v", err) } out.RawPublic = make([]byte, publicSize) if err := binary.Read(r, binary.BigEndian, &out.RawPublic); err != nil { return nil, fmt.Errorf("failed to decode TPM2B_PUBLIC.data: %v", err) } var creationDataSize uint16 if err := binary.Read(r, binary.BigEndian, &creationDataSize); err != nil { return nil, fmt.Errorf("failed to decode TPM2B_CREATION_DATA.size: %v", err) } out.RawCreationData = make([]byte, creationDataSize) if err := binary.Read(r, binary.BigEndian, &out.RawCreationData); err != nil { return nil, fmt.Errorf("failed to decode TPM2B_CREATION_DATA.data: %v", err) } var attestSize uint16 if err := binary.Read(r, binary.BigEndian, &attestSize); err != nil { return nil, fmt.Errorf("failed to decode TPM2B_ATTEST.size: %v", err) } out.RawAttest = make([]byte, attestSize) if err := binary.Read(r, binary.BigEndian, &out.RawAttest); err != nil { return nil, fmt.Errorf("failed to decode TPM2B_ATTEST.data: %v", err) } // The encoded TPMT_SIGNATURE structure represents the remaining bytes in // the ID binding blob. out.RawSignature = make([]byte, r.Len()) if err := binary.Read(r, binary.BigEndian, &out.RawSignature); err != nil { return nil, fmt.Errorf("failed to decode TPMT_SIGNATURE.data: %v", err) } return &out, nil } // LoadKeyByName returns a handle to the persistent PCP key with the specified // name. func (h *winPCP) LoadKeyByName(name string) (uintptr, error) { utf16Name, err := windows.UTF16FromString(name) if err != nil { return 0, err } var hKey uintptr r, _, msg := nCryptOpenKey.Call(h.hProv, uintptr(unsafe.Pointer(&hKey)), uintptr(unsafe.Pointer(&utf16Name[0])), 0, 0) if r != 0 { return 0, msg } return hKey, nil } // ActivateCredential performs TPM2_ActivateCredential or TPM_ActivateIdentity. func (h *winPCP) ActivateCredential(hKey uintptr, activationBlob []byte) ([]byte, error) { utf16ActivationStr, err := windows.UTF16FromString("PCP_TPM12_IDACTIVATION") if err != nil { return nil, err } r, _, msg := nCryptSetProperty.Call(hKey, uintptr(unsafe.Pointer(&utf16ActivationStr[0])), uintptr(unsafe.Pointer(&activationBlob[0])), uintptr(len(activationBlob)), 0) if r != 0 { if tpmErr := maybeWinErr(r); tpmErr != nil { msg = tpmErr } return nil, fmt.Errorf("NCryptSetProperty returned %X (%v) for key activation", r, msg) } secretBuff := make([]byte, 256) var size uint32 r, _, msg = nCryptGetProperty.Call(hKey, uintptr(unsafe.Pointer(&utf16ActivationStr[0])), uintptr(unsafe.Pointer(&secretBuff[0])), uintptr(len(secretBuff)), uintptr(unsafe.Pointer(&size)), 0) if r != 0 { if tpmErr := maybeWinErr(r); tpmErr != nil { msg = tpmErr } return nil, fmt.Errorf("NCryptGetProperty returned %X (%v) for key activation", r, msg) } return secretBuff[:size], nil } // openPCP initializes a reference to the Microsoft PCP provider. // The Caller is expected to call Close() when they are done. func openPCP() (*winPCP, error) { var err error var h winPCP pname, err := windows.UTF16FromString(pcpProviderName) if err != nil { return nil, err } r, _, err := nCryptOpenStorageProvider.Call(uintptr(unsafe.Pointer(&h.hProv)), uintptr(unsafe.Pointer(&pname[0])), 0) if r != 0 { // r is non-zero on error, err is always populated in this case. if tpmErr := maybeWinErr(r); tpmErr != nil { return nil, tpmErr } return nil, err } return &h, nil } go-attestation-0.5.1/attest/secureboot.go000066400000000000000000000255721452320553600205040ustar00rootroot00000000000000// Copyright 2020 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package attest import ( "bytes" "crypto/x509" "errors" "fmt" "github.com/google/go-attestation/attest/internal" ) // SecurebootState describes the secure boot status of a machine, as determined // by processing its event log. type SecurebootState struct { Enabled bool // PlatformKeys enumerates keys which can sign a key exchange key. PlatformKeys []x509.Certificate // PlatformKeys enumerates key hashes which can sign a key exchange key. PlatformKeyHashes [][]byte // ExchangeKeys enumerates keys which can sign a database of permitted or // forbidden keys. ExchangeKeys []x509.Certificate // ExchangeKeyHashes enumerates key hashes which can sign a database or // permitted or forbidden keys. ExchangeKeyHashes [][]byte // PermittedKeys enumerates keys which may sign binaries to run. PermittedKeys []x509.Certificate // PermittedHashes enumerates hashes which permit binaries to run. PermittedHashes [][]byte // ForbiddenKeys enumerates keys which must not permit a binary to run. ForbiddenKeys []x509.Certificate // ForbiddenKeys enumerates hashes which must not permit a binary to run. ForbiddenHashes [][]byte // PreSeparatorAuthority describes the use of a secure-boot key to authorize // the execution of a binary before the separator. PreSeparatorAuthority []x509.Certificate // PostSeparatorAuthority describes the use of a secure-boot key to authorize // the execution of a binary after the separator. PostSeparatorAuthority []x509.Certificate // DriverLoadSourceHints describes the origin of boot services drivers. // This data is not tamper-proof and must only be used as a hint. DriverLoadSourceHints []DriverLoadSource // DMAProtectionDisabled is true if the platform reports during boot that // DMA protection is supported but disabled. // // See: https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/oem-kernel-dma-protection DMAProtectionDisabled bool } // DriverLoadSource describes the logical origin of a boot services driver. type DriverLoadSource uint8 const ( UnknownSource DriverLoadSource = iota PciMmioSource ) // ParseSecurebootState parses a series of events to determine the // configuration of secure boot on a device. An error is returned if // the state cannot be determined, or if the event log is structured // in such a way that it may have been tampered post-execution of // platform firmware. func ParseSecurebootState(events []Event) (*SecurebootState, error) { // This algorithm verifies the following: // - All events in PCR 7 have event types which are expected in PCR 7. // - All events are parsable according to their event type. // - All events have digests values corresponding to their data/event type. // - No unverifiable events were present. // - All variables are specified before the separator and never duplicated. // - The SecureBoot variable has a value of 0 or 1. // - If SecureBoot was 1 (enabled), authority events were present indicating // keys were used to perform verification. // - If SecureBoot was 1 (enabled), platform + exchange + database keys // were specified. // - No UEFI debugger was attached. var ( out SecurebootState seenSeparator7 bool seenSeparator2 bool seenAuthority bool seenVars = map[string]bool{} driverSources [][]internal.EFIDevicePathElement ) for _, e := range events { if e.Index != 7 && e.Index != 2 { continue } et, err := internal.UntrustedParseEventType(uint32(e.Type)) if err != nil { return nil, fmt.Errorf("unrecognised event type: %v", err) } digestVerify := e.digestEquals(e.Data) switch e.Index { case 7: switch et { case internal.Separator: if seenSeparator7 { return nil, fmt.Errorf("duplicate separator at event %d", e.sequence) } seenSeparator7 = true if !bytes.Equal(e.Data, []byte{0, 0, 0, 0}) { return nil, fmt.Errorf("invalid separator data at event %d: %v", e.sequence, e.Data) } if digestVerify != nil { return nil, fmt.Errorf("invalid separator digest at event %d: %v", e.sequence, digestVerify) } case internal.EFIAction: switch string(e.Data) { case "UEFI Debug Mode": return nil, errors.New("a UEFI debugger was present during boot") case "DMA Protection Disabled": if digestVerify != nil { return nil, fmt.Errorf("invalid digest for EFI Action 'DMA Protection Disabled' on event %d: %v", e.sequence, digestVerify) } out.DMAProtectionDisabled = true default: return nil, fmt.Errorf("event %d: unexpected EFI action event", e.sequence) } case internal.EFIVariableDriverConfig: v, err := internal.ParseUEFIVariableData(bytes.NewReader(e.Data)) if err != nil { return nil, fmt.Errorf("failed parsing EFI variable at event %d: %v", e.sequence, err) } if _, seenBefore := seenVars[v.VarName()]; seenBefore { return nil, fmt.Errorf("duplicate EFI variable %q at event %d", v.VarName(), e.sequence) } seenVars[v.VarName()] = true if seenSeparator7 { return nil, fmt.Errorf("event %d: variable %q specified after separator", e.sequence, v.VarName()) } if digestVerify != nil { return nil, fmt.Errorf("invalid digest for variable %q on event %d: %v", v.VarName(), e.sequence, digestVerify) } switch v.VarName() { case "SecureBoot": if len(v.VariableData) != 1 { return nil, fmt.Errorf("event %d: SecureBoot data len is %d, expected 1", e.sequence, len(v.VariableData)) } out.Enabled = v.VariableData[0] == 1 case "PK": if out.PlatformKeys, out.PlatformKeyHashes, err = v.SignatureData(); err != nil { return nil, fmt.Errorf("event %d: failed parsing platform keys: %v", e.sequence, err) } case "KEK": if out.ExchangeKeys, out.ExchangeKeyHashes, err = v.SignatureData(); err != nil { return nil, fmt.Errorf("event %d: failed parsing key exchange keys: %v", e.sequence, err) } case "db": if out.PermittedKeys, out.PermittedHashes, err = v.SignatureData(); err != nil { return nil, fmt.Errorf("event %d: failed parsing signature database: %v", e.sequence, err) } case "dbx": if out.ForbiddenKeys, out.ForbiddenHashes, err = v.SignatureData(); err != nil { return nil, fmt.Errorf("event %d: failed parsing forbidden signature database: %v", e.sequence, err) } } case internal.EFIVariableAuthority: v, err := internal.ParseUEFIVariableData(bytes.NewReader(e.Data)) if err != nil { return nil, fmt.Errorf("failed parsing UEFI variable data: %v", err) } a, err := internal.ParseUEFIVariableAuthority(v) if err != nil { // Workaround for: https://github.com/google/go-attestation/issues/157 if err == internal.ErrSigMissingGUID { // Versions of shim which do not carry // https://github.com/rhboot/shim/commit/8a27a4809a6a2b40fb6a4049071bf96d6ad71b50 // have an erroneous additional byte in the event, which breaks digest // verification. If verification failed, we try removing the last byte. if digestVerify != nil && len(e.Data) > 0 { digestVerify = e.digestEquals(e.Data[:len(e.Data)-1]) } } else { return nil, fmt.Errorf("failed parsing EFI variable authority at event %d: %v", e.sequence, err) } } seenAuthority = true if digestVerify != nil { return nil, fmt.Errorf("invalid digest for authority on event %d: %v", e.sequence, digestVerify) } if !seenSeparator7 { out.PreSeparatorAuthority = append(out.PreSeparatorAuthority, a.Certs...) } else { out.PostSeparatorAuthority = append(out.PostSeparatorAuthority, a.Certs...) } default: return nil, fmt.Errorf("unexpected event type in PCR7: %v", et) } case 2: switch et { case internal.Separator: if seenSeparator2 { return nil, fmt.Errorf("duplicate separator at event %d", e.sequence) } seenSeparator2 = true if !bytes.Equal(e.Data, []byte{0, 0, 0, 0}) { return nil, fmt.Errorf("invalid separator data at event %d: %v", e.sequence, e.Data) } if digestVerify != nil { return nil, fmt.Errorf("invalid separator digest at event %d: %v", e.sequence, digestVerify) } case internal.EFIBootServicesDriver: if !seenSeparator2 { imgLoad, err := internal.ParseEFIImageLoad(bytes.NewReader(e.Data)) if err != nil { return nil, fmt.Errorf("failed parsing EFI image load at boot services driver event %d: %v", e.sequence, err) } dp, err := imgLoad.DevicePath() if err != nil { return nil, fmt.Errorf("failed to parse device path for driver load event %d: %v", e.sequence, err) } driverSources = append(driverSources, dp) } } } } // Compute driver source hints based on the EFI device path observed in // EFI Boot-services driver-load events. sourceLoop: for _, source := range driverSources { // We consider a driver to have originated from PCI-MMIO if any number // of elements in the device path [1] were PCI devices, and are followed by // an element representing a "relative offset range" read. // In the wild, we have typically observed 4-tuple device paths for such // devices: ACPI device -> PCI device -> PCI device -> relative offset. // // [1]: See section 9 of the UEFI specification v2.6 or greater. var seenPCI bool for _, e := range source { // subtype 0x1 corresponds to a PCI device (See: 9.3.2.1) if e.Type == internal.HardwareDevice && e.Subtype == 0x1 { seenPCI = true } // subtype 0x8 corresponds to "relative offset range" (See: 9.3.6.8) if seenPCI && e.Type == internal.MediaDevice && e.Subtype == 0x8 { out.DriverLoadSourceHints = append(out.DriverLoadSourceHints, PciMmioSource) continue sourceLoop } } out.DriverLoadSourceHints = append(out.DriverLoadSourceHints, UnknownSource) } if !out.Enabled { return &out, nil } if !seenAuthority { return nil, errors.New("secure boot was enabled but no key was used") } if len(out.PlatformKeys) == 0 && len(out.PlatformKeyHashes) == 0 { return nil, errors.New("secure boot was enabled but no platform keys were known") } if len(out.ExchangeKeys) == 0 && len(out.ExchangeKeyHashes) == 0 { return nil, errors.New("secure boot was enabled but no key exchange keys were known") } if len(out.PermittedKeys) == 0 && len(out.PermittedHashes) == 0 { return nil, errors.New("secure boot was enabled but no keys or hashes were permitted") } return &out, nil } go-attestation-0.5.1/attest/secureboot_test.go000066400000000000000000000257061452320553600215420ustar00rootroot00000000000000// Copyright 2020 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package attest import ( "encoding/base64" "encoding/json" "os" "testing" ) func TestSecureBoot(t *testing.T) { data, err := os.ReadFile("testdata/windows_gcp_shielded_vm.json") if err != nil { t.Fatalf("reading test data: %v", err) } var dump Dump if err := json.Unmarshal(data, &dump); err != nil { t.Fatalf("parsing test data: %v", err) } el, err := ParseEventLog(dump.Log.Raw) if err != nil { t.Fatalf("parsing event log: %v", err) } events, err := el.Verify(dump.Log.PCRs) if err != nil { t.Fatalf("validating event log: %v", err) } sbState, err := ParseSecurebootState(events) if err != nil { t.Fatalf("ExtractSecurebootState() failed: %v", err) } if got, want := sbState.Enabled, true; got != want { t.Errorf("secureboot.Enabled = %v, want %v", got, want) } } // See: https://github.com/google/go-attestation/issues/157 func TestSecureBootBug157(t *testing.T) { raw, err := os.ReadFile("testdata/sb_cert_eventlog") if err != nil { t.Fatalf("reading test data: %v", err) } elr, err := ParseEventLog(raw) if err != nil { t.Fatalf("parsing event log: %v", err) } pcrs := []PCR{ {'\x00', []byte("Q\xc3#\xde\f\fiOF\x01\xcd\xd0+\xebX\xff\x13b\x9ft"), '\x03', false}, {'\x01', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x03', false}, {'\x02', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x03', false}, {'\x03', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x03', false}, {'\x04', []byte("\xb7q\x00\x8d\x17<\x02+\xc1oKM\x1a\u007f\x8b\x99\xed\x88\xee\xb1"), '\x03', false}, {'\x05', []byte("\xd79j\xc6\xe8\x87\xda\"Þ ;@\x95/p\xb8\xdbÒ©\x96"), '\x03', false}, {'\x06', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x03', false}, {'\a', []byte("E\xa8b\x1d4\xa5}\xf2\xb2\xe7\xf1L\x92\xb9\x9a\xc8\xde}X\x05"), '\x03', false}, {'\b', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x03', false}, {'\t', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x03', false}, {'\n', []byte("\x82\x84\x10>\x06\xd4\x01\"\xbcd\xa0䡉\x1a\xf9\xec\xd4\\\xf6"), '\x03', false}, {'\v', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x03', false}, {'\f', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x03', false}, {'\r', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x03', false}, {'\x0e', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x03', false}, {'\x0f', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x03', false}, {'\x10', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x03', false}, {'\x11', []byte("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"), '\x03', false}, {'\x12', []byte("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"), '\x03', false}, {'\x13', []byte("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"), '\x03', false}, {'\x14', []byte("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"), '\x03', false}, {'\x15', []byte("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"), '\x03', false}, {'\x16', []byte("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"), '\x03', false}, {'\x17', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x03', false}, {'\x00', []byte("\xfc\xec\xb5j\xcc08b\xb3\x0e\xb3BÄ™\v\xebP\xb5ૉr$I\xc2Ù§?7\xb0\x19\xfe"), '\x05', false}, {'\x01', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x05', false}, {'\x02', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x05', false}, {'\x03', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x05', false}, {'\x04', []byte("\xa9)h\x80oy_\xa3D5\xd9\xf1\x18\x13hL\xa1\xe7\x05`w\xf7\x00\xbaI\xf2o\x99b\xf8m\x89"), '\x05', false}, {'\x05', []byte("̆\x18\xb7y2\xb4\xef\xda\x12\xccX\xba\xd9>\xcdÑ•\x9d\xea)\xe5\xabyE%\xa6\x19\xf5\xba\xab\xee"), '\x05', false}, {'\x06', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x05', false}, {'\a', []byte("Q\xb3\x04\x88\xc9\xe6%]\x82+\xdc\x1b Ù©,2\xbd\xe6\xc3\xe7\xbc\x02\xbc\xdd2\x82^\xb5\xef\x06\x9a"), '\x05', false}, {'\b', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x05', false}, {'\t', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x05', false}, {'\n', []byte("\xc3l\x9a\xb1\x10\x9b\xa0\x8a?dX!\x18\xf8G\x1a]i[\xc9#\xa0\xa2\xbd\x04]\xb1K\x97OB9"), '\x05', false}, {'\v', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x05', false}, {'\f', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x05', false}, {'\r', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x05', false}, {'\x0e', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x05', false}, {'\x0f', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x05', false}, {'\x10', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x05', false}, {'\x11', []byte("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"), '\x05', false}, {'\x12', []byte("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"), '\x05', false}, {'\x13', []byte("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"), '\x05', false}, {'\x14', []byte("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"), '\x05', false}, {'\x15', []byte("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"), '\x05', false}, {'\x16', []byte("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"), '\x05', false}, {'\x17', []byte("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), '\x05', false}, } events, err := elr.Verify(pcrs) if err != nil { t.Fatalf("failed to verify log: %v", err) } sbs, err := ParseSecurebootState(events) if err != nil { t.Fatalf("failed parsing secureboot state: %v", err) } if got, want := len(sbs.PostSeparatorAuthority), 3; got != want { t.Errorf("len(sbs.PostSeparatorAuthority) = %d, want %d", got, want) } } func b64MustDecode(input string) []byte { b, err := base64.StdEncoding.DecodeString(input) if err != nil { panic(err) } return b } func TestSecureBootOptionRom(t *testing.T) { raw, err := os.ReadFile("testdata/option_rom_eventlog") if err != nil { t.Fatalf("reading test data: %v", err) } elr, err := ParseEventLog(raw) if err != nil { t.Fatalf("parsing event log: %v", err) } pcrs := []PCR{ {'\x00', b64MustDecode("AVGK7ch6DvUF0nJh74NYCefaAIY="), '\x03', false}, {'\x01', b64MustDecode("vr/0wIpmd0c6tgTO3vuC+FDN6IM="), '\x03', false}, {'\x02', b64MustDecode("NmoxoMB1No8OEIVzM+ou1uigD9M="), '\x03', false}, {'\x03', b64MustDecode("sqg7Dr8vg3Qpmlsr38MeqVWtcjY="), '\x03', false}, {'\x04', b64MustDecode("OfOIw5WekEaUcm9MAVttzq4GgKE="), '\x03', false}, {'\x05', b64MustDecode("cjoFIM9/KXhUh0K9FUFwayRGRZ4="), '\x03', false}, {'\x06', b64MustDecode("sqg7Dr8vg3Qpmlsr38MeqVWtcjY="), '\x03', false}, {'\x07', b64MustDecode("IN59+6a838ytrX4+sJnJHU2Xxa0="), '\x03', false}, } events, err := elr.Verify(pcrs) if err != nil { t.Errorf("failed to verify log: %v", err) } sbs, err := ParseSecurebootState(events) if err != nil { t.Errorf("failed parsing secureboot state: %v", err) } if got, want := len(sbs.PostSeparatorAuthority), 2; got != want { t.Errorf("len(sbs.PostSeparatorAuthority) = %d, want %d", got, want) } if got, want := len(sbs.DriverLoadSourceHints), 1; got != want { t.Fatalf("len(sbs.DriverLoadSourceHints) = %d, want %d", got, want) } if got, want := sbs.DriverLoadSourceHints[0], PciMmioSource; got != want { t.Errorf("sbs.DriverLoadSourceHints[0] = %v, want %v", got, want) } } func TestSecureBootEventLogUbuntu(t *testing.T) { data, err := os.ReadFile("testdata/ubuntu_2104_shielded_vm_no_secure_boot_eventlog") if err != nil { t.Fatalf("reading test data: %v", err) } el, err := ParseEventLog(data) if err != nil { t.Fatalf("parsing event log: %v", err) } evts := el.Events(HashSHA256) if err != nil { t.Fatalf("verifying event log: %v", err) } _, err = ParseSecurebootState(evts) if err != nil { t.Errorf("parsing sb state: %v", err) } } func TestSecureBootEventLogFedora36(t *testing.T) { data, err := os.ReadFile("testdata/coreos_36_shielded_vm_no_secure_boot_eventlog") if err != nil { t.Fatalf("reading test data: %v", err) } el, err := ParseEventLog(data) if err != nil { t.Fatalf("parsing event log: %v", err) } evts := el.Events(HashSHA256) if err != nil { t.Fatalf("verifying event log: %v", err) } _, err = ParseSecurebootState(evts) if err != nil { t.Errorf("parsing sb state: %v", err) } } go-attestation-0.5.1/attest/storage.go000066400000000000000000000045221452320553600177660ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package attest import ( "encoding/json" "fmt" ) // serializedKey represents a loadable, TPM-backed key. type serializedKey struct { // Encoding describes the strategy by which the key should be // loaded/unloaded. Encoding keyEncoding `json:"KeyEncoding"` // TPMVersion describes the version of the TPM which the key was generated // on. deserializeKey() returns an error if it attempts to deserialize a key // which is from a different TPM version to the currently opened TPM. TPMVersion TPMVersion // Public represents the public key, in a TPM-specific format. This // field is populated on all platforms and TPM versions. Public []byte // The following fields are only valid for TPM 2.0 hardware, holding // information returned as the result to a TPM2_CertifyCreation command. // These are stored alongside the key for later use, as the certification // can only be obtained immediately after the key is generated. CreateData []byte CreateAttestation []byte CreateSignature []byte // Name is only valid for KeyEncodingOSManaged, which is only used // on Windows. Name string // Blob represents the key material for KeyEncodingEncrypted keys. This // is only used on Linux. Blob []byte `json:"KeyBlob"` } // Serialize represents the key in a persistent format which may be // loaded at a later time using deserializeKey(). func (k *serializedKey) Serialize() ([]byte, error) { return json.Marshal(k) } func deserializeKey(b []byte, version TPMVersion) (*serializedKey, error) { var k serializedKey var err error if err = json.Unmarshal(b, &k); err != nil { return nil, fmt.Errorf("json.Unmarshal() failed: %v", err) } if k.TPMVersion != version { return nil, fmt.Errorf("key for different TPM version: %v", k.TPMVersion) } return &k, nil } go-attestation-0.5.1/attest/testdata/000077500000000000000000000000001452320553600176015ustar00rootroot00000000000000go-attestation-0.5.1/attest/testdata/coreos_36_shielded_vm_no_secure_boot_eventlog000066400000000000000000000745271452320553600307000ustar00rootroot00000000000000)Spec ID Event03 0?p‹Û¯òfUµ@6GL  Ðüñ2¨ûõ¤á¥Œ×MÒ5}çP;[jýZy‰©Ž¾ m±‚.BÏ’4ö§ŠÅËIô›ÁÄ9?71a!‹¶ߊ÷¦ŒΦ‚ae‰¿ c0GCE Virtual Firmware v1+líÑca—»Á¯ª€ÌnÍ> jÉ$H¨ WU¦;Íe¹öÕrn’]Èi»F”(Å gã,8%ž¤€’4ÌϽ'…Ã+Þˆ(3»mö½˜šIôVcæ<á™üÐP, GCE NonHostInfo€WÍMÁ”BGZ¨'CHO;ªˆáB¸ Z¨'ÛÌûDÒ­žÏÚV½êb † ”¾Õ·¢{ºMØ Ï¤âÆõrb{ðmViÌ*±ƒXÒ{E¼cnÁ ϯ·@øG¦§K^®Ö·32ì5aßä‹Ê“Òª à˜+Œ SecureBoot€Z½”«ó>4§›=“ÓPçBØìØ Û»ã—fX…eÅ̘¢®¶äJ‘xÉñ“[ÒAóƒrD„» §cU<–w Ó¥æøàÁïÍòUZ÷Sú:jþCë{* ô¦øØäÝE–hó°àJaßä‹Ê“Òª à˜+Œ&PK¡YÀ¥ä”§J‡µ«\+ðr& ÒúÒˆ¤G—’[ªG»‰0‚ö0‚Þ  ÕJègƒ]ê0  *†H†÷  010 U newpk0 180821215115Z 180920215115Z010 U newpk0‚"0  *†H†÷ ‚0‚ ‚̹Õ|ømkcêÉbô “Éþã|,EÎ…RRH|ûC&¿ ¥‰°òÝÇ6èi•ªŒoТ#o4ÂO±žkÆú¸”ÁœŽp‡‘BÎi!“}ÚuŸ¿1 PÁï€#û¾;Vã ×Gê0¯Ô]©c‰¢ü9á–¡‡Ã=&²Ó¢lìÈ—×ÎÚ겕<³ÎŠÏÚ:Qˆ?%°K>ÌÝùÚÛQÕ‘š¡½ˆâñ´ñ³’·ãgæ­ŒjÜ'?ÜÔNlÁ½ïÞV*ÚY` yÓ©|WýQa7}ä·n•ðR›CžÜH<ͼ9Ÿ£èG F¸6Ü’³•¨ÎJãF#XK£S0Q0U˜P„Bó/Û—‚'(—t1F^`ËÅ0U#0€˜P„Bó/Û—‚'(—t1F^`ËÅ0Uÿ0ÿ0  *†H†÷  ‚Š¡R?ªç½°$«‹­2°Iý{4Ë;€v`=ŽÜÊkiÂ[”踜Œ,×¼¬}‚YõÄ.¢l¥ì˜ð1#6øË0ƒg::+b!`,ºõ.ù(nÊfpX(†gi„l'X%œPép¸`nT…J¯mE¦[4ü&M<á»$.yàÑȬ|Ù8GCk3PWãsž¦‡ÝÃâJüs{K ‡Çƒ 6Zêi‡@„ ,”€/=®=ËpÄ5¹>q²£Æ­Ø$?}`«o îzšÏuŸèL«ÍQ‡hX3²Ù¼8%*˜KEûg3›%œ?¬¤CDÌÍÓÈ ná€ðPy¶ÌBé.èZtÙÂviÀâ b&GØ[Šd}-.f‚Áb {l¦·"ZfWÂVµ‚ À§¦@“íy΋V—=ÞöÚ‘¿ ëW’³ÈBB7Bµ)C¥‹ß#(¤4“~2xˆ>aßä‹Ê“Òª à˜+ŒKEK¡YÀ¥ä”§J‡µ«\+ðrüÒúÒˆ¤G—’[ªG»‰0‚è0‚Р a ш0  *†H†÷  0‘1 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0 110624204129Z 260624205129Z0€1 0 UUS10U Washington10URedmond10U Microsoft Corporation1*0(U!Microsoft Corporation KEK CA 20110‚"0  *†H†÷ ‚0‚ ‚Ä赊¿­W&°&ÃêçûWzD] ÚJåt*æ°ìmëì¹ãZc2|Oã §8“ŽÆõà„±š›,çõ·‘Ö áâÀ¨¬0ßHóPšd§QÈ…O †Îþ/áŸÿ‚ÀíéÍÎôSjb: C¹â%ýþùÔÄ«â#‰p·¤Mì®åœúÂ×ÁËÔèÄ/å™î$‹ìò‹êÃJûC ~µG’lÜæ‰ëõ3ë*qåùƒ<ÿ% /hvFÿºO¾Ü­q*XªûÒy=ä›e;Ì)*ŸürY¢ë®’ïö5€Æìä_ÌvÍïc’Á¯y@„y‡ãR¨è{i£‚O0‚K0 +‚70UbüCÍ >¤ËgÒ[ÙU¬{̶Š_0 +‚7  SubCA0 U†0Uÿ0ÿ0U#0€EfRCá~X¿ÖNž#U;:"j¨0\UU0S0Q O M†Khttp://crl.microsoft.com/pki/crl/products/MicCorThiParMarRoo_2010-10-05.crl0`+T0R0P+0†Dhttp://www.microsoft.com/pki/certs/MicCorThiParMarRoo_2010-10-05.crt0  *†H†÷  ‚Ô„ˆõ”Ê*<û*’ × ÑñèRf¨î¢µuzª-¤vZêy·¹7jQ{döádòg¾÷¨x½ºÎˆXd ÖWÈ£_ÖÛÆÐiÎHK2·ë]Ò0õÀõ¸ºx£+þ›Û4V„ì‚Ê®A%pœkéþ×–å甲* Kÿ(){÷×|¥Ñv¹Èyí’œÂþßo~l{ÔÁEÝ4Q–9å^VØ–ô¦B³ wýòqVÌŸ†#¤‡Ë¦ýX~Ôig‘~òå ‹Š<‡„ëãνCå­-„“Žj+Z|DúRªÈ-»àRßøš=Á`°á3µ£ˆÑe ç¬|¤Á‚‡N8±/ Ňoý.¼9¶çæÃàäÍ'„ï”Bï)‹FA;gØùCYeË ¼ý’Oôu;§©$üPA@yà-O j'vnRí–i{¯÷‡ÐE­Sû0ª76aÚJi4ØhíÖÏl” ÓÏl"y­±ð¼¢F`©ÄÂ!‚ñýòèy2`¿Ø¬¥"KÊÁØKë}?W5²æOu´°`"S®‘yÖ›A†Tp²Þ 5|°4rº—`;ðy뢲]¢¸‡Åéöµ—%o8Ÿã‘úŠy˜Ãi·£ —øÊ®×ÄóÀuk4 µ™`ó\°ÅWN6Ò2„¿ž€ ¢œ'û¢a€`³"ÇÉr bº8Ã„Š”bù‡tņéÙTç)!³¥%A$¶62̯Z 5 Íbº¾öúà[î|<å(ó(yÓwŒ6ù»ñêóbB:؛Ȧ’ƒ­(!Åü7k ˲×:=–E£¼ÚÐgeoG db¡YÀ¥ä”§J‡µ«\+ðr@$ÒúÒˆ¤G—’[ªG»‰0‚0‚ø  aÓÄ0  *†H†÷  0‘1 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0 110627212245Z 260627213245Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1+0)U"Microsoft Corporation UEFI CA 20110‚"0  *†H†÷ ‚0‚ ‚¥lLÇE jK ¤À‡u CTdàí’} ²s¿ ÆJEa Å-–Óõ+ ûMI›A€<¹Týæ¼ÑĤŠAŠ\Yƒh2»ŒGÉîq¼!OšŠ|ÿD?2²&H®uµîÉLJ~䂚xwM °½öÓÓ¼ú+¥Q8]õûºÛxÛÿì –Õƒ¸é¶À{@{á('ÉúïV^æ~”~ÀðD²y9åÚ²b‹M¿8pâh$É3¤7ÕXi^Ó|íÁSçN°*‡caocYê²+y× agŠ[ý^­‡º†gOqX"""΋ïTqÎP5Xv•îj±¢Õ£‚v0‚r0 +‚70# +‚7øÁk·wSJó%7N¡&{ p€0U­¿C ½‚pœŒÕO1nÕ"˜ŠÔ0 +‚7  SubCA0 U†0Uÿ0ÿ0U#0€EfRCá~X¿ÖNž#U;:"j¨0\UU0S0Q O M†Khttp://crl.microsoft.com/pki/crl/products/MicCorThiParMarRoo_2010-10-05.crl0`+T0R0P+0†Dhttp://www.microsoft.com/pki/certs/MicCorThiParMarRoo_2010-10-05.crt0  *†H†÷  ‚5Bÿ0ÌÎ÷v ­hX5)F2v'|ïA'BJªm8HYUóéX4¦ ‚ª]­‚Ú€ƒA´ò¹ó]ñPù³U„B( ½²®QÅÀ¬—•!Ûüwž•s‘ˆÊ½½R¹P ßWž aí åm%Ù@@ÈΣJÂM¯šT½Ç¼¹+=I+2üj!iO›È~B4ü6‹ @À³š%u'ÍÉ£ö]Ñç6Tz¹PµÓÑ¿»tßÜ€Õíô/k/ÞfŒ°#åÇ„ØíêÁ3‚­VK-ñh•ÍÏðrð®»Ý†…˜,!L3+ðJðh‡µ’U2u¡j‚j<£%¤í­×®ËØ@Y „Ñ•Lb‘"tŒ=GD¦ä°›45±ú¶S¨,ì¤qȸºèDfäGTŽV³Ÿ˜²†Ðh>#µ/^P…Æ‚_A¡ô. à™Òluä¶iµ!†úÑöâMÑÚ­,wS%27ÇlRr•†°ñ5ajõ²;PV¦2-þ¢‰ùB†'U¡‚ÊZ›ø0˜T¦G–%/È&äA”\?å–ã…[<>?»GrUâ%"±Ù{ç*£÷Fà Ö‰ã5'bq¦ïÐ'  Y7`ø8”¸àxpøºL†‡”öà®Eîe¶£~iu’›õ¦¼YƒX¡YÀ¥ä”§J‡µ«\+ðrëÒúÒˆ¤G—’[ªG»‰0‚×0‚¿  avV0  *†H†÷  0ˆ1 0 UUS10U Washington10URedmond10U Microsoft Corporation1200U)Microsoft Root Certificate Authority 20100 111019184142Z 261019185142Z0„1 0 UUS10U Washington10URedmond10U Microsoft Corporation1.0,U%Microsoft Windows Production PCA 20110‚"0  *†H†÷ ‚0‚ ‚Ý »¢ä. ãçÅ÷–i¼!½i33ï­ËT€îƒ»Å „Ù÷Ò‹ó8°«¤­-|byÿãJ?5 pãÄçkàœÀ6uéŠ1ÝpåÜ7µtF–([‡`#,¿ÜG¥g÷Q'žrë¦É¹;S5|åÓì'¹‡þ¹É# o¨F‘Án–http://www.microsoft.com/pki/certs/MicRooCerAut_2010-06-23.crt0  *†H†÷  ‚ü|qQ¥yÂn²ï9>¼«\`ìß¨Ó éôö–…¶QˆfG¢°=*hw»‘Lb{¶ÁǺz‡4Kbz™éÊüÎJ7É-¤W|þ=ܸZúÖij…:ê³Ùnäi!7ÞÑöugÓ“W^)9Èî-áÍäEs[ÐÒÎz«‚FXÐ^³g¯l5ò¼å?$â5¢ uöV™Ôx,ÑëЈªñߺ~,c·›#!ÄùxlâX6+‘̤Ùò-ºù”@íEñΊ\k>«Óp* jà_GÑÕc 2ò¯×6*pZåBYqKWº~ƒð!<ôÁŹ“ˆE“†é± ™¾˜ËÅ•¤]bÖ c ½uw}=óE¹Ÿ—ŸËW€o3©Ïw¤bY~€^÷‡€f„Q®ß›¥|û^œå´ „£kV‘¹s@{   "¹¬^ÌQÑúä_ô:å@ɼ› B…%-•JA©xŽåÅN¦àñàßóœ|¨ˆÏÒÓzKxˆóŠ, c6ß—.ÖË­ÙÆ.˲×:=–E£¼ÚÐgeo .dbx¡YÀ¥ä”§J‡µ«\+ðrP4½šúwY2M½`(ôçxK0‚ 0‚ 0  *†H†÷  0„1 0 UGB10U Isle of Man10U Douglas10U Canonical Ltd.1402U +Canonical Ltd. Master Certificate Authority0 120412113908Z 420411113908Z01 0 UGB10U Isle of Man10U Canonical Ltd.10U Secure Boot1+0)U "Canonical Ltd. Secure Boot Signing0‚"0  *†H†÷ ‚0‚ ‚É_›b °d‚¬¾ÉâbãKÒŸŠÕa+]8ô·Î¹š¸C¸C—w«O pF ümÆmê€^Ò·f‡Þ mÐA—¨¥¯ cO÷|ÂRÌ 1©»‰]™FoUs¹viì×Áü!ÖÆçO½"Þä¨[-Û•4—Ö(K!LÊ»y¦Zùgæ\xE=m°Y&ÅWãN‚ºö,NÈ7Mÿ…„Gàí;|¼¯é§ oÃé£Î¾¦ãÍ<µX,žÂ`"79ÿAÁ)¤eQÿ34ªBù•xü-õÚŠ…|‚û7,k¥¨ß|U €.<°cáÍ8H‰è ‚¼ýÔh>ÙÝ”£ 00 Uÿ00U%0+ +‚7 0, `†H†øB OpenSSL Generated Certificate0UaH*¢ƒ ²­Zñ rPÚ3ÝÎð0U#0€­‘™ Â*±õŒ#¶eZ&Ž4Zc0  *†H†÷  ‚Š¡)· JÕÅý«%êÀ}âüj– y“gî%%äZöªñó‡^ñZ\Ë#se¹Þ"kÖIgÉ£Æ×bN\µùƒ@܇œaB"Ä*\NÅ£âàR²ëô‹+Ü89]ûˆ¡Ve_+O&ÿxëŒ]2ãÆE¯%› ÿŽïG £é‹7’’iv~4;’gN°%í¼^_´ÖÊ@ÿäâ1# …%® UìåG^ß[¼3ãÆõ¶Ù÷ݳ´¡1ÓZ\]}>¿ ääè´Y};´Œ£µ £¹>„oŒ!Ã9¡YÀ¥ä”§J‡µ«\+ðr¸œ½šúwY2M½`(ôçxK0‚ˆ0‚p  9\§’zPÂ0  *†H†÷  0A10U Toliman10 U Cisco10UVirtual UEFI Root CA0  180403174734Z20990403161930Z0?10 U Cisco10U Antares10U Virtual UEFI SubCA0‚"0  *†H†÷ ‚0‚ ‚¸M†Ð!¢+Ÿ ¦w˜1\WÀë>“aòe~Ñæˆ"Í¥‹O/øKh‘ïLQÂ÷gôF§‰ýBá¤ÎKj)g@ÈgìéàÞüðâ­EðÒ¨W»‹ £ŠsUãWÓüÂÄêPú‚IHf±x+¢GUH%Ìm".a—•¯›.MX¶~xùú²['Þ}¢¾ ¬sì—°^ííå¥u?xàqÎ/΃íS10˜Næù¢ˆˆ¦#| ·T:•í^y^Nþͪނüö–qNII¹Óé°«×*G·S0'|Üf˜ oÑ~õ=>Ô¢jˆY//=ÈÆ(ÞBþÙR=$Âü@˜öv¿Œ»e£9070 `†H†øB0U%0  +‚7 0 U€0  *†H†÷  ‚W¤`L)éò}k\“ÛÌlŸ?iHšuÞdóƒJ ©&!îéV]á>ÙuËÌ¿Mäè‰=~B‡@ÃÕàqyÜláqbǘÂË' /ŸÌìú‹²ó žóòÃÉŸÛ%“¤Í»åŽô×U¨´uA1ýN] Â¬ÅÞFçÜÏÕèG“Œ2ÍDÕtÇ0šW¥VÐ~Ï´ôó)ùÛ›SÒ½/­ju&Edºº(–‡Ž·ðyWúzd÷,Nïgyj„½½šúwY2M½`(ôçxK세Kle¥ ©¾q–R0! bÖÓ h2Û²Ò à'%'ß¶=IÒ•r¦ôL½šúwY2M½`(ôçxKo¬êÏìýN0;tô€ €˜âЀ+“oŽÇtÎ!ó†hœ½šúwY2M½`(ôçxKN: [CƦ»Ó@O4=Ï9bgΔøµ.#©Ú’ ½šúwY2M½`(ôçxK+™Ï&B.’þ6_¿Kà 'lžáKzoÿDû/ki™9½šúwY2M½`(ôçxK.p‘g†¦÷sQ§«pµWÆ2.©#²¨Ó¹+Q¯}½šúwY2M½`(ôçxK?ΛŸß>ðTR°ù^ä·ðmt:syqUŽpjÎ>s½šúwY2M½`(ôçxKGÌa'⚆à:kï,ÔøÅZmkÛ6!hÃ,ã*Zß½šúwY2M½`(ôçxKqòoÒ"I~T£Fb«$—üÈ wõhéãÙ¿Ëýcu½šúwY2M½`(ôçxK‚Û;δöCΗÃч͛YAÍ=èXo+ÚV7W_g½šúwY2M½`(ôçxKŠÖHYñ•µõ¯ª” jag¬ÖzˆnF“dr!ÅYE¹½šúwY2M½`(ôçxKŽ¢‰Ïç «seË(îQíÓ<òPmèˆû­Ö¿€H½šúwY2M½`(ôçxK®ë®1Q's핪.g9í1©…g0:3"˜ø7 ©ÕZ¡½šúwY2M½`(ôçxKÄ ½¬Gu­ØÛ’ª"µ·ûŒ”¡F,餹]Š3ˆÂü½šúwY2M½`(ôçxKÆÁ¨±î*(µ¨Lƒ×É‹[ '(aëæ’Â–½šúwY2M½`(ôçxKÉ3f¸çùƒ—TÉ—ñ së&Ø¡ ¹ã½¿Æg«Û‹½šúwY2M½`(ôçxKdW[Ùxš.­Vö4R¯kø ùDxYuéðN-d×E½šúwY2M½`(ôçxKEÇÈ®u Ï»Hü7R}dÝdM®Ø‘<ÍŠ$ÉM…igߎ½šúwY2M½`(ôçxKØûLž.z‚%ekK‚s·Ë¤°>òéë à )$졺†½šúwY2M½`(ôçxK¹*ò˜Ü›xÇt’ÖUq ×*­£×{åF ä2xïnM½šúwY2M½`(ôçxKᮃÀ.o(XÔëÑw#´õê5yÕD=ìÅù<½šúwY2M½`(ôçxK9ÛÂ(ŽôK_•3,·wãè@Û¦€cJ¨õɱ½šúwY2M½`(ôçxK2õ” ¢Ø¢ÁEæü‰df(ÿÌ|zBÊå3})Ä ½½šúwY2M½`(ôçxKÔ_Ë£–®ó>èöì®X¯èGj( &üqö!}ÏIº/½šúwY2M½`(ôçxKK†h¥Ôe¼ÝªüÿBOËЮÎ2üp¨>‘`èŸ ½šúwY2M½`(ôçxK‰óÑöä…Ã4Í •ãÍýÀq±„˜T„zDÜUHâÜû½šúwY2M½`(ôçxKÉì5ònUšÿ´ âëÞT5L5©˜`[Ï—-U½šúwY2M½`(ôçxK³å4¿kW†—3“Ÿ$¶k¤eã^‘°6**ÍépI½šúwY2M½`(ôçxKŸcíWÔ´.ñ f±D¦[¡¶WùK޲ðÄÍ`Á½šúwY2M½`(ôçxKÝY¯VDãŒcûà…0 ÍwF*!’Y°[ÂYæs½šúwY2M½`(ôçxKÛ¯žm=[8¶…S0J¼ˆ‚~¼ø ¹Çá—ͼX"Í1l½šúwY2M½`(ôçxKeóÀ „Ób¹r.˜÷^^™ln“O{+.kæÞÈ콚úwY2M½`(ôçxK[$Ž‘=q…==¥®ÝšKÅz‘q&W8û_Ë-†¢ñȆ½šúwY2M½`(ôçxK&yeãAòϨƒF 5Vª¯w§ kÄ„É0tl÷µ½šúwY2M½`(ôçxK»ÑmSco##§¨o=ÿ–Ÿ„ˆÀWKÂׇþÉ?½šúwY2M½`(ôçxK à!ö|~ø_Ní6¿p’8 <#Ê‘ýC ”° ½šúwY2M½`(ôçxK•ŸA7ǰÒvq•åos€}:Üøöç¿-M™0_‰½šúwY2M½`(ôçxKæ!jÊïd@¥Uì¾Ù@±¥òVší’•a7®XH.ñ·½šúwY2M½`(ôçxKnþþ [G‹{”LÓ¨¬¢Ì¤ ˆˆâŸŠËX$׺°½šúwY2M½`(ôçxK®LÔzAǃÜHóBÀvÂÁo4ôÒßPÑÊ;µ­…½šúwY2M½`(ôçxKØÔæÝöä-t¦¥6êbýä) \ž\6•£Bïµõ¤½šúwY2M½`(ôçxKòw¯O›Ü‘ŠèŸ£\Á³N4˜L®—e2,<°IWM6Pœ½šúwY2M½`(ôçxK ÂLuëïV¹ñ:¹Þ`âì¡ÄQ4⻳lö T›#L½šúwY2M½`(ôçxKƒXò¥W-pYµÈcPU(’éEbo_Éʬ÷½èW¤½šúwY2M½`(ôçxKºßõäðþ§p¨û"äÄ8!ã! õ-OtÝPñÐ9¼½šúwY2M½`(ôçxKÄR«„`sßZÎ%̦Mkz Ù0ŠeëR@ãÄëÊ©Ì ½šúwY2M½`(ôçxKñ†>È·ô?”­û ‹JiIzŒeì¼*Uà»Bw+ŒÜ‘½šúwY2M½`(ôçxK{ÉËTcε^¸ºwѬ҃Ä?JW`<Áò,ëÅy½šúwY2M½`(ôçxKè9]¾WèQx´ºõ¢Wðn‘!¦|Y_jâ%ý½šúwY2M½`(ôçxK´ÜÊòÈϧ´“Žqþ+–‘ä!oÙT(g-l~s½šúwY2M½`(ôçxK>Î'˳ìD8Ìå#¹'Äð_Ü\Y:7fÛ˜L^Cz?ö¡k½šúwY2M½`(ôçxKhîF2ǾfÈ>‰Ý“ê¿E´ÂÇ-}ÇIš¢ C½šúwY2M½`(ôçxKâK1ZUqH=‹s³-áMáë.«!ý-œ1Ÿõ^нšúwY2M½`(ôçxKç :´ìˆUì¥)7ØKZÂOˆ&kRpçì´ª%8½šúwY2M½`(ôçxK~¬€©ÈLÔ¯ìc‰ÙN±h¨UyQ¤Õ9°q0(U+kŒ½šúwY2M½`(ôçxKçh1!êg÷K¼°ÍÅåp,ŒÅ_¶]p-û©Hµô½šúwY2M½`(ôçxKÜÌ<áÀä°±‡Ór úGõÂoW£Y¾{'€N¬ºÄ½šúwY2M½`(ôçxKWÿq*䉳t“Àv§Í©a)بýhÒ¶¯c91]½šúwY2M½`(ôçxK:‘ðùå(¢™L}“ ,^áLèáÈ0Jä•­ÅŒÄE< ½šúwY2M½`(ôçxKISyl›òQ «¥³Õ~+…××d4ìuº£…t彚úwY2M½`(ôçxK¨²Éuë«§ÛÞ^éiÀêî*1Ë‘¨gV¦·p½šúwY2M½`(ôçxKŽSïÜøRÎå¦é)1¼Bæ<ÓöI̧èrRäY– ½šúwY2M½`(ôçxKŸ¤Õ?Ô>ÊÿBº~CS%+~^rµ nÿ€'ÖmC½šúwY2M½`(ôçxKÓrÀÐôýÉõ.ž#üVîrAJóPÐΦÂj5¦Ã!z½šúwY2M½`(ôçxK\Xj…é7‰EpÔùëh(¹|AË›¦ÓÜÌ_RzU½šúwY2M½`(ôçxK€N5Lch»'©®ŽIŠW+)4%šœOS¢rTI½šúwY2M½`(ôçxKöJ)”Šˆ¾ÿÛ^ §7 Ï ÙÎkÏŽd !1«‡½šúwY2M½`(ôçxKØ~q4Tao[ׄšµÁq*¸O4”xì*8ùpÀ‰½šúwY2M½`(ôçxKë[­ÒnO®eù¤#XÞï|å,À_»Çgvæ˜*½šúwY2M½`(ôçxK»"‰ééM ÿ?bQj°~—›,lïâ«pÆßÁŸ¥½šúwY2M½`(ôçxK (ð@‹÷%ægØq8¨î¼R–-(Gñn5‡;A¶­½šúwY2M½`(ôçxK ùŠ©…Œ sø›§~‡ìoYlIPû‹º€¦/»‘K½šúwY2M½`(ôçxK uê pê¤Óót$mµOÇ´>Yj53 ¹ÃkOÙur^½šúwY2M½`(ôçxK Q×oÄ“Iv]¨†‚Bk,þžj¤òrSê´2ã§½šúwY2M½`(ôçxK£¢šÐQ0×þ[ôÒYecÍí‡@–ªÌi“*.IQš½šúwY2M½`(ôçxKw0´/þI?é¶%—Í+o4Ójõ“0ñ¤/” ½šúwY2M½`(ôçxKáqZŸÏá¤DÎÿ…†ž´"3 ÀK1L)]m§ž½šúwY2M½`(ôçxK‘¨Ôså(¨x#½bæUß®Tú+úrýÀ)†Ö¸½šúwY2M½`(ôçxK‹XÁý¸Ú‹3Ìî_—:÷4Ùóã?]±W<+ ˆ¨ ½šúwY2M½`(ôçxK‘†ïß^òÞ‚Eº®4††º 5ÿ=˜eÁS|퓽šúwY2M½`(ôçxK' „²†ñc°jªäë¸ßøÞ} ‚[ˆ9ÿf'NÿG½šúwY2M½`(ôçxK)̤TN£0Ö‘Ç„i\œk"¬{[‰Ë×(Ñ@꽚úwY2M½`(ôçxK+"˜ê¢kĤUŠé.{°äø\óKøHýö6ÀÁ¾Ä˜—½šúwY2M½`(ôçxK-ÏŽp#ÑèáE=hÖì0Ù¾ÙL¼¸ÝÁ̬½šúwY2M½`(ôçxK1*Å[PÀ›0³Ì“¹”¡>î¬Tï‰/ÄG»½–¡½šúwY2M½`(ôçxK2­2–‚›ÄmϬ^ÝË¿,í\ø;"Ïœn`ǘԧ½šúwY2M½`(ôçxK4 £+X3Ž+V¯0 ©ßÖ¹Ò'àâ£IX±Æ%ž…½šúwY2M½`(ôçxK6.Ó ±à’(1©o ÏÞa‰Sæ•Éï.°ºÃuP½šúwY2M½`(ôçxK6z1僈1­,FGˆjlßò決‘ ÿ…Üz‡®›^˜½šúwY2M½`(ôçxK7e×iÀ[ù‹B{5;!7褛o… ñYíj†xj¦4½šúwY2M½`(ôçxK8mi\ß-EvàÊÌõäžxÚQ¯™UÀ¸úv7;y”³½šúwY2M½`(ôçxK:Ot¾¯®+“ƒ­‚Ò3¦Ï=³Çâè—¾ïBUúúwY2M½`(ôçxK:çlEÊpé Y˜Bb-ÒQ¼¡ûæ¹Å.Ás°5½šúwY2M½`(ôçxK;èçë45Á’Çi„gˆ™AÑöÏ QL¡i“OsY½šúwY2M½`(ôçxK>9&ð¸¡ZÕ¡Ag»dz„<=C!ã]¼DÜèÈ7A-(°½šúwY2M½`(ôçxK@ ÆmY·°”©ã ¦½:ÿ0WƒçY/B¾_ôº½šúwY2M½`(ôçxKA…‚m«[¨4{x¢+_š upÊ\“§MGŠy=ƒºÄ˜½šúwY2M½`(ôçxKAÑî±wÀ2NÝeWó„å2Þ õšDkï³Q¼%w½šúwY2M½`(ôçxKE‡kMØaÔ[:”€tz]´ZH²§)A ¶A/Їé]½šúwY2M½`(ôçxKFg¿% ×Á k„tÆͱßdŠXso¿WÐ]ou]«gô½šúwY2M½`(ôçxKGÿc±@¶üíy1æQÚ[./]®ô=ÂûÅ2±½šúwY2M½`(ôçxKWæ‘:úÌR"½vͯ1øíˆ‰Td%Stï z‚×õšÓ•–½šúwY2M½`(ôçxKXú"q!ÇmížcÈ~:e3î öð¡¢?ÄE›Æ¼ß½šúwY2M½`(ôçxK]šË»J}KhRßYpâÎÖoö"îœÐíØAÌ­½šúwY2M½`(ôçxKaÎÄ£w¿YÀþ®ãp4¿—Õ¼nâ:ߺæãõû<ý½šúwY2M½`(ôçxKcW´E6,Ƙ KĶ(â=¾$¶élŠãܰլ½šúwY2M½`(ôçxKe²çÌÙÃ1ßRßsÊ É2ÒŸ™tÅo0‡²Ý1G½šúwY2M½`(ôçxKfª íÂ8MœB]9'æíJ]@ÅçÍM¬ˆõwòñ½šúwY2M½`(ôçxKhsÒö)½RéTîÿYwªƒgC™—bÿ!,”3Æ—½šúwY2M½`(ôçxKm»êÒ>Œ† ø´tûü¥ Mã⋈»ÌÜGG“N½šúwY2M½`(ôçxKmêÑ2WßÃÌÆ¤³pº‘u_éàìAP0”.Z¼Gð|ˆ½šúwY2M½`(ôçxKp¡E ò­9Ui­ þ±ÙÁ%2Né ì9ÂXˆ4Ô‰-Q«½šúwY2M½`(ôçxKrÂo‚|ë’˜—˜–Æ®tÓë϶]A²fÉ ¾‚½šúwY2M½`(ôçxKxd!ˆ¨´±sÔ¨õì”Ø(dqV ™5zXbK7u ½šúwY2M½`(ôçxKxƒƒ¤Ç3»‡Ò¿Qg=Ç>’ß«}QÜqV'®whm#¼½šúwY2M½`(ôçxKx´íÊ«ÈÙ > â€,®´ðž#£9LJÌn‡èóS•1½šúwY2M½`(ôçxKI̳ 2;z±“ÉU¸ÇDð¢·\1I^`pP'½šúwY2M½`(ôçxK‚¬ºHÕ#lÏ÷ešüYMî+Ö.ñ£ ›P†(Ï4ô½šúwY2M½`(ôçxK‰Mx962˜Ì‘Zèt.ó0×¢f™ôYGŒò,+k²…f½šúwY2M½`(ôçxKŒI×Wåª!ÁcH#22—ØhòX‘e)ïÅ ïp½šúwY2M½`(ôçxK“Ö iYevåÜFKá*…úR€¶õ$Ô¡ÃüÉÐHÏ­½šúwY2M½`(ôçxKcõûÅåz¶Þl”ˆ` ár±vÕ«WÔÈŸ`þ-⽚úwY2M½`(ôçxK‘ej¤ïI;8$ ·&2HäâÖW¥ÈHˆ ¶[s 2ûS½šúwY2M½`(ôçxK‘——¿Ž[Æ„9¬Äcë¸ú«ývMËè/;©wÊÈÏj½šúwY2M½`(ôçxK”pxù|a––Œ:霚]Xf~†ˆ,öÈÉÕ‰g¤–»zô<½šúwY2M½`(ôçxK–äP”PÓ€ÚÃbÿŽ)U‰ŠåX…Ò ‰Â{¢©Ð ½šúwY2M½`(ôçxK—ƒµîD’éè‘ÆUñô€5•­E<b:ðþ{òÀ¥x…㽚úwY2M½`(ôçxK—¥ DDb óŒØÆQ,¬šuýCzáäÒ))€va#'½šúwY2M½`(ôçxK—¨ÅºÖï»]jÚNºG-ÄÆÍIrü]ã!4/佚úwY2M½`(ôçxK™( æìŒAÚ®KØ«Hõ‚héC¦pÓ\¥â½Í>|L” r½šúwY2M½`(ôçxK™-5š§¥÷‰Òh¹L¹HZkæCb°í´DÌ|9d{½šúwY2M½`(ôçxK™T¡©U豉«ÊAK‘ö l@¨ko>óh݆1½šúwY2M½`(ôçxK›¯Ov×kõÖ¨—¿½_B›¡Mà‹HÃîv“ ‚ÿ8‘½šúwY2M½`(ôçxKœ%ŸË0_Ç9~Õu™càïk6ä WýsnkЋŸu½šúwY2M½`(ôçxKÒÜ·/^t'òéà:±…£@<ö©¤y¤ÛÙ~"P©½šúwY2M½`(ôçxKžÓ?¼ À2øœ¢Ä«4íÃ:E¥ %!£µ‡j£ê,½šúwY2M½`(ôçxK¤Ùx·Ä½¡T5Õø¹Y.Â¥­ûê{­j5ìµ0”d/½šúwY2M½`(ôçxK©$ÓÊÖÚB·9›– • oö±«¥¸s°Õó î!s´‹l½šúwY2M½`(ôçxK­;å‰ÀGN—Þ[²¿3SIH·k¸vßÜX±þ×gµ¡[ü½šúwY2M½`(ôçxK¸Öµç…{Eƒ|{ãØV­ë—Ç)°fZ=G:KëQÜó½šúwY2M½`(ôçxK¹?™Y‹ ú ¬Á,üü%hy?nwžy^m|"Su½šúwY2M½`(ôçxK»Ú3»cœ~€m°VÉŠSò/ïû äm®Iš½šúwY2M½`(ôçxK¼uùÿ2\µ™žf»ÔOJå7¤/ßï5SHãf⽚úwY2M½`(ôçxK½Ð&éØWÓþu¯Áp*)ð´öýö¢²\—©ÎŽšúwY2M½`(ôçxK¾C]÷Í(ª*|´üsG[wå«ó’÷k|vú?iŒ·š½šúwY2M½`(ôçxK¾÷f;åêM¿Øhn$poLûÍg¦Åfí”Î ÄDp½šúwY2M½`(ôçxKÂF—YÁ”~ô¶_r©õ³¯‹onr{h» ‘8\¿BjнšúwY2M½`(ôçxKÃP[ó쥬äÇk‹Ñ 9 eÑóNu¸£^ãÆ›–½šúwY2M½`(ôçxKÄ-Ç Ï^Œóû‘ýòˆ@!­ƒl¦Šß,»y•Á õˆÔ½šúwY2M½`(ôçxKÆd¥¸9ä¡gBR~jÎ<'oÒn4ÇÐã"½šúwY2M½`(ôçxKË4¯ë tÄ¥ˆ³nº¤A–èÒú€Ü¨Á8rÈPyk½šúwY2M½`(ôçxKÌŽìn¹!,¿‰zZÎ~оìáŸmï x•‘ËGñð„½šúwY2M½`(ôçxKÏ¢CÁÍ.<Œë~p‡ÎËûƒ%»ùз y­óèA(½šúwY2M½`(ôçxKØšÑlHÔû¼TKúøg f ”HåK¿òpNBˆ½šúwY2M½`(ôçxKÙfе'…g†Á4µä½Û÷$R;is"š¹*¡¥M õ½šúwY2M½`(ôçxKÚ5`ý 2µLƒÔòÿ†Ò“i¬òÈ–ø¯§CkúFU½šúwY2M½`(ôçxKߪ´ƒ‡©áÔÆR(œ¶«á–Èô³–Çä»Ã•Þiwö½šúwY2M½`(ôçxKß‘¬…©OÍ ûU½|¾ú¬¸Åîs—þ,ÈY„Ež.¡N½šúwY2M½`(ôçxKàQ·ˆìºí¥0FÇjö•",aW¸ÄÁ¹ÂÏÆ_F彚úwY2M½`(ôçxKãmüq!Âãšêˆ„ž(E«2ooçNS›~TØ61½šúwY2M½`(ôçxK㘑ô‹¼Å“¸í†Î‚ÎfoÁ[ŸËý+ºÐ¨›ôÇ¿¿½šúwY2M½`(ôçxKæ…oy™-ÉO¢ô2—ì2ÒÙ§o{æaÆ¡>ü;ÍõȽšúwY2M½`(ôçxKêÿŒ…ºM[k€FõÖG×yºÚwhæIÐGÿ›f ½šúwY2M½`(ôçxKfIa §OjÆäß»)¢à®;Š#(Ž~.r½šúwY2M½`(ôçxKî×àïòíUž*yî6™b¯;™‘1ã ·ýTo® rg½šúwY2M½`(ôçxKñ´öQ; TJh­Â‘ï¨ÅŸB ¥Ü²> Zú~ =½šúwY2M½`(ôçxKò¡m5µTiA‡§ @Êh)Yôó\,àê¸ýd÷¬*¹õÂJ½šúwY2M½`(ôçxKóÔaÅé•@?É|¢Ø©ËâpY}2ºßÖkwI_”½šúwY2M½`(ôçxKôŽmØqŽ•;`¢O,¾¦ •!Þ®gÛ%B[}:Îô1³[ôÀæ‹Óµw¹«á©ÏñËßTiÊxçE (QsC>RÅÂR™äs ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ 9CA·,Ò'ÅÆ°~ø ߨa6Ä)+ŽWes­~Ù®AŸX´¹qÉïü`á­Ÿ‰ð€7ˆØ»z'º1¢ö!.ŒGí`Þ wB«6dðuÆV—jŽ ß¤‚–jµÖi^„­çrõ ò„’Ô¢å…;¼¬bìšü ÃkŠŸ0*û¿8v̧Çj’ÇD ·C:ìq$›åÚ˜-8aßä‹Ê“Òª à˜+Œ BootOrder€BPÀF>î–.Äî-ò«»b8&¼‹ ëŸ\hHhd¡.ÂfD â¨cƒ÷ÞØ7õ²"ŸŽ¢ÔÑZ 7¨ìú§Õ—'Nî5Š°Ú€lòÚ©:»»B޹Ñu£ Û¢£fŽSB~Y@qߦaßä‹Ê“Òª à˜+ŒvBoot0002bFedora*ø×Ù¹" ;G‚à&ÞÙÐ=(4\EFI\fedora\shimx64.efiÿ€"¤öîšöÛ 5(Þ¶Ktµ‚ü+ 1—¾0¡` „ä½J¡T¿µFÏ.lö _Œ6*“ #­ Rañ/4 ½ŽFv bÖ´Õv¤ñþ¡ÆKÆV±Òެ÷zæégÅÒ©‹út˜naßä‹Ê“Òª à˜+Œ>Boot0000 ,UiAppɽ¸|ëø4Oªê>ä¯e¡!ª,FvEƒnжôf#1ÿ€5Áy{fÎ0ý^ŸQ Pͽ©É“‡ +ç¤Yã Ç»xˆûX(9‡þ ÑÓÁ¾'kÉév“æ\I ¢S3Ç®Âà™04“Œ‰;<+Êö~ˆÃB£Õ†ö÷úâÆ¡$zžØiˆ mKä—Ôû¶aßä‹Ê“Òª à˜+Œ`Boot0001&UEFI nvme_card-pd ÐA ÿN¬ŸYM…âR,Y²€ÍÛE1¦ìA¾'Sº&7Öå÷òV =gr´øNÔu•×*,L_ýõ»rÇPâo*®âÆV3º w Ú²1+NW¨M†Z!å²îgz!*Ú ˜˜€xÓ×@ö4kþ º©8Ê Cšq(Calling EFI Application from Boot OptioniÊxçE (QsC>RÅÂR™äs ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ 9CA·,Ò'ÅÆ°~ø ߨa6Ä)+ŽWes­~Ù®AŸX´¹qÉïü`á­Ÿ‰ðiÊxçE (QsC>RÅÂR™äs ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ 9CA·,Ò'ÅÆ°~ø ߨa6Ä)+ŽWes­~Ù®AŸX´¹qÉïü`á­Ÿ‰ðiÊxçE (QsC>RÅÂR™äs ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ 9CA·,Ò'ÅÆ°~ø ߨa6Ä)+ŽWes­~Ù®AŸX´¹qÉïü`á­Ÿ‰ðiÊxçE (QsC>RÅÂR™äs ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ 9CA·,Ò'ÅÆ°~ø ߨa6Ä)+ŽWes­~Ù®AŸX´¹qÉïü`á­Ÿ‰ðiÊxçE (QsC>RÅÂR™äs ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ 9CA·,Ò'ÅÆ°~ø ߨa6Ä)+ŽWes­~Ù®AŸX´¹qÉïü`á­Ÿ‰ðiÊxçE (QsC>RÅÂR™äs ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ 9CA·,Ò'ÅÆ°~ø ߨa6Ä)+ŽWes­~Ù®AŸX´¹qÉïü`á­Ÿ‰ðiÊxçE (QsC>RÅÂR™äs ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ 9CA·,Ò'ÅÆ°~ø ߨa6Ä)+ŽWes­~Ù®AŸX´¹qÉïü`á­Ÿ‰ð€tØ“ z~ Ë,a 潨Ðß »šƒ3Ï9L–|ÈlL¥uÚFªá‚ãðÍ‘Ÿízc³‚¥¤ ß%k¡€ÖeåŸuðûícäÐÞbü¯ÛŒÁ®³V4”Œ‰øB¸ŽÂ8F^ÖdEFI PART\«Âz1ÿÿ?"Þÿ?@ €€þk9´Hah!IdontNeedEFI¢ðm•péG´`’ÊãýáÿBIOS-BOOT(s*ÁøÒºK É>É;×Ù¹" ;G‚à&ÞÙÐ=(ÿEFI-SYSTEM¯=ƃ„rGŽy=iØG}äŠ}"—MLŽ•šp¶{0ÿboot¯=ƃ„rGŽy=iØG}ä§±üµÂ«·E¦é´zúeÿÿIroot€1“{Oø:q°;KÔ3¡a2½P -xØ€«¸u{[ÝRJáü8B"±ç¡„ãÆ Ã 3x|U]ÔV2ïÜ•$TÀ¸cí°xb[‘9£Ú:Kµ­W­Ö›Îá%ñtʤۤÀ©¼r„ ÐA *ø×Ù¹" ;G‚à&ÞÙÐ=(4\EFI\fedora\shimx64.efiÿ )‘Óú-A;8YçåC!²‡ˆ0ow ½ÈªF[IF dxˆ®œD.–hƒç‹Rôãˆeá P?޼7Ð…ñ¤yS#' <ùª—uŠXìá}*~¶$å 7ýYu 7|4û‰vMokList R_÷ LúK,v¢â?ÄI—“+Óò Š:®PÕÒX8É\J­Î{TŒš•.·’^6nÚS|Yð €î%q3JW¿#!–DGåBHú‡ˆx©}Ër h: ±¬cLvÀÀ¾w÷a MokListXà€‡]9¸‡/Šÿ:’üŸž@¬u&Ž ’.“šUeyŠ^ñ/à‹I¿•މ Ì§¥6i=A£M ñCâ”cüÓD.„³j~qð¨”eA–éÑ.pÐrxt` V&MºS.݇)Åë8DP«]`FàC«¶=ØÝ‹# SbatLevelsbat,1,2021030218 à€>þ¸zôе®çü½5º·í†\ _b¢¡àH_ÒRÒæÆËŽÐu†•¿í &¿nÖ+ „)õ ‘á .d¦ce‡ºÅ¸T–¦~m<<õ$§«rkM"YM„é!‘¬Žá[x=P«]`FàC«¶=ØÝ‹#MokListTrusted ¿‹E0ØÒFÝt¬S¡4q»¡yAß÷ Kõ/4ETÅ;Þ.»ŒÒ·ãÑ` Ö1Ã…¥×ÌâÙ^E”¶|Cx¨2Ö|‰Q£¥ç.‘ž¹œ_ˆ UÙ“Š ·‰’÷µ~€HÜZÕ3J‚=Ë.q‹Ûv–ñôƒÛd&Bo² ÆKœÔ±grub_cmd: set pager=1 P°I BþqÒ»jÔ’üþÿLþ‡ ¢¦1ì=»‘ÿ åÊ2ûëvƒW€ú4¡=?3ˆ ê ˆ„êù,¥/ŒØãÕoÚÒʪm‡-Ï·Ç8Ц‚|aü ‘ƒ©Øö_fÙÆGQ›+¥ÿ8éùfëàŒò‘`à­ @@z8wÊ\CÁDºýÁY ~)‚È= I<„™m€#ßê´Xä*zy½¢×|Ë|êZ¦*/grub_cmd: [ -f (hd0,gpt3)/grub2/bootuuid.cfg ] z†Áò8gØ•¹Tqa‹Þ- $6¯ãËT«€}l¥&í12ÜYxžÓòñHèiHéx L÷&ìÔ"µm÷Ê/7|²¤îmœ¡õ´@–øüf·;VÐïü91Å©3'QrË÷grub_cmd: [ -n ] †¶iðOu(Ö{’£0óµDþì ¥Ò®°?ß)PNâCB¬á,”òˆØÞV¬œ ÙÚåœú£1 bRE÷SØ\”¾âúYØ! Ã¸½wöü1ÀÈʘ÷ß“/ 1äÙ°„\zûÈs5grub_cmd: search --label boot --set boot --no-floppy ßjg@€ !½çBò þ¤²h͘R má-&±_öÈé\á[ !–HœK„.¾X!¨óòM [ ¥âoù@·-¶¤‰ë¨*xXfÄ÷îW¯RÑzÅi™ g;¾¥„l’Ù8ÕŠgrub_cmd: set root=hd0,gpt3 ·)N¥}âz2…¯W7'ð•¢ ¡R ôZ¬$²ƒã Ÿ½ ðe½™EMfùjµ›Ù uõàÊÆÀ½„b7°FêdWÿhðl Ž7ÑÄã”&ƒQÕBÏs÷ŠûL£Ôž†ƒº}*grub_cmd: [ -f (hd0,gpt3)/grub2/grubenv ] ÝHð=`¨h,ñÈG«Å8Ú0œJ ö¦™ìbž+~Z !`MóRÕ}' ÌSÎF¯¤@_XT …óÜê¸nÃáâË÷x²‰]eÿé“´Œ³g¥NÚÎ "Ì[å&Iä¼BÆ£ÒÓýd&q÷Û —Kˆ t0 ¦±;§R§Ö1èùç(²7âÈŒ_^¡ÚÆrðdr±[Ã3³.b)cÏ7ßE¹‰(hd0,gpt3)/grub2/grubenv õ°gåœ?g±›ƒo¾é複¡œÝ Eh6·X1¤-dZµ40/¹÷B­ª7·ýáR!]iâYû ±øÐ6®ý2ÎwêBn{=®ãxÝy®Ú–;,S‰‡‡–,éêåWÌéJgrub_cmd: [ xy = xy ] ½R å eüõÂÑ*‹è'~C€# ñ}MûK—ñbFc,!±¬!%É\ˆ™î埻46U †a•?QŒ‰Œ¹@|ƒ¦Tý¯˜Ò]™ËÃÑRUµ2ºÐD÷¦;)aîÑ龬f#grub_cmd: menuentry_id_option=--id ¨¸7 ZWQ„wÿÔ"!a$’fX "¯ÔrÖ,ñ 3¯ãé£všò3JÚ_^½#‹B ¤—ª õøÛ%ÍC 1ÞÃDÕ-‘(Ózq‰6l/% ƒ€ÂøåÏå/õ ƒ܈iÿ grub_cmd: serial --speed=115200 h­AÌWF‡¿ÞÇš}ß„ßQÏ .õ¥¥2$~å‹ or³Ë9û$¶S̯ãÝõ œI¨ ÅLÃã¦Â_*‡äÛüóƒü•ò\Q1R‡#r é&ù´×iŠ›^¦Ö†ù(grub_cmd: terminal_input serial console ¥qU™èyèÛ@ö”Qª¾œT™è6+ È“°¦È0 Í uzh™×ÜISàB·³hµ0N\9¹ ïÁÞ/3ª%Ÿ}æžÔßvx‡C!Á0*G?¶Yƒžò— 7»?Öà·‡1tƦ)grub_cmd: terminal_output serial console õ°gåœ?g±›ƒo¾é複¡œÝ Eh6·X1¤-dZµ40/¹÷B­ª7·ýáR!]iâYû ±øÐ6®ý2ÎwêBn{=®ãxÝy®Ú–;,S‰‡‡–,éêåWÌéJgrub_cmd: [ xy = xy ] Å +#LªAn÷Á–«N’¸à Vƒ˜Ï.Jõˆu»×ÿàXìE¾ tQ/©¢þ}´¦ %Àؼߴ sÎ( ¸XœD°¸%÷·ùýTXV±°:Þò‹n°CàÊijrž )æ&!grub_cmd: set timeout_style=menu Ô B(p€ä®±«?d1ú‘_¦Á ýæ* ˆÖ!Uy XëÍHšy®E:U¦ Z ?5 = °Wx×<˜žÝÕzB8MURxT·ºîL:ô|<툷¹Úcð™’a“ïȾ¢grub_cmd: set timeout=1 &XÙ…5]ýÚóÚ •­Ë ¿6ˆ ˆ­v`/0Õœ£7„B÷5Ç™õh竎 Ž“€³ÞŸ½iç â¹L U{4#òÑ~Hm0m>ëU¦À¼ Æ/qô«vù*óD¼Í2ãüî N1†"grub_cmd: set ignition_firstboot= a=:^î-ÒÌL(°DÔ¯¥@|2 ®Í³Û<Ö^²ã×LÊùîæ‰rƒàš&ìûgØz%grub_cmd: [ -f /ignition.firstboot ] ·tŸ÷ •RœŽø aœ ÿò¬< ¹áN*EÏq}P fPs=Ø®{ÚÂáÄš>5ûŒEV½ï ¦ÿ"F+…îèÖv`Îê’ì,¯á•èASÎS ÕzA›ùˆ ¨½ú6ž)grub_cmd: set ignition_network_kcmdline= ·%ý, ÂÙu¡¨ëÒFC|bñæÚF Äñd p§s½\@éûh”|R ÜV 6ô_õ^F… ¶—µ~ªÙsÕó'¿¬†b¾ùSÚôà‘§E_ow.\’ ljélçIî·ÍdY%grub_cmd: source /ignition.firstboot Ú9£î^kK 2U¿ï•`¯Ø ã°ÄB˜üšûôÈ™o¹$'®Aäd›“L¤•™xR¸U 8°`§Q¬–8LÙ2~±±ãj!ý·¾CL Ç¿cöáÚ'NÞ¿çoeûÕÒñH˜¹[/ignition.firstboot L".f®'á-÷$QA¨­°õÁ0 Ýj­}Où‡,¸S®KÕ³Úì¹|iTV‚dþ8ë% lÿLJ¯p_å¸m_•~1~uG,Þ¦ï9åG¹ÊHYÏï»#¤Ÿõ5yûÒP¼ó5grub_cmd: set ignition_firstboot=ignition.firstboot  93ŒVOÚ$&•ófÃïtÈð* QjõD{•ÉÐdÆùf”±Fwtz«p$mî{d¦ ¡k';ãݹPÛ.¹ËÑi•ó…NÚÆGƒb1egð+v!LB\è ö6-\çϾ+grub_cmd: [ -f (hd0,gpt3)/grub2/user.cfg ] ÀgÃõ¼Èu¥õã‰fšÖ ¥? ¥W|¶²B·µ¯ôý"E˜ÑãT“­É•L«=Ç… ãИXO…—ÍO$^´BI“¤Tò,÷Hîí{¯·Q ù~=_Çp¡oFïw+RËc™^pgrub_cmd: blscfg ˆ~{B®có,ÛŽÇÀtiûË ®j¦â>ƤÁc8k)³äñ3÷'CúY¥7e6šÙÑŽV ÉËìW¬Ûnå ñ+T!ÉmHóõ˜:ÅþuP5@û÷GŸ{_T³ർJÑp7(hd0,gpt3)/loader/entries//ostree-1-fedora-coreos.conf åžfÖì„ G$÷‘é)ñSáD v&«Ø¾tBÂåu6J>•Ë:;S?ÄÉ똢µÐoÌ |^¡± ¦’ $á-µö¥°ënÓfÌëŠËDx…rB"õc#¤“ѳ©Xú|grub_cmd: set gfxpayload=keep ºPœ£‚ðhû lFtÔÆRîg¹Šb×TËòÕÜ ÚãÖn‚ǔė„ †*ç—aS$ý\=ûü²&9b…^ÒÛ)iù„VðÚ¶ªŠ¢âþ¼g)W†¨w´ ÍνqXáqT¤ûg 8d ™Í.•vc,Ñ¢Tħ¥CÍ>ª gbDEX ¿ õ:†¸„¼u?ø6<à®è•5ö2ø‚?FÍZn‘ÖVCsöCÉ>XçÁz(hd0,gpt3)/ostree/fedora-coreos-28f8e018c4312083b210ce13c9fdab9dcb7883a0200802dca4eeddc1030eb715/vmlinuz-5.18.13-200.fc36.x86_64 èJùþ+Íôr«-¢~Õ{ß}i ÑÍ‚!ç7Ù½èû¼=”aE´rݤ.:×3#èÙ {VÀGyý®¬±ï:×’–ç Êa¡HˆoŽÜ±›¯±”,KH_mº†Àö`€…_kernel_cmdline: (hd0,gpt3)/ostree/fedora-coreos-28f8e018c4312083b210ce13c9fdab9dcb7883a0200802dca4eeddc1030eb715/vmlinuz-5.18.13-200.fc36.x86_64 mitigations=auto,nosmt console=tty0 console=ttyS0,115200n8 ignition.firstboot ostree=/ostree/boot.1/fedora-coreos/28f8e018c4312083b210ce13c9fdab9dcb7883a0200802dca4eeddc1030eb715/0 ignition.platform.id=gcp ü“Ð.ºÕ“} |IÝG'„÷I´ äô‰\‘.àî3çÇè%àÌâšK Q¢h™{ …ŒVñÁ›ß;J¸/JÉôýFÙH‰íäq“P~õ'u„íÆxÎ yjåv(˜grub_cmd: initrd (hd0,gpt3)/ostree/fedora-coreos-28f8e018c4312083b210ce13c9fdab9dcb7883a0200802dca4eeddc1030eb715/initramfs-5.18.13-200.fc36.x86_64.img E^ÐÁàç‹Úca¼& äÿ:‹ Ÿüù˜…D ='箽¹ÇÚR½×!]‹ŠŠ›BðGC º_‰ÿä˜Ü¡Oà,ðǼ)[Ê}ä‡Åá=rP·pz£â+i’èe¬‘øR3G‡(hd0,gpt3)/ostree/fedora-coreos-28f8e018c4312083b210ce13c9fdab9dcb7883a0200802dca4eeddc1030eb715/initramfs-5.18.13-200.fc36.x86_64.img€D:k{‚·¯VO.9<ÙÕ£ˆ·úJ˜ Ø=k{…­5޳¶®j‡:·ï#¢cRÅÜOªZîÚÏ^´ !K ïyu`4Hwt?Ü*S‚ºÆçbÖ$ÌóöT@|K­÷Øù)]ÓÚ½ïe²vwàExit Boot Services Invocation€GUEÝÉx׿Ð6úÌ~.˜HŸ µOuBËØr¨ꃛ+t|~½^¦a\@ô/D¦Ûë  .È]êç¥0­Œm ¨@ º¾l‰‰&ž• Œô@Æé—i^dÔUÄJe,Ѐö# t(Exit Boot Services Returned with Successgo-attestation-0.5.1/attest/testdata/crypto_agile_eventlog000066400000000000000000000333501452320553600241140ustar00rootroot00000000000000!Spec ID Event03  ‘‹'¥ÖéÀê±ñW&züî^¿rÚ¨_‹Ðî(ÁAÞo{Boot Guard Measured S-CRTM Ôr @ C‚¸V€ù ?kꊴ}(=³+n«í»ñUûkT U@¤­Nô¿¸: “yâ¦EÈÏEn­. ­ˆF¢çò°Ž(ÿñ”ÿC¢ÿN€ Μㆵ. Ÿ0å Ö-kVþOóåfu%âùÂcß4aßä‹Ê“Òª à˜+Œ SecureBoot€ xhB˜ÌTÏuP½8ÓÃxîîYÓ®v2ͦõ¬\Í%{5kaßä‹Ê“Òª à˜+ŒGPK¡YÀ¥ä”§J‡µ«\+ðrG+3Ì¿%!ÑBŒm‚#Àx0‚0‚ÿ  Ã9Êï=‹Ý0  *†H†÷  0"1 0U Intel(R) Desktop Boards0 130202000949Z 230131000949Z0"1 0U Intel(R) Desktop Boards0‚"0  *†H†÷ ‚0‚ ‚à2wM¥ó1A_Ÿ69ѓβøENeÁB,eÕ–^™"]Š-‰Rãæ#Ç}¸U„{Ê*']î¤3jRÿ9©Ô!Âõ¸ø<…C`ah#rñ‚±mh­i ûÑZíÒÍÁÄÓÒºoÎo­X%o92ÅÿW€RÖ‹cì§KÏ*°.÷.ü§[ly† Ò³um‹z5¸œqr¤Œ$Ô ÕéÊÐ; 6ÆUKX³ó}X-{’ð8ã?ªy2.nPÜŒá÷ÛK¯a¼½ÒºÖ_ìy>¸È7Ü©ZM€ì[ÎëlTht*\ª¼%ÒiáÁQ[5ÅûϦX©løs3Æõ¨Ò ïëâìóª„ £P0N0UÒîv€ÁæVÒþ×ï‹ZØ <±90U#0€Òîv€ÁæVÒþ×ï‹ZØ <±90 U0ÿ0  *†H†÷  ‚8çÃ!”—š –[-Šw‘Ú•ÆÒ¼„Ìì„|Œ 6',ÒŠ29>NFÙBì-”84$æÙ.¥òβŽÀQ°y‹@,ÕËp‰êù.c±#€ÉAIÞÐ_Z¿†03ÄWÆN/³éc]i ¹ö´>‰×—Óî,nʨ˺ØJ8FÞoá.mþíâUøoÇz¸}ÛÛ4>žž7÷;RïE¬Ô ÎŒø=6ÿ/›ô弟_×k‹ýcÔ±iCË®¡èíi : =Ò°è²·o%,œ>$¥Š^¶ Å?‹ƒ3}Ó7B€Ën#ø ÝWYßã‹´ú÷‚BرqÆþy‡€ cÀîxëI¹Â°7h¨'ëù±#pöXQ±šˆ;ó.¯*>aßä‹Ê“Òª à˜+ŒKEK¡YÀ¥ä”§J‡µ«\+ðrü½šúwY2M½`(ôçxK0‚è0‚Р a ш0  *†H†÷  0‘1 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0 110624204129Z 260624205129Z0€1 0 UUS10U Washington10URedmond10U Microsoft Corporation1*0(U!Microsoft Corporation KEK CA 20110‚"0  *†H†÷ ‚0‚ ‚Ä赊¿­W&°&ÃêçûWzD] ÚJåt*æ°ìmëì¹ãZc2|Oã §8“ŽÆõà„±š›,çõ·‘Ö áâÀ¨¬0ßHóPšd§QÈ…O †Îþ/áŸÿ‚ÀíéÍÎôSjb: C¹â%ýþùÔÄ«â#‰p·¤Mì®åœúÂ×ÁËÔèÄ/å™î$‹ìò‹êÃJûC ~µG’lÜæ‰ëõ3ë*qåùƒ<ÿ% /hvFÿºO¾Ü­q*XªûÒy=ä›e;Ì)*ŸürY¢ë®’ïö5€Æìä_ÌvÍïc’Á¯y@„y‡ãR¨è{i£‚O0‚K0 +‚70UbüCÍ >¤ËgÒ[ÙU¬{̶Š_0 +‚7  SubCA0 U†0Uÿ0ÿ0U#0€EfRCá~X¿ÖNž#U;:"j¨0\UU0S0Q O M†Khttp://crl.microsoft.com/pki/crl/products/MicCorThiParMarRoo_2010-10-05.crl0`+T0R0P+0†Dhttp://www.microsoft.com/pki/certs/MicCorThiParMarRoo_2010-10-05.crt0  *†H†÷  ‚Ô„ˆõ”Ê*<û*’ × ÑñèRf¨î¢µuzª-¤vZêy·¹7jQ{döádòg¾÷¨x½ºÎˆXd ÖWÈ£_ÖÛÆÐiÎHK2·ë]Ò0õÀõ¸ºx£+þ›Û4V„ì‚Ê®A%pœkéþ×–å甲* Kÿ(){÷×|¥Ñv¹Èyí’œÂþßo~l{ÔÁEÝ4Q–9å^VØ–ô¦B³ wýòqVÌŸ†#¤‡Ë¦ýX~Ôig‘~òå ‹Š<‡„ëãνCå­-„“Žj+Z|DúRªÈ-»àRßøš=Á`°á3µ£ˆÑe ç¬|¤Á‚‡N8±/ Ňoý.¼9¶çæÃàäÍ'„ï”Bï)‹FA;gØùCYeË ¼ý’Oôu;§©$üPA@yà-O j'vnRí–i{¯÷‡ÐE­Sû0ª76aÚJi4ØhíÖÏl” ÓÏl"y­±ð¼¢F`©ÄÂ!‚ñýòèy2`¿Ø¬¥"KÊÁØKë}?W5²æOu´°`"S®‘yÖ›A†Tp²Þ 5|°4rº—`;ðy뢲]¢¸‡Åéöµ—%o8Ÿã‘úŠy˜Ãi·£ —øÊ®×ÄóÀuk4 µ™`ó\°ÅWN6Ò2„¿ž€ YvUžD¿7“]í‹¶Ï|€œ­îœx׌…»QÚÉÏ˲×:=–E£¼ÚÐgeo«db¡YÀ¥ä”§J‡µ«\+ðr@$½šúwY2M½`(ôçxK0‚0‚ø  aÓÄ0  *†H†÷  0‘1 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0 110627212245Z 260627213245Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1+0)U"Microsoft Corporation UEFI CA 20110‚"0  *†H†÷ ‚0‚ ‚¥lLÇE jK ¤À‡u CTdàí’} ²s¿ ÆJEa Å-–Óõ+ ûMI›A€<¹Týæ¼ÑĤŠAŠ\Yƒh2»ŒGÉîq¼!OšŠ|ÿD?2²&H®uµîÉLJ~䂚xwM °½öÓÓ¼ú+¥Q8]õûºÛxÛÿì –Õƒ¸é¶À{@{á('ÉúïV^æ~”~ÀðD²y9åÚ²b‹M¿8pâh$É3¤7ÕXi^Ó|íÁSçN°*‡caocYê²+y× agŠ[ý^­‡º†gOqX"""΋ïTqÎP5Xv•îj±¢Õ£‚v0‚r0 +‚70# +‚7øÁk·wSJó%7N¡&{ p€0U­¿C ½‚pœŒÕO1nÕ"˜ŠÔ0 +‚7  SubCA0 U†0Uÿ0ÿ0U#0€EfRCá~X¿ÖNž#U;:"j¨0\UU0S0Q O M†Khttp://crl.microsoft.com/pki/crl/products/MicCorThiParMarRoo_2010-10-05.crl0`+T0R0P+0†Dhttp://www.microsoft.com/pki/certs/MicCorThiParMarRoo_2010-10-05.crt0  *†H†÷  ‚5Bÿ0ÌÎ÷v ­hX5)F2v'|ïA'BJªm8HYUóéX4¦ ‚ª]­‚Ú€ƒA´ò¹ó]ñPù³U„B( ½²®QÅÀ¬—•!Ûüwž•s‘ˆÊ½½R¹P ßWž aí åm%Ù@@ÈΣJÂM¯šT½Ç¼¹+=I+2üj!iO›È~B4ü6‹ @À³š%u'ÍÉ£ö]Ñç6Tz¹PµÓÑ¿»tßÜ€Õíô/k/ÞfŒ°#åÇ„ØíêÁ3‚­VK-ñh•ÍÏðrð®»Ý†…˜,!L3+ðJðh‡µ’U2u¡j‚j<£%¤í­×®ËØ@Y „Ñ•Lb‘"tŒ=GD¦ä°›45±ú¶S¨,ì¤qȸºèDfäGTŽV³Ÿ˜²†Ðh>#µ/^P…Æ‚_A¡ô. à™Òluä¶iµ!†úÑöâMÑÚ­,wS%27ÇlRr•†°ñ5ajõ²;PV¦2-þ¢‰ùB†'U¡‚ÊZ›ø0˜T¦G–%/È&äA”\?å–ã…[<>?»GrUâ%"±Ù{ç*£÷Fà Ö‰ã5'bq¦ïÐ'  Y7`ø8”¸àxpøºL†‡”öà®Eîe¶£~iu’›õ¦¼YƒX¡YÀ¥ä”§J‡µ«\+ðr뽚úwY2M½`(ôçxK0‚×0‚¿  avV0  *†H†÷  0ˆ1 0 UUS10U Washington10URedmond10U Microsoft Corporation1200U)Microsoft Root Certificate Authority 20100 111019184142Z 261019185142Z0„1 0 UUS10U Washington10URedmond10U Microsoft Corporation1.0,U%Microsoft Windows Production PCA 20110‚"0  *†H†÷ ‚0‚ ‚Ý »¢ä. ãçÅ÷–i¼!½i33ï­ËT€îƒ»Å „Ù÷Ò‹ó8°«¤­-|byÿãJ?5 pãÄçkàœÀ6uéŠ1ÝpåÜ7µtF–([‡`#,¿ÜG¥g÷Q'žrë¦É¹;S5|åÓì'¹‡þ¹É# o¨F‘Án–http://www.microsoft.com/pki/certs/MicRooCerAut_2010-06-23.crt0  *†H†÷  ‚ü|qQ¥yÂn²ï9>¼«\`ìß¨Ó éôö–…¶QˆfG¢°=*hw»‘Lb{¶ÁǺz‡4Kbz™éÊüÎJ7É-¤W|þ=ܸZúÖij…:ê³Ùnäi!7ÞÑöugÓ“W^)9Èî-áÍäEs[ÐÒÎz«‚FXÐ^³g¯l5ò¼å?$â5¢ uöV™Ôx,ÑëЈªñߺ~,c·›#!ÄùxlâX6+‘̤Ùò-ºù”@íEñΊ\k>«Óp* jà_GÑÕc 2ò¯×6*pZåBYqKWº~ƒð!<ôÁŹ“ˆE“†é± ™¾˜ËÅ•¤]bÖ c ½uw}=óE¹Ÿ—ŸËW€o3©Ïw¤bY~¡YÀ¥ä”§J‡µ«\+ðrdH[­³€€˜ùJ¦Eåjh¾‰Þ0‚40‚ ‚h´¤“…BbÔ›Ox0  *†H†÷  0'1%0#UCISD FW Update - Certificate0 170830042121Z 391231235959Z0'1%0#UCISD FW Update - Certificate0‚"0  *†H†÷ ‚0‚ ‚ kÙRÂ!]lÌtô†°ªt[¼æu:Ÿ¿údwjž€×¬ƒ{;·z^;)#¨¤áªEã™)¢HêÖž£·lœ´c¿ aþ°SJYžPnæ§øN¥Ôb’µ™v6¿D\C%Œœó¥/Ð$LjêhðÀQEº3N‰n"Ø„7@bmj‹ÙÊñ®µœõ£\0Z0XUQ0O€C!ƒ[P× q5¹ÐjÀÜ¡)0'1%0#UCISD FW Update - Certificate‚‚h´¤“…BbÔ›Ox0  *†H†÷  ‚]?*×»1Û›æ¦Ä%º_÷ ¹šõo¸…SXs^3 ¬šlv6q~ûtgìøÜ.ÆÀò1A=ê®…(¤³{å¨ÉNW­Y‡s® Ô$Uû¶Þë4h ¬²3 ~&ÆVˆO~—v»Ô™ñ\á(Q'N‰Ó¼>ó¥L¥5=·/1ærVRö|‡%=n$ß Ä; Ó ¹›mXÿ%.À”9õ=!ã\|iœ¸u„+pbŒ:˜íû7›‹ó±ˆkÐ|;‹ ™3èé[ö ìA{.T™ËP‰Ÿ/ÞY £s YG¬xMä²Á:"ê Íw-Þ¢o‹\&¥«™ 𱹪 Ç€  D´ÎJMÊšóÈ—ÜVî'Ã…ëˆ÷Ϲ +‚e[²˲×:=–E£¼ÚÐgeoŒdbx&ÄÁLP’@¬©Aù6“C(Œ0½šúwY2M½`(ôçxK€´Ùi1¿ ý‘¦ÑO¤Ræm²@Œ¨`MA’eŸ ½šúwY2M½`(ôçxKõ/ƒ£úœûÖ’r($ÛäE4Ò[…$k;•}¬nÎz½šúwY2M½`(ôçxKÅÙØ¡†âÈ- ¯ª*o.s‡ >d÷,Nïgyj„½½šúwY2M½`(ôçxK63„ÑM. xbd„ÄY­W£ïC–&`HÐXÅ¡›¿v½šúwY2M½`(ôçxK세Kle¥ ©¾q–R0! bÖÓ h2Û²Ò à'%'ß¶=IÒ•r¦ôL½šúwY2M½`(ôçxK^ê‰T‹ `²þíÚ< Çþ›Ík”覃¸R8½šúwY2M½`(ôçxKæÆ¨Xdo±ïÆyþ(±#gþ’æ¾+6™žÿ9О½šúwY2M½`(ôçxK ß_NQìx¹mÐ%ý¶†ãŸor’xRY›eœ&½šúwY2M½`(ôçxK »C’Ú¬z¸›0¤¬eu1¹{ú«ù ¯åù¶ë ct½šúwY2M½`(ôçxK “9v-ó6«=ФcßqZ9ϰô’F\`lk×½‰Œ½šúwY2M½`(ôçxK ¾Êo)ì o3}räˆK ³H˜:* ×?O½šúwY2M½`(ôçxK Éóû™–!HÃʃ62u>Ôü ¹[1æR*Í[ü½šúwY2M½`(ôçxKo¬êÏìýN0;tô€ €˜âЀ+“oŽÇtÎ!ó†hœ½šúwY2M½`(ôçxKN: [CƦ»Ó@O4=Ï9bgΔøµ.#©Ú’ ½šúwY2M½`(ôçxK34)ÿbퟗ>HÜîå-¾.ImTµÏÖÈdÒѽšúwY2M½`(ôçxK+™Ï&B.’þ6_¿Kà 'lžáKzoÿDû/ki™9½šúwY2M½`(ôçxK+¿,§¸ñÙ'îR¶û*]ÐI¸Z+›Rœ]fb°Uø½šúwY2M½`(ôçxK,sÙ3%ºmËå‰Ô¤Æ<[“UYï’ûðPíPÄâRñ}½šúwY2M½`(ôçxK.p‘g†¦÷sQ§«pµWÆ2.©#²¨Ó¹+Q¯}½šúwY2M½`(ôçxK0f(úTw0W(ºJF}çÐ8zTõiÓvŸÎ^uì‰Ò“½šúwY2M½`(ôçxK6íºõ­A¤¡wz¿/¯^g4g^Ù^i5‚ž ªÒ½šúwY2M½`(ôçxK8AÒ!6ƒ×\ æ!`9MlN g`¶ö¹b¼…[½šúwY2M½`(ôçxK?ΛŸß>ðTR°ù^ä·ðmt:syqUŽpjÎ>s½šúwY2M½`(ôçxKC—Úʃžc|µ ’ßC¼-/²¨õŸ&üzKÔÙu’½šúwY2M½`(ôçxKGÌa'⚆à:kï,ÔøÅZmkÛ6!hÃ,ã*Zß½šúwY2M½`(ôçxKQˆ1þs‚µÐ>Æ!"‹Š¶Ty½ ¿£ÅÁÐôœ0a5½šúwY2M½`(ôçxKZéIêˆUë“ä9ÛÆ[Ú.B…,/ßg‰úg6ãÃA+\½šúwY2M½`(ôçxKk€xäAЦë{³^`’ÏGžëŒäÍçÐrÌ´/f½šúwY2M½`(ôçxKlˆTGÕYâ“Q¸&Àl¸¿ï+”­585‡rÑ“ø.ÑʽšúwY2M½`(ôçxKo(ÿqÉÛÕ¯.{¿Ë«d|ÂeÝõ²“Ͷ&õ :x^½šúwY2M½`(ôçxKqòoÒ"I~T£Fb«$—üÈ wõhéãÙ¿Ëýcu½šúwY2M½`(ôçxKrk>¶Tj0óø=›–Îöpé¨ÑpŠqæ-Ä,#Á½šúwY2M½`(ôçxKrà½gÏ]V«Šß;ݼ‚¿2¨ØªŒ^/mò”(ÖØ½šúwY2M½`(ôçxKx'¯™6,úðq}­ä±¿àCŠÑqÁZÝÂH·[øÊ¤K²Å½šúwY2M½`(ôçxK¨¹e»„Ó‡k”)©TÌ•SϪØÈ£;ý3ÿð佚úwY2M½`(ôçxK‚Û;δöCΗÃч͛YAÍ=èXo+ÚV7W_g½šúwY2M½`(ôçxK‰Z—…öÊ~ÔOÁ¡G qóñ"8bÙÿÌ:âß’=¯½šúwY2M½`(ôçxKŠÖHYñ•µõ¯ª” jag¬ÖzˆnF“dr!ÅYE¹½šúwY2M½`(ôçxK‹ô4´žÌ÷¢ÍeËì;= <5¾P_ß{Õcõ!½šúwY2M½`(ôçxKŽ¢‰Ïç «seË(îQíÓ<òPmèˆû­Ö¿€H½šúwY2M½`(ôçxK™˜ÓcÄ‘¾½tº¹M’‘soܦC£fd¼1ZB½šúwY2M½`(ôçxKžJi1ah.Uýèþõ`ëˆìþܯfÀÊ÷²·4½šúwY2M½`(ôçxK¦µ6UÓ¢¯ G'Yykä¤ T•§ØiuLHH…t§½šúwY2M½`(ôçxK§ó/PN°þ­š~ùNѺ ì]æ÷ïoð¦+“¾ß]E½šúwY2M½`(ôçxK­h&á”m&Óêóh\ˆÙ}…Þ;MË=â®Ç`ÑùÂ$Q?¼eYW×5ú)õ@νšúwY2M½`(ôçxKØËë—5õg+6~O–ÍÇIia]JélrMBÎøóú½šúwY2M½`(ôçxKé,"ë;VBÖ\ÂÊòGÒYG8„D•oYâ°Ñú½šúwY2M½`(ôçxKýÝn=)ê„Çt=­JÛǵþÁ³‘ù2@†¬ÇÖÛØ½šúwY2M½`(ôçxKþc¨Ox,ÉÓüòÌùüûÐ7`‡‡XÒb…íf›Ünm½šúwY2M½`(ôçxKþϲ2Ñ.™KmH],qgrŠ¥RY„­\¦u"š6½šúwY2M½`(ôçxKÊaJ~“”ŒÐþUÓ™ùÑ©nE AR'ÂÆ[½šúwY2M½`(ôçxKU¹› å=¼þHZ©Ç7Ï?¶ï=‘úµ™ª|«í§cµº½šúwY2M½`(ôçxKwÝ£ ˆÿ^; æb x  S^ˇæðˆŠ k/½šúwY2M½`(ôçxKÈ<±9"­™õ`tFuÝ7̔ܭZ˦G/î4qÙ9脽šúwY2M½`(ôçxK;‡S> ÃÐì¨#Ëð©AªØryÑÄ™€-Ñæ6¸©½šúwY2M½`(ôçxK“šîôõúQâ3@ÃòäHΈrRjý÷Rçó£ò¼Ÿ`I½šúwY2M½`(ôçxKdW[Ùxš.­Vö4R¯kø ùDxYuéðN-d×E½šúwY2M½`(ôçxKEÇÈ®u Ï»Hü7R}dÝdM®Ø‘<ÍŠ$ÉM…igߎ ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸€ õBX§zõI“&®Ç4Ló?Z>„Í»|Š­¤¸Ž³˜,äEFI PART\ÿ¹(v¯mpt"Žmpt:Ýt·éL¯îW ¬ƒ%€€Î;rê(s*ÁøÒºK É>É;Ñ9Í#ùBkO‰‘>š& ÿGEFI System Partition¢ Ðëå¹3D‡Àh¶·&™ÇÌÿ0•*¢îD¹áÙ•á,HÿG&yÓÖæõÂD¢<#*=ù(n­™¿Iv~I’µPépS —H&ÿ'R)¯=ƃ„rGŽy=iØG}äÞI3ý|”I¬}2ÚV(R)ÿ×>L¯=ƃ„rGŽy=iØG}ä¨U0 –KDØŠ5”Ø>Lÿ‡+o€ ýJ¸ i£ºmˆ½»çyãTñõÀ¾˜z7ƒ“`gú>aßä‹Ê“Òª à˜+Œ BootOrder€ ÖÐÿO†V`¾"ÜfqÓÄÇí­siüâW …¬6†aßä‹Ê“Òª à˜+ŒVBoot0005UEFI : Built-in EFI Shell\¹#P&Û›B¦H½GfL€ÿBO€ )¦³(Î Ör/ˆ>»i~ ‰¤¹“¬m³cæ‚ä\`¦aßä‹Ê“Òª à˜+ŒvBoot0002bCentOS*@Ñ9Í#ùBkO‰‘>š& 4\EFI\centos\shimx64.efiÿ€ ¡â½:“¤Åfø„/ŸÄlœpÖÊNu …c§‚¢ü«¾aßä‹Ê“Òª à˜+ŒŽBoot0001 zubuntuçuâ™ u7K¢æÅ8^lËÿ*@Î9u-—¥FœðT¯mÑÓ4\EFI\ubuntu\shimx64.efiÿ€ …ù%£O<ø¨*“bïÞè5ðgnø5Nl¹¥˜€:Ø)õ¶aßä‹Ê“Òª à˜+Œ†Boot0004 tshellçuâ™ u7K¢æÅ8^lËÿ*@ÙäÂTzÄuA¹BOOˆ¥„ß.\EFI\shell\Shell.efiÿ€  k®ÃA#)øˆ4 Ü,ª¹ZVñ ÿ_U³ž@†¾aßä‹Ê“Òª à˜+ŒŽBoot0003 zFedoraçuâ™ u7K¢æÅ8^lËÿ*@ÙäÂTzÄuA¹BOOˆ¥„ß4\EFI\fedora\shimx64.efiÿ€ nƒݶoynd!7Ÿù'®FÚ2A ëïÆûœÎ2staßä‹Ê“Òª à˜+ŒDBoot0000 ŒWindows Boot Managerçuâ™ u7K¢æÅ8^lËÿ* Pç I ÷ HšÇ8"ç½F\EFI\Microsoft\Boot\bootmgfw.efiÿWINDOWSˆxBCDOBJECT={9dea862c-5cdd-4e70-acc1-f32b344d4795}ÿ€ Ú֬߷†ŽÎ¤MAÈiÂ)V¯šD¢ÑÔÀå}f‡8pÿ…Ä \¹#P&Û›B¦H½GfL€ÿ€ (qªÏ¡bºYS4ï«"†„!4i¦¤Ì![Õš& \EFI\centosgrubx64.efiÿgo-attestation-0.5.1/attest/testdata/ebs_event_missing_eventlog000066400000000000000000000377211452320553600251440ustar00rootroot00000000000000˜qé«\Û‘G U­Å³;ÎM602¾€÷Ìâ.Gáªaö$ë^44~0¸©bÖ4lr™¸×¢õÊ ‹¦ƒí¹ûaHH7$[žš2è€tdù²_'ª£ÖŒ¨iï噑ÀHʪQ\…¬ vdÉ„˜+‹Š¯.žI‘ýäÑiK£‡Á~PJ„»fÙªö1+pÁhºí¼ñUo©09‚/éºÕõI[nÆÂRþçÐeZÚP‹¤:"Ý%xh?ZéÅëAAP×Ч>Ο“`8ÐÓÐÒwçnó?úè[1¦j†VlJáàB‘å¡­=cC>37"TâÐÓ¾ç‘×–Žº9wƒ)ë±X>sI98I׆¶¹×‚ €Õ-Ä(½™_ ÒƒÜ¿ûG1§éØ™£‚0‚0 Uÿ00kUd0b0` ^ \†Zhttp://onsitecrl.verisign.com/HewlettPackardCompanyDeSPrintingDeviceCSIDTemp/LatestCRL.crl0Uÿ€0áU Ù0Ö0Ó + 0Ä0Á+0´±Hewlett Packard Company, 2, Authority to bind Hewlett-Packard Company does not correspond with use or possession of this certificate. Issued to facilitate communication with HP.0;+/0-0++0†http://onsite-ocsp.verisign.com0U`Ñ%Aæv<^Í”O:£Ñ§Ãª.Þ0U#0€¸¡ ½_Fé€Û÷™½ôýê Æ0U%ÿ 0 +0  *†H†÷  ‚m²sæÁâÉ#ÄÂ@ ð> ß³‘Î’haÏ&© S áHŠlÄ“"r—±FpÙi»ÙÕ.QÊï2☡ì6bòÄg·1ñÑÈÇk·.]'}£*ÔÀ `è&ŸÛño”“×ø`áŸ[¿Kך2LÒ÷-RÇÒ‚)é÷²A!ú* }Î,p³ë©V<˜óM?RX£‘;JTMlx1‰{dÅU †b¶Ä7µL :b¶ûÚRü6wYLãëô׎k¸¸ÄÂ͆9‡²z©é¶)Ób‚‚j˜Lˆ’D¹~AÄ´WÎŽ÷a‹ÁGìã€bX5ܤjÿ ý#€[ãî™,ø³¼jeè>ŽøŠSù aßä‹Ê“Òª à˜+ŒÓ KEK¡YÀ¥ä”§J‡µ«\+ðr»Ÿ1k©õ ÛªO¤*z ˜2vŽ0‚‹0‚s 1u£¶¡uqUên7Rm@0  *†H†÷  0k1 0 UUS1 0U Hewlett-Packard Company1:08U1Hewlett-Packard Printing Device Infrastructure CA0 120808000000Z 320808235959Z0‹1 0U Hewlett-Packard Company1+0)U "Long Lived CodeSigning Certificate1:08U1Hewlett-Packard UEFI Secure Boot Key Exchange Key0‚"0  *†H†÷ ‚0‚ ‚¯¢iê4Ãjò`^ÝÇÖ P¢$ ܵC¹LÓ~‰Š)',Y?ÉÕÿ:uJÑø)yük[¾ÁçÕÞ™¦‰<˜äj¼®ÅÞýªÄ,•®¼69Úç|u\¼ „_ªÆÆÕÀÞC¿íK³%sˆ•ª×ùx_m¹Àm ÔÖæc1‡(OA© Â+½¶5ùø’%ʾ±ÏO÷“ÏHX%×ëåˆÞ0•Ô{9P‚«€ÈHó~è;Ë9cÕË £]ó'R•ÓÇ«Ær˜¾ûË ŽÉìEšÉ©zSÔ¸’·á«˜½²šÊ`øÄc‡³“´“Œ¸YÀŒÇÒXݳᣂ0‚0 Uÿ00kUd0b0` ^ \†Zhttp://onsitecrl.verisign.com/HewlettPackardCompanyDeSPrintingDeviceCSIDTemp/LatestCRL.crl0Uÿ€0áU Ù0Ö0Ó + 0Ä0Á+0´±Hewlett Packard Company, 2, Authority to bind Hewlett-Packard Company does not correspond with use or possession of this certificate. Issued to facilitate communication with HP.0;+/0-0++0†http://onsite-ocsp.verisign.com0UÐÈ ¢êz×”‰FÜqhË#|0U#0€¸¡ ½_Fé€Û÷™½ôýê Æ0U%ÿ 0 +0  *†H†÷  ‚,O­Çý™i†³²,Ýmä9|n+AZv.N4 ŸÔýúÖöÛ:¯U‰c?´f)FPÈÑ’²¹öÒÞXGHîÃÿ‹Ë«¹!1ý D†•ØIŒ•ù·¬ô`% 'Æ;5¼Îb L#€L(k(ˆ]L3IS­Zïêl.ÎåRó-;2>I­Ä÷¾í€§/¡„4'¬?R,›©™yì·~gé³Ì”ÏdÓ°æ@€àªªQ¶ ²¯²HSüâIøQ\f…,WA̬oÛÀfhÌ)¹#ÁÇØ!oɶ±-šX[ñ¾0»¡šš»;ÃIG¤üðf\Jjñ¸¬Aì„È¡YÀ¥ä”§J‡µ«\+ðrü½šúwY2M½`(ôçxK0‚è0‚Р a ш0  *†H†÷  0‘1 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0 110624204129Z 260624205129Z0€1 0 UUS10U Washington10URedmond10U Microsoft Corporation1*0(U!Microsoft Corporation KEK CA 20110‚"0  *†H†÷ ‚0‚ ‚Ä赊¿­W&°&ÃêçûWzD] ÚJåt*æ°ìmëì¹ãZc2|Oã §8“ŽÆõà„±š›,çõ·‘Ö áâÀ¨¬0ßHóPšd§QÈ…O †Îþ/áŸÿ‚ÀíéÍÎôSjb: C¹â%ýþùÔÄ«â#‰p·¤Mì®åœúÂ×ÁËÔèÄ/å™î$‹ìò‹êÃJûC ~µG’lÜæ‰ëõ3ë*qåùƒ<ÿ% /hvFÿºO¾Ü­q*XªûÒy=ä›e;Ì)*ŸürY¢ë®’ïö5€Æìä_ÌvÍïc’Á¯y@„y‡ãR¨è{i£‚O0‚K0 +‚70UbüCÍ >¤ËgÒ[ÙU¬{̶Š_0 +‚7  SubCA0 U†0Uÿ0ÿ0U#0€EfRCá~X¿ÖNž#U;:"j¨0\UU0S0Q O M†Khttp://crl.microsoft.com/pki/crl/products/MicCorThiParMarRoo_2010-10-05.crl0`+T0R0P+0†Dhttp://www.microsoft.com/pki/certs/MicCorThiParMarRoo_2010-10-05.crt0  *†H†÷  ‚Ô„ˆõ”Ê*<û*’ × ÑñèRf¨î¢µuzª-¤vZêy·¹7jQ{döádòg¾÷¨x½ºÎˆXd ÖWÈ£_ÖÛÆÐiÎHK2·ë]Ò0õÀõ¸ºx£+þ›Û4V„ì‚Ê®A%pœkéþ×–å甲* Kÿ(){÷×|¥Ñv¹Èyí’œÂþßo~l{ÔÁEÝ4Q–9å^VØ–ô¦B³ wýòqVÌŸ†#¤‡Ë¦ýX~Ôig‘~òå ‹Š<‡„ëãνCå­-„“Žj+Z|DúRªÈ-»àRßøš=Á`°á3µ£ˆÑe ç¬|¤Á‚‡N8±/ Ňoý.¼9¶çæÃàäÍ'„ï”Bï)‹FA;gØùCYeË ¼ý’Oôu;§©$üPA@yà-O j'vnRí–i{¯÷‡ÐE­Sû0ª76aÚJi4ØhíÖÏl” ÓÏl"y­±ð¼¢F`©ÄÂ!‚ñýòèy2`¿Ø¬¥"KÊÁØKë}?W5²æOu´°`"S®‘yÖ›A†Tp²Þ 5|°4rº—`;ðy뢲]¢¸‡Åéöµ—%o8Ÿã‘úŠy˜Ãi·£ —øÊ®×ÄóÀuk4 µ™`ó\°ÅWN6Ò2„¿ž€yÞ"¸W߃¿â ‘( 'öû]Ä˲×:=–E£¼ÚÐgeo db¡YÀ¥ä”§J‡µ«\+ðr¨Œ1k©õ ÛªO¤*z ˜2vŽ0‚x0‚` Vt§ï9 ‹GShsmm0  *†H†÷  0k1 0 UUS1 0U Hewlett-Packard Company1:08U1Hewlett-Packard Printing Device Infrastructure CA0 130823000000Z 330823235959Z0y1 0U Hewlett-Packard Company1+0)U "Long Lived CodeSigning Certificate1(0&UHP UEFI Secure Boot 2013 DB key0‚"0  *†H†÷ ‚0‚ ‚ÉG¿ˆd¦YWol Êß—‚¡;ï6C›êš«åM¼û´´O…‰ä§å%Ôæ›6K™Ž/}áØŠ9aŽfŸsÓó8.hýæÛó>¬„ìdé£òçRk(uo4y«$?§Ìýü:2qü³"`vë1¢(ró<¯M•½¢ð±Cj]3;rŒiq«´£Ç3d†ŠáA3ØšqߺvÉý\:Lœ婶@à{uGz:>:Q¯ÓC*+ÊjÏÐ9é'gyòÚ:Aš™¡yáÆ”kð˜íÛ”D›Ò<ËÈÓ5Gר–ÇÓ?¤ém4ì©lhX#Ÿ'j6æâš˜á’¦²°n)ì“Ò5Y¦«ƒ¾ÏÃ~]øÙºgvz™áQú4…ë…_ª2½2A˜r"i$A"ˬ®sZY(×)ø§ýTŽÏ¾ëF‚w“Í“›VÚ²²NÉ–ˆm—rˆã÷¨ 7¯Ün®èÈP(ZA£êJí~ ­ün€ëÉ6T—§Ta 4`@¡YÀ¥ä”§J‡µ«\+ðr±•1k©õ ÛªO¤*z ˜2vŽ0‚0‚i Sù¾“£Ëk['¯‰²0  *†H†÷  0k1 0 UUS1 0U Hewlett-Packard Company1:08U1Hewlett-Packard Printing Device Infrastructure CA0 120823000000Z 320823235959Z01 0U Hewlett-Packard Company1+0)U "Long Lived CodeSigning Certificate100.U'Hewlett-Packard UEFI Secure Boot DB Key0‚"0  *†H†÷ ‚0‚ ‚ÎVÓÀ…áÉi bssï゘ú¤Âµ…òkðЏw'à3aÿŽ+ÃÂmµÄÑ>zN“ÚÊ …Ž „È hçå‰j;º}û–ÒOÁ`I…·¤ýò£D!Äï¼øñ©_Lx<[—[iu÷x”ÿ<¯®–‹Q½šâã”S5ìrùw5ÅÅ~ËóäOhÓìŒF°-²7f#Q—û&‰œ-w¥‚±ÒƒZÑ6ñýÔ|à,+øVKªÛ Ϥ-h¸IÓ7m}ÞÓ…?æÙLDÚêàEêÉ/¯Á Ä5CÊ“‚òÑÎÞäד1êf;Ô†U¤Hûjáà÷„P†½È]>*¤m£‚0‚0 Uÿ00kUd0b0` ^ \†Zhttp://onsitecrl.verisign.com/HewlettPackardCompanyDeSPrintingDeviceCSIDTemp/LatestCRL.crl0Uÿ€0áU Ù0Ö0Ó + 0Ä0Á+0´±Hewlett Packard Company, 2, Authority to bind Hewlett-Packard Company does not correspond with use or possession of this certificate. Issued to facilitate communication with HP.0;+/0-0++0†http://onsite-ocsp.verisign.com0Uç :‹„<C/jH]ÑôǸå)0U#0€¸¡ ½_Fé€Û÷™½ôýê Æ0U%ÿ 0 +0  *†H†÷  ‚gީȬ›ÛuÂŽå_8ªrÅà/£Î§›Ë9|˜æOš6Õ!ꤠ]S@tæÂ+üòØhžiöÄ$ñ‘‚·?¡Æ`=<6={q#ÌlÜ®£ KÐK£u^URçÚ·iêÐ(Ö¶9¬Ò°?4CÄʨ)8²&õL Ï!·KyCC йA4_'žƒweȸ¡¦Mí°^Oîî¶ ,~·üC«SÍW˜gß:IÞs¸¦ž,¶UA…$×ÏáÛ3ƒ$’zú?^‡ õÛñíˆgÃÌÚM¦š?§p0W†·úÞé6¯)wΕØÂÛ—…ˆ ¢ŽEv-¨"¤’é³¼l†÷§sð|¡YÀ¥ä”§J‡µ«\+ðr뽚úwY2M½`(ôçxK0‚×0‚¿  avV0  *†H†÷  0ˆ1 0 UUS10U Washington10URedmond10U Microsoft Corporation1200U)Microsoft Root Certificate Authority 20100 111019184142Z 261019185142Z0„1 0 UUS10U Washington10URedmond10U Microsoft Corporation1.0,U%Microsoft Windows Production PCA 20110‚"0  *†H†÷ ‚0‚ ‚Ý »¢ä. ãçÅ÷–i¼!½i33ï­ËT€îƒ»Å „Ù÷Ò‹ó8°«¤­-|byÿãJ?5 pãÄçkàœÀ6uéŠ1ÝpåÜ7µtF–([‡`#,¿ÜG¥g÷Q'žrë¦É¹;S5|åÓì'¹‡þ¹É# o¨F‘Án–http://www.microsoft.com/pki/certs/MicRooCerAut_2010-06-23.crt0  *†H†÷  ‚ü|qQ¥yÂn²ï9>¼«\`ìß¨Ó éôö–…¶QˆfG¢°=*hw»‘Lb{¶ÁǺz‡4Kbz™éÊüÎJ7É-¤W|þ=ܸZúÖij…:ê³Ùnäi!7ÞÑöugÓ“W^)9Èî-áÍäEs[ÐÒÎz«‚FXÐ^³g¯l5ò¼å?$â5¢ uöV™Ôx,ÑëЈªñߺ~,c·›#!ÄùxlâX6+‘̤Ùò-ºù”@íEñΊ\k>«Óp* jà_GÑÕc 2ò¯×6*pZåBYqKWº~ƒð!<ôÁŹ“ˆE“†é± ™¾˜ËÅ•¤]bÖ c ½uw}=óE¹Ÿ—ŸËW€o3©Ïw¤bY~¡YÀ¥ä”§J‡µ«\+ðr@$½šúwY2M½`(ôçxK0‚0‚ø  aÓÄ0  *†H†÷  0‘1 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0 110627212245Z 260627213245Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1+0)U"Microsoft Corporation UEFI CA 20110‚"0  *†H†÷ ‚0‚ ‚¥lLÇE jK ¤À‡u CTdàí’} ²s¿ ÆJEa Å-–Óõ+ ûMI›A€<¹Týæ¼ÑĤŠAŠ\Yƒh2»ŒGÉîq¼!OšŠ|ÿD?2²&H®uµîÉLJ~䂚xwM °½öÓÓ¼ú+¥Q8]õûºÛxÛÿì –Õƒ¸é¶À{@{á('ÉúïV^æ~”~ÀðD²y9åÚ²b‹M¿8pâh$É3¤7ÕXi^Ó|íÁSçN°*‡caocYê²+y× agŠ[ý^­‡º†gOqX"""΋ïTqÎP5Xv•îj±¢Õ£‚v0‚r0 +‚70# +‚7øÁk·wSJó%7N¡&{ p€0U­¿C ½‚pœŒÕO1nÕ"˜ŠÔ0 +‚7  SubCA0 U†0Uÿ0ÿ0U#0€EfRCá~X¿ÖNž#U;:"j¨0\UU0S0Q O M†Khttp://crl.microsoft.com/pki/crl/products/MicCorThiParMarRoo_2010-10-05.crl0`+T0R0P+0†Dhttp://www.microsoft.com/pki/certs/MicCorThiParMarRoo_2010-10-05.crt0  *†H†÷  ‚5Bÿ0ÌÎ÷v ­hX5)F2v'|ïA'BJªm8HYUóéX4¦ ‚ª]­‚Ú€ƒA´ò¹ó]ñPù³U„B( ½²®QÅÀ¬—•!Ûüwž•s‘ˆÊ½½R¹P ßWž aí åm%Ù@@ÈΣJÂM¯šT½Ç¼¹+=I+2üj!iO›È~B4ü6‹ @À³š%u'ÍÉ£ö]Ñç6Tz¹PµÓÑ¿»tßÜ€Õíô/k/ÞfŒ°#åÇ„ØíêÁ3‚­VK-ñh•ÍÏðrð®»Ý†…˜,!L3+ðJðh‡µ’U2u¡j‚j<£%¤í­×®ËØ@Y „Ñ•Lb‘"tŒ=GD¦ä°›45±ú¶S¨,ì¤qȸºèDfäGTŽV³Ÿ˜²†Ðh>#µ/^P…Æ‚_A¡ô. à™Òluä¶iµ!†úÑöâMÑÚ­,wS%27ÇlRr•†°ñ5ajõ²;PV¦2-þ¢‰ùB†'U¡‚ÊZ›ø0˜T¦G–%/È&äA”\?å–ã…[<>?»GrUâ%"±Ù{ç*£÷Fà Ö‰ã5'bq¦ïÐ'  Y7`ø8”¸àxpøºL†‡”öà®Eîe¶£~iu’›õ¦¼YƒX€fg}Bœù0—,gµ»Ý!$Äb¬üuþ˲×:=–E£¼ÚÐgeoØdbx&ÄÁLP’@¬©Aù6“C(L0n4 œÿ³z˜œ¥Dæ»x ,x?³78v…£¯ &ÄÁLP’@¬©Aù6“C(Œ0½šúwY2M½`(ôçxK€´Ùi1¿ ý‘¦ÑO¤Ræm²@Œ¨`MA’eŸ ½šúwY2M½`(ôçxKõ/ƒ£úœûÖ’r($ÛäE4Ò[…$k;•}¬nÎz½šúwY2M½`(ôçxKÅÙØ¡†âÈ- ¯ª*o.s‡ >d÷,Nïgyj„½½šúwY2M½`(ôçxK63„ÑM. xbd„ÄY­W£ïC–&`HÐXÅ¡›¿v½šúwY2M½`(ôçxK세Kle¥ ©¾q–R0! bÖÓ h2Û²Ò à'%'ß¶=IÒ•r¦ôLiÊxçE (QsC>RÅÂR™äs%9±˜s!ú‡_H>ÚŸ¾) ACPI DATA°Fš¡9©Ž¾®–“X…Tº±rL ACPI DATA€9½…ìážBNæžÓ„j`ã³ëTaßä‹Ê“Òª à˜+Œ "BootOrder  €ÛJñÀ=rB.›Â£Iš1Eª®aßä‹Ê“Òª à˜+Œ~Boot0012bdebian* È·Õ9¦ÜH¼âï²ú=K)4\EFI\debian\grubx64.efiÿISPH€Í—@¿µ ÍÙÍ HèÔ Œë–Ø\raßä‹Ê“Òª à˜+ŒBBoot000CUSB:  ÐA ÿN¬ŸYM…âR,Y² ISPH€µƒ†ó“JÚ£WPºµUÝB¬Í€aßä‹Ê“Òª à˜+ŒPBoot000D CDROM:  ÐA  ÿN¬ŸYM…âR,Y² ISPH€b÷Pk³ÿPã{$ãÅ9Ç0tO¨X maßä‹Ê“Òª à˜+Œ=Boot000EUSB:  ÿÿ ÐA ÿÿÿ ISPH€ œŽ—ïfËøA¯V椆º©{aßä‹Ê“Òª à˜+ŒKBoot000F)CDROM:  ÿÿ ÐA  ÿÿÿ ISPH€8~Šm ƒPÌ¢8GÍqšúUbˆŠ¦aßä‹Ê“Òª à˜+ŒvBoot000A6MTFDDAK512MBF-1AN1ZABHA €MTFDDAK512MBF-1AN1ZABHA ÐA ÿISPH€4lÇtc¶h§Ÿ$#äÃ0›ä˜£aßä‹Ê“Òª à˜+ŒsBoot000B5IBA GE Slot 00C8 v1550IBA GE Slot 00C8 v1550 ÐA ÿISPH€ªh Åò íº ^¦¾Bó€ÝÈÔ„aßä‹Ê“Òª à˜+ŒTBoot0000,Startup Menu5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿISPH€,Ã%Ÿ„õýüa©½¼Ô`Z|{’aßä‹Ê“Òª à˜+ŒbBoot0001,System Information5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿñISPH€âc˱E‹›ª Ö6ü’J…Iç‚aßä‹Ê“Òª à˜+ŒRBoot0002,Bios Setup5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿISPH€@·‡ö!9î?š··Î>'0ûðü¬aßä‹Ê“Òª à˜+Œ|Boot0003,3rd Party Option ROM Management5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿóISPH€&Êþ†ÅjèâaÔô>Lù’aßä‹Ê“Òª à˜+ŒbBoot0004,System Diagnostics5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿòISPH€A'ôâ;¥Ô¨þDó àµóh‚î’aßä‹Ê“Òª à˜+ŒbBoot0005,System Diagnostics5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿòISPH€¿dTõ‡ÐƒÑW3Ù„;^팒aßä‹Ê“Òª à˜+ŒbBoot0006,System Diagnostics5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿòISPH€ìûdˆÐEBôJ±QG *\a™’aßä‹Ê“Òª à˜+ŒbBoot0007,System Diagnostics5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿòISPH€Xkû(êéìÛ!˜u,Ø•íeˆEƒ€aßä‹Ê“Òª à˜+ŒPBoot0008,Boot Menu5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿùISPH€X–ÑÁrSA[1‰¶VEõNþ/–†aßä‹Ê“Òª à˜+ŒVBoot0010,Network Boot5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿISPH€ÍÛE1¦ìA¾'Sº&7Öå÷òV(Calling EFI Application from Boot OptioniÊxçE (QsC>RÅÂR™äsiÊxçE (QsC>RÅÂR™äsiÊxçE (QsC>RÅÂR™äsiÊxçE (QsC>RÅÂR™äsiÊxçE (QsC>RÅÂR™äsiÊxçE (QsC>RÅÂR™äsiÊxçE (QsC>RÅÂR™äs€É\Ô±Q_íÃÙ‘ãÖ§ëjÕU:dEFI PART\w6 ѯž;"Žž;з—fÒZM’Ö5ßÿT©Œ€€ê·ÑHah!IdontNeedEFIgÏb™ÂîD˜Ê‰ÅMÁÿ(s*ÁøÒºK É>É;È·Õ9¦ÜH¼âï²ú=K)ÿ¯EFI System Partition(s*ÁøÒºK É>É;‡µ®y@”%j&žò)_°ÿï¯=ƃ„rGŽy=iØG}änˆ¯Ü®³`LšVîqMí=ðÿž;€¡ŒøSêÏÇà בԜTnÂV©ð‰ ÐA Åú1ÏNÂÒ…ó É>É;€* È·Õ9¦ÜH¼âï²ú=K)4\EFI\debian\grubx64.efiÿgo-attestation-0.5.1/attest/testdata/linux_tpm12.json000066400000000000000000000521051452320553600226610ustar00rootroot00000000000000{"Static":{"TPMVersion":1,"EKPem":"LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJDZ0tDQVFFQWxpeWp3c1o3ZU5WMVkxRGVSMUtrL0JIdHFhcnRhREZQTXh5S05tWXdSbHZiTDJ1UXBObGIKT2MwaXpWVlZaelJORTY2T2pmcUZCT045K3d5ZUdsQXZGMW5LdWtxM3BLTlBFMVNwUm80eUUvbWZVdW14d1pPUgpzWnlNZXZPelNhbVQxaWdhMHZ0c1Q4TktvVGdRQTFjQUNLNXNYeGpDRDRjMmxYb1dtV3dlRWJMc3N6andualBVCkNNU1pWWnZlQ2RLM1NtL05WamhVdnRab1JodTc3NEZXOUl1NUhZaFVQWXFRNWVBaEVtMlFQT1NQOE10MmJIWTcKM3UzYlkwd0pvNVlxRzNaRkJQYjJLaUxlY3hacFZYY0k5VHNxbmlLcW5XLzJkdlhMRyt5WHVxVTBpVkhiSTZZTQozTjdTUmVGODhNMXBaQTZXSTI5emNtQThHN0NXL3NVWW1RSURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K"},"AK":{"Public":"AAAAAQABAAIAAAAMAAAIAAAAAAIAAAAAAAABAJt+7mczx4uRZR3Y2MUSBBBipAK588vhMHYMI4tDGwXBF+4Ri7spbIrYoRykafNupO57w+sS0GwpAotbkm7LLWXjNkioFVxige6uKsh+gqlNOy98tou9y4kgQFHmJbchxmz9o9Mo2Oi/MLC9thq/iYt5b2nmiNILnQZS+YGg1lPIoBxOhkVEoTSzpAFV1CstJJRhqkKlPmeR9fm1lnJeUapN0BD0WZ0PSWYmS/iUno1OnDp/mrqIrX28HPIaU3hDNVnQvgRmtl+e35VpoqXpW58Ej5jnLaipJsG7PWVd33JTu5ezTk3OG3C4zjgrHq4eTszV7F1BPUwq4Zmb2e6FsxU=","UseTCSDActivationFormat":true,"CreateData":null,"CreateAttestation":null,"CreateSignature":null},"Quote":{"Nonce":"","Alg":4,"Quote":"AQEAAFFVT1TUe8hZBOBgoRyPd07c7+kmB3KYG9o5o+5ea0sNMlW/75VgGJCv2AcJ","Signature":"AYWsgkmbV1kr65B4tHA3dYN4LD2+FaZQz8mq80Bu+M+yqBxGdGsELKC0TSLfXRXTbmA8fQAH7X++tM2M9z5PaIWtqULfGfkn/ao8dhFE0T/gm2c47/BgG7oyxtdnSlzFaQwQQzdprkHq6bBZDMA7AhcUXKfnxIllh9DsHGgPSrrOT44mwAnmpf/3eNDQ++2b+Sy01csAXtkVCB4tRyOgf48KpS0uEQ647bYsjCJatMOAXx+YV3XB7c9Drj4hsORsOpXaaFOTpN5HOAmIQqsS0tJKM78i1Sbp1/E/WlqLjffTwoeP2OJlsT85Xkmss0vhy9xBLcHV1oe0X5PUziZfjg=="},"Log":{"PCRs":[{"Index":11,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":0,"Digest":"g1hNOUmsEYL7BJe1mz33M2uGSPo=","DigestAlg":3},{"Index":2,"Digest":"sqg7Dr8vg3Qpmlsr38MeqVWtcjY=","DigestAlg":3},{"Index":15,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":22,"Digest":"//////////////////////////8=","DigestAlg":3},{"Index":1,"Digest":"DaB6FWt2viN2iGOSkoJNPmDLm0w=","DigestAlg":3},{"Index":19,"Digest":"//////////////////////////8=","DigestAlg":3},{"Index":18,"Digest":"//////////////////////////8=","DigestAlg":3},{"Index":23,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":8,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":4,"Digest":"krsrnniakXVjtxmHfpilZCyBCp8=","DigestAlg":3},{"Index":5,"Digest":"wkFtAPfMHl/BdtCt4He+zj8ksXM=","DigestAlg":3},{"Index":6,"Digest":"sqg7Dr8vg3Qpmlsr38MeqVWtcjY=","DigestAlg":3},{"Index":21,"Digest":"//////////////////////////8=","DigestAlg":3},{"Index":7,"Digest":"mhb64z08eV0diLoORWo98L745Yc=","DigestAlg":3},{"Index":13,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":14,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":16,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":17,"Digest":"//////////////////////////8=","DigestAlg":3},{"Index":12,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":3,"Digest":"sqg7Dr8vg3Qpmlsr38MeqVWtcjY=","DigestAlg":3},{"Index":9,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":20,"Digest":"//////////////////////////8=","DigestAlg":3},{"Index":10,"Digest":"RoMGhc7O9bCOMFX7dG5X04Hj4/k=","DigestAlg":3}],"PCRAlg":0,"Raw":"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"}} go-attestation-0.5.1/attest/testdata/option_rom_eventlog000066400000000000000000002161611452320553600236230ustar00rootroot00000000000000'ù˜<ÆUƒ]Šl×® ;hs¬YM60jGÍÊÃpººVèéQÈ’Þcì³[’ò_ê&0Š­Ÿ³oÁõ.Š$[¢ÁOv A‚‰·ì˜ž9¿U¦ûÉHÆ®6aÔÇ;ý u»µ¸êæ±y[ǯWiö'îò.„6cô»á‘mMyœõ]ù".t;:_&£à-ê+nMl#¥v°%ë¢ î¹}eÄñ»û)–Äë<®Ðà¬Û½Žµöº£Çþs·7£9lzš¸ÞOyS·ç ÇiŒ% ›zL¾ûñ{qŽ’„PzryXœ<öžûyû-IŒ2%sûr+R³ÀæÒƒR¥ÿgÅ¥kj,ø>²k@ …ú!ƒüN€{ÝÀgÄg}`,©Æßgl±hkNjÿð_€ÔýÑñM@AIMëÉÄSCÒ'}5aßä‹Ê“Òª à˜+Œ SecureBoot€ß†.®‰Ñ=¥¬Áƒ­‰Æ Þ}Ûaßä‹Ê“Òª à˜+Œ·PK¡YÀ¥ä”§J‡µ«\+ðr·›1k©õ ÛªO¤*z ˜2vŽ0‚‡0‚o jïIŒû¶2èžÂï0  *†H†÷  0k1 0 UUS1 0U Hewlett-Packard Company1:08U1Hewlett-Packard Printing Device Infrastructure CA0 120808000000Z 320808235959Z0‡1 0U Hewlett-Packard Company1+0)U "Long Lived CodeSigning Certificate1604U-Hewlett-Packard UEFI Secure Boot Platform Key0‚"0  *†H†÷ ‚0‚ ‚é¸b¸YÙàEPdT  `[²Y‰%8¡7Îe¨¢•Kô æ=‰î0Ç–dŽ_äÈQKóOìz~· 1‰¸&!UQðd =±vÆÙUO‹Üµ2ÈoÒøÉ¬oçr±èâÝ@·É°ã\χV‚g‚$ŽnÌJ×))W(Š@»RŸ»Ë"z®Ê=´VË,苦 RNç—)„¯ñ”# ß´¬b8 ÚP ¦¼¶oG­u\wC±É-s0=oxñD {ÍXlÙ¿ûG1§éØ™£‚0‚0 Uÿ00kUd0b0` ^ \†Zhttp://onsitecrl.verisign.com/HewlettPackardCompanyDeSPrintingDeviceCSIDTemp/LatestCRL.crl0Uÿ€0áU Ù0Ö0Ó + 0Ä0Á+0´±Hewlett Packard Company, 2, Authority to bind Hewlett-Packard Company does not correspond with use or possession of this certificate. Issued to facilitate communication with HP.0;+/0-0++0†http://onsite-ocsp.verisign.com0U`Ñ%Aæv<^Í”O:£Ñ§Ãª.Þ0U#0€¸¡ ½_Fé€Û÷™½ôýê Æ0U%ÿ 0 +0  *†H†÷  ‚m²sæÁâÉ#ÄÂ@ ð> ß³‘Î’haÏ&© S áHŠlÄ“"r—±FpÙi»ÙÕ.QÊï2☡ì6bòÄg·1ñÑÈÇk·.]'}£*ÔÀ `è&ŸÛño”“×ø`áŸ[¿Kך2LÒ÷-RÇÒ‚)é÷²A!ú* }Î,p³ë©V<˜óM?RX£‘;JTMlx1‰{dÅU †b¶Ä7µL :b¶ûÚRü6wYLãëô׎k¸¸ÄÂ͆9‡²z©é¶)Ób‚‚j˜Lˆ’D¹~AÄ´WÎŽ÷a‹ÁGìã€bX5ܤjÿ ý#€[ãî™,ø³¼jeè>ŽøŠSù aßä‹Ê“Òª à˜+ŒÓ KEK¡YÀ¥ä”§J‡µ«\+ðr»Ÿ1k©õ ÛªO¤*z ˜2vŽ0‚‹0‚s 1u£¶¡uqUên7Rm@0  *†H†÷  0k1 0 UUS1 0U Hewlett-Packard Company1:08U1Hewlett-Packard Printing Device Infrastructure CA0 120808000000Z 320808235959Z0‹1 0U Hewlett-Packard Company1+0)U "Long Lived CodeSigning Certificate1:08U1Hewlett-Packard UEFI Secure Boot Key Exchange Key0‚"0  *†H†÷ ‚0‚ ‚¯¢iê4Ãjò`^ÝÇÖ P¢$ ܵC¹LÓ~‰Š)',Y?ÉÕÿ:uJÑø)yük[¾ÁçÕÞ™¦‰<˜äj¼®ÅÞýªÄ,•®¼69Úç|u\¼ „_ªÆÆÕÀÞC¿íK³%sˆ•ª×ùx_m¹Àm ÔÖæc1‡(OA© Â+½¶5ùø’%ʾ±ÏO÷“ÏHX%×ëåˆÞ0•Ô{9P‚«€ÈHó~è;Ë9cÕË £]ó'R•ÓÇ«Ær˜¾ûË ŽÉìEšÉ©zSÔ¸’·á«˜½²šÊ`øÄc‡³“´“Œ¸YÀŒÇÒXݳᣂ0‚0 Uÿ00kUd0b0` ^ \†Zhttp://onsitecrl.verisign.com/HewlettPackardCompanyDeSPrintingDeviceCSIDTemp/LatestCRL.crl0Uÿ€0áU Ù0Ö0Ó + 0Ä0Á+0´±Hewlett Packard Company, 2, Authority to bind Hewlett-Packard Company does not correspond with use or possession of this certificate. Issued to facilitate communication with HP.0;+/0-0++0†http://onsite-ocsp.verisign.com0UÐÈ ¢êz×”‰FÜqhË#|0U#0€¸¡ ½_Fé€Û÷™½ôýê Æ0U%ÿ 0 +0  *†H†÷  ‚,O­Çý™i†³²,Ýmä9|n+AZv.N4 ŸÔýúÖöÛ:¯U‰c?´f)FPÈÑ’²¹öÒÞXGHîÃÿ‹Ë«¹!1ý D†•ØIŒ•ù·¬ô`% 'Æ;5¼Îb L#€L(k(ˆ]L3IS­Zïêl.ÎåRó-;2>I­Ä÷¾í€§/¡„4'¬?R,›©™yì·~gé³Ì”ÏdÓ°æ@€àªªQ¶ ²¯²HSüâIøQ\f…,WA̬oÛÀfhÌ)¹#ÁÇØ!oɶ±-šX[ñ¾0»¡šš»;ÃIG¤üðf\Jjñ¸¬Aì„È¡YÀ¥ä”§J‡µ«\+ðrü½šúwY2M½`(ôçxK0‚è0‚Р a ш0  *†H†÷  0‘1 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0 110624204129Z 260624205129Z0€1 0 UUS10U Washington10URedmond10U Microsoft Corporation1*0(U!Microsoft Corporation KEK CA 20110‚"0  *†H†÷ ‚0‚ ‚Ä赊¿­W&°&ÃêçûWzD] ÚJåt*æ°ìmëì¹ãZc2|Oã §8“ŽÆõà„±š›,çõ·‘Ö áâÀ¨¬0ßHóPšd§QÈ…O †Îþ/áŸÿ‚ÀíéÍÎôSjb: C¹â%ýþùÔÄ«â#‰p·¤Mì®åœúÂ×ÁËÔèÄ/å™î$‹ìò‹êÃJûC ~µG’lÜæ‰ëõ3ë*qåùƒ<ÿ% /hvFÿºO¾Ü­q*XªûÒy=ä›e;Ì)*ŸürY¢ë®’ïö5€Æìä_ÌvÍïc’Á¯y@„y‡ãR¨è{i£‚O0‚K0 +‚70UbüCÍ >¤ËgÒ[ÙU¬{̶Š_0 +‚7  SubCA0 U†0Uÿ0ÿ0U#0€EfRCá~X¿ÖNž#U;:"j¨0\UU0S0Q O M†Khttp://crl.microsoft.com/pki/crl/products/MicCorThiParMarRoo_2010-10-05.crl0`+T0R0P+0†Dhttp://www.microsoft.com/pki/certs/MicCorThiParMarRoo_2010-10-05.crt0  *†H†÷  ‚Ô„ˆõ”Ê*<û*’ × ÑñèRf¨î¢µuzª-¤vZêy·¹7jQ{döádòg¾÷¨x½ºÎˆXd ÖWÈ£_ÖÛÆÐiÎHK2·ë]Ò0õÀõ¸ºx£+þ›Û4V„ì‚Ê®A%pœkéþ×–å甲* Kÿ(){÷×|¥Ñv¹Èyí’œÂþßo~l{ÔÁEÝ4Q–9å^VØ–ô¦B³ wýòqVÌŸ†#¤‡Ë¦ýX~Ôig‘~òå ‹Š<‡„ëãνCå­-„“Žj+Z|DúRªÈ-»àRßøš=Á`°á3µ£ˆÑe ç¬|¤Á‚‡N8±/ Ňoý.¼9¶çæÃàäÍ'„ï”Bï)‹FA;gØùCYeË ¼ý’Oôu;§©$üPA@yà-O j'vnRí–i{¯÷‡ÐE­Sû0ª76aÚJi4ØhíÖÏl” ÓÏl"y­±ð¼¢F`©ÄÂ!‚ñýòèy2`¿Ø¬¥"KÊÁØKë}?W5²æOu´°`"S®‘yÖ›A†Tp²Þ 5|°4rº—`;ðy뢲]¢¸‡Åéöµ—%o8Ÿã‘úŠy˜Ãi·£ —øÊ®×ÄóÀuk4 µ™`ó\°ÅWN6Ò2„¿ž€ë Ç稢GÑ2½8ÂŒj¡˲×:=–E£¼ÚÐgeoødb¡YÀ¥ä”§J‡µ«\+ðr±•1k©õ ÛªO¤*z ˜2vŽ0‚0‚i Sù¾“£Ëk['¯‰²0  *†H†÷  0k1 0 UUS1 0U Hewlett-Packard Company1:08U1Hewlett-Packard Printing Device Infrastructure CA0 120823000000Z 320823235959Z01 0U Hewlett-Packard Company1+0)U "Long Lived CodeSigning Certificate100.U'Hewlett-Packard UEFI Secure Boot DB Key0‚"0  *†H†÷ ‚0‚ ‚ÎVÓÀ…áÉi bssï゘ú¤Âµ…òkðЏw'à3aÿŽ+ÃÂmµÄÑ>zN“ÚÊ …Ž „È hçå‰j;º}û–ÒOÁ`I…·¤ýò£D!Äï¼øñ©_Lx<[—[iu÷x”ÿ<¯®–‹Q½šâã”S5ìrùw5ÅÅ~ËóäOhÓìŒF°-²7f#Q—û&‰œ-w¥‚±ÒƒZÑ6ñýÔ|à,+øVKªÛ Ϥ-h¸IÓ7m}ÞÓ…?æÙLDÚêàEêÉ/¯Á Ä5CÊ“‚òÑÎÞäד1êf;Ô†U¤Hûjáà÷„P†½È]>*¤m£‚0‚0 Uÿ00kUd0b0` ^ \†Zhttp://onsitecrl.verisign.com/HewlettPackardCompanyDeSPrintingDeviceCSIDTemp/LatestCRL.crl0Uÿ€0áU Ù0Ö0Ó + 0Ä0Á+0´±Hewlett Packard Company, 2, Authority to bind Hewlett-Packard Company does not correspond with use or possession of this certificate. Issued to facilitate communication with HP.0;+/0-0++0†http://onsite-ocsp.verisign.com0Uç :‹„<C/jH]ÑôǸå)0U#0€¸¡ ½_Fé€Û÷™½ôýê Æ0U%ÿ 0 +0  *†H†÷  ‚gީȬ›ÛuÂŽå_8ªrÅà/£Î§›Ë9|˜æOš6Õ!ꤠ]S@tæÂ+üòØhžiöÄ$ñ‘‚·?¡Æ`=<6={q#ÌlÜ®£ KÐK£u^URçÚ·iêÐ(Ö¶9¬Ò°?4CÄʨ)8²&õL Ï!·KyCC йA4_'žƒweȸ¡¦Mí°^Oîî¶ ,~·üC«SÍW˜gß:IÞs¸¦ž,¶UA…$×ÏáÛ3ƒ$’zú?^‡ õÛñíˆgÃÌÚM¦š?§p0W†·úÞé6¯)wΕØÂÛ—…ˆ ¢ŽEv-¨"¤’é³¼l†÷§sð|¡YÀ¥ä”§J‡µ«\+ðr뽚úwY2M½`(ôçxK0‚×0‚¿  avV0  *†H†÷  0ˆ1 0 UUS10U Washington10URedmond10U Microsoft Corporation1200U)Microsoft Root Certificate Authority 20100 111019184142Z 261019185142Z0„1 0 UUS10U Washington10URedmond10U Microsoft Corporation1.0,U%Microsoft Windows Production PCA 20110‚"0  *†H†÷ ‚0‚ ‚Ý »¢ä. ãçÅ÷–i¼!½i33ï­ËT€îƒ»Å „Ù÷Ò‹ó8°«¤­-|byÿãJ?5 pãÄçkàœÀ6uéŠ1ÝpåÜ7µtF–([‡`#,¿ÜG¥g÷Q'žrë¦É¹;S5|åÓì'¹‡þ¹É# o¨F‘Án–http://www.microsoft.com/pki/certs/MicRooCerAut_2010-06-23.crt0  *†H†÷  ‚ü|qQ¥yÂn²ï9>¼«\`ìß¨Ó éôö–…¶QˆfG¢°=*hw»‘Lb{¶ÁǺz‡4Kbz™éÊüÎJ7É-¤W|þ=ܸZúÖij…:ê³Ùnäi!7ÞÑöugÓ“W^)9Èî-áÍäEs[ÐÒÎz«‚FXÐ^³g¯l5ò¼å?$â5¢ uöV™Ôx,ÑëЈªñߺ~,c·›#!ÄùxlâX6+‘̤Ùò-ºù”@íEñΊ\k>«Óp* jà_GÑÕc 2ò¯×6*pZåBYqKWº~ƒð!<ôÁŹ“ˆE“†é± ™¾˜ËÅ•¤]bÖ c ½uw}=óE¹Ÿ—ŸËW€o3©Ïw¤bY~¡YÀ¥ä”§J‡µ«\+ðr@$½šúwY2M½`(ôçxK0‚0‚ø  aÓÄ0  *†H†÷  0‘1 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0 110627212245Z 260627213245Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1+0)U"Microsoft Corporation UEFI CA 20110‚"0  *†H†÷ ‚0‚ ‚¥lLÇE jK ¤À‡u CTdàí’} ²s¿ ÆJEa Å-–Óõ+ ûMI›A€<¹Týæ¼ÑĤŠAŠ\Yƒh2»ŒGÉîq¼!OšŠ|ÿD?2²&H®uµîÉLJ~䂚xwM °½öÓÓ¼ú+¥Q8]õûºÛxÛÿì –Õƒ¸é¶À{@{á('ÉúïV^æ~”~ÀðD²y9åÚ²b‹M¿8pâh$É3¤7ÕXi^Ó|íÁSçN°*‡caocYê²+y× agŠ[ý^­‡º†gOqX"""΋ïTqÎP5Xv•îj±¢Õ£‚v0‚r0 +‚70# +‚7øÁk·wSJó%7N¡&{ p€0U­¿C ½‚pœŒÕO1nÕ"˜ŠÔ0 +‚7  SubCA0 U†0Uÿ0ÿ0U#0€EfRCá~X¿ÖNž#U;:"j¨0\UU0S0Q O M†Khttp://crl.microsoft.com/pki/crl/products/MicCorThiParMarRoo_2010-10-05.crl0`+T0R0P+0†Dhttp://www.microsoft.com/pki/certs/MicCorThiParMarRoo_2010-10-05.crt0  *†H†÷  ‚5Bÿ0ÌÎ÷v ­hX5)F2v'|ïA'BJªm8HYUóéX4¦ ‚ª]­‚Ú€ƒA´ò¹ó]ñPù³U„B( ½²®QÅÀ¬—•!Ûüwž•s‘ˆÊ½½R¹P ßWž aí åm%Ù@@ÈΣJÂM¯šT½Ç¼¹+=I+2üj!iO›È~B4ü6‹ @À³š%u'ÍÉ£ö]Ñç6Tz¹PµÓÑ¿»tßÜ€Õíô/k/ÞfŒ°#åÇ„ØíêÁ3‚­VK-ñh•ÍÏðrð®»Ý†…˜,!L3+ðJðh‡µ’U2u¡j‚j<£%¤í­×®ËØ@Y „Ñ•Lb‘"tŒ=GD¦ä°›45±ú¶S¨,ì¤qȸºèDfäGTŽV³Ÿ˜²†Ðh>#µ/^P…Æ‚_A¡ô. à™Òluä¶iµ!†úÑöâMÑÚ­,wS%27ÇlRr•†°ñ5ajõ²;PV¦2-þ¢‰ùB†'U¡‚ÊZ›ø0˜T¦G–%/È&äA”\?å–ã…[<>?»GrUâ%"±Ù{ç*£÷Fà Ö‰ã5'bq¦ïÐ'  Y7`ø8”¸àxpøºL†‡”öà®Eîe¶£~iu’›õ¦¼YƒX€ÉV… Póù`!!ˆ ò×/˲×:=–E£¼ÚÐgeoôdbx&ÄÁLP’@¬©Aù6“C(L0n4 œÿ³z˜œ¥Dæ»x ,x?³78v…£¯ &ÄÁLP’@¬©Aù6“C(Œ0½šúwY2M½`(ôçxK€´Ùi1¿ ý‘¦ÑO¤Ræm²@Œ¨`MA’eŸ ½šúwY2M½`(ôçxKõ/ƒ£úœûÖ’r($ÛäE4Ò[…$k;•}¬nÎz½šúwY2M½`(ôçxKÅÙØ¡†âÈ- ¯ª*o.s‡ >d÷,Nïgyj„½½šúwY2M½`(ôçxK63„ÑM. xbd„ÄY­W£ïC–&`HÐXÅ¡›¿v½šúwY2M½`(ôçxK세Kle¥ ©¾q–R0! bÖÓ h2Û²Ò à'%'ß¶=IÒ•r¦ôL&ÄÁLP’@¬©Aù6“C( 0½šúwY2M½`(ôçxK^ê‰T‹ `²þíÚ< Çþ›Ík”覃¸R8½šúwY2M½`(ôçxKæÆ¨Xdo±ïÆyþ(±#gþ’æ¾+6™žÿ9О½šúwY2M½`(ôçxK ß_NQìx¹mÐ%ý¶†ãŸor’xRY›eœ&½šúwY2M½`(ôçxK »C’Ú¬z¸›0¤¬eu1¹{ú«ù ¯åù¶ë ct½šúwY2M½`(ôçxK “9v-ó6«=ФcßqZ9ϰô’F\`lk×½‰Œ½šúwY2M½`(ôçxK ¾Êo)ì o3}räˆK ³H˜:* ×?O½šúwY2M½`(ôçxK Éóû™–!HÃʃ62u>Ôü ¹[1æR*Í[ü½šúwY2M½`(ôçxKo¬êÏìýN0;tô€ €˜âЀ+“oŽÇtÎ!ó†hœ½šúwY2M½`(ôçxKN: [CƦ»Ó@O4=Ï9bgΔøµ.#©Ú’ ½šúwY2M½`(ôçxK34)ÿbퟗ>HÜîå-¾.ImTµÏÖÈdÒѽšúwY2M½`(ôçxK+™Ï&B.’þ6_¿Kà 'lžáKzoÿDû/ki™9½šúwY2M½`(ôçxK+¿,§¸ñÙ'îR¶û*]ÐI¸Z+›Rœ]fb°Uø½šúwY2M½`(ôçxK,sÙ3%ºmËå‰Ô¤Æ<[“UYï’ûðPíPÄâRñ}½šúwY2M½`(ôçxK.p‘g†¦÷sQ§«pµWÆ2.©#²¨Ó¹+Q¯}½šúwY2M½`(ôçxK0f(úTw0W(ºJF}çÐ8zTõiÓvŸÎ^uì‰Ò“½šúwY2M½`(ôçxK6íºõ­A¤¡wz¿/¯^g4g^Ù^i5‚ž ªÒ½šúwY2M½`(ôçxK8AÒ!6ƒ×\ æ!`9MlN g`¶ö¹b¼…[½šúwY2M½`(ôçxK?ΛŸß>ðTR°ù^ä·ðmt:syqUŽpjÎ>s½šúwY2M½`(ôçxKC—Úʃžc|µ ’ßC¼-/²¨õŸ&üzKÔÙu’½šúwY2M½`(ôçxKGÌa'⚆à:kï,ÔøÅZmkÛ6!hÃ,ã*Zß½šúwY2M½`(ôçxKQˆ1þs‚µÐ>Æ!"‹Š¶Ty½ ¿£ÅÁÐôœ0a5½šúwY2M½`(ôçxKZéIêˆUë“ä9ÛÆ[Ú.B…,/ßg‰úg6ãÃA+\½šúwY2M½`(ôçxKk€xäAЦë{³^`’ÏGžëŒäÍçÐrÌ´/f½šúwY2M½`(ôçxKlˆTGÕYâ“Q¸&Àl¸¿ï+”­585‡rÑ“ø.ÑʽšúwY2M½`(ôçxKo(ÿqÉÛÕ¯.{¿Ë«d|ÂeÝõ²“Ͷ&õ :x^½šúwY2M½`(ôçxKqòoÒ"I~T£Fb«$—üÈ wõhéãÙ¿Ëýcu½šúwY2M½`(ôçxKrk>¶Tj0óø=›–Îöpé¨ÑpŠqæ-Ä,#Á½šúwY2M½`(ôçxKrà½gÏ]V«Šß;ݼ‚¿2¨ØªŒ^/mò”(ÖØ½šúwY2M½`(ôçxKx'¯™6,úðq}­ä±¿àCŠÑqÁZÝÂH·[øÊ¤K²Å½šúwY2M½`(ôçxK¨¹e»„Ó‡k”)©TÌ•SϪØÈ£;ý3ÿð佚úwY2M½`(ôçxK‚Û;δöCΗÃч͛YAÍ=èXo+ÚV7W_g½šúwY2M½`(ôçxK‰Z—…öÊ~ÔOÁ¡G qóñ"8bÙÿÌ:âß’=¯½šúwY2M½`(ôçxKŠÖHYñ•µõ¯ª” jag¬ÖzˆnF“dr!ÅYE¹½šúwY2M½`(ôçxK‹ô4´žÌ÷¢ÍeËì;= <5¾P_ß{Õcõ!½šúwY2M½`(ôçxKŽ¢‰Ïç «seË(îQíÓ<òPmèˆû­Ö¿€H½šúwY2M½`(ôçxK™˜ÓcÄ‘¾½tº¹M’‘soܦC£fd¼1ZB½šúwY2M½`(ôçxKžJi1ah.Uýèþõ`ëˆìþܯfÀÊ÷²·4½šúwY2M½`(ôçxK¦µ6UÓ¢¯ G'Yykä¤ T•§ØiuLHH…t§½šúwY2M½`(ôçxK§ó/PN°þ­š~ùNѺ ì]æ÷ïoð¦+“¾ß]E½šúwY2M½`(ôçxK­h&á”m&Óêóh\ˆÙ}…Þ;MË=â®Ç`ÑùÂ$Q?¼eYW×5ú)õ@νšúwY2M½`(ôçxKØËë—5õg+6~O–ÍÇIia]JélrMBÎøóú½šúwY2M½`(ôçxKé,"ë;VBÖ\ÂÊòGÒYG8„D•oYâ°Ñú½šúwY2M½`(ôçxKýÝn=)ê„Çt=­JÛǵþÁ³‘ù2@†¬ÇÖÛØ½šúwY2M½`(ôçxKþc¨Ox,ÉÓüòÌùüûÐ7`‡‡XÒb…íf›Ünm½šúwY2M½`(ôçxKþϲ2Ñ.™KmH],qgrŠ¥RY„­\¦u"š6½šúwY2M½`(ôçxKÊaJ~“”ŒÐþUÓ™ùÑ©nE AR'ÂÆ[½šúwY2M½`(ôçxKU¹› å=¼þHZ©Ç7Ï?¶ï=‘úµ™ª|«í§cµº½šúwY2M½`(ôçxKwÝ£ ˆÿ^; æb x  S^ˇæðˆŠ k/½šúwY2M½`(ôçxKÈ<±9"­™õ`tFuÝ7̔ܭZ˦G/î4qÙ9脽šúwY2M½`(ôçxK;‡S> ÃÐì¨#Ëð©AªØryÑÄ™€-Ñæ6¸©½šúwY2M½`(ôçxK“šîôõúQâ3@ÃòäHΈrRjý÷Rçó£ò¼Ÿ`I½šúwY2M½`(ôçxKdW[Ùxš.­Vö4R¯kø ùDxYuéðN-d×E½šúwY2M½`(ôçxKEÇÈ®u Ï»Hü7R}dÝdM®Ø‘<ÍŠ$ÉM…igߎiÊxçE (QsC>RÅÂR™äs òw”ò9¡6 àEmÞs2©Ž÷È8Load microcode revision 000000A1 for processor 000306F2WØtœÃ@¶ÉQr‚–Q]çI= ACPI DATAà€‹Xf…L ‚Ùg¡Ùñ£’ A'’H˲×:=–E£¼ÚÐgeo$db½šúwY2M½`(ôçxK0‚0‚ø  aÓÄ0  *†H†÷  0‘1 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0 110627212245Z 260627213245Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1+0)U"Microsoft Corporation UEFI CA 20110‚"0  *†H†÷ ‚0‚ ‚¥lLÇE jK ¤À‡u CTdàí’} ²s¿ ÆJEa Å-–Óõ+ ûMI›A€<¹Týæ¼ÑĤŠAŠ\Yƒh2»ŒGÉîq¼!OšŠ|ÿD?2²&H®uµîÉLJ~䂚xwM °½öÓÓ¼ú+¥Q8]õûºÛxÛÿì –Õƒ¸é¶À{@{á('ÉúïV^æ~”~ÀðD²y9åÚ²b‹M¿8pâh$É3¤7ÕXi^Ó|íÁSçN°*‡caocYê²+y× agŠ[ý^­‡º†gOqX"""΋ïTqÎP5Xv•îj±¢Õ£‚v0‚r0 +‚70# +‚7øÁk·wSJó%7N¡&{ p€0U­¿C ½‚pœŒÕO1nÕ"˜ŠÔ0 +‚7  SubCA0 U†0Uÿ0ÿ0U#0€EfRCá~X¿ÖNž#U;:"j¨0\UU0S0Q O M†Khttp://crl.microsoft.com/pki/crl/products/MicCorThiParMarRoo_2010-10-05.crl0`+T0R0P+0†Dhttp://www.microsoft.com/pki/certs/MicCorThiParMarRoo_2010-10-05.crt0  *†H†÷  ‚5Bÿ0ÌÎ÷v ­hX5)F2v'|ïA'BJªm8HYUóéX4¦ ‚ª]­‚Ú€ƒA´ò¹ó]ñPù³U„B( ½²®QÅÀ¬—•!Ûüwž•s‘ˆÊ½½R¹P ßWž aí åm%Ù@@ÈΣJÂM¯šT½Ç¼¹+=I+2üj!iO›È~B4ü6‹ @À³š%u'ÍÉ£ö]Ñç6Tz¹PµÓÑ¿»tßÜ€Õíô/k/ÞfŒ°#åÇ„ØíêÁ3‚­VK-ñh•ÍÏðrð®»Ý†…˜,!L3+ðJðh‡µ’U2u¡j‚j<£%¤í­×®ËØ@Y „Ñ•Lb‘"tŒ=GD¦ä°›45±ú¶S¨,ì¤qȸºèDfäGTŽV³Ÿ˜²†Ðh>#µ/^P…Æ‚_A¡ô. à™Òluä¶iµ!†úÑöâMÑÚ­,wS%27ÇlRr•†°ñ5ajõ²;PV¦2-þ¢‰ùB†'U¡‚ÊZ›ø0˜T¦G–%/È&äA”\?å–ã…[<>?»GrUâ%"±Ù{ç*£÷Fà Ö‰ã5'bq¦ïÐ'  Y7`ø8”¸àxpøºL†‡”öà®Eîe¶£~iu’›õ¦¼YƒX€»ž;¾ÙüTZ‰#jPpý8×½ÕT ƒÄ@4 ÐA öÿÿ€TñÜä30x²Ïl~€È­†2†Zaßä‹Ê“Òª à˜+Œ (BootOrder  €éhn²4è–H„'@PJXóPÖdaßä‹Ê“Òª à˜+Œ4Boot0013tWindows Boot Manager*h g8ãx A¦šEtp#LÝF\EFI\Microsoft\Boot\bootmgfw.efiÿWINDOWSˆxBCDOBJECT={9dea862c-5cdd-4e70-acc1-f32b344d4795}9ÿISPH€Í—@¿µ ÍÙÍ HèÔ Œë–Ø\raßä‹Ê“Òª à˜+ŒBBoot000CUSB:  ÐA ÿN¬ŸYM…âR,Y² ISPH€µƒ†ó“JÚ£WPºµUÝB¬Í€aßä‹Ê“Òª à˜+ŒPBoot000D CDROM:  ÐA  ÿN¬ŸYM…âR,Y² ISPH€ñʵJÍ[ÑÊ¡ÌS/¶èò5aßä‹Ê“Òª à˜+ŒBoot0009wIPV6 Network - Intel(R) Ethernet Connection (2) I218-LM ÐA  %ÜJ>| <@ÿN¬ŸYM…âR,Y²ISPH€àJ#XÝð'àÉ£³aþ30jØôaßä‹Ê“Òª à˜+ŒäBoot0011VIPV4 Network - Intel(R) Ethernet Connection (2) I218-LM ÐA  %ÜJ>| ÿN¬ŸYM…âR,Y²ISPH€b÷Pk³ÿPã{$ãÅ9Ç0tO¨X maßä‹Ê“Òª à˜+Œ=Boot000EUSB:  ÿÿ ÐA ÿÿÿ ISPH€ œŽ—ïfËøA¯V椆º©{aßä‹Ê“Òª à˜+ŒKBoot000F)CDROM:  ÿÿ ÐA  ÿÿÿ ISPH€éËã:,¸ ü.O˜«^#GXE'˜aßä‹Ê“Òª à˜+ŒhBoot000A(MTFDDAK512MBF-1AN1ZABHAHarddisk1 ÐA ÿISPH€° 1OxúÑß>Eÿø_ؤdp?†•aßä‹Ê“Òª à˜+ŒeBoot000B'IBA GE Slot 00C8 v1550Network1 ÐA ÿISPH€ªh Åò íº ^¦¾Bó€ÝÈÔ„aßä‹Ê“Òª à˜+ŒTBoot0000,Startup Menu5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿISPH€,Ã%Ÿ„õýüa©½¼Ô`Z|{’aßä‹Ê“Òª à˜+ŒbBoot0001,System Information5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿñISPH€âc˱E‹›ª Ö6ü’J…Iç‚aßä‹Ê“Òª à˜+ŒRBoot0002,Bios Setup5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿISPH€@·‡ö!9î?š··Î>'0ûðü¬aßä‹Ê“Òª à˜+Œ|Boot0003,3rd Party Option ROM Management5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿóISPH€&Êþ†ÅjèâaÔô>Lù’aßä‹Ê“Òª à˜+ŒbBoot0004,System Diagnostics5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿòISPH€A'ôâ;¥Ô¨þDó àµóh‚î’aßä‹Ê“Òª à˜+ŒbBoot0005,System Diagnostics5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿòISPH€¿dTõ‡ÐƒÑW3Ù„;^팒aßä‹Ê“Òª à˜+ŒbBoot0006,System Diagnostics5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿòISPH€ìûdˆÐEBôJ±QG *\a™’aßä‹Ê“Òª à˜+ŒbBoot0007,System Diagnostics5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿòISPH€Xkû(êéìÛ!˜u,Ø•íeˆEƒ€aßä‹Ê“Òª à˜+ŒPBoot0008,Boot Menu5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿùISPH€X–ÑÁrSA[1‰¶VEõNþ/–†aßä‹Ê“Òª à˜+ŒVBoot0010,Network Boot5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿISPH€œS‘O¯zUñŠŸÜÎÅ0”´F\„aßä‹Ê“Òª à˜+ŒTBoot0012,HP Recovery5{»Í3hÖNš²WÒ¬ÝöðèC‚ƒ=E¬ëÃPîwWÊÿISPH€ÍÛE1¦ìA¾'Sº&7Öå÷òV(Calling EFI Application from Boot OptioniÊxçE (QsC>RÅÂR™äsiÊxçE (QsC>RÅÂR™äsiÊxçE (QsC>RÅÂR™äsiÊxçE (QsC>RÅÂR™äsiÊxçE (QsC>RÅÂR™äsiÊxçE (QsC>RÅÂR™äsiÊxçE (QsC>RÅÂR™äsà€ŸÇ·$™¡ Û=PÁN¹´ÿ'!˲×:=–E£¼ÚÐgeoëdb½šúwY2M½`(ôçxK0‚×0‚¿  avV0  *†H†÷  0ˆ1 0 UUS10U Washington10URedmond10U Microsoft Corporation1200U)Microsoft Root Certificate Authority 20100 111019184142Z 261019185142Z0„1 0 UUS10U Washington10URedmond10U Microsoft Corporation1.0,U%Microsoft Windows Production PCA 20110‚"0  *†H†÷ ‚0‚ ‚Ý »¢ä. ãçÅ÷–i¼!½i33ï­ËT€îƒ»Å „Ù÷Ò‹ó8°«¤­-|byÿãJ?5 pãÄçkàœÀ6uéŠ1ÝpåÜ7µtF–([‡`#,¿ÜG¥g÷Q'žrë¦É¹;S5|åÓì'¹‡þ¹É# o¨F‘Án–http://www.microsoft.com/pki/certs/MicRooCerAut_2010-06-23.crt0  *†H†÷  ‚ü|qQ¥yÂn²ï9>¼«\`ìß¨Ó éôö–…¶QˆfG¢°=*hw»‘Lb{¶ÁǺz‡4Kbz™éÊüÎJ7É-¤W|þ=ܸZúÖij…:ê³Ùnäi!7ÞÑöugÓ“W^)9Èî-áÍäEs[ÐÒÎz«‚FXÐ^³g¯l5ò¼å?$â5¢ uöV™Ôx,ÑëЈªñߺ~,c·›#!ÄùxlâX6+‘̤Ùò-ºù”@íEñΊ\k>«Óp* jà_GÑÕc 2ò¯×6*pZåBYqKWº~ƒð!<ôÁŹ“ˆE“†é± ™¾˜ËÅ•¤]bÖ c ½uw}=óE¹Ÿ—ŸËW€o3©Ïw¤bY~€WW¡U&4»usQ…žP~Ô(3ÀäEFI PART\YBe㯞;"Žž;XëÁˆÃ(àI…ú„îvUG€€êáv'¤»”ÞÑ@M¡j¿ÕyÖ¬WV"óÑ¡I›Ø JÊ@ßÝÿg €Basic data partition(s*ÁøÒºK É>É;g8ãx A¦šEtp#LÝh ÿ‡€EFI system partitionãÉã\ ¸M}ù-ð®;dK;«u+D³®\𴻈ÿ‡€Microsoft reserved partition¢ Ðëå¹3D‡Àh¶·&™ÇÝ)½Öô@†­ÇTf{sˆŒûŠ;Basic data partition¤»”ÞÑ@M¡j¿ÕyÖ¬"ûÂ1›é.J¹¿®›p²?§‹;ÿž;€€L5¸ù9SééÇxCä¥/°°IÄ8O ÐA  €*h g8ãx A¦šEtp#LÝF\EFI\Microsoft\Boot\bootmgfw.efiÿ T—°‘?Wrr=ï;6 .eC'Á› ½±’S;`öTÛhÉ^ì–¸óÚ‚r@(Tž Á@8 Páw°EÊ?æá¡¾Â8öWù¼¿¡&jù`5@8 ÔŠ£ìלè1a“ØC¸vPÏo4¸,.3,­uí]1 š  !  õx9“ökn=LªäEOO=ïõML”@Œ  ! )4 t¾'»ŒÐËÆ¯CØ÷RøkýØn՛ůóS<øy-C.€¡š­psÓ vÞ¡åJÚ .v[Û0 šW9e¬å•½šðÝ‚Bœ>óx ó@T<\WINDOWS\system32\winload.efiÐ € ÔŠ£ìלè1a“ØC¸vPÏo4¸,.3,­uí]1 LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@ @bV\EFI\Microsoft\Boot\en-US\bootmgfw.efi.MUI  € Páw°EÊ?æá¡¾Â8öWù¼¿¡&jù LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„Rý`§44²^è‡'ýCkZ =.&0‚"0  *†H†÷ ‚0‚ ‚Ý »¢ä. ãçÅ÷–i¼!½i33ï­ËT€îƒ»Å „Ù÷Ò‹ó8°«¤­-|byÿãJ?5 pãÄçkàœÀ6uéŠ1ÝpåÜ7µtF–([‡`#,¿ÜG¥g÷Q'žrë¦É¹;S5|åÓì'¹‡þ¹É# o¨F‘Án–$À@8 ]<ÙÕ¢tUαßàµé£xþ½åF7ŠvéM;x@!  \WINDOWS\system32\hvloader.dll € ô³†sqÀŽ›ÞÊãÍ:|r67ÀîðjÍ'î#í+ LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@F:\WINDOWS\system32\hvix64.exe€ € ý:¥rôÜÍ;´}ž®Wz¸Ä*ÎÆIZ¬Òn^åÔø>$ LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@\P\WINDOWS\system32\en-US\winload.efi.MUIp € ú·Ýû¶úÑî~ñ—iÒ])ÖxE–k^°g¦¢F LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„Rý`§44²^è‡'ýCkZ =.&0‚"0  *†H†÷ ‚0‚ ‚Ý »¢ä. ãçÅ÷–i¼!½i33ï­ËT€îƒ»Å „Ù÷Ò‹ó8°«¤­-|byÿãJ?5 pãÄçkàœÀ6uéŠ1ÝpåÜ7µtF–([‡`#,¿ÜG¥g÷Q'žrë¦É¹;S5|åÓì'¹‡þ¹É# o¨F‘Án–Î !À«š ¶ªñâGsÔâ™Þ/ü|2‹kÒeljC@8 x?S½o Ä€lP¤®PÉRÑÍ·,™Ð+|Z%æ¶F@8 5´ô}ÞMÏîøŽìVqÙo: :Ç}àv„þŒúžUM@8 Ké†<,ž0`¯*ó$Wc»ü™[Às¾ƒ‡ûŸ!Ú½ˆP@8 ? kAâ“Þ;HlyžzRMåƒÀ{Gû°ù6å W@8 hÿÙp66¿ÞNŠt¸ªJçNYÂDÉ2ÎÌÔë×8“bY@8 6ªÀDÚu®ã.ôy¾G @o Ÿç¯Uƒ…I;–«’íZ@8 $o}-4ke¢Xä8Œt@8 &Øtk)÷ÿ@ðxöò“•Ëý¥Ï{à=„ÄÌ&‡™bÀ@8 1’)#VÛÐi‡ÿBF漆Lr"6…©ÝT¥> V·PÎ@8 {<Éžîÿ XS‰€žu÷ÃBäF3-ߊÏǪ&­ú’Ú@8 |Ï„UZ^¥Î æÛHáñù ÙõîêNµ{A´6p}´›u@8 tµXåfÌø|XX";˜›€ˆ+Œx"½µÚÔãØãÀ8Ú¿w@8 tl>2`ïi.8ýãˆÌQ‹ßûh¦•œU\SE­x@8 ¸??¨0ε_1Ïá Ëk̨ý „òI»÷S¢ªz@8 J5“–âíç€`ãÄ×¢8«NSâ•ÖiÖó^u[²è@8 o>ƒ¯† œ’˜ضðxÚãlžL®]Ãg¹Ç©ï«f}@8 ‚¼;¦¤Ìö[†Îù´ñ?g‰œˆE–òúJÿ –g6d@8 7á9À ¢¼FðÜ?7f/Ïü½”µ£ìôØ7áràí@8  :ÆÿeË”Á¾a²ÙJ¦Tú\W…é7œü)Sÿ@8 vkZ>•b]XÁȦ›Rˆ‡ÿ£0Lê’p[-dkT±F= @8 .ë!3ù‹2—#PÚë>.‘Ñ ¨uÝÉ‹>²©" @8 AO ÿ¦©“űïsº3R&6™Ï)|Oº<Âõ°}@8 ÔUÏgot1E´êЉu§ÊŽ%`îtê!jºÎ!?{ù@8 ö0ɲÑKb-ËOÙ6* ŸXç&zšâß’>@8 .ªÞ½raA]ºK¤Î­>LüLçÝ…“|MKÌË4@8 7 ˜”i!N(>DúÑf;/L°_ù’„áYahuÍC@8 Ul&g‹ä(WsÒ{‚v#³ÑeZg ï‚ØÌ%pß#@8 ÿ+7Èäò¼»ÎppF/Ø®Ö`8QE±æânrÚ@ªe%@8 —ìèÿ±Ëa¹Õãt˜/+áÙ­Œ³^½Æç"·&@8 ‚ð#1ùvÒíð4Ê 0KNûͤ\\4çb‚ö8뚪—(@8 ZPB«WºOmIz¯»²¡‘ºr-'8ÊÀaa€ñ*@8 HÑlF·“í¯E²o¶Fgu%“ vÇ µ¼¤ã ',@8 Œ”=>Eˆˆ?Û;ª^I3$"ÀúÐo*üò9ï’lZ1@8 áñ–‹ŽÁ ¹Ÿ$6=~À~ešYb½Ç#B)†|„uÂ5@8 O5Jî¦I$Yæ‰áRüï}$…’æ$ÒŸð"¤y7@8 Å$ýɼï "7§Ô: X&-¶©Ý‚LT70D;@8 ;G­ßÝ“‘4—iB¿÷[öó®9iy|cZ‚òù„<@8 HËptj£æŠúÏ[ÕZ´=5ÁÊ(’@›Èrín›cÌ>@8 ߘºtÎ’WML¬øÐYfž1â@ޤΞ"•r«I@8 ²K´¬¹5D½þ²Þ«”rJ6~¡È“í¼ Dp᛫.J@8 ¢ÕåSôIÕ‹| ddÀÕÂî´H‡m´z¤¨^ÛXôL@8 æÜ|œ^ÏLZ®XOJ‡ßÔj£¡‚º¼ãñ*zyNýQ@8 +º{ägð½ZPÉö€.Aò¢WO-e°æÙZ”SX@8 ò´ß ŠØ…°’‡®wv‹À饇®#ÕZ@8 Ä©ìà÷¨ÆrjïÏ&%¾°Þö@4Ÿ`c€„\@8 æŽWZ´ŸæÔj{i¡MOÜàœôñÜÅ'Œ‰›7-‹7]@8 Sõ‚JTÆ é,E#Pïv `šFh}=ywQÄb®¸?ÚWa@8 é©3Ó 7èÞuÿ»x°¹¬¬}\Mã{(m£ul™¹d@8 MªßŽKïýÿ$ÅTŸÁÅMlL±tú— ¼¾‹¿×‡‹o@,0aA¹ÊóuU]ørQ‰*Ú×r@,0aA¹ÊóuU]ørQ‰*Ú×@8 ! Î¦OÞ~AµŒû¹’ûB¿«QÖ'yz UçXWoŒ@8 ÿÊvéàgP œ‚G^ ®Ë×gD|¡ÀÂÅúœ3pùæÕŽ@8 VX'¹CÞ—ËÈóâ¼ß£Í?øé¶#))¾9éPÞKý@8 .3¨¥¨ˆÌc`ÈZxŠà&9nÙÏ“ÚÎï³¹é§<Ø”@8 ¤ S¢ê±wÛàwé¸Ãj~ïÞW[C 4\2ß§LeQ›@8 —NWºŒåbžAú>x[8k¶ûT÷IDÞdy±@8 tö­f öv¿¥?ÛBÎz'똷†%:ŽúõÖ³º@8 Xá¤Ç™Ä¯1cn“€íM`u"™¸Ü‰Qf|‡0÷3¾@8 mKý7Si˜ÁKÛiÒɇvH  >Ö¿@8 Ž˜ýõ½0åPU’càH¯žæ˜ºâFÆÜ˵{'-ä*@8 éÇíç§áÃëŤâhMB r·™½Oe7Ï´hÕÃàN3@8 –NøœÁò–ÿ[×…ëT·ün:êð_nöø£i‰†Dç 5@8 ¼Fl¹×>7Ѭ-M†yVb1L‹“Î5]˜\¼ƒÚ=@8 j¸(KDóÅSºÔº‘Òœ|Só·›i¿Ú+ïº@@8 TVa±û6ð"&¢Ú¸*t wü:A[öâl«ÍÌVK@8 ®((sêVO:/9/Eu/ƒx¥yµñ0&¶‡Hn*ø¥ö|êL@8 AËÀ& ùˆ(lÅŠ÷ÜôÿIX@Î÷úä Ô‡ÅÃGd@8 ¶Òáý˜ÿü„DV’XÝ H6"OèÿíxŒÊzù»pn@8 6òϹ†&-ÏØ:‘Þ3¦žO¿U½Ï9ÔáOl§,U6r@8 úô7†Ý”Õ¢$(¸µE;wo慌ýY¶0K£ß¡@8 ùF‹ º/ó,ÿ£žú7óVN-}Õ/K™G0YgÙ‡©@8 ±Ìïþ³' Û››W¾”TÁ¨=§þéÏVn—ÆWÞC¦w­@8 Ió°³ÀÉs6ãfËVz^¬±Ñó¸Ô› 8‡= Þô¯@8 /ZG•‡@ˆÔ%x–ƒØzȪ½„3Pòf©õjk™ŠL²@8 ¬ ›ƒFí×Z@”O%4 'öFdð>eÄ6 6]³@8 2ÂÞk⊠iÓ§´ú%u(påC7ÔG)”€F˜bÀ@8 ™BnÊ<ñ¤´e_¼FÖ¼6¡gvS@K¡IÉñJÁ@8 Œ^œM4–¯XŒý¤Yßw 5dއèÛw^Â’È@8 ô˜àpÕ]°¬]ÿ:ï ŸPH\üQº0ų¨ÒÑ@8 ²3âŠgcAbƒÇ&[ @Ù ¦Ö'¸®âc_¶€ïñÝCÔ@8 $]à¶ð‘!yï1£–É û¡ü»ÛùbÕ;F¸7lÖ@8 ݹ «7Ä]TUV‰ {y^]yôbf¥Ò€ÇWB׉–Ø@8 I(úrÓ¡MfGœ²òñ0T´´ø³"X`ks††Å´‹Ú@8 ΞcÐ|sf#À3ØX_ П Ô';  fô¬+Üß@8 ~ty6¸ß¿Ñ…ÎÄ^º¹ä¼dØVF梘OËÛŒñcë!â@8 éWůÆegp/ƒp¦­®\Î)¨·[#©/i•”ü8³“ä@8 ݹC.©WJ ×þÕ Ë}_þÿ7—Éú¶’‘>?sb;ÀLæ@8 Ôמœ‘U.DCµ”ƒÊàKšÔvtd¡ã€wGœ;âè@8 –­ b‚k ñ€>Z“ýÃŤ-\BY˜&ôHM£ùÐÿ@8 ±-œ…Ýñàð£µØ/‰ždU]¬­¿Z‚÷ÇÙü-[²Mp£@8 è[TsSn†ì/(Ô´niVý¶nïJ»ìí R¹À²@8 1’)#VÛÐi‡ÿBF漆Lr"6…©ÝT¥> V·P°· \WINDOWS "$%&     (@F "Windows Defender }[Åb—Üóþÿ`*4.Ö˜ÒÌ ,CƒœR©CÈi RȘ¾v'w!C× Ž@Ž \WINDOWS "$%&     (.€¡š­psÓ vÞ¡åJÚ .v[Û0 šW9e¬å•½šðÝ‚Bœ>óx ó.€fB¥psÓ «xű™6Æž¦ :1G SÒÆ)EU²w.8|Þ@ZN\WINDOWS\System32\drivers\fileinfo.sys  € ÿÊvéàgP œ‚G^ ®Ë×gD|¡ÀÂÅúœ3pùæÕ LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@VJ\WINDOWS\System32\drivers\volume.sys° € 2ÂÞk⊠iÓ§´ú%u(påC7ÔG)”€F˜b LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@ZN\WINDOWS\System32\drivers\cmimcext.sysà € ›—ï÷MZŠ»Í0Éyú`|ÙÖîrAw™7^¤i{ð LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@ZN\WINDOWS\system32\drivers\vmbkmclr.sys € Ió°³ÀÉs6ãfËVz^¬±Ñó¸Ô› 8‡= Þô LMicrosoft Windows Production PCA 2011$Microsoft Windows32AûY™mÌMÿ2 ÿ‚¼8áÚ^YmótÅ>6÷í£k@RF\WINDOWS\System32\drivers\CLFS.SYS€ € Ké†<,ž0`¯*ó$Wc»ü™[Às¾ƒ‡ûŸ!Ú½ˆ LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@H<\WINDOWS\system32\BOOTVID.dll° € hÿÙp66¿ÞNŠt¸ªJçNYÂDÉ2ÎÌÔë×8“b LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@VJ\WINDOWS\System32\drivers\pciide.sys  € Å$ýɼï "7§Ô: X&-¶©Ý‚LT70D LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@RF\WINDOWS\System32\Drivers\Ntfs.sysÐ) € —NWºŒåbžAú>x[8k¶ûT÷IDÞdy± LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@XL\WINDOWS\System32\Drivers\ksecpkg.sys  € ¶Òáý˜ÿü„DV’XÝ H6"OèÿíxŒÊzù»p LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@XL\WINDOWS\System32\drivers\USBPORT.SYS  € –NøœÁò–ÿ[×…ëT·ün:êð_nöø£i‰†Dç LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@\P\WINDOWS\System32\drivers\werkernel.sys € fÙð4lQ5ÂAsÐäü7`ƒÚÍÖ7'£–N LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@VJ\WINDOWS\system32\drivers\LXCORE.SYS@ € 7á9À ¢¼FðÜ?7f/Ïü½”µ£ìôØ7árà LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@PD\WINDOWS\system32\drivers\CEA.sys € áñ–‹ŽÁ ¹Ÿ$6=~À~ešYb½Ç#B)†|„u LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@VJ\WINDOWS\System32\drivers\WMILIB.SYSÀ € vkZ>•b]XÁȦ›Rˆ‡ÿ£0Lê’p[-dkT±F= LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@˜N\WINDOWS\System32\drivers\intelpep.sys° € 7 ˜”i!N(>DúÑf;/L°_ù’„áYahuÍC @Microsoft Code Signing PCA 2010nMicrosoft Windows Hardware Abstraction Layer Publisher3Æ/ÕçÚgÄâÆ åÑHèÙxù¢Óĵ)§ ÒÔ@RF\WINDOWS\System32\drivers\disk.sysÀ € ݹC.©WJ ×þÕ Ë}_þÿ7—Éú¶’‘>?sb;ÀL LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@RF\WINDOWS\system32\securekernel.exe@ € ±-œ…Ýñàð£µØ/‰ždU]¬­¿Z‚÷ÇÙü-[²M LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@ZN\WINDOWS\System32\drivers\fwpkclnt.sys  € úô7†Ý”Õ¢$(¸µE;wo慌ýY¶0K£ß LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@PD\WINDOWS\System32\drivers\cng.sysÀ  € 1’)#VÛÐi‡ÿBF漆Lr"6…©ÝT¥> V·P LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@PD\WINDOWS\System32\drivers\cng.sysÀ  € 1’)#VÛÐi‡ÿBF漆Lr"6…©ÝT¥> V·P LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@ZN\WINDOWS\System32\drivers\stornvme.sysp € MªßŽKïýÿ$ÅTŸÁÅMlL±tú— ¼¾‹¿×‡‹ LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@ÔÈ\WINDOWS\System32\DriverStore\FileRepository\urschipidea.inf_amd64_86da23c455846f41\urschipidea.sysÐ € mKý7Si˜ÁKÛiÒɇvH  >Ö LMicrosoft Windows Production PCA 2011$Microsoft Windows32AûY™mÌMÿ2 ÿ‚¼8áÚ^YmótÅ>6÷í£k@ªb\WINDOWS\system32\drivers\CrowdStrike\CSBoot.sys € .ªÞ½raA]ºK¤Î­>LüLçÝ…“|MKÌË4 @Microsoft Code Signing PCA 2010lMicrosoft Windows Early Launch Anti-malware Publisher3h¾ Ü’ø­h ÜËuFóZìo DÕËëþ =z@VJ\WINDOWS\System32\drivers\clipsp.sysP € 6ªÀDÚu®ã.ôy¾G @o Ÿç¯Uƒ…I;–«’í LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@TH\WINDOWS\System32\drivers\sdbus.sysà € ¢ÕåSôIÕ‹| ddÀÕÂî´H‡m´z¤¨^ÛXô LMicrosoft Windows Production PCA 2011$Microsoft Windows32AûY™mÌMÿ2 ÿ‚¼8áÚ^YmótÅ>6÷í£k@VJ\WINDOWS\System32\Drivers\Fs_Rec.sysÐ € TVa±û6ð"&¢Ú¸*t wü:A[öâl«ÍÌV LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@bV\WINDOWS\system32\drivers\VmsProxyHNic.sysð € /ZG•‡@ˆÔ%x–ƒØzȪ½„3Pòf©õjk™ŠL LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@²h\WINDOWS\System32\drivers\WindowsTrustedRTProxy.sys° € ÿ+7Èäò¼»ÎppF/Ø®Ö`8QE±æânrÚ@ªe @Microsoft Code Signing PCA 2010nMicrosoft Windows Hardware Abstraction Layer Publisher3?X=÷X3? ßfÕ,HQEü¡Øzÿs÷“Ý2Õ@j^\WINDOWS\system32\drivers\SleepStudyHelper.sysð € tµXåfÌø|XX";˜›€ˆ+Œx"½µÚÔãØãÀ8Ú¿ LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@^R\WINDOWS\system32\drivers\urscx01000.sys€ € +º{ägð½ZPÉö€.Aò¢WO-e°æÙZ”S LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@>2\WINDOWS\system32\CI.dllà  € &Øtk)÷ÿ@ðxöò“•Ëý¥Ï{à=„ÄÌ&‡™b LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@PD\WINDOWS\System32\drivers\pcw.sysP € —ìèÿ±Ëa¹Õãt˜/+áÙ­Œ³^½Æç"· LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@RF\WINDOWS\system32\drivers\ndis.sys € ®((sêVO:/9/Eu/ƒx¥yµñ0&¶‡Hn*ø¥ö|ê LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@`T\WINDOWS\system32\drivers\WppRecorder.sys € tl>2`ïi.8ýãˆÌQ‹ßûh¦•œU\SE­ LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@`T\WINDOWS\system32\drivers\wd\WdFilter.sysÀ € .3¨¥¨ˆÌc`ÈZxŠà&9nÙÏ“ÚÎï³¹é§<Ø LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@PD\WINDOWS\System32\Drivers\Wof.sysÐ € VX'¹CÞ—ËÈóâ¼ß£Í?øé¶#))¾9éPÞKý LMicrosoft Windows Production PCA 2011$Microsoft Windows32AûY™mÌMÿ2 ÿ‚¼8áÚ^YmótÅ>6÷í£k@ZN\WINDOWS\System32\drivers\rdyboost.sysà € I(úrÓ¡MfGœ²òñ0T´´ø³"X`ks††Å´‹ LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@TH\WINDOWS\System32\drivers\atapi.sysÐ € Ä©ìà÷¨ÆrjïÏ&%¾°Þö@4Ÿ`c€„ LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@VJ\WINDOWS\System32\DRIVERS\fvevol.sys  € ¬ ›ƒFí×Z@”O%4 'öFdð>eÄ6 6] LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@ZN\WINDOWS\System32\drivers\CLASSPNP.SYS° € Ôמœ‘U.DCµ”ƒÊàKšÔvtd¡ã€wGœ;â LMicrosoft Windows Production PCA 2011$Microsoft Windows32AûY™mÌMÿ2 ÿ‚¼8áÚ^YmótÅ>6÷í£k@XL\WINDOWS\System32\drivers\partmgr.sys € O5Jî¦I$Yæ‰áRüï}$…’æ$ÒŸð"¤y LMicrosoft Windows Production PCA 2011$Microsoft Windows32AûY™mÌMÿ2 ÿ‚¼8áÚ^YmótÅ>6÷í£k@VJ\WINDOWS\system32\drivers\WDFLDR.SYS0 € |Ï„UZ^¥Î æÛHáñù ÙõîêNµ{A´6p}´› LMicrosoft Windows Production PCA 2011$Microsoft Windows32AûY™mÌMÿ2 ÿ‚¼8áÚ^YmótÅ>6÷í£k@\P\WINDOWS\System32\drivers\spaceport.sysP  € HËptj£æŠúÏ[ÕZ´=5ÁÊ(’@›Èrín›cÌ LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@VJ\WINDOWS\System32\drivers\ksecdd.sys € É3>Î !À«š ¶ªñâGsÔâ™Þ/ü|2‹kÒelj LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@’L\WINDOWS\System32\drivers\iaStorB.sys` €0aA¹ÊóuU]ørQ‰*Ú× FIntel External Basic Issuing CA 3BpIntel Corporation  Non-Volatile Memory Solutions Group3´¬^;ãnŽË¢ò´¬ ßìU Ú¬kuµ1"IúFÂÈ9@’L\WINDOWS\System32\drivers\iaStorA.sys` €0aA¹ÊóuU]ørQ‰*Ú× FIntel External Basic Issuing CA 3BpIntel Corporation  Non-Volatile Memory Solutions Group3´¬^;ãnŽË¢ò´¬ ßìU Ú¬kuµ1"IúFÂÈ9@>2\WINDOWS\system32\kd.dll° € Ì áÙJ€‰Š¨†l{û…)¯Ÿ#ÕObDÇ ½fg LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@NB\WINDOWS\System32\drivers\tm.sysp € 5´ô}ÞMÏîøŽìVqÙo: :Ç}àv„þŒúžU LMicrosoft Windows Production PCA 2011$Microsoft Windows32AûY™mÌMÿ2 ÿ‚¼8áÚ^YmótÅ>6÷í£k@ZN\WINDOWS\System32\drivers\uaspstor.sys€ € ²3âŠgcAbƒÇ&[ @Ù ¦Ö'¸®âc_¶€ïñÝC LMicrosoft Windows Production PCA 2011$Microsoft Windows32AûY™mÌMÿ2 ÿ‚¼8áÚ^YmótÅ>6÷í£k@TH\WINDOWS\System32\drivers\msrpc.sys € x?S½o Ä€lP¤®PÉRÑÍ·,™Ð+|Z%æ¶ LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@TH\WINDOWS\System32\drivers\tcpip.sys. € 6òϹ†&-ÏØ:‘Þ3¦žO¿U½Ï9ÔáOl§,U6 LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@XL\WINDOWS\System32\drivers\PCIIDEX.SYS0 € ;G­ßÝ“‘4—iB¿÷[öó®9iy|cZ‚òù„ LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@XL\WINDOWS\System32\drivers\usbccgp.sys0 € tö­f öv¿¥?ÛBÎz'똷†%:ŽúõÖ³ LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@VJ\WINDOWS\System32\drivers\FLTMGR.SYS € $o}-4ke¢Xä8Œƒ¯† œ’˜ضðxÚãlžL®]Ãg¹Ç©ï«f LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@B6\WINDOWS\system32\skci.dllà € è[TsSn†ì/(Ô´niVý¶nïJ»ìí R¹ LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@ZN\WINDOWS\System32\drivers\intelide.sys° € ߘºtÎ’WML¬øÐYfž1â@ޤΞ"•r« LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@TH\WINDOWS\system32\drivers\NETIO.SYS@  € AËÀ& ùˆ(lÅŠ÷ÜôÿIX@Î÷úä Ô‡ÅÃG LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@XL\WINDOWS\System32\drivers\UsbHub3.sys  € j¸(KDóÅSºÔº‘Òœ|Só·›i¿Ú+ïº LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@ZN\WINDOWS\System32\drivers\hwpolicy.sys € éWůÆegp/ƒp¦­®\Î)¨·[#©/i•”ü8³“ LMicrosoft Windows Production PCA 2011$Microsoft Windows32AûY™mÌMÿ2 ÿ‚¼8áÚ^YmótÅ>6÷í£k@ZN\WINDOWS\System32\drivers\storahci.sysà € Sõ‚JTÆ é,E#Pïv `šFh}=ywQÄb®¸?ÚW LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@ZN\WINDOWS\system32\drivers\Wdf01000.sysP  € {<Éžîÿ XS‰€žu÷ÃBäF3-ߊÏǪ&­ú’ LMicrosoft Windows Production PCA 2011$Microsoft Windows32AûY™mÌMÿ2 ÿ‚¼8áÚ^YmótÅ>6÷í£k@ZN\WINDOWS\system32\drivers\ucx01000.sys € HÑlF·“í¯E²o¶Fgu%“ vÇ µ¼¤ã ' LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@PD\WINDOWS\system32\drivers\pdc.sys0 € Œ”=>Eˆˆ?Û;ª^I3$"ÀúÐo*üò9ï’lZ LMicrosoft Windows Production PCA 2011$Microsoft Windows32AûY™mÌMÿ2 ÿ‚¼8áÚ^YmótÅ>6÷í£k@h\\WINDOWS\boot\resources\en-US\bootres.dll.mui0 € –­ b‚k ñ€>Z“ýÃŤ-\BY˜&ôHM£ù LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@XL\WINDOWS\System32\drivers\USBXHCI.SYS € Œ^œM4–¯XŒý¤Yßw 5dއèÛw^Â’ LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@`T\WINDOWS\System32\drivers\EhStorClass.sys° € ! Î¦OÞ~AµŒû¹’ûB¿«QÖ'yz UçXWo LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@ZN\WINDOWS\System32\drivers\storport.sys  € é©3Ó 7èÞuÿ»x°¹¬¬}\Mã{(m£ul™¹ LMicrosoft Windows Production PCA 2011$Microsoft Windows32AûY™mÌMÿ2 ÿ‚¼8áÚ^YmótÅ>6÷í£k@VJ\WINDOWS\System32\drivers\usbhub.sys  € Ž˜ýõ½0åPU’càH¯žæ˜ºâFÆÜ˵{'-ä LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@VJ\WINDOWS\System32\drivers\volmgr.sys  € ²K´¬¹5D½þ²Þ«”rJ6~¡È“í¼ Dp᛫. LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@J>\WINDOWS\system32\ntoskrnl.exeP« € ®ˆbChGbekóÐMcÅÚmÍ*ÔÔ79oô  trŒš LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@WJ\WINDOWS\system32\DRIVERS\Parity.sys € ¤ S¢ê±wÛàwé¸Ãj~ïÞW[C 4\2ß§LeQ PSymantec Class 3 SHA256 Code Signing CA$Carbon Black, Inc.S¯ýà¶G¨Ô.ðÕS [ MfÕ—kÞ6®«35Õ¾Éû˜7@ZN\WINDOWS\system32\drivers\mssecflt.sys€ € J5“–âíç€`ãÄ×¢8«NSâ•ÖiÖó^u[² LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@PD\WINDOWS\System32\drivers\pci.sysð € AO ÿ¦©“űïsº3R&6™Ï)|Oº<Âõ°} LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@ZN\WINDOWS\System32\drivers\msisadrv.sys° € .ë!3ù‹2—#PÚë>.‘Ñ ¨uÝÉ‹>²©" LMicrosoft Windows Production PCA 2011$Microsoft Windows32AûY™mÌMÿ2 ÿ‚¼8áÚ^YmótÅ>6÷í£k@XL\WINDOWS\System32\drivers\storufs.sys0 € $]à¶ð‘!yï1£–É û¡ü»ÛùbÕ;F¸7l LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@PD\WINDOWS\System32\drivers\tpm.sys € ÔUÏgot1E´êЉu§ÊŽ%`îtê!jºÎ!?{ù LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@ZN\WINDOWS\System32\drivers\vdrvroot.sys0 € ‚ð#1ùvÒíð4Ê 0KNûͤ\\4çb‚ö8뚪— LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@XL\WINDOWS\System32\drivers\ntosext.sysÀ € ÚÆhñÆZ•@=@|wµŽTnS:Û~ Î ç¨è¦“Æ¡> LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@˜P\WINDOWS\system32\drivers\wd\WdBoot.sys € ö0ɲÑKb-ËOÙ6* ŸXç&zšâß’> @Microsoft Code Signing PCA 2010lMicrosoft Windows Early Launch Anti-malware Publisher3 rýÀ…."i ©Ä1‚ȭ;Ú{A_È7><б@XL\WINDOWS\System32\drivers\volsnap.sysÐ € ™BnÊ<ñ¤´e_¼FÖ¼6¡gvS@K¡IÉñJ LMicrosoft Windows Production PCA 2011$Microsoft Windows32AûY™mÌMÿ2 ÿ‚¼8áÚ^YmótÅ>6÷í£k@ZN\WINDOWS\system32\drivers\VmsProxy.sys € ±Ìïþ³' Û››W¾”TÁ¨=§þéÏVn—ÆWÞC¦w LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@RF\WINDOWS\System32\drivers\ACPI.sysÀ  €  :ÆÿeË”Á¾a²ÙJ¦Tú\W…é7œü)S LMicrosoft Windows Production PCA 2011$Microsoft Windows3eQ®½\¿½e áh`“Sóò71W´ëŒÕÐz+ÿ@qb\WINDOWS\system32\DRIVERS\CSFirmwareAnalysis.sys € ZPB«WºOmIz¯»²¡‘ºr-'8ÊÀaa€ñ RDigiCert SHA2 Assured ID Code Signing CA$CrowdStrike, Inc. $™±--¢E|†(¡º‘ ÍH^ªÛXMÏ‘¹Úæì®SðS@VJ\WINDOWS\System32\Drivers\acpiex.sysP € ¸??¨0ε_1Ïá Ëk̨ý „òI»÷S¢ª LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@RF\WINDOWS\system32\drivers\lxss.sys  € ‚¼;¦¤Ìö[†Îù´ñ?g‰œˆE–òúJÿ –g6d LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@k\\WINDOWS\System32\drivers\CSDeviceControl.sys` € ¼Fl¹×>7Ѭ-M†yVb1L‹“Î5]˜\¼ƒÚ RDigiCert SHA2 Assured ID Code Signing CA$CrowdStrike, Inc. $™±--¢E|†(¡º‘ ÍH^ªÛXMÏ‘¹Úæì®SðS@XL\WINDOWS\System32\drivers\USBSTOR.SYSP € ô˜àpÕ]°¬]ÿ:ï ŸPH\üQº0ų¨Ò LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@XL\WINDOWS\System32\drivers\volmgrx.sys0 € æÜ|œ^ÏLZ®XOJ‡ßÔj£¡‚º¼ãñ*zyNý LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@@4\WINDOWS\system32\hal.dll@  € éZ{s))œÙ¼æHG7ûÅ¡ ÛýtÒån¼˜C+'kºì LMicrosoft Windows Production PCA 2011$Microsoft Windows32AûY™mÌMÿ2 ÿ‚¼8áÚ^YmótÅ>6÷í£k@¨^\WINDOWS\system32\drivers\WindowsTrustedRT.sysp € Ul&g‹ä(WsÒ{‚v#³ÑeZg ï‚ØÌ%pß @Microsoft Code Signing PCA 2010nMicrosoft Windows Hardware Abstraction Layer Publisher3?X=÷X3? ßfÕ,HQEü¡Øzÿs÷“Ý2Õ@RF\WINDOWS\system32\ApiSetSchema.dllà € µÐê¨æ )«è‘a$'¦‘<'Êð®l›9N¹ƒ‰ LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R@ZN\WINDOWS\System32\drivers\mountmgr.sysð € ò´ß ŠØ…°’‡®wv‹À饇®#Õ LMicrosoft Windows Production PCA 2011$Microsoft Windows32AûY™mÌMÿ2 ÿ‚¼8áÚ^YmótÅ>6÷í£k@PD\WINDOWS\System32\Drivers\mup.sys` € ΞcÐ|sf#À3ØX_ П Ô';  fô¬+Ü LMicrosoft Windows Production PCA 2011$Microsoft Windows3f½€ï§\ÖÓf ¤4ŸÕ¹–Bƒ" 6¡ïooªx@@D8\WINDOWS\system32\PSHED.dll  € ? kAâ“Þ;HlyžzRMåƒÀ{Gû°ù6å LMicrosoft Windows Production PCA 2011$Microsoft Windows3Ä"²÷›y=¬²Ä ®œåGc‚.ìBGIƒØ¶5l„R/™ú7Â\_jííÛÖÇ3¾åZ(:î@æ&0‚"0  *†H†÷ ‚0‚ ‚°“®òÊl¦MÌH¿J#ü*›Èní ƒ±Ö‹Šh¨“qþ0Òå—¬ï †ê±÷nCmóžs§×¡Ô£XÛma¾Qj£$úo€'2 Ø|œöFX¶Èajª…÷(á)ˤßsv*û®˜¿ëØ b;¿±ËŒŒâêÌE²•ãú‡ô¨ê쿱@O{¼é¶ª3âdÆCo®©rå&÷á+QP°œR $ »&ÝðÓ^1¬àÄç*³ûŸÊÓÇÝoji©²~…&0‚"0  *†H†÷ ‚0‚ ‚Ý »¢ä. ãçÅ÷–i¼!½i33ï­ËT€îƒ»Å „Ù÷Ò‹ó8°«¤­-|byÿãJ?5 pãÄçkàœÀ6uéŠ1ÝpåÜ7µtF–([‡`#,¿ÜG¥g÷Q'žrë¦É¹;S5|åÓì'¹‡þ¹É# o¨F‘Án–¬p¢«Îé|Ë’¡å;1Ïêò äW»Jµétæ+þlË~t96 ïäµN¤©êj «„ó¬gNµÄ÷ŒÑ %#ëd>R–ÁòôÅŽÁ¢è,Q÷s¼½…±bƒsA‚ä8‹js Ðds<žŸ¦3©ýß%“Ñ&0‚"0  *†H†÷ ‚0‚ ‚—ƒ¯,±ÒÄ×h“Q`qöâG´ÛXM#bj´¿ZQ÷£ wh»Ø6«/!PÚžóç_'N Â—È p“©Ú\ N¤ ‘ ´ìΑrT.ΣÛDéR?A<ÊJäªÀè9«SÌ!ÐÌÏ›æÂÌXj‚î=6ÏÅ—$Žñ{¾1-=nܵ™BŸKa•_pî}Û‹åa‰xÇh¯x˜®ÄUGSÙ³2Ö¡F@Å—’ŠÑS§™[…5WÓê“ba Ç0w$Mbƒ¶º{h‚1îeÊßùÕ²5ÜŒ+ojr\`„œò ”^ÀVRHÌÓø¥}Þ/×ä8¨„ÕF¸†ÂêZ8Ý›Û :@rÌkwâcOÜ‘Éü¼>3Ãÿÿ I“ˆÚ¨ç×ñã™an9å‰9WBCL I“ˆÚ¨ç×ñã™an9å‰9WBCLI“ˆÚ¨ç×ñã™an9å‰9WBCL€D:k{‚·¯VO.9<ÙÕ£ˆ·úJ˜Exit Boot Services Invocation€GUEÝÉx׿Ð6úÌ~.˜HŸ (Exit Boot Services Returned with Successÿÿÿÿ¦+ ‚ÝQ yÌ·-ã°w › ¨ÀÉ€EWindows AIK€»nÓ×:.(èI¬u lë¡[€P6QUT2·Ô÷B¤Ö÷ªßB Mi™‚ëŽ*æè/™0(IFX (wtpm61ÿÿÿ€!Ómcá^âwiól|ÿÐäêN~›k¡ÕÔÐ "4¡R?A—5^„ZÌÒ€i‰Çœé{r‘q8²_(ˆ²Ÿ":ƒK`ÐZ¿ÅL"14$†Öó–,™¾r”-S* æz_š©iî,a Øu}ÕpUò©oKÝVÑÓC´“ªÚ T- l_Ô¥-×¾>¨^¸?Pä-ä­PÝyÊ03‚É Äôrv®îÃæ«ª/×Êðµ—²×;èjV‡t´Îíæ.+—?ÆÊøÔÂÚîo¶‡tÅ^P„+4ü3÷¿¯›ÏÆUÖâÔ~OÖ ÝÞ(ESJW‰Aü‚°go-attestation-0.5.1/attest/testdata/sb_cert_eventlog000066400000000000000000000450031452320553600230520ustar00rootroot00000000000000)Spec ID Event03 0‰ù#Äܧ)‹>23E…PØÝß) –¢–Ò$ò…Æ{î“Ê0‘WðÚ£]Ÿ~A xc ÏÇ Ö÷´W­ˆ „ AÉa(;«hޔ䵓YêEheéìΣÆ$±"aø$óë`® |€ÔýÑñM@AIMëÉÄSCÒ'} ÌüK³(ˆ£E¼ŠêÚºU+b}™4Œvv«1Aõ°@¤ ,ÞÐÆôSÔÆõœ^ìa«Æ°1E@¢6|º2jRª+1\ÌÎh¨Î Æï*Çå®5aßä‹Ê“Òª à˜+Œ SecureBoot€Z½”«ó>4§›=“ÓPçBØìØ Û»ã—fX…eÅ̘¢®¶äJ‘xÉñ“[ÒAóƒrD„» §cU<–w Ó¥æøàÁïÍòUZ÷Sú:jþCë{* ô¦øØäÝE–hó°àJaßä‹Ê“Òª à˜+Œ&PK¡YÀ¥ä”§J‡µ«\+ðr& ÒúÒˆ¤G—’[ªG»‰0‚ö0‚Þ  ÕJègƒ]ê0  *†H†÷  010 U newpk0 180821215115Z 180920215115Z010 U newpk0‚"0  *†H†÷ ‚0‚ ‚̹Õ|ømkcêÉbô “Éþã|,EÎ…RRH|ûC&¿ ¥‰°òÝÇ6èi•ªŒoТ#o4ÂO±žkÆú¸”ÁœŽp‡‘BÎi!“}ÚuŸ¿1 PÁï€#û¾;Vã ×Gê0¯Ô]©c‰¢ü9á–¡‡Ã=&²Ó¢lìÈ—×ÎÚ겕<³ÎŠÏÚ:Qˆ?%°K>ÌÝùÚÛQÕ‘š¡½ˆâñ´ñ³’·ãgæ­ŒjÜ'?ÜÔNlÁ½ïÞV*ÚY` yÓ©|WýQa7}ä·n•ðR›CžÜH<ͼ9Ÿ£èG F¸6Ü’³•¨ÎJãF#XK£S0Q0U˜P„Bó/Û—‚'(—t1F^`ËÅ0U#0€˜P„Bó/Û—‚'(—t1F^`ËÅ0Uÿ0ÿ0  *†H†÷  ‚Š¡R?ªç½°$«‹­2°Iý{4Ë;€v`=ŽÜÊkiÂ[”踜Œ,×¼¬}‚YõÄ.¢l¥ì˜ð1#6øË0ƒg::+b!`,ºõ.ù(nÊfpX(†gi„l'X%œPép¸`nT…J¯mE¦[4ü&M<á»$.yàÑȬ|Ù8GCk3PWãsž¦‡ÝÃâJüs{K ‡Çƒ 6Zêi‡@„ ,”€/=®=ËpÄ5¹>q²£Æ­Ø$?}`«o îzšÏuŸèL«ÍQ‡hX3²Ù¼8%*˜KEûg3›%œ?¬¤CDÌÍÓÈ ná€ðPy¶ÌBé.èZtÙÂviÀâ b&GØ[Šd}-.f‚Áb {l¦·"ZfWÂVµ‚ À§¦@“íy΋V—=ÞöÚ‘¿ ëW’³ÈBB7Bµ)C¥‹ß#(¤4“~2xˆ>aßä‹Ê“Òª à˜+ŒKEK¡YÀ¥ä”§J‡µ«\+ðrüÒúÒˆ¤G—’[ªG»‰0‚è0‚Р a ш0  *†H†÷  0‘1 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0 110624204129Z 260624205129Z0€1 0 UUS10U Washington10URedmond10U Microsoft Corporation1*0(U!Microsoft Corporation KEK CA 20110‚"0  *†H†÷ ‚0‚ ‚Ä赊¿­W&°&ÃêçûWzD] ÚJåt*æ°ìmëì¹ãZc2|Oã §8“ŽÆõà„±š›,çõ·‘Ö áâÀ¨¬0ßHóPšd§QÈ…O †Îþ/áŸÿ‚ÀíéÍÎôSjb: C¹â%ýþùÔÄ«â#‰p·¤Mì®åœúÂ×ÁËÔèÄ/å™î$‹ìò‹êÃJûC ~µG’lÜæ‰ëõ3ë*qåùƒ<ÿ% /hvFÿºO¾Ü­q*XªûÒy=ä›e;Ì)*ŸürY¢ë®’ïö5€Æìä_ÌvÍïc’Á¯y@„y‡ãR¨è{i£‚O0‚K0 +‚70UbüCÍ >¤ËgÒ[ÙU¬{̶Š_0 +‚7  SubCA0 U†0Uÿ0ÿ0U#0€EfRCá~X¿ÖNž#U;:"j¨0\UU0S0Q O M†Khttp://crl.microsoft.com/pki/crl/products/MicCorThiParMarRoo_2010-10-05.crl0`+T0R0P+0†Dhttp://www.microsoft.com/pki/certs/MicCorThiParMarRoo_2010-10-05.crt0  *†H†÷  ‚Ô„ˆõ”Ê*<û*’ × ÑñèRf¨î¢µuzª-¤vZêy·¹7jQ{döádòg¾÷¨x½ºÎˆXd ÖWÈ£_ÖÛÆÐiÎHK2·ë]Ò0õÀõ¸ºx£+þ›Û4V„ì‚Ê®A%pœkéþ×–å甲* Kÿ(){÷×|¥Ñv¹Èyí’œÂþßo~l{ÔÁEÝ4Q–9å^VØ–ô¦B³ wýòqVÌŸ†#¤‡Ë¦ýX~Ôig‘~òå ‹Š<‡„ëãνCå­-„“Žj+Z|DúRªÈ-»àRßøš=Á`°á3µ£ˆÑe ç¬|¤Á‚‡N8±/ Ňoý.¼9¶çæÃàäÍ'„ï”Bï)‹FA;gØùCYeË ¼ý’Oôu;§©$üPA@yà-O j'vnRí–i{¯÷‡ÐE­Sû0ª76aÚJi4ØhíÖÏl” ÓÏl"y­±ð¼¢F`©ÄÂ!‚ñýòèy2`¿Ø¬¥"KÊÁØKë}?W5²æOu´°`"S®‘yÖ›A†Tp²Þ 5|°4rº—`;ðy뢲]¢¸‡Åéöµ—%o8Ÿã‘úŠy˜Ãi·£ —øÊ®×ÄóÀuk4 µ™`ó\°ÅWN6Ò2„¿ž€ÔļY›‘p'7¬è¾BCÓsT ßó EOiMÊ(á¢Ô"ßͨjús\GÌÌxü“à ¼Ö'åœ/q“kÀ¼¸ºIÀ7þ°³œüÆ àPA¬:ºnņò#Ol‘]„·O–ß·˲×:=–E£¼ÚÐgeo“db¡YÀ¥ä”§J‡µ«\+ðr@$ÒúÒˆ¤G—’[ªG»‰0‚0‚ø  aÓÄ0  *†H†÷  0‘1 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0 110627212245Z 260627213245Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1+0)U"Microsoft Corporation UEFI CA 20110‚"0  *†H†÷ ‚0‚ ‚¥lLÇE jK ¤À‡u CTdàí’} ²s¿ ÆJEa Å-–Óõ+ ûMI›A€<¹Týæ¼ÑĤŠAŠ\Yƒh2»ŒGÉîq¼!OšŠ|ÿD?2²&H®uµîÉLJ~䂚xwM °½öÓÓ¼ú+¥Q8]õûºÛxÛÿì –Õƒ¸é¶À{@{á('ÉúïV^æ~”~ÀðD²y9åÚ²b‹M¿8pâh$É3¤7ÕXi^Ó|íÁSçN°*‡caocYê²+y× agŠ[ý^­‡º†gOqX"""΋ïTqÎP5Xv•îj±¢Õ£‚v0‚r0 +‚70# +‚7øÁk·wSJó%7N¡&{ p€0U­¿C ½‚pœŒÕO1nÕ"˜ŠÔ0 +‚7  SubCA0 U†0Uÿ0ÿ0U#0€EfRCá~X¿ÖNž#U;:"j¨0\UU0S0Q O M†Khttp://crl.microsoft.com/pki/crl/products/MicCorThiParMarRoo_2010-10-05.crl0`+T0R0P+0†Dhttp://www.microsoft.com/pki/certs/MicCorThiParMarRoo_2010-10-05.crt0  *†H†÷  ‚5Bÿ0ÌÎ÷v ­hX5)F2v'|ïA'BJªm8HYUóéX4¦ ‚ª]­‚Ú€ƒA´ò¹ó]ñPù³U„B( ½²®QÅÀ¬—•!Ûüwž•s‘ˆÊ½½R¹P ßWž aí åm%Ù@@ÈΣJÂM¯šT½Ç¼¹+=I+2üj!iO›È~B4ü6‹ @À³š%u'ÍÉ£ö]Ñç6Tz¹PµÓÑ¿»tßÜ€Õíô/k/ÞfŒ°#åÇ„ØíêÁ3‚­VK-ñh•ÍÏðrð®»Ý†…˜,!L3+ðJðh‡µ’U2u¡j‚j<£%¤í­×®ËØ@Y „Ñ•Lb‘"tŒ=GD¦ä°›45±ú¶S¨,ì¤qȸºèDfäGTŽV³Ÿ˜²†Ðh>#µ/^P…Æ‚_A¡ô. à™Òluä¶iµ!†úÑöâMÑÚ­,wS%27ÇlRr•†°ñ5ajõ²;PV¦2-þ¢‰ùB†'U¡‚ÊZ›ø0˜T¦G–%/È&äA”\?å–ã…[<>?»GrUâ%"±Ù{ç*£÷Fà Ö‰ã5'bq¦ïÐ'  Y7`ø8”¸àxpøºL†‡”öà®Eîe¶£~iu’›õ¦¼YƒX¡YÀ¥ä”§J‡µ«\+ðrÒúÒˆ¤G—’[ªG»‰0‚í0‚Õ (Ì:%¿ºD¬Dš›XkC9ª0  *†H†÷  0ˆ1 0 UUS10U Washington10URedmond10U Microsoft Corporation1200U)Microsoft Root Certificate Authority 20100 100623215724Z 350623220401Z0ˆ1 0 UUS10U Washington10URedmond10U Microsoft Corporation1200U)Microsoft Root Certificate Authority 20100‚"0  *†H†÷ ‚0‚ ‚¹ž(ääìNPh³AÅ{ë®¶Ž¯º"De4iL¾p@ò{âyý†í 9ô¨­’Ë=vZÙµ‘.<Šm$TçíV­ƒ´Pœ¥tˆY üÅ„vÓhÔo(xÎ\¸óPDÿãc_¾¡š,–Öþ„!àB1Ä(6”ÏP¤bžÉÖ«q²[ æ–Ô $–õÿÆÕ·×Ë·!b¯Ü¡]7ãûF˜À›Àçc*“~jŽòŸ‰ä"…¢±„W@ÿõØoœíâE1Íé°Eãª!@&¡rª§O<~îƒX±^c™b‘x‚· “ $j´Û'ì_•?“J0õ—³§ù§“3ÈÛ"R\×%ÉFù¢û‡YC¾›b±-†DF¬xa~0 ú®‰ÄA*"f‘9EœÇ‹ ¨Ê /ûRê ÷c3#þ°­gÖ§PÆpcµ,±†ZC·û®ùn)n!!A&ŒÉÃî°Â…“¡¹…Ùæ2lKL?Ö]£åµwÜÀU·tã¸8«ƒ—PášB$ÆÀ£0ÑZÈR4÷sñÇ3­zìËA`ó#” ÂHE¬\QÆ.€Ââw½…‡í6–‘îµ£pìŸã€hƒvº¯]pR"âfûº³ÅÂ÷>/w¦ÊÞÁ¦ÆHLÃ7Q#Ó'׸Np–ð¡Dv¯xÏšáf£Q0O0 U†0Uÿ0ÿ0UÕöVËè¢\bhÑ=”[×ΚÄ0 +‚70  *†H†÷  ‚¬¥–Œ¿»®¦ö×q‡C1Vˆý2q[5·Ôð‘ò¯7âñó&>º¸Oû‰²²çÔ Ìm¹[;depf·ò±ZßóõQ¸gmyó¿V{䄹+›@œ&4ùG˜iØ×¶Ñ¿aÂgĵï`CŽ6Iä Ê­§Á±'e øÍõ[*Є3óïòõœ X“7 u ÞrÞlu*f"õŒ0VŸ@¹0ª@w‚׋ìÀÓ²½ƒÅw ®¯S MyqŸ¯0ÎgùÖ,Ì"Azò—BÎYyUÞoä¸Úƒf@ h#[—.&š»WŒÅ¸ºib2€‰ž¡ýÀ’|{+3„*cÅhbúŸG™zE:§éíîiBµó›GV{üp6„sêïù—Mž3#Ý& º*·?D܃'ÿ½aY+·ÊOÛÅ‹ 1®2øø¹B÷Üašv±Zá=fE·q¾É$…ÖóÔºA4]-%¹¦HmK°}™“ atW&Š«iãäÙLjÌ$ØìR$\¼‘â–Þë ÚžÝ_³[ÛÔ‚ìÆ P‡%@:ûÇîÍþ3ånÄ U%9Àé5]e1¨ö¿  Í)dz62.Ü•óƒÁZÏ‹öê³!ø¤í1¶L«` ¤#"£6d‚‘à«oËPa´@ÿY†qÑÕ3i|©sŠ8×d ñi¡YÀ¥ä”§J‡µ«\+ðrëÒúÒˆ¤G—’[ªG»‰0‚×0‚¿  avV0  *†H†÷  0ˆ1 0 UUS10U Washington10URedmond10U Microsoft Corporation1200U)Microsoft Root Certificate Authority 20100 111019184142Z 261019185142Z0„1 0 UUS10U Washington10URedmond10U Microsoft Corporation1.0,U%Microsoft Windows Production PCA 20110‚"0  *†H†÷ ‚0‚ ‚Ý »¢ä. ãçÅ÷–i¼!½i33ï­ËT€îƒ»Å „Ù÷Ò‹ó8°«¤­-|byÿãJ?5 pãÄçkàœÀ6uéŠ1ÝpåÜ7µtF–([‡`#,¿ÜG¥g÷Q'žrë¦É¹;S5|åÓì'¹‡þ¹É# o¨F‘Án–http://www.microsoft.com/pki/certs/MicRooCerAut_2010-06-23.crt0  *†H†÷  ‚ü|qQ¥yÂn²ï9>¼«\`ìß¨Ó éôö–…¶QˆfG¢°=*hw»‘Lb{¶ÁǺz‡4Kbz™éÊüÎJ7É-¤W|þ=ܸZúÖij…:ê³Ùnäi!7ÞÑöugÓ“W^)9Èî-áÍäEs[ÐÒÎz«‚FXÐ^³g¯l5ò¼å?$â5¢ uöV™Ôx,ÑëЈªñߺ~,c·›#!ÄùxlâX6+‘̤Ùò-ºù”@íEñΊ\k>«Óp* jà_GÑÕc 2ò¯×6*pZåBYqKWº~ƒð!<ôÁŹ“ˆE“†é± ™¾˜ËÅ•¤]bÖ c ½uw}=óE¹Ÿ—ŸËW€o3©Ïw¤bY~¡YÀ¥ä”§J‡µ«\+ðr/ÒúÒˆ¤G—’[ªG»‰0‚ÿ0‚ç 3•œPHq‘B8ßsÓ´š=0  *†H†÷  0‘1 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0 101005220228Z 351005220933Z0‘1 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0‚"0  *†H†÷ ‚0‚ ‚ð­^‚@-h$YËÞ è„ÌH¹;°‹R%Ä:„¾àuæºøaãkÎߟ(36Úƒ2È¡¡íYJâŒ` j‚±š ¢\".9í’özÿ‘h…£œŠ—ƒq”n2×'æg åzûÿðIÏ0 {ÿéN¨ý"1mÞIm–ª‘&A›[KÓñ/Û~0üy¦hJ†w<ìå3ÃßêU­^eÓÞ¯½^t&ƒœÎXVHàŠ§i’írÛg‚Âæ8NÏ_+ ;ÓËššUT¦ds”øSVòá»ÙÎ’â'[}ÄVœëWü žä¢zY™½#Äelm²^‡n§Ñðê2…xPI–˜‰(Vk )y5g¸bŸ£Ïï…cø¾Üí”|ma›x4‚LÝ*m€¶Ýz„íØU×뇓ŸšM(tª¬ O¿þY¿fîâóQŽ>>[$x£ôÊÂÖýèëíO”¥_4ÄœâTºHƒ‹dDÓB;jÆ h$*"K°yÖÞåã˜:ëY¦Nô–#?¢ÌvÈN½hU<Øý„D9‰Ma•èœÌ¯ñM8®‚c¿hêE¢6¶ˆj,kËfÔÇA ­ó°´˜si'Ž`æìîŠo0å]ÛVðð+R<§;*~ÀÿÅìà)ߣQ0O0 U†0Uÿ0ÿ0UEfRCá~X¿ÖNž#U;:"j¨0 +‚70  *†H†÷  ‚/’W™zÝɤ`â6¥GA@„¡H >¤öµ“Ï**d”AFì$õÈ[Ôv—EµäÕQÈÛ]™@N<åG©Å¡†]3lÑŽñ õÌt¸ nŸGJȲPcqS†µ gÉW ™!×È.’ë=Z@yº‡¶¿õ öA»dŠ·âØ¾4ý:pç¨ûºùsDÊ:M¾ãrª¦1»4~Â|}ÓnƒÛ ›ÃK“Þ[ï0oFf6Ö)ƒ¨Z¸` ä<²Dp|\+1tq8_ºÍ¨úEŠ’Ñer•èO0(¼âöGa};6%* Fɯ[ `¯p•æ_ôB²Ìÿª†ß&È8†¸ÀÿmL"Åã4äf ÐZä[,«cÈíq4ÛLúr@27f"Ç©[?ßå”Äö‹ °ƒÈ‰E¾Ÿ¯‡ýIš0ñôƒºÉ^ƒ9S[躲×#u_©yö(‘Ö¨3c˜©3n€BöÊ5R°*ec&Œè‹OhJÛä„F[`„¿½ÜŸ•|H‡‚×s]á=X"²Rä%pÍ:T”¦˜È™¿ ÕØEE‘I5J\²]™¾?Kû$ôÚ4­·AMÀø°J.KøúϱBªyOJ÷Ä(”. Œt2š5»h'ú¡ú‡m±Ù§ ïÎÀ®n6ìÀóN ý¦ãöma3I$Î.€ž¶ƒ±­çBpÜ`ƒÝqjÌc£3  D´ÎJMÊšóÈ—ÜVî'Ã…ëˆ÷Ϲ +‚e[ œ)>o~{¶«ñ£û-<Ä»( TM¼IƒÕ€0©/!­f$¥a›¿¹°²˲×:=–E£¼ÚÐgeoŒdbx&ÄÁLP’@¬©Aù6“C(Œ0½šúwY2M½`(ôçxK€´Ùi1¿ ý‘¦ÑO¤Ræm²@Œ¨`MA’eŸ ½šúwY2M½`(ôçxKõ/ƒ£úœûÖ’r($ÛäE4Ò[…$k;•}¬nÎz½šúwY2M½`(ôçxKÅÙØ¡†âÈ- ¯ª*o.s‡ >d÷,Nïgyj„½½šúwY2M½`(ôçxK63„ÑM. xbd„ÄY­W£ïC–&`HÐXÅ¡›¿v½šúwY2M½`(ôçxK세Kle¥ ©¾q–R0! bÖÓ h2Û²Ò à'%'ß¶=IÒ•r¦ôL½šúwY2M½`(ôçxK^ê‰T‹ `²þíÚ< Çþ›Ík”覃¸R8½šúwY2M½`(ôçxKæÆ¨Xdo±ïÆyþ(±#gþ’æ¾+6™žÿ9О½šúwY2M½`(ôçxK ß_NQìx¹mÐ%ý¶†ãŸor’xRY›eœ&½šúwY2M½`(ôçxK »C’Ú¬z¸›0¤¬eu1¹{ú«ù ¯åù¶ë ct½šúwY2M½`(ôçxK “9v-ó6«=ФcßqZ9ϰô’F\`lk×½‰Œ½šúwY2M½`(ôçxK ¾Êo)ì o3}räˆK ³H˜:* ×?O½šúwY2M½`(ôçxK Éóû™–!HÃʃ62u>Ôü ¹[1æR*Í[ü½šúwY2M½`(ôçxKo¬êÏìýN0;tô€ €˜âЀ+“oŽÇtÎ!ó†hœ½šúwY2M½`(ôçxKN: [CƦ»Ó@O4=Ï9bgΔøµ.#©Ú’ ½šúwY2M½`(ôçxK34)ÿbퟗ>HÜîå-¾.ImTµÏÖÈdÒѽšúwY2M½`(ôçxK+™Ï&B.’þ6_¿Kà 'lžáKzoÿDû/ki™9½šúwY2M½`(ôçxK+¿,§¸ñÙ'îR¶û*]ÐI¸Z+›Rœ]fb°Uø½šúwY2M½`(ôçxK,sÙ3%ºmËå‰Ô¤Æ<[“UYï’ûðPíPÄâRñ}½šúwY2M½`(ôçxK.p‘g†¦÷sQ§«pµWÆ2.©#²¨Ó¹+Q¯}½šúwY2M½`(ôçxK0f(úTw0W(ºJF}çÐ8zTõiÓvŸÎ^uì‰Ò“½šúwY2M½`(ôçxK6íºõ­A¤¡wz¿/¯^g4g^Ù^i5‚ž ªÒ½šúwY2M½`(ôçxK8AÒ!6ƒ×\ æ!`9MlN g`¶ö¹b¼…[½šúwY2M½`(ôçxK?ΛŸß>ðTR°ù^ä·ðmt:syqUŽpjÎ>s½šúwY2M½`(ôçxKC—Úʃžc|µ ’ßC¼-/²¨õŸ&üzKÔÙu’½šúwY2M½`(ôçxKGÌa'⚆à:kï,ÔøÅZmkÛ6!hÃ,ã*Zß½šúwY2M½`(ôçxKQˆ1þs‚µÐ>Æ!"‹Š¶Ty½ ¿£ÅÁÐôœ0a5½šúwY2M½`(ôçxKZéIêˆUë“ä9ÛÆ[Ú.B…,/ßg‰úg6ãÃA+\½šúwY2M½`(ôçxKk€xäAЦë{³^`’ÏGžëŒäÍçÐrÌ´/f½šúwY2M½`(ôçxKlˆTGÕYâ“Q¸&Àl¸¿ï+”­585‡rÑ“ø.ÑʽšúwY2M½`(ôçxKo(ÿqÉÛÕ¯.{¿Ë«d|ÂeÝõ²“Ͷ&õ :x^½šúwY2M½`(ôçxKqòoÒ"I~T£Fb«$—üÈ wõhéãÙ¿Ëýcu½šúwY2M½`(ôçxKrk>¶Tj0óø=›–Îöpé¨ÑpŠqæ-Ä,#Á½šúwY2M½`(ôçxKrà½gÏ]V«Šß;ݼ‚¿2¨ØªŒ^/mò”(ÖØ½šúwY2M½`(ôçxKx'¯™6,úðq}­ä±¿àCŠÑqÁZÝÂH·[øÊ¤K²Å½šúwY2M½`(ôçxK¨¹e»„Ó‡k”)©TÌ•SϪØÈ£;ý3ÿð佚úwY2M½`(ôçxK‚Û;δöCΗÃч͛YAÍ=èXo+ÚV7W_g½šúwY2M½`(ôçxK‰Z—…öÊ~ÔOÁ¡G qóñ"8bÙÿÌ:âß’=¯½šúwY2M½`(ôçxKŠÖHYñ•µõ¯ª” jag¬ÖzˆnF“dr!ÅYE¹½šúwY2M½`(ôçxK‹ô4´žÌ÷¢ÍeËì;= <5¾P_ß{Õcõ!½šúwY2M½`(ôçxKŽ¢‰Ïç «seË(îQíÓ<òPmèˆû­Ö¿€H½šúwY2M½`(ôçxK™˜ÓcÄ‘¾½tº¹M’‘soܦC£fd¼1ZB½šúwY2M½`(ôçxKžJi1ah.Uýèþõ`ëˆìþܯfÀÊ÷²·4½šúwY2M½`(ôçxK¦µ6UÓ¢¯ G'Yykä¤ T•§ØiuLHH…t§½šúwY2M½`(ôçxK§ó/PN°þ­š~ùNѺ ì]æ÷ïoð¦+“¾ß]E½šúwY2M½`(ôçxK­h&á”m&Óêóh\ˆÙ}…Þ;MË=â®Ç`ÑùÂ$Q?¼eYW×5ú)õ@νšúwY2M½`(ôçxKØËë—5õg+6~O–ÍÇIia]JélrMBÎøóú½šúwY2M½`(ôçxKé,"ë;VBÖ\ÂÊòGÒYG8„D•oYâ°Ñú½šúwY2M½`(ôçxKýÝn=)ê„Çt=­JÛǵþÁ³‘ù2@†¬ÇÖÛØ½šúwY2M½`(ôçxKþc¨Ox,ÉÓüòÌùüûÐ7`‡‡XÒb…íf›Ünm½šúwY2M½`(ôçxKþϲ2Ñ.™KmH],qgrŠ¥RY„­\¦u"š6½šúwY2M½`(ôçxKÊaJ~“”ŒÐþUÓ™ùÑ©nE AR'ÂÆ[½šúwY2M½`(ôçxKU¹› å=¼þHZ©Ç7Ï?¶ï=‘úµ™ª|«í§cµº½šúwY2M½`(ôçxKwÝ£ ˆÿ^; æb x  S^ˇæðˆŠ k/½šúwY2M½`(ôçxKÈ<±9"­™õ`tFuÝ7̔ܭZ˦G/î4qÙ9脽šúwY2M½`(ôçxK;‡S> ÃÐì¨#Ëð©AªØryÑÄ™€-Ñæ6¸©½šúwY2M½`(ôçxK“šîôõúQâ3@ÃòäHΈrRjý÷Rçó£ò¼Ÿ`I½šúwY2M½`(ôçxKdW[Ùxš.­Vö4R¯kø ùDxYuéðN-d×E½šúwY2M½`(ôçxKEÇÈ®u Ï»Hü7R}dÝdM®Ø‘<ÍŠ$ÉM…igߎiÊxçE (QsC>RÅÂR™äs ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ 9CA·,Ò'ÅÆ°~ø ߨa6Ä)+ŽWes­~Ù®AŸX´¹qÉïü`á­Ÿ‰ðà€ ŒVà’w¬Í`:£Ë–+KY\ 1‡¬.7üDéwÍ ó"7بZè½Iemø¢ [2}›”„ —š,nõ¥rÝŽ¾Iv)a(}¥¬¡ýÖíD&-“·ÿCo€èuYCH˲×:=–E£¼ÚÐgeo$dbÒúÒˆ¤G—’[ªG»‰0‚0‚ø  aÓÄ0  *†H†÷  0‘1 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0 110627212245Z 260627213245Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1+0)U"Microsoft Corporation UEFI CA 20110‚"0  *†H†÷ ‚0‚ ‚¥lLÇE jK ¤À‡u CTdàí’} ²s¿ ÆJEa Å-–Óõ+ ûMI›A€<¹Týæ¼ÑĤŠAŠ\Yƒh2»ŒGÉîq¼!OšŠ|ÿD?2²&H®uµîÉLJ~䂚xwM °½öÓÓ¼ú+¥Q8]õûºÛxÛÿì –Õƒ¸é¶À{@{á('ÉúïV^æ~”~ÀðD²y9åÚ²b‹M¿8pâh$É3¤7ÕXi^Ó|íÁSçN°*‡caocYê²+y× agŠ[ý^­‡º†gOqX"""΋ïTqÎP5Xv•îj±¢Õ£‚v0‚r0 +‚70# +‚7øÁk·wSJó%7N¡&{ p€0U­¿C ½‚pœŒÕO1nÕ"˜ŠÔ0 +‚7  SubCA0 U†0Uÿ0ÿ0U#0€EfRCá~X¿ÖNž#U;:"j¨0\UU0S0Q O M†Khttp://crl.microsoft.com/pki/crl/products/MicCorThiParMarRoo_2010-10-05.crl0`+T0R0P+0†Dhttp://www.microsoft.com/pki/certs/MicCorThiParMarRoo_2010-10-05.crt0  *†H†÷  ‚5Bÿ0ÌÎ÷v ­hX5)F2v'|ïA'BJªm8HYUóéX4¦ ‚ª]­‚Ú€ƒA´ò¹ó]ñPù³U„B( ½²®QÅÀ¬—•!Ûüwž•s‘ˆÊ½½R¹P ßWž aí åm%Ù@@ÈΣJÂM¯šT½Ç¼¹+=I+2üj!iO›È~B4ü6‹ @À³š%u'ÍÉ£ö]Ñç6Tz¹PµÓÑ¿»tßÜ€Õíô/k/ÞfŒ°#åÇ„ØíêÁ3‚­VK-ñh•ÍÏðrð®»Ý†…˜,!L3+ðJðh‡µ’U2u¡j‚j<£%¤í­×®ËØ@Y „Ñ•Lb‘"tŒ=GD¦ä°›45±ú¶S¨,ì¤qȸºèDfäGTŽV³Ÿ˜²†Ðh>#µ/^P…Æ‚_A¡ô. à™Òluä¶iµ!†úÑöâMÑÚ­,wS%27ÇlRr•†°ñ5ajõ²;PV¦2-þ¢‰ùB†'U¡‚ÊZ›ø0˜T¦G–%/È&äA”\?å–ã…[<>?»GrUâ%"±Ù{ç*£÷Fà Ö‰ã5'bq¦ïÐ'  Y7`ø8”¸àxpøºL†‡”öà®Eîe¶£~iu’›õ¦¼YƒX€C¸æÐA¼ZøXûAÚÓa+â ´·Œ?Ü^mb &LS¡tp¥"7hGd¥»â8‰½ xˆÂj »•Í ÜHp2iì©5£âX•~nI’ÓU{à2ISx?’ xɑبìmäEFI PART\l àÿÿ?"Þÿ?Ï´Âê[&—O§Sño»÷€€£Þ=â¯=ƃ„rGŽy=iØG}䨯×ññ|A•€µÌ÷"èxÞÿ?Hah!IdontNeedEFIW· =¢J‰—Oy€f;ÿ'(s*ÁøÒºK É>É;‹*‡'ü‡ÂI¿':üLøE†(ÿw€Ðæù9ñ0Jƒ—_4ÿg¥s®+>å L•W± >!f>-#ãÁ®œäµÞ X¢—3#6¢Ø ˜ýß»­“â…”³G+ÌE DÐo-†í—&’Ϻç`*± ©«MC­š–`©¢# ¿ó˜Z¾ ^x ÐA *(P‹*‡'ü‡ÂI¿':üLøE†0\EFI\BOOT\BOOTX64.EFIÿ€i[oåÕžV^¦Wà>¨¡TEHµ †8{¡me™hƒE÷ÇHŸ”@ð•@}lÕJ²F©3Å é^‚§¿ív²Ë þaö<ŽÝbáø4CœrG„_4˜r;WžGRJ´2æ2j¿l)tx¯à€]¶zD±òç(˜'Rfîlµß pðÜ ý“@>.ÒçgÛ+ºçó¢â<«FëcIÒ ã! ™Ej“ób¶Ÿ Ðöö ë^PµÝÌ$›G{µÔÇAs¬“ökóQS9] fP«]`FàC«¶=ØÝ‹#8Shim0‚40‚  ¹A$ ,’g0  *†H†÷  0„1 0 UGB10U Isle of Man10U Douglas10U Canonical Ltd.1402U +Canonical Ltd. Master Certificate Authority0 120412111251Z 420411111251Z0„1 0 UGB10U Isle of Man10U Douglas10U Canonical Ltd.1402U +Canonical Ltd. Master Certificate Authority0‚"0  *†H†÷ ‚0‚ ‚¿[:tî!]®aíV¬½ÞÞróÝ~-Lb¬ÀmHÏ‹ûa'ÌnÙU=9Të@;±»â…4yÊ÷{¿ºzÈ-}­YϦÔéNÚ®RêLžÎÆ™ Ngex]ùÑÕ8JJz“œ£…ÛÎú‹÷¢!-›TA5Wl¼)PJ~ꙩh§;Ç2ž ‡y»h™-~“RåöëÉ›ù+í¸hI¼Ù•P@[Ųqªë\WÞqù@ Ý[¬„-PRÖáókndO[´ë äaÚZðêäB×Äþ!Ù¹ÀT•BRrIdzÈl$ñp M¥ 2Ñ W¨M㯥Ž>C¡£¦0£0U­‘™ Â*±õŒ#¶eZ&Ž4Zc0U#0€­‘™ Â*±õŒ#¶eZ&Ž4Zc0Uÿ0ÿ0 U†0CU<0:08 6 4†2http://www.canonical.com/secure-boot-master-ca.crl0  *†H†÷  ‚?}öv¥³ƒ´+zÐmRƒÄ§PœG’ÌÀ”w‚Ò®W³™õ2:ÆUÛ©VúØÔv ëäÃQÛš\œ’?sÚ”j¡™8Œ¤ˆmÁü9qÐtv>V#5ÕUG[AÂÓLÜÿ® ’œb œsà^±ý¼Öµz~Í>~fÛ[¨É9HQÿSáœ1S‘;uºæ€”pLF·”°=ÍŽàhûùG}¢ÆQÄšÌíÝÏ£]í’»¾Ñýæì3Qs¾©ô™ÛÎ fÄm½¸'wÁB”½üj ¼¯€Wf©÷KJÜÅ»¢Ù¦Kýp‚ ]÷îFV1YÆ(ÂkWÖ#WÝQÒ+Ǭ)5º‘°!ÿ^ ˆxËMÃÉÙA– ±"\¢B‘—3.r•]\‡à¾î‘®îU‹Fm°ä›áS]ºm~ª)€—‹€™‹¯à€]¶zD±òç(˜'Rfîlµß pðÜ ý“@>.ÒçgÛ+ºçó¢â<«FëcIÒ ã! ™Ej“ób¶Ÿ Ðöö ë^PµÝÌ$›G{µÔÇAs¬“ökóQS9] fP«]`FàC«¶=ØÝ‹#8Shim0‚40‚  ¹A$ ,’g0  *†H†÷  0„1 0 UGB10U Isle of Man10U Douglas10U Canonical Ltd.1402U +Canonical Ltd. Master Certificate Authority0 120412111251Z 420411111251Z0„1 0 UGB10U Isle of Man10U Douglas10U Canonical Ltd.1402U +Canonical Ltd. Master Certificate Authority0‚"0  *†H†÷ ‚0‚ ‚¿[:tî!]®aíV¬½ÞÞróÝ~-Lb¬ÀmHÏ‹ûa'ÌnÙU=9Të@;±»â…4yÊ÷{¿ºzÈ-}­YϦÔéNÚ®RêLžÎÆ™ Ngex]ùÑÕ8JJz“œ£…ÛÎú‹÷¢!-›TA5Wl¼)PJ~ꙩh§;Ç2ž ‡y»h™-~“RåöëÉ›ù+í¸hI¼Ù•P@[Ųqªë\WÞqù@ Ý[¬„-PRÖáókndO[´ë äaÚZðêäB×Äþ!Ù¹ÀT•BRrIdzÈl$ñp M¥ 2Ñ W¨M㯥Ž>C¡£¦0£0U­‘™ Â*±õŒ#¶eZ&Ž4Zc0U#0€­‘™ Â*±õŒ#¶eZ&Ž4Zc0Uÿ0ÿ0 U†0CU<0:08 6 4†2http://www.canonical.com/secure-boot-master-ca.crl0  *†H†÷  ‚?}öv¥³ƒ´+zÐmRƒÄ§PœG’ÌÀ”w‚Ò®W³™õ2:ÆUÛ©VúØÔv ëäÃQÛš\œ’?sÚ”j¡™8Œ¤ˆmÁü9qÐtv>V#5ÕUG[AÂÓLÜÿ® ’œb œsà^±ý¼Öµz~Í>~fÛ[¨É9HQÿSáœ1S‘;uºæ€”pLF·”°=ÍŽàhûùG}¢ÆQÄšÌíÝÏ£]í’»¾Ñýæì3Qs¾©ô™ÛÎ fÄm½¸'wÁB”½üj ¼¯go-attestation-0.5.1/attest/testdata/short_no_action_eventlog000066400000000000000000000000611452320553600246140ustar00rootroot00000000000000StartupLocalitygo-attestation-0.5.1/attest/testdata/ubuntu_2104_shielded_vm_no_secure_boot_eventlog000066400000000000000000001125741452320553600310610ustar00rootroot00000000000000)Spec ID Event03 0?p‹Û¯òfUµ@6GL  Ðüñ2¨ûõ¤á¥Œ×MÒ5}çP;[jýZy‰©Ž¾ m±‚.BÏ’4ö§ŠÅËIô›ÁÄ9?71a!‹¶ߊ÷¦ŒΦ‚ae‰¿ c0GCE Virtual Firmware v1žŠ÷Bqð@’U'Ár7i¬þ~ {tÞ£Lé´—U««èºÉ­R=ZÝìN/¢˜ã®hý'o §Mæ'¤­+{FñÔ (ë?^àU«Éˆ?,§Ù¾ßŽÈÈHüåª Ò/PÎxõ»ñ^ GCE NonHostInfo€WÍMÁ”BGZ¨'CHO;ªˆáB¸ Z¨'ÛÌûDÒ­žÏÚV½êb † ”¾Õ·¢{ºMØ Ï¤âÆõrb{ðmViÌ*±ƒXÒ{E¼cnÁ ϯ·@øG¦§K^®Ö·32ì5aßä‹Ê“Òª à˜+Œ SecureBoot€Z½”«ó>4§›=“ÓPçBØìØ Û»ã—fX…eÅ̘¢®¶äJ‘xÉñ“[ÒAóƒrD„» §cU<–w Ó¥æøàÁïÍòUZ÷Sú:jþCë{* ô¦øØäÝE–hó°àJaßä‹Ê“Òª à˜+Œ&PK¡YÀ¥ä”§J‡µ«\+ðr& ÒúÒˆ¤G—’[ªG»‰0‚ö0‚Þ  ÕJègƒ]ê0  *†H†÷  010 U newpk0 180821215115Z 180920215115Z010 U newpk0‚"0  *†H†÷ ‚0‚ ‚̹Õ|ømkcêÉbô “Éþã|,EÎ…RRH|ûC&¿ ¥‰°òÝÇ6èi•ªŒoТ#o4ÂO±žkÆú¸”ÁœŽp‡‘BÎi!“}ÚuŸ¿1 PÁï€#û¾;Vã ×Gê0¯Ô]©c‰¢ü9á–¡‡Ã=&²Ó¢lìÈ—×ÎÚ겕<³ÎŠÏÚ:Qˆ?%°K>ÌÝùÚÛQÕ‘š¡½ˆâñ´ñ³’·ãgæ­ŒjÜ'?ÜÔNlÁ½ïÞV*ÚY` yÓ©|WýQa7}ä·n•ðR›CžÜH<ͼ9Ÿ£èG F¸6Ü’³•¨ÎJãF#XK£S0Q0U˜P„Bó/Û—‚'(—t1F^`ËÅ0U#0€˜P„Bó/Û—‚'(—t1F^`ËÅ0Uÿ0ÿ0  *†H†÷  ‚Š¡R?ªç½°$«‹­2°Iý{4Ë;€v`=ŽÜÊkiÂ[”踜Œ,×¼¬}‚YõÄ.¢l¥ì˜ð1#6øË0ƒg::+b!`,ºõ.ù(nÊfpX(†gi„l'X%œPép¸`nT…J¯mE¦[4ü&M<á»$.yàÑȬ|Ù8GCk3PWãsž¦‡ÝÃâJüs{K ‡Çƒ 6Zêi‡@„ ,”€/=®=ËpÄ5¹>q²£Æ­Ø$?}`«o îzšÏuŸèL«ÍQ‡hX3²Ù¼8%*˜KEûg3›%œ?¬¤CDÌÍÓÈ ná€ðPy¶ÌBé.èZtÙÂviÀâ b&GØ[Šd}-.f‚Áb {l¦·"ZfWÂVµ‚ À§¦@“íy΋V—=ÞöÚ‘¿ ëW’³ÈBB7Bµ)C¥‹ß#(¤4“~2xˆ>aßä‹Ê“Òª à˜+ŒKEK¡YÀ¥ä”§J‡µ«\+ðrüÒúÒˆ¤G—’[ªG»‰0‚è0‚Р a ш0  *†H†÷  0‘1 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0 110624204129Z 260624205129Z0€1 0 UUS10U Washington10URedmond10U Microsoft Corporation1*0(U!Microsoft Corporation KEK CA 20110‚"0  *†H†÷ ‚0‚ ‚Ä赊¿­W&°&ÃêçûWzD] ÚJåt*æ°ìmëì¹ãZc2|Oã §8“ŽÆõà„±š›,çõ·‘Ö áâÀ¨¬0ßHóPšd§QÈ…O †Îþ/áŸÿ‚ÀíéÍÎôSjb: C¹â%ýþùÔÄ«â#‰p·¤Mì®åœúÂ×ÁËÔèÄ/å™î$‹ìò‹êÃJûC ~µG’lÜæ‰ëõ3ë*qåùƒ<ÿ% /hvFÿºO¾Ü­q*XªûÒy=ä›e;Ì)*ŸürY¢ë®’ïö5€Æìä_ÌvÍïc’Á¯y@„y‡ãR¨è{i£‚O0‚K0 +‚70UbüCÍ >¤ËgÒ[ÙU¬{̶Š_0 +‚7  SubCA0 U†0Uÿ0ÿ0U#0€EfRCá~X¿ÖNž#U;:"j¨0\UU0S0Q O M†Khttp://crl.microsoft.com/pki/crl/products/MicCorThiParMarRoo_2010-10-05.crl0`+T0R0P+0†Dhttp://www.microsoft.com/pki/certs/MicCorThiParMarRoo_2010-10-05.crt0  *†H†÷  ‚Ô„ˆõ”Ê*<û*’ × ÑñèRf¨î¢µuzª-¤vZêy·¹7jQ{döádòg¾÷¨x½ºÎˆXd ÖWÈ£_ÖÛÆÐiÎHK2·ë]Ò0õÀõ¸ºx£+þ›Û4V„ì‚Ê®A%pœkéþ×–å甲* Kÿ(){÷×|¥Ñv¹Èyí’œÂþßo~l{ÔÁEÝ4Q–9å^VØ–ô¦B³ wýòqVÌŸ†#¤‡Ë¦ýX~Ôig‘~òå ‹Š<‡„ëãνCå­-„“Žj+Z|DúRªÈ-»àRßøš=Á`°á3µ£ˆÑe ç¬|¤Á‚‡N8±/ Ňoý.¼9¶çæÃàäÍ'„ï”Bï)‹FA;gØùCYeË ¼ý’Oôu;§©$üPA@yà-O j'vnRí–i{¯÷‡ÐE­Sû0ª76aÚJi4ØhíÖÏl” ÓÏl"y­±ð¼¢F`©ÄÂ!‚ñýòèy2`¿Ø¬¥"KÊÁØKë}?W5²æOu´°`"S®‘yÖ›A†Tp²Þ 5|°4rº—`;ðy뢲]¢¸‡Åéöµ—%o8Ÿã‘úŠy˜Ãi·£ —øÊ®×ÄóÀuk4 µ™`ó\°ÅWN6Ò2„¿ž€ ¢œ'û¢a€`³"ÇÉr bº8Ã„Š”bù‡tņéÙTç)!³¥%A$¶62̯Z 5 Íbº¾öúà[î|<å(ó(yÓwŒ6ù»ñêóbB:؛Ȧ’ƒ­(!Åü7k ˲×:=–E£¼ÚÐgeoG db¡YÀ¥ä”§J‡µ«\+ðr@$ÒúÒˆ¤G—’[ªG»‰0‚0‚ø  aÓÄ0  *†H†÷  0‘1 0 UUS10U Washington10URedmond10U Microsoft Corporation1;09U2Microsoft Corporation Third Party Marketplace Root0 110627212245Z 260627213245Z01 0 UUS10U Washington10URedmond10U Microsoft Corporation1+0)U"Microsoft Corporation UEFI CA 20110‚"0  *†H†÷ ‚0‚ ‚¥lLÇE jK ¤À‡u CTdàí’} ²s¿ ÆJEa Å-–Óõ+ ûMI›A€<¹Týæ¼ÑĤŠAŠ\Yƒh2»ŒGÉîq¼!OšŠ|ÿD?2²&H®uµîÉLJ~䂚xwM °½öÓÓ¼ú+¥Q8]õûºÛxÛÿì –Õƒ¸é¶À{@{á('ÉúïV^æ~”~ÀðD²y9åÚ²b‹M¿8pâh$É3¤7ÕXi^Ó|íÁSçN°*‡caocYê²+y× agŠ[ý^­‡º†gOqX"""΋ïTqÎP5Xv•îj±¢Õ£‚v0‚r0 +‚70# +‚7øÁk·wSJó%7N¡&{ p€0U­¿C ½‚pœŒÕO1nÕ"˜ŠÔ0 +‚7  SubCA0 U†0Uÿ0ÿ0U#0€EfRCá~X¿ÖNž#U;:"j¨0\UU0S0Q O M†Khttp://crl.microsoft.com/pki/crl/products/MicCorThiParMarRoo_2010-10-05.crl0`+T0R0P+0†Dhttp://www.microsoft.com/pki/certs/MicCorThiParMarRoo_2010-10-05.crt0  *†H†÷  ‚5Bÿ0ÌÎ÷v ­hX5)F2v'|ïA'BJªm8HYUóéX4¦ ‚ª]­‚Ú€ƒA´ò¹ó]ñPù³U„B( ½²®QÅÀ¬—•!Ûüwž•s‘ˆÊ½½R¹P ßWž aí åm%Ù@@ÈΣJÂM¯šT½Ç¼¹+=I+2üj!iO›È~B4ü6‹ @À³š%u'ÍÉ£ö]Ñç6Tz¹PµÓÑ¿»tßÜ€Õíô/k/ÞfŒ°#åÇ„ØíêÁ3‚­VK-ñh•ÍÏðrð®»Ý†…˜,!L3+ðJðh‡µ’U2u¡j‚j<£%¤í­×®ËØ@Y „Ñ•Lb‘"tŒ=GD¦ä°›45±ú¶S¨,ì¤qȸºèDfäGTŽV³Ÿ˜²†Ðh>#µ/^P…Æ‚_A¡ô. à™Òluä¶iµ!†úÑöâMÑÚ­,wS%27ÇlRr•†°ñ5ajõ²;PV¦2-þ¢‰ùB†'U¡‚ÊZ›ø0˜T¦G–%/È&äA”\?å–ã…[<>?»GrUâ%"±Ù{ç*£÷Fà Ö‰ã5'bq¦ïÐ'  Y7`ø8”¸àxpøºL†‡”öà®Eîe¶£~iu’›õ¦¼YƒX¡YÀ¥ä”§J‡µ«\+ðrëÒúÒˆ¤G—’[ªG»‰0‚×0‚¿  avV0  *†H†÷  0ˆ1 0 UUS10U Washington10URedmond10U Microsoft Corporation1200U)Microsoft Root Certificate Authority 20100 111019184142Z 261019185142Z0„1 0 UUS10U Washington10URedmond10U Microsoft Corporation1.0,U%Microsoft Windows Production PCA 20110‚"0  *†H†÷ ‚0‚ ‚Ý »¢ä. ãçÅ÷–i¼!½i33ï­ËT€îƒ»Å „Ù÷Ò‹ó8°«¤­-|byÿãJ?5 pãÄçkàœÀ6uéŠ1ÝpåÜ7µtF–([‡`#,¿ÜG¥g÷Q'žrë¦É¹;S5|åÓì'¹‡þ¹É# o¨F‘Án–http://www.microsoft.com/pki/certs/MicRooCerAut_2010-06-23.crt0  *†H†÷  ‚ü|qQ¥yÂn²ï9>¼«\`ìß¨Ó éôö–…¶QˆfG¢°=*hw»‘Lb{¶ÁǺz‡4Kbz™éÊüÎJ7É-¤W|þ=ܸZúÖij…:ê³Ùnäi!7ÞÑöugÓ“W^)9Èî-áÍäEs[ÐÒÎz«‚FXÐ^³g¯l5ò¼å?$â5¢ uöV™Ôx,ÑëЈªñߺ~,c·›#!ÄùxlâX6+‘̤Ùò-ºù”@íEñΊ\k>«Óp* jà_GÑÕc 2ò¯×6*pZåBYqKWº~ƒð!<ôÁŹ“ˆE“†é± ™¾˜ËÅ•¤]bÖ c ½uw}=óE¹Ÿ—ŸËW€o3©Ïw¤bY~€^÷‡€f„Q®ß›¥|û^œå´ „£kV‘¹s@{   "¹¬^ÌQÑúä_ô:å@ɼ› B…%-•JA©xŽåÅN¦àñàßóœ|¨ˆÏÒÓzKxˆóŠ, c6ß—.ÖË­ÙÆ.˲×:=–E£¼ÚÐgeo .dbx¡YÀ¥ä”§J‡µ«\+ðrP4½šúwY2M½`(ôçxK0‚ 0‚ 0  *†H†÷  0„1 0 UGB10U Isle of Man10U Douglas10U Canonical Ltd.1402U +Canonical Ltd. Master Certificate Authority0 120412113908Z 420411113908Z01 0 UGB10U Isle of Man10U Canonical Ltd.10U Secure Boot1+0)U "Canonical Ltd. Secure Boot Signing0‚"0  *†H†÷ ‚0‚ ‚É_›b °d‚¬¾ÉâbãKÒŸŠÕa+]8ô·Î¹š¸C¸C—w«O pF ümÆmê€^Ò·f‡Þ mÐA—¨¥¯ cO÷|ÂRÌ 1©»‰]™FoUs¹viì×Áü!ÖÆçO½"Þä¨[-Û•4—Ö(K!LÊ»y¦Zùgæ\xE=m°Y&ÅWãN‚ºö,NÈ7Mÿ…„Gàí;|¼¯é§ oÃé£Î¾¦ãÍ<µX,žÂ`"79ÿAÁ)¤eQÿ34ªBù•xü-õÚŠ…|‚û7,k¥¨ß|U €.<°cáÍ8H‰è ‚¼ýÔh>ÙÝ”£ 00 Uÿ00U%0+ +‚7 0, `†H†øB OpenSSL Generated Certificate0UaH*¢ƒ ²­Zñ rPÚ3ÝÎð0U#0€­‘™ Â*±õŒ#¶eZ&Ž4Zc0  *†H†÷  ‚Š¡)· JÕÅý«%êÀ}âüj– y“gî%%äZöªñó‡^ñZ\Ë#se¹Þ"kÖIgÉ£Æ×bN\µùƒ@܇œaB"Ä*\NÅ£âàR²ëô‹+Ü89]ûˆ¡Ve_+O&ÿxëŒ]2ãÆE¯%› ÿŽïG £é‹7’’iv~4;’gN°%í¼^_´ÖÊ@ÿäâ1# …%® UìåG^ß[¼3ãÆõ¶Ù÷ݳ´¡1ÓZ\]}>¿ ääè´Y};´Œ£µ £¹>„oŒ!Ã9¡YÀ¥ä”§J‡µ«\+ðr¸œ½šúwY2M½`(ôçxK0‚ˆ0‚p  9\§’zPÂ0  *†H†÷  0A10U Toliman10 U Cisco10UVirtual UEFI Root CA0  180403174734Z20990403161930Z0?10 U Cisco10U Antares10U Virtual UEFI SubCA0‚"0  *†H†÷ ‚0‚ ‚¸M†Ð!¢+Ÿ ¦w˜1\WÀë>“aòe~Ñæˆ"Í¥‹O/øKh‘ïLQÂ÷gôF§‰ýBá¤ÎKj)g@ÈgìéàÞüðâ­EðÒ¨W»‹ £ŠsUãWÓüÂÄêPú‚IHf±x+¢GUH%Ìm".a—•¯›.MX¶~xùú²['Þ}¢¾ ¬sì—°^ííå¥u?xàqÎ/΃íS10˜Næù¢ˆˆ¦#| ·T:•í^y^Nþͪނüö–qNII¹Óé°«×*G·S0'|Üf˜ oÑ~õ=>Ô¢jˆY//=ÈÆ(ÞBþÙR=$Âü@˜öv¿Œ»e£9070 `†H†øB0U%0  +‚7 0 U€0  *†H†÷  ‚W¤`L)éò}k\“ÛÌlŸ?iHšuÞdóƒJ ©&!îéV]á>ÙuËÌ¿Mäè‰=~B‡@ÃÕàqyÜláqbǘÂË' /ŸÌìú‹²ó žóòÃÉŸÛ%“¤Í»åŽô×U¨´uA1ýN] Â¬ÅÞFçÜÏÕèG“Œ2ÍDÕtÇ0šW¥VÐ~Ï´ôó)ùÛ›SÒ½/­ju&Edºº(–‡Ž·ðyWúzd÷,Nïgyj„½½šúwY2M½`(ôçxK세Kle¥ ©¾q–R0! bÖÓ h2Û²Ò à'%'ß¶=IÒ•r¦ôL½šúwY2M½`(ôçxKo¬êÏìýN0;tô€ €˜âЀ+“oŽÇtÎ!ó†hœ½šúwY2M½`(ôçxKN: [CƦ»Ó@O4=Ï9bgΔøµ.#©Ú’ ½šúwY2M½`(ôçxK+™Ï&B.’þ6_¿Kà 'lžáKzoÿDû/ki™9½šúwY2M½`(ôçxK.p‘g†¦÷sQ§«pµWÆ2.©#²¨Ó¹+Q¯}½šúwY2M½`(ôçxK?ΛŸß>ðTR°ù^ä·ðmt:syqUŽpjÎ>s½šúwY2M½`(ôçxKGÌa'⚆à:kï,ÔøÅZmkÛ6!hÃ,ã*Zß½šúwY2M½`(ôçxKqòoÒ"I~T£Fb«$—üÈ wõhéãÙ¿Ëýcu½šúwY2M½`(ôçxK‚Û;δöCΗÃч͛YAÍ=èXo+ÚV7W_g½šúwY2M½`(ôçxKŠÖHYñ•µõ¯ª” jag¬ÖzˆnF“dr!ÅYE¹½šúwY2M½`(ôçxKŽ¢‰Ïç «seË(îQíÓ<òPmèˆû­Ö¿€H½šúwY2M½`(ôçxK®ë®1Q's핪.g9í1©…g0:3"˜ø7 ©ÕZ¡½šúwY2M½`(ôçxKÄ ½¬Gu­ØÛ’ª"µ·ûŒ”¡F,餹]Š3ˆÂü½šúwY2M½`(ôçxKÆÁ¨±î*(µ¨Lƒ×É‹[ '(aëæ’Â–½šúwY2M½`(ôçxKÉ3f¸çùƒ—TÉ—ñ së&Ø¡ ¹ã½¿Æg«Û‹½šúwY2M½`(ôçxKdW[Ùxš.­Vö4R¯kø ùDxYuéðN-d×E½šúwY2M½`(ôçxKEÇÈ®u Ï»Hü7R}dÝdM®Ø‘<ÍŠ$ÉM…igߎ½šúwY2M½`(ôçxKØûLž.z‚%ekK‚s·Ë¤°>òéë à )$졺†½šúwY2M½`(ôçxK¹*ò˜Ü›xÇt’ÖUq ×*­£×{åF ä2xïnM½šúwY2M½`(ôçxKᮃÀ.o(XÔëÑw#´õê5yÕD=ìÅù<½šúwY2M½`(ôçxK9ÛÂ(ŽôK_•3,·wãè@Û¦€cJ¨õɱ½šúwY2M½`(ôçxK2õ” ¢Ø¢ÁEæü‰df(ÿÌ|zBÊå3})Ä ½½šúwY2M½`(ôçxKÔ_Ë£–®ó>èöì®X¯èGj( &üqö!}ÏIº/½šúwY2M½`(ôçxKK†h¥Ôe¼ÝªüÿBOËЮÎ2üp¨>‘`èŸ ½šúwY2M½`(ôçxK‰óÑöä…Ã4Í •ãÍýÀq±„˜T„zDÜUHâÜû½šúwY2M½`(ôçxKÉì5ònUšÿ´ âëÞT5L5©˜`[Ï—-U½šúwY2M½`(ôçxK³å4¿kW†—3“Ÿ$¶k¤eã^‘°6**ÍépI½šúwY2M½`(ôçxKŸcíWÔ´.ñ f±D¦[¡¶WùK޲ðÄÍ`Á½šúwY2M½`(ôçxKÝY¯VDãŒcûà…0 ÍwF*!’Y°[ÂYæs½šúwY2M½`(ôçxKÛ¯žm=[8¶…S0J¼ˆ‚~¼ø ¹Çá—ͼX"Í1l½šúwY2M½`(ôçxKeóÀ „Ób¹r.˜÷^^™ln“O{+.kæÞÈ콚úwY2M½`(ôçxK[$Ž‘=q…==¥®ÝšKÅz‘q&W8û_Ë-†¢ñȆ½šúwY2M½`(ôçxK&yeãAòϨƒF 5Vª¯w§ kÄ„É0tl÷µ½šúwY2M½`(ôçxK»ÑmSco##§¨o=ÿ–Ÿ„ˆÀWKÂׇþÉ?½šúwY2M½`(ôçxK à!ö|~ø_Ní6¿p’8 <#Ê‘ýC ”° ½šúwY2M½`(ôçxK•ŸA7ǰÒvq•åos€}:Üøöç¿-M™0_‰½šúwY2M½`(ôçxKæ!jÊïd@¥Uì¾Ù@±¥òVší’•a7®XH.ñ·½šúwY2M½`(ôçxKnþþ [G‹{”LÓ¨¬¢Ì¤ ˆˆâŸŠËX$׺°½šúwY2M½`(ôçxK®LÔzAǃÜHóBÀvÂÁo4ôÒßPÑÊ;µ­…½šúwY2M½`(ôçxKØÔæÝöä-t¦¥6êbýä) \ž\6•£Bïµõ¤½šúwY2M½`(ôçxKòw¯O›Ü‘ŠèŸ£\Á³N4˜L®—e2,<°IWM6Pœ½šúwY2M½`(ôçxK ÂLuëïV¹ñ:¹Þ`âì¡ÄQ4⻳lö T›#L½šúwY2M½`(ôçxKƒXò¥W-pYµÈcPU(’éEbo_Éʬ÷½èW¤½šúwY2M½`(ôçxKºßõäðþ§p¨û"äÄ8!ã! õ-OtÝPñÐ9¼½šúwY2M½`(ôçxKÄR«„`sßZÎ%̦Mkz Ù0ŠeëR@ãÄëÊ©Ì ½šúwY2M½`(ôçxKñ†>È·ô?”­û ‹JiIzŒeì¼*Uà»Bw+ŒÜ‘½šúwY2M½`(ôçxK{ÉËTcε^¸ºwѬ҃Ä?JW`<Áò,ëÅy½šúwY2M½`(ôçxKè9]¾WèQx´ºõ¢Wðn‘!¦|Y_jâ%ý½šúwY2M½`(ôçxK´ÜÊòÈϧ´“Žqþ+–‘ä!oÙT(g-l~s½šúwY2M½`(ôçxK>Î'˳ìD8Ìå#¹'Äð_Ü\Y:7fÛ˜L^Cz?ö¡k½šúwY2M½`(ôçxKhîF2ǾfÈ>‰Ý“ê¿E´ÂÇ-}ÇIš¢ C½šúwY2M½`(ôçxKâK1ZUqH=‹s³-áMáë.«!ý-œ1Ÿõ^нšúwY2M½`(ôçxKç :´ìˆUì¥)7ØKZÂOˆ&kRpçì´ª%8½šúwY2M½`(ôçxK~¬€©ÈLÔ¯ìc‰ÙN±h¨UyQ¤Õ9°q0(U+kŒ½šúwY2M½`(ôçxKçh1!êg÷K¼°ÍÅåp,ŒÅ_¶]p-û©Hµô½šúwY2M½`(ôçxKÜÌ<áÀä°±‡Ór úGõÂoW£Y¾{'€N¬ºÄ½šúwY2M½`(ôçxKWÿq*䉳t“Àv§Í©a)بýhÒ¶¯c91]½šúwY2M½`(ôçxK:‘ðùå(¢™L}“ ,^áLèáÈ0Jä•­ÅŒÄE< ½šúwY2M½`(ôçxKISyl›òQ «¥³Õ~+…××d4ìuº£…t彚úwY2M½`(ôçxK¨²Éuë«§ÛÞ^éiÀêî*1Ë‘¨gV¦·p½šúwY2M½`(ôçxKŽSïÜøRÎå¦é)1¼Bæ<ÓöI̧èrRäY– ½šúwY2M½`(ôçxKŸ¤Õ?Ô>ÊÿBº~CS%+~^rµ nÿ€'ÖmC½šúwY2M½`(ôçxKÓrÀÐôýÉõ.ž#üVîrAJóPÐΦÂj5¦Ã!z½šúwY2M½`(ôçxK\Xj…é7‰EpÔùëh(¹|AË›¦ÓÜÌ_RzU½šúwY2M½`(ôçxK€N5Lch»'©®ŽIŠW+)4%šœOS¢rTI½šúwY2M½`(ôçxKöJ)”Šˆ¾ÿÛ^ §7 Ï ÙÎkÏŽd !1«‡½šúwY2M½`(ôçxKØ~q4Tao[ׄšµÁq*¸O4”xì*8ùpÀ‰½šúwY2M½`(ôçxKë[­ÒnO®eù¤#XÞï|å,À_»Çgvæ˜*½šúwY2M½`(ôçxK»"‰ééM ÿ?bQj°~—›,lïâ«pÆßÁŸ¥½šúwY2M½`(ôçxK (ð@‹÷%ægØq8¨î¼R–-(Gñn5‡;A¶­½šúwY2M½`(ôçxK ùŠ©…Œ sø›§~‡ìoYlIPû‹º€¦/»‘K½šúwY2M½`(ôçxK uê pê¤Óót$mµOÇ´>Yj53 ¹ÃkOÙur^½šúwY2M½`(ôçxK Q×oÄ“Iv]¨†‚Bk,þžj¤òrSê´2ã§½šúwY2M½`(ôçxK£¢šÐQ0×þ[ôÒYecÍí‡@–ªÌi“*.IQš½šúwY2M½`(ôçxKw0´/þI?é¶%—Í+o4Ójõ“0ñ¤/” ½šúwY2M½`(ôçxKáqZŸÏá¤DÎÿ…†ž´"3 ÀK1L)]m§ž½šúwY2M½`(ôçxK‘¨Ôså(¨x#½bæUß®Tú+úrýÀ)†Ö¸½šúwY2M½`(ôçxK‹XÁý¸Ú‹3Ìî_—:÷4Ùóã?]±W<+ ˆ¨ ½šúwY2M½`(ôçxK‘†ïß^òÞ‚Eº®4††º 5ÿ=˜eÁS|퓽šúwY2M½`(ôçxK' „²†ñc°jªäë¸ßøÞ} ‚[ˆ9ÿf'NÿG½šúwY2M½`(ôçxK)̤TN£0Ö‘Ç„i\œk"¬{[‰Ë×(Ñ@꽚úwY2M½`(ôçxK+"˜ê¢kĤUŠé.{°äø\óKøHýö6ÀÁ¾Ä˜—½šúwY2M½`(ôçxK-ÏŽp#ÑèáE=hÖì0Ù¾ÙL¼¸ÝÁ̬½šúwY2M½`(ôçxK1*Å[PÀ›0³Ì“¹”¡>î¬Tï‰/ÄG»½–¡½šúwY2M½`(ôçxK2­2–‚›ÄmϬ^ÝË¿,í\ø;"Ïœn`ǘԧ½šúwY2M½`(ôçxK4 £+X3Ž+V¯0 ©ßÖ¹Ò'àâ£IX±Æ%ž…½šúwY2M½`(ôçxK6.Ó ±à’(1©o ÏÞa‰Sæ•Éï.°ºÃuP½šúwY2M½`(ôçxK6z1僈1­,FGˆjlßò決‘ ÿ…Üz‡®›^˜½šúwY2M½`(ôçxK7e×iÀ[ù‹B{5;!7褛o… ñYíj†xj¦4½šúwY2M½`(ôçxK8mi\ß-EvàÊÌõäžxÚQ¯™UÀ¸úv7;y”³½šúwY2M½`(ôçxK:Ot¾¯®+“ƒ­‚Ò3¦Ï=³Çâè—¾ïBUúúwY2M½`(ôçxK:çlEÊpé Y˜Bb-ÒQ¼¡ûæ¹Å.Ás°5½šúwY2M½`(ôçxK;èçë45Á’Çi„gˆ™AÑöÏ QL¡i“OsY½šúwY2M½`(ôçxK>9&ð¸¡ZÕ¡Ag»dz„<=C!ã]¼DÜèÈ7A-(°½šúwY2M½`(ôçxK@ ÆmY·°”©ã ¦½:ÿ0WƒçY/B¾_ôº½šúwY2M½`(ôçxKA…‚m«[¨4{x¢+_š upÊ\“§MGŠy=ƒºÄ˜½šúwY2M½`(ôçxKAÑî±wÀ2NÝeWó„å2Þ õšDkï³Q¼%w½šúwY2M½`(ôçxKE‡kMØaÔ[:”€tz]´ZH²§)A ¶A/Їé]½šúwY2M½`(ôçxKFg¿% ×Á k„tÆͱßdŠXso¿WÐ]ou]«gô½šúwY2M½`(ôçxKGÿc±@¶üíy1æQÚ[./]®ô=ÂûÅ2±½šúwY2M½`(ôçxKWæ‘:úÌR"½vͯ1øíˆ‰Td%Stï z‚×õšÓ•–½šúwY2M½`(ôçxKXú"q!ÇmížcÈ~:e3î öð¡¢?ÄE›Æ¼ß½šúwY2M½`(ôçxK]šË»J}KhRßYpâÎÖoö"îœÐíØAÌ­½šúwY2M½`(ôçxKaÎÄ£w¿YÀþ®ãp4¿—Õ¼nâ:ߺæãõû<ý½šúwY2M½`(ôçxKcW´E6,Ƙ KĶ(â=¾$¶élŠãܰլ½šúwY2M½`(ôçxKe²çÌÙÃ1ßRßsÊ É2ÒŸ™tÅo0‡²Ý1G½šúwY2M½`(ôçxKfª íÂ8MœB]9'æíJ]@ÅçÍM¬ˆõwòñ½šúwY2M½`(ôçxKhsÒö)½RéTîÿYwªƒgC™—bÿ!,”3Æ—½šúwY2M½`(ôçxKm»êÒ>Œ† ø´tûü¥ Mã⋈»ÌÜGG“N½šúwY2M½`(ôçxKmêÑ2WßÃÌÆ¤³pº‘u_éàìAP0”.Z¼Gð|ˆ½šúwY2M½`(ôçxKp¡E ò­9Ui­ þ±ÙÁ%2Né ì9ÂXˆ4Ô‰-Q«½šúwY2M½`(ôçxKrÂo‚|ë’˜—˜–Æ®tÓë϶]A²fÉ ¾‚½šúwY2M½`(ôçxKxd!ˆ¨´±sÔ¨õì”Ø(dqV ™5zXbK7u ½šúwY2M½`(ôçxKxƒƒ¤Ç3»‡Ò¿Qg=Ç>’ß«}QÜqV'®whm#¼½šúwY2M½`(ôçxKx´íÊ«ÈÙ > â€,®´ðž#£9LJÌn‡èóS•1½šúwY2M½`(ôçxKI̳ 2;z±“ÉU¸ÇDð¢·\1I^`pP'½šúwY2M½`(ôçxK‚¬ºHÕ#lÏ÷ešüYMî+Ö.ñ£ ›P†(Ï4ô½šúwY2M½`(ôçxK‰Mx962˜Ì‘Zèt.ó0×¢f™ôYGŒò,+k²…f½šúwY2M½`(ôçxKŒI×Wåª!ÁcH#22—ØhòX‘e)ïÅ ïp½šúwY2M½`(ôçxK“Ö iYevåÜFKá*…úR€¶õ$Ô¡ÃüÉÐHÏ­½šúwY2M½`(ôçxKcõûÅåz¶Þl”ˆ` ár±vÕ«WÔÈŸ`þ-⽚úwY2M½`(ôçxK‘ej¤ïI;8$ ·&2HäâÖW¥ÈHˆ ¶[s 2ûS½šúwY2M½`(ôçxK‘——¿Ž[Æ„9¬Äcë¸ú«ývMËè/;©wÊÈÏj½šúwY2M½`(ôçxK”pxù|a––Œ:霚]Xf~†ˆ,öÈÉÕ‰g¤–»zô<½šúwY2M½`(ôçxK–äP”PÓ€ÚÃbÿŽ)U‰ŠåX…Ò ‰Â{¢©Ð ½šúwY2M½`(ôçxK—ƒµîD’éè‘ÆUñô€5•­E<b:ðþ{òÀ¥x…㽚úwY2M½`(ôçxK—¥ DDb óŒØÆQ,¬šuýCzáäÒ))€va#'½šúwY2M½`(ôçxK—¨ÅºÖï»]jÚNºG-ÄÆÍIrü]ã!4/佚úwY2M½`(ôçxK™( æìŒAÚ®KØ«Hõ‚héC¦pÓ\¥â½Í>|L” r½šúwY2M½`(ôçxK™-5š§¥÷‰Òh¹L¹HZkæCb°í´DÌ|9d{½šúwY2M½`(ôçxK™T¡©U豉«ÊAK‘ö l@¨ko>óh݆1½šúwY2M½`(ôçxK›¯Ov×kõÖ¨—¿½_B›¡Mà‹HÃîv“ ‚ÿ8‘½šúwY2M½`(ôçxKœ%ŸË0_Ç9~Õu™càïk6ä WýsnkЋŸu½šúwY2M½`(ôçxKÒÜ·/^t'òéà:±…£@<ö©¤y¤ÛÙ~"P©½šúwY2M½`(ôçxKžÓ?¼ À2øœ¢Ä«4íÃ:E¥ %!£µ‡j£ê,½šúwY2M½`(ôçxK¤Ùx·Ä½¡T5Õø¹Y.Â¥­ûê{­j5ìµ0”d/½šúwY2M½`(ôçxK©$ÓÊÖÚB·9›– • oö±«¥¸s°Õó î!s´‹l½šúwY2M½`(ôçxK­;å‰ÀGN—Þ[²¿3SIH·k¸vßÜX±þ×gµ¡[ü½šúwY2M½`(ôçxK¸Öµç…{Eƒ|{ãØV­ë—Ç)°fZ=G:KëQÜó½šúwY2M½`(ôçxK¹?™Y‹ ú ¬Á,üü%hy?nwžy^m|"Su½šúwY2M½`(ôçxK»Ú3»cœ~€m°VÉŠSò/ïû äm®Iš½šúwY2M½`(ôçxK¼uùÿ2\µ™žf»ÔOJå7¤/ßï5SHãf⽚úwY2M½`(ôçxK½Ð&éØWÓþu¯Áp*)ð´öýö¢²\—©ÎŽšúwY2M½`(ôçxK¾C]÷Í(ª*|´üsG[wå«ó’÷k|vú?iŒ·š½šúwY2M½`(ôçxK¾÷f;åêM¿Øhn$poLûÍg¦Åfí”Î ÄDp½šúwY2M½`(ôçxKÂF—YÁ”~ô¶_r©õ³¯‹onr{h» ‘8\¿BjнšúwY2M½`(ôçxKÃP[ó쥬äÇk‹Ñ 9 eÑóNu¸£^ãÆ›–½šúwY2M½`(ôçxKÄ-Ç Ï^Œóû‘ýòˆ@!­ƒl¦Šß,»y•Á õˆÔ½šúwY2M½`(ôçxKÆd¥¸9ä¡gBR~jÎ<'oÒn4ÇÐã"½šúwY2M½`(ôçxKË4¯ë tÄ¥ˆ³nº¤A–èÒú€Ü¨Á8rÈPyk½šúwY2M½`(ôçxKÌŽìn¹!,¿‰zZÎ~оìáŸmï x•‘ËGñð„½šúwY2M½`(ôçxKÏ¢CÁÍ.<Œë~p‡ÎËûƒ%»ùз y­óèA(½šúwY2M½`(ôçxKØšÑlHÔû¼TKúøg f ”HåK¿òpNBˆ½šúwY2M½`(ôçxKÙfе'…g†Á4µä½Û÷$R;is"š¹*¡¥M õ½šúwY2M½`(ôçxKÚ5`ý 2µLƒÔòÿ†Ò“i¬òÈ–ø¯§CkúFU½šúwY2M½`(ôçxKߪ´ƒ‡©áÔÆR(œ¶«á–Èô³–Çä»Ã•Þiwö½šúwY2M½`(ôçxKß‘¬…©OÍ ûU½|¾ú¬¸Åîs—þ,ÈY„Ež.¡N½šúwY2M½`(ôçxKàQ·ˆìºí¥0FÇjö•",aW¸ÄÁ¹ÂÏÆ_F彚úwY2M½`(ôçxKãmüq!Âãšêˆ„ž(E«2ooçNS›~TØ61½šúwY2M½`(ôçxK㘑ô‹¼Å“¸í†Î‚ÎfoÁ[ŸËý+ºÐ¨›ôÇ¿¿½šúwY2M½`(ôçxKæ…oy™-ÉO¢ô2—ì2ÒÙ§o{æaÆ¡>ü;ÍõȽšúwY2M½`(ôçxKêÿŒ…ºM[k€FõÖG×yºÚwhæIÐGÿ›f ½šúwY2M½`(ôçxKfIa §OjÆäß»)¢à®;Š#(Ž~.r½šúwY2M½`(ôçxKî×àïòíUž*yî6™b¯;™‘1ã ·ýTo® rg½šúwY2M½`(ôçxKñ´öQ; TJh­Â‘ï¨ÅŸB ¥Ü²> Zú~ =½šúwY2M½`(ôçxKò¡m5µTiA‡§ @Êh)Yôó\,àê¸ýd÷¬*¹õÂJ½šúwY2M½`(ôçxKóÔaÅé•@?É|¢Ø©ËâpY}2ºßÖkwI_”½šúwY2M½`(ôçxKôŽmØqŽ•;`¢O,¾¦ •!Þ®gÛ%B[}:Îô1³[ôÀæ‹Óµw¹«á©ÏñËßTiÊxçE (QsC>RÅÂR™äs ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ 9CA·,Ò'ÅÆ°~ø ߨa6Ä)+ŽWes­~Ù®AŸX´¹qÉïü`á­Ÿ‰ð€¶ ëïp®$Ùþ‘=ÐÆÒ´àØ ÀI AP“Ç á«¡õO‡®wG"1Ëôí@¦„vÔŠFQUã ¬uŠôlž¨øc%CÄD0mÐlÊžüŽÏ9l0•ô{¦“¼ðaèuŸÁ9‰:aßä‹Ê“Òª à˜+Œ BootOrder€æú/±B3È®ÎÜËZv-hÑow´ ºÌ}¦æ™É>2ù?4ÄU“¢¡çÕk6vfÙØ Á© ›*ž'B‚"2;Q÷­¨ÚT¤Hó-úXj‘ }¥%€à¿†XûE“ªëA¡–€z‘h¦aßä‹Ê“Òª à˜+ŒvBoot0003bubuntu*(PaïœNLDˆ9Ïq±% \4\EFI\ubuntu\shimx64.efiÿ€"¤öîšöÛ 5(Þ¶Ktµ‚ü+ 1—¾0¡` „ä½J¡T¿µFÏ.lö _Œ6*“ #­ Rañ/4 ½ŽFv bÖ´Õv¤ñþ¡ÆKÆV±Òެ÷zæégÅÒ©‹út˜naßä‹Ê“Òª à˜+Œ>Boot0000 ,UiAppɽ¸|ëø4Oªê>ä¯e¡!ª,FvEƒnжôf#1ÿ€íÛèÄA+ù˜‡™Ô{ãÚ7ô ¨°ex,ÿ¾ÿÝhŒõE |–0«fe×*©%|òÛ6 œ o o½6Y?WÀ–:Ø9…qM–t–NDrG([Æ C(nàm¥ «ˆõ»/Kžœaßä‹Ê“Òª à˜+ŒlBoot0001UEFI Google PersistentDisk  ÐA ÿN¬ŸYM…âR,Y²€1—‰À=^—§t®Êì’ôŸ ¡:‰‹ƒf4¦,açÎÔêZï½®ZšÚ9¬¯„—¬º €¡Þ|Óׇdz,xEÊx´}Ùö£3Q®'àcsD[góÙDó¬]¦4KËøiƒaßä‹Ê“Òª à˜+ŒSBoot0002!VirtScsi(0,3,0) DiskVirtScsi(0,3,0) Diskÿ€ÍÛE1¦ìA¾'Sº&7Öå÷òV =gr´øNÔu•×*,L_ýõ»rÇPâo*®âÆV3º w Ú²1+NW¨M†Z!å²îgz!*Ú ˜˜€xÓ×@ö4kþ º©8Ê Cšq(Calling EFI Application from Boot OptioniÊxçE (QsC>RÅÂR™äs ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ 9CA·,Ò'ÅÆ°~ø ߨa6Ä)+ŽWes­~Ù®AŸX´¹qÉïü`á­Ÿ‰ðiÊxçE (QsC>RÅÂR™äs ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ 9CA·,Ò'ÅÆ°~ø ߨa6Ä)+ŽWes­~Ù®AŸX´¹qÉïü`á­Ÿ‰ðiÊxçE (QsC>RÅÂR™äs ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ 9CA·,Ò'ÅÆ°~ø ߨa6Ä)+ŽWes­~Ù®AŸX´¹qÉïü`á­Ÿ‰ðiÊxçE (QsC>RÅÂR™äs ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ 9CA·,Ò'ÅÆ°~ø ߨa6Ä)+ŽWes­~Ù®AŸX´¹qÉïü`á­Ÿ‰ðiÊxçE (QsC>RÅÂR™äs ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ 9CA·,Ò'ÅÆ°~ø ߨa6Ä)+ŽWes­~Ù®AŸX´¹qÉïü`á­Ÿ‰ðiÊxçE (QsC>RÅÂR™äs ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ 9CA·,Ò'ÅÆ°~ø ߨa6Ä)+ŽWes­~Ù®AŸX´¹qÉïü`á­Ÿ‰ðiÊxçE (QsC>RÅÂR™äs ß?a˜©/Û@W-Ä=×HêwŠÜR¼IŒè$À¸ 9CA·,Ò'ÅÆ°~ø ߨa6Ä)+ŽWes­~Ù®AŸX´¹qÉïü`á­Ÿ‰ð€ïˆUÓù{)nª©cø‰ ØtÅ€ ñ®;·7ëOT?yq÷é!½ÃÌT°ŽþÇÊ*ç¦ha „90«ê„ Áç8m,*e Ffå½ñºP²Kz„€‹o m›º¤ë½]‘úô²)äEFI PART\ øfÿ_F"Þ_FÕÍ•“ èê@‡§‰xËõe€€nà‘¯=ƃ„rGŽy=iØG}䮦Cdéå÷MšÑ2žPó<xÞ_FHah!IdontNeedEFIb ÅÌÃÓH¸9>l¸­ê}ÿ'(s*ÁøÒºK É>É;aïœNLDˆ9Ïq±% \(ÿw€"ß@Öã-G!ñ²@k+J;°ÊêÕ be·2°³ó0¼Ñ„3tåìnÅ®ò|Û—¢=®¸X »õ& OIÚYðœÑe#´M².ƒØ¶ñFVÓ°xÝEG«QwüxÏUx7o_›¸!œ@Þ½Ð| ÐA *(PaïœNLDˆ9Ïq±% \4\EFI\ubuntu\shimx64.efiÿ h¼ì`åÃòûÝš©ª‘Ú’ü‰?) /k VGd̦t^Í—‰Žtí8‘ÇÆ<æñ}È&J 3Wêe_ ŒªÂeÏÕè |Ç%O£ñåê4Z‡<÷aG*/#ñR—õ\þ$MokList â„¿Y£mêWow(c “tiTò¾‘CëKvpas×Ù¦Œ2çÉt°ÿ\í‰`9'(hd0,gpt1)/boot/grub/x86_64-efi/fs.lst ÿÒ9Œñ R2””Ö:Îëòš vo8©I'þ›{Áè ð6>wŽÆèúê'.uÓüC ÇÐåAe°Òj`Ö;‘Ntw‚]^͇„ 6CLkÙVrTA¸*f¶X6½8úÔ+(hd0,gpt1)/boot/grub/x86_64-efi/crypto.lst f·&ÆÖKÁ ӔЕ(õꔓŽô FøˆÅ/6ºù¶-`¼Bj1J­ZøjCb©%¡ßœ €$ýMñêýkº6Å–Ã:ûµ'ãkXÁŸ­ÎÔ{È®’øžóÊï#F³½T\ýØÞ-(hd0,gpt1)/boot/grub/x86_64-efi/terminal.lst „¾åh¯.2jÜãD+çÕ ‡M>æÕwm„tüºívÍÔO2W-„T3ïq84~†m} «ŒS¬ÌGÿïUĶr[KÚÇëcäí~ÂÕePë —JåFµß¶±¹ÆVŸG7­š×»3grub_cmd: configfile (hd0,gpt1)/boot/grub/grub.cfg l— 36A‘jQyÕ¹ú÷z¢ûä ê™U–UÖ¼d¦“qjW÷Ù7Ú¢ÜleÓ†ª!þÑ? 膸ÍfҜʢܳ´˜ÁoÅìuæ’ }¡œ}Ú5¿ù¯ÅAý_dÒµ_;¾ú ˆ(hd0,gpt1)/boot/grub/grub.cfg >\×êÜ.+/•mAù ãs/¸3 ~+4“º£ù䯍6(-fµ…V’îDÔoâ ÛÁs V»Í†G¦å¿çÈqo6Îÿô¬¡´ÃïJÙôzlîh»ƒätf0¾×ÐSá*©u.grub_cmd: [ -s (hd0,gpt1)/boot/grub/grubenv ] ²~¾U…1—›dZBDµ^núÛM® .B4ÈQÝòQ°ÿÉ5î¹k{ïÔò߆šVâ‚ÞÂ?À d7>wÆ·ªÿPè¹e>¨Q×dƒ¥;Aþ×IìöÝðèÔŠé6ôvëU’…]¥(hd0,gpt1)/boot/grub/grubenv wÆ·ªÿPè¹e>¨Q×dƒ¥;Aþ×IìöÝðèÔŠé6ôvëU’…]¥(hd0,gpt1)/boot/grub/grubenv ´é›@ÒÝÜßhèªCžÝ^ºËÿÉ Ò¹)ƒæjÿ™˜/å¯Uàù'}Àø‡™4á{~AVž -š‰ù `îGd‹mèl,x@²kÓH¾tÃjàÈ>ˆ˜‡þ!*Cݽ«]2Fgrub_cmd: [ = 2 ] ºE+ð ˆ(³]é‰À…8 ‚¤¡NC¤÷a®c(] ðZñ9ò`úå{, szó8+ ®aÄ[<%Èœê?}ÞädŽw`†÷Ö/´¹ÁÕaH¡¾¿Þj9SDV{SŒmðmžgrub_cmd: [ = 1 ] q ¿#|š½©A2H¾Ç°û Î$¼¼ µÍG3Œ ÇÕõDmy“nD: –±’§½e ".%på/r»™óï—ËuÔÞ:TUƒêMfV€g?t»'ÐÊ\³µŠ%ìxÎHQgrub_cmd: [ ] u@‘ E+»î0«â‰¯—>Í×àïk :‰@¿&u}ó6Œ¶Ô\òuo2>uÚöš—ÒѼX kö$/ްÊrÆã¥ÔƦ.XXDdèF–Íg0nòÛŒö%•-_ÙªÞý9G—@grub_cmd: set default=0 õ°gåœ?g±›ƒo¾é複¡œÝ Eh6·X1¤-dZµ40/¹÷B­ª7·ýáR!]iâYû ±øÐ6®ý2ÎwêBn{=®ãxÝy®Ú–;,S‰‡‡–,éêåWÌéJgrub_cmd: [ xy = xy ] ½R å eüõÂÑ*‹è'~C€# ñ}MûK—ñbFc,!±¬!%É\ˆ™î埻46U †a•?QŒ‰Œ¹@|ƒ¦Tý¯˜Ò]™ËÃÑRUµ2ºÐD÷¦;)aîÑ龬f#grub_cmd: menuentry_id_option=--id bHY›® x̽¡…í/΂íAâ— Jð»7 ž;y‚}àL“^2Õ+R€GküPÓm†^ •-Î9©âƒî{=ï¶dü”*•˜½‹m ©„;(xnÇÂk¯¢Œ <ûˆÛ·µh%grub_cmd: export menuentry_id_option q ¿#|š½©A2H¾Ç°û Î$¼¼ µÍG3Œ ÇÕõDmy“nD: –±’§½e ".%på/r»™óï—ËuÔÞ:TUƒêMfV€g?t»'ÐÊ\³µŠ%ìxÎHQgrub_cmd: [ ] }ÂrÚ°╉a»™¢ãnÂJ ß$ñÊæ´(ýЛÁKß%_“ð]VÃw$…–÷=_ \ÓLîœâL¦ä¨ËFTûÏåŲòÙgo„Sèšiìô¡S°%ÿ{¤°:.*!grub_cmd: terminal_input console ^ Gõ4± ÖŠRU@æ þ×É0“J#'Ÿ¡w£˜‘ͯlÍ"¼ÌéjÍÑ ¤}T"ï "F¥[Äæö æôªÜ ]^€ºÎz´€¬“ &Ñu²æ‹£ iL"grub_cmd: terminal_output console ºE+ð ˆ(³]é‰À…8 ‚¤¡NC¤÷a®c(] ðZñ9ò`úå{, szó8+ ®aÄ[<%Èœê?}ÞädŽw`†÷Ö/´¹ÁÕaH¡¾¿Þj9SDV{SŒmðmžgrub_cmd: [ = 1 ] õ°gåœ?g±›ƒo¾é複¡œÝ Eh6·X1¤-dZµ40/¹÷B­ª7·ýáR!]iâYû ±øÐ6®ý2ÎwêBn{=®ãxÝy®Ú–;,S‰‡‡–,éêåWÌéJgrub_cmd: [ xy = xy ] Xy^…’Ùÿ;k9­ÖÛ©XïõG¢ aÊ¥OÂK¨³ç›æ?7Zót$NNÞŽ `€ £ú_» ŸvͧoØ.KE %ƒW§F.§Þä7zÐÙKHŸ}‹DçˆeBõÜŠñV#grub_cmd: set timeout_style=hidden 1¸æBþ“aïY™mµ'‚O" Íõ“¦ªªë•rC»Ž'ÙoLrnÅ#Í8)‚½ñúõM œE+¥¹¦LŽØÌ’·æœvÀÿéŸÀó‰@õ@´e¸kUh…ëZÌéñlï grub_cmd: set timeout=0.1 UÏÖF>ó4«¶´€€³>Àc©ÀQë ϤgoþuGçzf 3µ›>í4Ù³£Ò`‘«Y “J¯Éœ°§ËøÂ^DBF4Š* NîøÜĦ8†Êil­E‘=9"¹§òdºxð.€ \›f‚)ìÿ—,Lņ±M˜p4grub_cmd: set menu_color_highlight=black/light-gray ÿí‹­,šÛÇ÷Ú@þ­Îry­ ¢»¡¾Ñ(£ ·ž"ÄfÊÝ(”+Mugå Lc‹Q Ÿ>Û‘4àåã8ÍUl:ú½û#Æ@aŠšh U,€Qpò1ÀQ/"rºfÂóËD*<grub_cmd: set partuuid=6443a6ae-e5e9-4df7-9a06-d1329e50f33c B2‡¤ ‘Kµ—Û2ùf—Ñûž ð´³Â1‚Ž¢úJ,üåïÉÑ^™ÿ¹ÆsIÁ07A¯ zZÀyo¨/Núˆ¶!9…²ØxæIˆj™XvfÏ…ÅôwŠ£Ï„•,¦ÊÓó…SËgrub_cmd: [ != 1 ] ),ÎÒŽ6¨éèT ›ðãË6‘ ]ˆNRÐá‘Ø‚wǨS¨š-„GCÈ釴tØñÇæ ¥à|ü–qvk›¸8sÆÿKí}û¹'Õ°'=*ë¹0Û¤c 7 u ’Û×ÅI_¯§E>Ð7grub_cmd: [ -e (hd0,gpt1)/boot/grub/gfxblacklist.txt ] ‹Ó·zd}¹ˆ¶±êüi`ªE õå6]n—d”6,ƒâè€|ï¡OÔ¬f 2Q îÕTHˆ,»Ý¨ðFˆFY° grub_cmd: export linux_gfx_mode êUð¦ÀHA™òIÛåZUcÿ0lôîÌÌ@©OÔáx„:ýŽ” grub_cmd: submenu Advanced options for Ubuntu --id gnulinux-advanced-fadc363a-fae5-4b46-9bf5-303a0043410b { menuentry 'Ubuntu, with Linux 5.11.0-1006-gcp' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.11.0-1006-gcp-advanced-fadc363a-fae5-4b46-9bf5-303a0043410b' { recordfail load_video gfxmode $linux_gfx_mode insmod gzio if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi insmod part_gpt insmod ext2 if [ x$feature_platform_search_hint = xy ]; then search --no-floppy --fs-uuid --set=root fadc363a-fae5-4b46-9bf5-303a0043410b else search --no-floppy --fs-uuid --set=root fadc363a-fae5-4b46-9bf5-303a0043410b fi echo 'Loading Linux 5.11.0-1006-gcp ...' if [ "${initrdfail}" = 1 ]; then echo 'GRUB_FORCE_PARTUUID set, initrdless boot failed. Attempting with initrd.' linux /boot/vmlinuz-5.11.0-1006-gcp root=PARTUUID=6443a6ae-e5e9-4df7-9a06-d1329e50f33c ro console=ttyS0 echo 'Loading initial ramdisk ...' initrd /boot/initrd.img-5.11.0-1006-gcp else echo 'GRUB_FORCE_PARTUUID set, attempting initrdless boot.' linux /boot/vmlinuz-5.11.0-1006-gcp root=PARTUUID=6443a6ae-e5e9-4df7-9a06-d1329e50f33c ro console=ttyS0 panic=-1 fi initrdfail } menuentry 'Ubuntu, with Linux 5.11.0-1006-gcp (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.11.0-1006-gcp-recovery-fadc363a-fae5-4b46-9bf5-303a0043410b' { recordfail load_video insmod gzio if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi insmod part_gpt insmod ext2 if [ x$feature_platform_search_hint = xy ]; then search --no-floppy --fs-uuid --set=root fadc363a-fae5-4b46-9bf5-303a0043410b else search --no-floppy --fs-uuid --set=root fadc363a-fae5-4b46-9bf5-303a0043410b fi echo 'Loading Linux 5.11.0-1006-gcp ...' if [ "${initrdfail}" = 1 ]; then echo 'GRUB_FORCE_PARTUUID set, initrdless boot failed. Attempting with initrd.' linux /boot/vmlinuz-5.11.0-1006-gcp root=PARTUUID=6443a6ae-e5e9-4df7-9a06-d1329e50f33c ro recovery nomodeset dis_ucode_ldr echo 'Loading initial ramdisk ...' initrd /boot/initrd.img-5.11.0-1006-gcp else echo 'GRUB_FORCE_PARTUUID set, attempting initrdless boot.' linux /boot/vmlinuz-5.11.0-1006-gcp root=PARTUUID=6443a6ae-e5e9-4df7-9a06-d1329e50f33c ro recovery nomodeset dis_ucode_ldr panic=-1 fi initrdfail } } '?\€Á.“\7ÂÏãáa¼B׎ £t0• ƒp!ëÌùŒŒ1å“ãfB”6á55„Çìr ®Ø–¢±a!VÙ>Ò3Lj„f 4•ÍÉè–.‡cŸØÏAÉNŠH„áš+Áá1grub_cmd: [ -f (hd0,gpt1)/boot/grub/custom.cfg ] £2móBW^Qù¡ÈÕÑzïòÐ ÕGWX1¿oósƒ°·Žy #r£¦zÐÑÊ5Û û³†EHa±º§zaWm4,'ÀÐ%—d˜%ÎäLöX¯+ تI–ák›l2±ã;´Lgrub_cmd: [ -z (hd0,gpt1)/boot/grub -a -f (hd0,gpt1)/boot/grub/custom.cfg ] ÇjeëÚj£Ú«¼ÖH;ð ô ¿]¤fÀ÷x™ ÜÈú,Eaº’‘-_¼JÁãû £ {äû›ë‹"‚ÿФ~±6G&(Ô(KÙ®ŽŠt¨á_ „´cm·i*J`Ìgrub_cmd: setparams Ubuntu ˜ÐføÿÐFºË8±Œ¾é­§) ¥~~(nüNê‰e@ñ:8Ì’ä'{í‚ ígL”¿.­ °»…ÿxŸ%ÝcãAsk”ô¿:Íÿö ÓÿÊW‰ës}(£šömäf@Kû» Ú×grub_cmd: recordfail ºÁp…þõ6b¥ ï¿6hDÀtÿ d½¨ö[…׆‚H¢’ÄIf È÷PuÁ ‡®Y¤Û@á ³SϘ3›é«­ñ€Ø:¾µîîÀC³ò$v»]°º/Ca & óF ì³Á$í© l§¢grub_cmd: set recordfail=1 UÏÖF>ó4«¶´€€³>Àc©ÀQë ϤgoþuGçzf 3µ›>í4Ù³£Ò`‘«Y “J¯Éœ°§ËøwíEìüqHàÉ4ÐRk(&Å|“€,Éb<%’6‰Þ/ËbfŸãáágrub_cmd: [ -z ] ’^æ›|ŠÄ“|¾GÕÈSQØi´è× Î,Âwº;Ç[f!cëãp4MK®×_µ½@¶ºß .GÅä›óÉ4ôˆüÀsH•P¦M¶* | DÉÝœ*ù7d|‡½wã8>pž úgrub_cmd: save_env recordfail åžfÖì„ G$÷‘é)ñSáD v&«Ø¾tBÂåu6J>•Ë:;S»á†<ךæk eÍéŒû ‰q˜jˆÍøgrub_cmd: gfxmode keep .gmÝ›ð× Í\fØW2Þ{w¶ ¥‹wÏœIÀ¹yßgçòÁ“Óa>?ÄÉ똢µÐoÌ |^¡± ¦’ $á-µö¥°ënÓfÌëŠËDx…rB"õc#¤“ѳ©Xú|grub_cmd: set gfxpayload=keep RAµß¥†y‰]•÷Ÿú _BºKUê µ]„»° ^»ÆÊÝjœ´›5¿ÌlNùÅ;f ÷ÇDY» ø®$‘X‡œʳ¸¯”^ ÷±iw½e¨ \ˆÿ)Ëvó½Ögrub_cmd: [ keep = keep ] ˆn*¡™ôöÒ™~ Šèk ÏÐ;6èoaq"çóÿèŸ|ðú§sñ¼í(÷ðÁú ‹ÈèÅaòYˆ¾žiÚ*ö&ÇÓÇ5õ™«Ï'ø<S §hGÜ^I/Az$²ôW&grub_cmd: set vt_handoff=vt.handoff=7 ºPœ£‚ðhû lFtÔÆRîg¹Šb×TËòÕÜ ÚãÖn‚ǔė„ †*ç—aS$ý\=ûü²&9b…^ÒÛ)iù„VðÚ¶ªŠ¢âþ¼g)W†¨çê¤^6Í£úóÐ¥õü’ìM$ïJÙXFiY4¶Â² åkå+Ûâ÷Oûgrub_cmd: insmod part_gpt ¯?«¬ž\V¸/ «˜2‰ª»öï ¸8¤Ò† û±z·ö eY ›; ›1ØÒû áB¥”Ùˆý¥¦[$¤¤Œ,ô°6ÝwJ♯E·Ó; þ¤©iÓÀÚrºSùîê÷¦grub_cmd: insmod ext2 õ°gåœ?g±›ƒo¾é複¡œÝ Eh6·X1¤-dZµ40/¹÷B­ª7·ýáR!]iâYû ±øÐ6®ý2ÎwêBn{=®ãxÝy®Ú–;,S‰‡‡–,éêåWÌéJgrub_cmd: [ xy = xy ] © ·D“7˜=ít~;ü7™·&«â yi¯§4·aN9·ëÇ}ïXÀ.tçeÍé9IÈ0en œ¤ˆvE.шUGé4@Qu¢Ô“¾,êÅ{›ì¬[Ôѧ㥳&w¬¤þC1ºWgrub_cmd: search --no-floppy --fs-uuid --set=root fadc363a-fae5-4b46-9bf5-303a0043410b ºE+ð ˆ(³]é‰À…8 ‚¤¡NC¤÷a®c(] ðZñ9ò`úå{, szó8+ ®aÄ[<%Èœê?}ÞädŽw`†÷Ö/´¹ÁÕaH¡¾¿Þj9SDV{SŒmðmžgrub_cmd: [ = 1 ] T –‚-†@ÏeOc~º—Réâ Ñ»×ÕsÖ6… žûϬžXŸÍ4ö±kLJ"uêl= !dÙFâ|îщŒ~Øv™))c¹-@Øê0…´2„¥{?=ûƒ¬ Eë(®pÝ_ýQ„Dgrub_cmd: echo GRUB_FORCE_PARTUUID set, attempting initrdless boot. !©Ðï2ˆ B %ø ¨JoÎg ‚ õ ßóÔm¬öÄ`ŒôÙ¹©yáÅÍsñbó³x¾¢ 2 ö9yQ®kþ¬p¥mOØÕî¶Ñ}d\ýºZç=LgÉ'‚àê‹Ï]1>)t´¢¶“{grub_cmd: linux /boot/vmlinuz-5.11.0-1006-gcp root=PARTUUID=6443a6ae-e5e9-4df7-9a06-d1329e50f33c ro console=ttyS0 panic=-1 Õå}ýã.¹Š2”Õ>nIõiÂ& G嘷¹DþˆÖA©…ørÑêØ}'­ŠéÖÍgycûõ Ñ-Z  J˜£#òm,7Mÿ¢"˜½ŸÀ7«szt£ë×Ûܸ-BE¿Í›Á«Q˜Šà/boot/vmlinuz-5.11.0-1006-gcp Ìå³Û'«€u`‚äŠdú]·f§ µsv‘F¨e±/$  NBˆ /QèËçŒp=ȉ ¯×ýt›¦n¾GÒef^Xz³PjÎ…Zþxýµ)ç7«Õ{ý˜Zi–…v’ï4{kernel_cmdline: /boot/vmlinuz-5.11.0-1006-gcp root=PARTUUID=6443a6ae-e5e9-4df7-9a06-d1329e50f33c ro console=ttyS0 panic=-1 ŒiDÅퟄ?Õõ¼2”çÛ v¼lmpÎ4¢KÚ&5„íÐý]”ù ¢Ý^P é‹=ò sÕü÷ucÔ*³k1Ú€ G˜sä8>ÂØBŽÕrúBžÌûÖ>¿}4+¡š~è(í3Ó•grub_cmd: initrdfail UÏÖF>ó4«¶´€€³>Àc©ÀQë ϤgoþuGçzf 3µ›>í4Ù³£Ò`‘«Y “J¯Éœ°§ËøwíEìüqHàÉ4ÐRk(&Å|“€,Éb<%’6‰Þ/ËbfŸãáágrub_cmd: [ -z ] p&‰ ü¨4˜9Ü·‘=ÈKÕ{Ñ k,—ö@ºØsÈ¡4G’®þ;©>Øò ¸è‘“Rlÿ_» É2 }ú‹ /¿àéRâ¿ ˜G‹²xç‹2è¯_/ÊÞö‚âòèO'›«N"²grub_cmd: set initrdfail=1 z†Áò8gØ•¹Tqa‹Þ- $6¯ãËT«€}l¥&í12ÜYxžÓòñHèiHéx L÷&ìÔ"µm÷Ê/7|²¤îmœ¡õ´@–øüf·;VÐïü91Å©3'QrË÷grub_cmd: [ -n ] ŸP–{Àf‚iDj©/+ˆb  X9ý›þ¾;Þw9ßjƒ 7âZGÿ¦¡d´¢ PÈ &%Ðýô` , ™>¹`ɸ­*Í0™ê#ë?êX³&=Ù‰UóJ¨”Ž4èd·G ­grub_cmd: save_env initrdfail€D:k{‚·¯VO.9<ÙÕ£ˆ·úJ˜ Ø=k{…­5޳¶®j‡:·ï#¢cRÅÜOªZîÚÏ^´ !K ïyu`4Hwt?Ü*S‚ºÆçbÖ$ÌóöT@|K­÷Øù)]ÓÚ½ïe²vwàExit Boot Services Invocation€GUEÝÉx׿Ð6úÌ~.˜HŸ µOuBËØr¨ꃛ+t|~½^¦a\@ô/D¦Ûë  .È]êç¥0­Œm ¨@ º¾l‰‰&ž• Œô@Æé—i^dÔUÄJe,Ѐö# t(Exit Boot Services Returned with Successgo-attestation-0.5.1/attest/testdata/windows_gcp_shielded_vm.json000066400000000000000000001674321452320553600253770ustar00rootroot00000000000000{"Static":{"TPMVersion":2,"EKPem":null},"AK":{"Public":"AAEACwAFBHIAIJ3/y/NsODrmmfuYaNxty4nXFTiEvigDkiwSQVi/rSKuABAAFAAECAAAAAAAAQDGp8kViXRjbtQShAo1UlsWVsnLJXYCnnsgbdCRN6KDBJPLtv5+vCqAS9Yk2I9t92UsPY1CJoVOAX85/WrNv6PnE1feQ0F9/VEyxYHFA2RAuKkWjNBgGGOYskKKI/2L+R+A1s5mNBmkpjyx6WDm2xGyBbQQP28oVdpBcLbohihowYvUwGnLh7g0sRN51S1KDrh1rP4sfKHFEn9r0aGlhrsOEbEAwQtB6XfLm1IBLQLVciRS5/HjM3EiH3doqZy2FpcE6G7nGKxAwk2H8MnEL7dOsdhXBBH1obLSUB7DYKnMhFaJuf2uAB0gPCjFt+Elou+g7MlMoJ38RPIG7HE1uQ2b","UseTCSDActivationFormat":false,"CreateData":"AAAAAAAg47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFUBAAsAIgALE74YF3O3QIzm9WkS7PEgSTqNLPwhzCsCz8IGGhBTvSsAIgALhnEUd3MQr47yE795W7oTqJErIscsuOaZC4CaoEMp+JAAAA==","CreateAttestation":"/1RDR4AaACIAC61Cfn/Igh90x8aWRkH5+gU3chItS5SmzDo/z8zdVbWtAAAAAAAAAJyC5z5NueQxBjbaAUHkNW35ZuA1ACIAC0zpsVH3UInXTBXavp1SDP+vvK/V1DvgqtLi2I1UcX4uACADNgYgV1PHcDwJirgW+Zzx2Hi4RVCXRuwqYXG8Ncj5dA==","CreateSignature":"ABQABAEAXvzxtf81ORJufzKz6Xa7OD8+o9BmTR4pPwgv/K6rzW4JQlEG23bxyOn2OPKdwOcqouAEe2tAZlKaqAhpwinOjIlAJy+XDF6t4KW/9WySswfYEIXlA1ftX8oIjij3hE25R0ARCK+peXUI5Fm/fzJKj/ldjGHOV4RwDJ03HsV7bF+tGPumTPN9vzf/Ccb6nUfvLqOOHVx0A9LvLON9d3imsHLxNgk634PEfw22RjXSC8O4zuqPXiMoTGY6qhEL3x0gCkrdzGKz4q72jyVYSXkbkPRlbyyVjiT94r7MSWC7G8RbNqE2KmWdCh6fZ/lo0ZADjypOthEwZUP9NmZ7omcDKA=="},"Quote":{"Nonce":"","Alg":4,"Quote":"/1RDR4AYACIAC61Cfn/Igh90x8aWRkH5+gU3chItS5SmzDo/z8zdVbWtAAAAAAAAAJyDEz5NueQxBjbaAUHkNW35ZuA1AAAAAQAEA////wAUphDye8aHzpBiQyh9gycGA2559uE=","Signature":"ABQABAEAkcDC54zyAEZkCOfLiKrZouPp7fvLHIBxIPY4yNR2tgG76Swp4M2PxU9JzWA/hcGyebceehMQYwOr2ID3Fk8FSKg0PQDLXwltQuBcWwcl7T9YXDwwgZpZJl8zoV0/fs4WMZH3dmCQb0+fPwlI6n9W4+niX4TEhwWN+TYVHM7ChnrTwxl2cHw727sjl+iVIXSXSt6s6CxqaO3FPYuhTJrNQQe9215lIX/lEcogP5miki5Yx+Lk6c+s96p4J3lU24yq97F/GUJbVVeVHjasaNw2ABkj0qzIM+1wVupRdvQTJHIzpdW59QpgW4YWJpNjvTHZIYRVyahb6ZhtL5WgoTSroQ=="},"Log":{"PCRs":[{"Index":21,"Digest":"//////////////////////////8=","DigestAlg":3},{"Index":14,"Digest":"J1pon51fgkSkuZn6vmAMWBa+VRE=","DigestAlg":3},{"Index":20,"Digest":"//////////////////////////8=","DigestAlg":3},{"Index":9,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":23,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":22,"Digest":"//////////////////////////8=","DigestAlg":3},{"Index":3,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":13,"Digest":"OD3nn73eYpYgXir+RIAODAU/yC8=","DigestAlg":3},{"Index":4,"Digest":"DKS0pHhL9O7Zw1Vquh2sVYWllRo=","DigestAlg":3},{"Index":19,"Digest":"//////////////////////////8=","DigestAlg":3},{"Index":2,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":15,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":8,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":7,"Digest":"hZpYdyZrXJCWE0aAkaczgKU4Z4Y=","DigestAlg":3},{"Index":0,"Digest":"UcMj3gwMaU9GAc3QK+tY/xNin3Q=","DigestAlg":3},{"Index":12,"Digest":"dfPha27wtFUoLtj7vfzD2pq9JB0=","DigestAlg":3},{"Index":10,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":5,"Digest":"KwIil9Tx4BAcjJhr4inI3QNQUU0=","DigestAlg":3},{"Index":1,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":16,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":6,"Digest":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","DigestAlg":3},{"Index":11,"Digest":"67mN92YTKA8g3DgiEUOp5yc5lIY=","DigestAlg":3},{"Index":18,"Digest":"//////////////////////////8=","DigestAlg":3},{"Index":17,"Digest":"//////////////////////////8=","DigestAlg":3}],"PCRAlg":0,"Raw":"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DGgy27LSCeAnJSfftj1J0pVypvRMvZr6d1kDMk29YCj05494Swde6gYFiVSLoGCy/u0Q2jwgx/6bF80Ca5TopoO4EVI4vZr6d1kDMk29YCj05494SwfmxqhYZG+x78Z5A/4osRYBHyNn/pLmvis2mZ7/OdCevZr6d1kDMk29YCj05494SwnfX05REgjseLltEtCBJf22A4aN459vcpJ4UlmbZZwmvZr6d1kDMk29YCj05494Swu7Q5LarHq4mzCkrGV1Mbl7+qsE+QsNr+X5tuuQoGN0vZr6d1kDMk29YCj05494SwwYkzl2LfM2qz3QBqRj33FaOc+w9JJGXGAObGvXvYmMvZr6d1kDMk29YCj05494Sw0NvspvKeygbzMafXLkiEsSCX+zSJg6KhSg1z9PEBQPvZr6d1kDMk29YCj05494Sw3J8/uZliFIw8qDNjJ1jT7U/I0LAAe5WzHmUo8qzVv8vZr6d1kDMk29YCj05494SxBvrOrP7P1OMDt09ICggJji0IArk2+Ox3TOIfMWhmicvZr6d1kDMk29YCj05494SxdOOgtbQ8amB7vTQE8FNB49zzliZ86U+LUOLiOp2pIMvZr6d1kDMk29YCj05494SxgzNCn/BWLtn5cDPhFI3O7lLb4uSW1UELXP1shk0tEPvZr6d1kDMk29YCj05494SyuZzyZCLpL+Nl+/S8MNJwhsnuFLem//RPsva5ABaZk5vZr6d1kDMk29YCj05494Syu/LKe48dkfJ+5StvsqXdBJuForm1KcXWZiBoEEsFX4vZr6d1kDMk29YCj05494Syxz2TMlum3L5YnUpMY8W5NVWe+S+/BQ7VDE4ghSBvF9vZr6d1kDMk29YCj05494Sy5wkWeGpvdzUR+nGB+rDx1wtVfGMi6pI7Ko07krUa99vZr6d1kDMk29YCj05494SzBmKPpUdzBXKLpKRn3n0Dh6VPVp03afzl517InSjRWTvZr6d1kDMk29YCj05494SzYI7br1rQ9BpBShd3q/L69eZwM0Z17DmV5pNYKeDKrSvZr6d1kDMk29YCj05494SzhB0iE2jRWD11wKAuYhYDlNbE4KZ2C29ge5A2K8hVsCvZr6d1kDMk29YCj05494Sz/Om5/fPvCdVFKw+V7kgcK38G10OnN5cVWOcBNqzj5zvZr6d1kDMk29YCj05494S0OX2sqDnn9jB3y1DJLfQ7wtL7Ko9Z8m/HoOS9TZdRaSvZr6d1kDMk29YCj05494S0fMCGEn4gaahuA6a+8s1BD4xVpta9s2IWjDGyzjKlrfvZr6d1kDMk29YCj05494S1GIMf5zgrUU0D4VxiEii4q2VHm9DL+jxcHQ9I2cMGE1vZr6d1kDMk29YCj05494S1rpSeqIVeuT5DnbxlvaLkKFLC/fZ4n6FGc248NBDytcvZr6d1kDMk29YCj05494S2sdE4B45EGKpo3re7NeBmCSz0ee64zkzRLn0HLMtC9mvZr6d1kDMk29YCj05494S2yIVEeN1Vnik1G4JsBsuL/vK5StNTg1h3LRk/gu0coRvZr6d1kDMk29YCj05494S28UKP9xydsO1a8fLnu/y6tkfMJl3fWyk822JvUKOnhevZr6d1kDMk29YCj05494S3HykG/SIkl+VKNGYqskl/zIECB3D/UTaOnj2b/L/WN1vZr6d1kDMk29YCj05494S3JrPrZUBGow8/g9m5bOA/Zw6agG0XCKA3HmLcSdLCPBvZr6d1kDMk29YCj05494S3LgvRhnz12dVqsVit873byCvzKo2KodjF4vbfKUKNbYvZr6d1kDMk29YCj05494S3gnr5k2LPrwcX2t5LG/4EOK0XHBWt3CSLdb+MqkS7LFvZr6d1kDMk29YCj05494S4GouWW7hNOHa5QpqVSBzJVTGM+qFBLYCMijO/0z//DkvZr6d1kDMk29YCj05494S4LbO8609ghDzp2Xw9GHzZtZQc096BAOWG8r2lY3V19nvZr6d1kDMk29YCj05494S4lal4X2F8odftRPwaFHC3Hz8SI4Ytn/ncw64t+SFj2vvZr6d1kDMk29YCj05494S4rWSFnxlbX1ja+qlAtqYWes1nqIbo9Gk2QXciHFWUW5vZr6d1kDMk29YCj05494S4v0NLSeAMz3FQKizZAIZcsB7Ds9oDw1vlBf33vVY/UhvZr6d1kDMk29YCj05494S42OoonP5wocB6tzZcso7lHt0zzyUG3oiPut1g6/gEgcvZr6d1kDMk29YCj05494S5mY02PEkb4WvXS6ELlNkpEAFhFzb9ymQ6NmZLwPMVpCvZr6d1kDMk29YCj05494S55KaRcxYWguVf3o/vVg64jsH/7crwQAH2bAyvcHsrc0vZr6d1kDMk29YCj05494S6a1FR82VdOirw1HJ1l5a+SkIA5UlafYaXVMSEiFdAinvZr6d1kDMk29YCj05494S6fzL1CNTrD+rZoIfvlO0boK7F3m9+9v8KYrk77fXUWNvZr6d1kDMk29YCj05494S61oJuGUbSbT6vNoXIjZfYXeO03LPQ7iroHHBWDRPFcgvZr6d1kDMk29YCj05494S67rrjFRJxJz7ZWqLmcROe0xqYVnMDozIpj4Nwmp1VqhvZr6d1kDMk29YCj05494S6/iAwr7fSzaE/n6MzoC409nUa/sEbAQ281EH99MQAKzvZr6d1kDMk29YCj05494S7VPHuY2Yx+taAWNOwk3AxrBuQzLFwYqORzKaK/b5A1VvZr6d1kDMk29YCj05494S7jweNmDokrEMyFjk4g1FM2TLDOvGOfdcIhMgjX0J1c2vZr6d1kDMk29YCj05494S7l6CIkFnANf8dVLbbU7Ebl2ZmjZ+VUkfAKLKDfXoEzZvZr6d1kDMk29YCj05494S7yHpmjoGWZInLUI7oBRg8Geas0kzxd5nKBi0uOE2g6nvZr6d1kDMk29YCj05494S8QJvaxHda3Y25KqIrW3GPuMlKFGLB/ppBa5XYoziML8vZr6d1kDMk29YCj05494S8YXwaix7iqBHCi1qBtMg9fJi1sMJygdYQIH6+aSwpZ/vZr6d1kDMk29YCj05494S8kPM2YXuOf5g5dUE8mX8Qtz6yZ/2KEMueO9v8Znq9uLvZr6d1kDMk29YCj05494S8trhYtA06CYdlgVtZLBUUpJYE+v1ggZ2ojXp26XeP73vZr6d1kDMk29YCj05494S847+r5Z1nzorI39Shb3xD75wiRRP7xlWVfXNfop9UDOvZr6d1kDMk29YCj05494S9jL65c19WcrNn5Pls3HSWlhXRcHSulsck1CzgIW+PP6vZr6d1kDMk29YCj05494S+ksIus7VkLWXB7CyvJH0llHOO67f7OEGkSVb1nisNH6vZr6d1kDMk29YCj05494S/3dbj0p6oTHdD2tShvbxwC1/sGzkfkyQJCGrMcd1tvYvZr6d1kDMk29YCj05494S/5jqE94LMnT/PLM+fwR+9A3YIeHWNJihe0SZpvcbm0BvZr6d1kDMk29YCj05494S/7PsjLRLplLbUhdLHFncoqlUlmErVym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"}} go-attestation-0.5.1/attest/tpm.go000066400000000000000000000406321452320553600171240ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package attest import ( "bytes" "crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/asn1" "encoding/base64" "encoding/binary" "fmt" "io" "net/url" "strings" "github.com/google/go-tpm/legacy/tpm2" "github.com/google/go-tpm/tpmutil" ) const ( tpmPtManufacturer = 0x00000100 + 5 // PT_FIXED + offset of 5 tpmPtVendorString = 0x00000100 + 6 // PT_FIXED + offset of 6 tpmPtFwVersion1 = 0x00000100 + 11 // PT_FIXED + offset of 11 // Defined in "Registry of reserved TPM 2.0 handles and localities". nvramRSACertIndex = 0x1c00002 nvramRSAEkNonceIndex = 0x1c00003 nvramECCCertIndex = 0x1c0000a nvramECCEkNonceIndex = 0x1c0000b // Defined in "Registry of reserved TPM 2.0 handles and localities", and checked on a glinux machine. commonRSAEkEquivalentHandle = 0x81010001 commonECCEkEquivalentHandle = 0x81010002 ) var ( akTemplate = tpm2.Public{ Type: tpm2.AlgRSA, NameAlg: tpm2.AlgSHA256, Attributes: tpm2.FlagSignerDefault | tpm2.FlagNoDA, RSAParameters: &tpm2.RSAParams{ Sign: &tpm2.SigScheme{ Alg: tpm2.AlgRSASSA, Hash: tpm2.AlgSHA256, }, KeyBits: 2048, }, } defaultRSASRKTemplate = tpm2.Public{ Type: tpm2.AlgRSA, NameAlg: tpm2.AlgSHA256, Attributes: tpm2.FlagStorageDefault | tpm2.FlagNoDA, RSAParameters: &tpm2.RSAParams{ Symmetric: &tpm2.SymScheme{ Alg: tpm2.AlgAES, KeyBits: 128, Mode: tpm2.AlgCFB, }, ModulusRaw: make([]byte, 256), KeyBits: 2048, }, } defaultECCSRKTemplate = tpm2.Public{ Type: tpm2.AlgECC, NameAlg: tpm2.AlgSHA256, Attributes: tpm2.FlagStorageDefault | tpm2.FlagNoDA, ECCParameters: &tpm2.ECCParams{ Symmetric: &tpm2.SymScheme{ Alg: tpm2.AlgAES, KeyBits: 128, Mode: tpm2.AlgCFB, }, CurveID: tpm2.CurveNISTP256, Point: tpm2.ECPoint{ XRaw: make([]byte, 32), YRaw: make([]byte, 32), }, }, } // Default RSA and ECC EK templates defined in: // https://trustedcomputinggroup.org/wp-content/uploads/Credential_Profile_EK_V2.0_R14_published.pdf defaultRSAEKTemplate = tpm2.Public{ Type: tpm2.AlgRSA, NameAlg: tpm2.AlgSHA256, Attributes: tpm2.FlagFixedTPM | tpm2.FlagFixedParent | tpm2.FlagSensitiveDataOrigin | tpm2.FlagAdminWithPolicy | tpm2.FlagRestricted | tpm2.FlagDecrypt, AuthPolicy: []byte{ 0x83, 0x71, 0x97, 0x67, 0x44, 0x84, 0xB3, 0xF8, 0x1A, 0x90, 0xCC, 0x8D, 0x46, 0xA5, 0xD7, 0x24, 0xFD, 0x52, 0xD7, 0x6E, 0x06, 0x52, 0x0B, 0x64, 0xF2, 0xA1, 0xDA, 0x1B, 0x33, 0x14, 0x69, 0xAA, }, RSAParameters: &tpm2.RSAParams{ Symmetric: &tpm2.SymScheme{ Alg: tpm2.AlgAES, KeyBits: 128, Mode: tpm2.AlgCFB, }, KeyBits: 2048, ModulusRaw: make([]byte, 256), }, } defaultECCEKTemplate = tpm2.Public{ Type: tpm2.AlgECC, NameAlg: tpm2.AlgSHA256, Attributes: tpm2.FlagFixedTPM | tpm2.FlagFixedParent | tpm2.FlagSensitiveDataOrigin | tpm2.FlagAdminWithPolicy | tpm2.FlagRestricted | tpm2.FlagDecrypt, AuthPolicy: []byte{ 0x83, 0x71, 0x97, 0x67, 0x44, 0x84, 0xB3, 0xF8, 0x1A, 0x90, 0xCC, 0x8D, 0x46, 0xA5, 0xD7, 0x24, 0xFD, 0x52, 0xD7, 0x6E, 0x06, 0x52, 0x0B, 0x64, 0xF2, 0xA1, 0xDA, 0x1B, 0x33, 0x14, 0x69, 0xAA, }, ECCParameters: &tpm2.ECCParams{ Symmetric: &tpm2.SymScheme{ Alg: tpm2.AlgAES, KeyBits: 128, Mode: tpm2.AlgCFB, }, CurveID: tpm2.CurveNISTP256, Point: tpm2.ECPoint{ XRaw: make([]byte, 32), YRaw: make([]byte, 32), }, }, } // Basic template for an ECDSA key signing outside-TPM objects. Other // fields are populated depending on the key creation options. ecdsaKeyTemplate = tpm2.Public{ Type: tpm2.AlgECC, Attributes: tpm2.FlagSignerDefault ^ tpm2.FlagRestricted, ECCParameters: &tpm2.ECCParams{ Sign: &tpm2.SigScheme{ Alg: tpm2.AlgECDSA, }, }, } // Basic template for an RSA key signing outside-TPM objects. Other // fields are populated depending on the key creation options. rsaKeyTemplate = tpm2.Public{ Type: tpm2.AlgRSA, NameAlg: tpm2.AlgSHA256, Attributes: tpm2.FlagSignerDefault ^ tpm2.FlagRestricted, RSAParameters: &tpm2.RSAParams{}, } ) type tpm20Info struct { vendor string manufacturer TCGVendorID fwMajor int fwMinor int } func readTPM2VendorAttributes(tpm io.ReadWriter) (tpm20Info, error) { var vendorInfo string // The Vendor String is split up into 4 sections of 4 bytes, // for a maximum length of 16 octets of ASCII text. We iterate // through the 4 indexes to get all 16 bytes & construct vendorInfo. // See: TPM_PT_VENDOR_STRING_1 in TPM 2.0 Structures reference. for i := 0; i < 4; i++ { caps, _, err := tpm2.GetCapability(tpm, tpm2.CapabilityTPMProperties, 1, tpmPtVendorString+uint32(i)) if err != nil { return tpm20Info{}, fmt.Errorf("tpm2.GetCapability(PT_VENDOR_STRING_%d) failed: %v", i+1, err) } subset, ok := caps[0].(tpm2.TaggedProperty) if !ok { return tpm20Info{}, fmt.Errorf("got capability of type %T, want tpm2.TaggedProperty", caps[0]) } // Reconstruct the 4 ASCII octets from the uint32 value. b := make([]byte, 4) binary.BigEndian.PutUint32(b, subset.Value) vendorInfo += string(b) } caps, _, err := tpm2.GetCapability(tpm, tpm2.CapabilityTPMProperties, 1, tpmPtManufacturer) if err != nil { return tpm20Info{}, fmt.Errorf("tpm2.GetCapability(PT_MANUFACTURER) failed: %v", err) } manu, ok := caps[0].(tpm2.TaggedProperty) if !ok { return tpm20Info{}, fmt.Errorf("got capability of type %T, want tpm2.TaggedProperty", caps[0]) } caps, _, err = tpm2.GetCapability(tpm, tpm2.CapabilityTPMProperties, 1, tpmPtFwVersion1) if err != nil { return tpm20Info{}, fmt.Errorf("tpm2.GetCapability(PT_FIRMWARE_VERSION_1) failed: %v", err) } fw, ok := caps[0].(tpm2.TaggedProperty) if !ok { return tpm20Info{}, fmt.Errorf("got capability of type %T, want tpm2.TaggedProperty", caps[0]) } return tpm20Info{ vendor: strings.Trim(vendorInfo, "\x00"), manufacturer: TCGVendorID(manu.Value), fwMajor: int((fw.Value & 0xffff0000) >> 16), fwMinor: int(fw.Value & 0x0000ffff), }, nil } // ParseEKCertificate parses a raw DER encoded EK certificate blob. func ParseEKCertificate(ekCert []byte) (*x509.Certificate, error) { var wasWrapped bool // TCG PC Specific Implementation section 7.3.2 specifies // a prefix when storing a certificate in NVRAM. We look // for and unwrap the certificate if its present. if len(ekCert) > 5 && bytes.Equal(ekCert[:3], []byte{0x10, 0x01, 0x00}) { certLen := int(binary.BigEndian.Uint16(ekCert[3:5])) if len(ekCert) < certLen+5 { return nil, fmt.Errorf("parsing nvram header: ekCert size %d smaller than specified cert length %d", len(ekCert), certLen) } ekCert = ekCert[5 : 5+certLen] wasWrapped = true } // If the cert parses fine without any changes, we are G2G. if c, err := x509.ParseCertificate(ekCert); err == nil { return c, nil } // There might be trailing nonsense in the cert, which Go // does not parse correctly. As ASN1 data is TLV encoded, we should // be able to just get the certificate, and then send that to Go's // certificate parser. var cert struct { Raw asn1.RawContent } if _, err := asn1.UnmarshalWithParams(ekCert, &cert, "lax"); err != nil { return nil, fmt.Errorf("asn1.Unmarshal() failed: %v, wasWrapped=%v", err, wasWrapped) } c, err := x509.ParseCertificate(cert.Raw) if err != nil { return nil, fmt.Errorf("x509.ParseCertificate() failed: %v", err) } return c, nil } const ( manufacturerIntel = "Intel" intelEKCertServiceURL = "https://ekop.intel.com/ekcertservice/" ) func intelEKURL(ekPub *rsa.PublicKey) string { pubHash := sha256.New() pubHash.Write(ekPub.N.Bytes()) pubHash.Write([]byte{0x1, 0x00, 0x01}) return intelEKCertServiceURL + url.QueryEscape(base64.URLEncoding.EncodeToString(pubHash.Sum(nil))) } func readEKCertFromNVRAM20(tpm io.ReadWriter, nvramCertIndex tpmutil.Handle) (*x509.Certificate, error) { // By passing nvramCertIndex as our auth handle we're using the NV index // itself as the auth hierarchy, which is the same approach // tpm2_getekcertificate takes. ekCert, err := tpm2.NVReadEx(tpm, nvramCertIndex, nvramCertIndex, "", 0) if err != nil { return nil, fmt.Errorf("reading EK cert: %v", err) } return ParseEKCertificate(ekCert) } func quote20(tpm io.ReadWriter, akHandle tpmutil.Handle, hashAlg tpm2.Algorithm, nonce []byte, selectedPCRs []int) (*Quote, error) { sel := tpm2.PCRSelection{Hash: hashAlg, PCRs: selectedPCRs} quote, sig, err := tpm2.Quote(tpm, akHandle, "", "", nonce, sel, tpm2.AlgNull) if err != nil { return nil, err } rawSig, err := tpmutil.Pack(sig.Alg, sig.RSA.HashAlg, sig.RSA.Signature) return &Quote{ Version: TPMVersion20, Quote: quote, Signature: rawSig, }, err } func readAllPCRs20(tpm io.ReadWriter, alg tpm2.Algorithm) (map[uint32][]byte, error) { numPCRs := 24 out := map[uint32][]byte{} // The TPM 2.0 spec says that the TPM can partially fulfill the // request. As such, we repeat the command up to 24 times to get all // 24 PCRs. for i := 0; i < numPCRs; i++ { // Build a selection structure, specifying all PCRs we do // not have the value for. sel := tpm2.PCRSelection{Hash: alg} for pcr := 0; pcr < numPCRs; pcr++ { if _, present := out[uint32(pcr)]; !present { sel.PCRs = append(sel.PCRs, pcr) } } // Ask the TPM for those PCR values. ret, err := tpm2.ReadPCRs(tpm, sel) if err != nil { return nil, fmt.Errorf("tpm2.ReadPCRs(%+v) failed with err: %v", sel, err) } // Keep track of the PCRs we were actually given. for pcr, digest := range ret { out[uint32(pcr)] = digest } if len(out) == numPCRs { break } } if len(out) != numPCRs { return nil, fmt.Errorf("failed to read all PCRs, only read %d", len(out)) } return out, nil } // tpmBase defines the implementation of a TPM invariant. type tpmBase interface { close() error tpmVersion() TPMVersion eks() ([]EK, error) ekCertificates() ([]EK, error) info() (*TPMInfo, error) loadAK(opaqueBlob []byte) (*AK, error) loadAKWithParent(opaqueBlob []byte, parent ParentKeyConfig) (*AK, error) newAK(opts *AKConfig) (*AK, error) loadKey(opaqueBlob []byte) (*Key, error) loadKeyWithParent(opaqueBlob []byte, parent ParentKeyConfig) (*Key, error) newKey(ak *AK, opts *KeyConfig) (*Key, error) pcrs(alg HashAlg) ([]PCR, error) measurementLog() ([]byte, error) } // TPM interfaces with a TPM device on the system. type TPM struct { // tpm refers to a concrete implementation of TPM logic, based on the current // platform and TPM version. tpm tpmBase } // Close shuts down the connection to the TPM. func (t *TPM) Close() error { return t.tpm.close() } // EKs returns the endorsement keys burned-in to the platform. func (t *TPM) EKs() ([]EK, error) { return t.tpm.eks() } // EKCertificates returns the endorsement key certificates burned-in to the platform. // It is guaranteed that each EK.Certificate field will be populated. func (t *TPM) EKCertificates() ([]EK, error) { return t.tpm.ekCertificates() } // Info returns information about the TPM. func (t *TPM) Info() (*TPMInfo, error) { return t.tpm.info() } // LoadAK loads a previously-created ak into the TPM for use. // A key loaded via this function needs to be closed with .Close(). // Only blobs generated by calling AK.Marshal() are valid parameters // to this function. func (t *TPM) LoadAK(opaqueBlob []byte) (*AK, error) { return t.tpm.loadAK(opaqueBlob) } // LoadAKWithParent loads a previously-created ak into the TPM // under the given parent for use. func (t *TPM) LoadAKWithParent(opaqueBlob []byte, parent ParentKeyConfig) (*AK, error) { return t.tpm.loadAKWithParent(opaqueBlob, parent) } // MeasurementLog returns the present value of the System Measurement Log. // // This is a low-level API. Consumers seeking to attest the state of the // platform should use tpm.AttestPlatform() instead. func (t *TPM) MeasurementLog() ([]byte, error) { el, err := t.tpm.measurementLog() if err != nil { return nil, err } // A valid event log contains at least one SpecID event header (28 bytes). // For TPM 1.2, we would expect at least an event header (32 bytes). if minValidSize := 28; len(el) < minValidSize { return nil, fmt.Errorf("event log too short: %d < %d", len(el), minValidSize) } return el, nil } // NewAK creates an attestation key. func (t *TPM) NewAK(opts *AKConfig) (*AK, error) { return t.tpm.newAK(opts) } // NewKey creates an application key certified by the attestation key. If opts is nil // then DefaultConfig is used. func (t *TPM) NewKey(ak *AK, opts *KeyConfig) (*Key, error) { if opts == nil { opts = defaultConfig } if opts.Algorithm == "" && opts.Size == 0 { opts = defaultConfig } return t.tpm.newKey(ak, opts) } // LoadKey loads a previously-created application key into the TPM for use. // A key loaded via this function needs to be closed with .Close(). // Only blobs generated by calling Key.Marshal() are valid parameters // to this function. func (t *TPM) LoadKey(opaqueBlob []byte) (*Key, error) { return t.tpm.loadKey(opaqueBlob) } // PCRs returns the present value of Platform Configuration Registers with // the given digest algorithm. // // This is a low-level API. Consumers seeking to attest the state of the // platform should use tpm.AttestPlatform() instead. func (t *TPM) PCRs(alg HashAlg) ([]PCR, error) { return t.tpm.pcrs(alg) } func (t *TPM) attestPCRs(ak *AK, nonce []byte, alg HashAlg) (*Quote, []PCR, error) { pcrs, err := t.PCRs(alg) if err != nil { return nil, nil, fmt.Errorf("failed to read %v PCRs: %v", alg, err) } quote, err := ak.Quote(t, nonce, alg) if err != nil { return nil, nil, fmt.Errorf("failed to quote using %v: %v", alg, err) } // Make sure that the pcrs and quote values are consistent. See details in Section 17.6.2 of // https://trustedcomputinggroup.org/wp-content/uploads/TCG_TPM2_r1p59_Part1_Architecture_pub.pdf pub, err := ParseAKPublic(t.Version(), ak.AttestationParameters().Public) if err != nil { return nil, nil, fmt.Errorf("failed to parse AK public: %v", err) } if err := pub.Verify(*quote, pcrs, nonce); err != nil { return nil, nil, fmt.Errorf("local quote verification failed: %v", err) } return quote, pcrs, nil } func (t *TPM) attestPlatform(ak *AK, nonce []byte, eventLog []byte) (*PlatformParameters, error) { out := PlatformParameters{ TPMVersion: t.Version(), Public: ak.AttestationParameters().Public, EventLog: eventLog, } algs := []HashAlg{HashSHA1} if t.Version() == TPMVersion20 { algs = []HashAlg{HashSHA1, HashSHA256} } var lastErr error for _, alg := range algs { quote, pcrs, err := t.attestPCRs(ak, nonce, alg) if err != nil { lastErr = err continue } out.Quotes = append(out.Quotes, *quote) out.PCRs = append(out.PCRs, pcrs...) } if len(out.Quotes) == 0 { return nil, lastErr } return &out, nil } // PlatformAttestConfig configures how attestations are generated through // tpm.AttestPlatform(). type PlatformAttestConfig struct { // If non-nil, the raw event log will be read from EventLog // instead of being obtained from the running system. EventLog []byte } // AttestPlatform computes the set of information necessary to attest the // state of the platform. For TPM 2.0 devices, AttestPlatform will attempt // to read both SHA1 & SHA256 PCR banks and quote both of them, so bugs in // platform firmware which break replay for one PCR bank can be mitigated // using the other. // The provided config, if not nil, can be used to configure aspects of the // platform attestation. func (t *TPM) AttestPlatform(ak *AK, nonce []byte, config *PlatformAttestConfig) (*PlatformParameters, error) { if config == nil { config = &PlatformAttestConfig{} } var el []byte if config.EventLog != nil { el = config.EventLog } else { var err error if el, err = t.MeasurementLog(); err != nil { return nil, fmt.Errorf("failed to read event log: %v", err) } } return t.attestPlatform(ak, nonce, el) } // Version returns the version of the TPM. func (t *TPM) Version() TPMVersion { return t.tpm.tpmVersion() } go-attestation-0.5.1/attest/tpm12_linux.go000066400000000000000000000116571452320553600205130ustar00rootroot00000000000000// Copyright 2020 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. //go:build linux && !gofuzz && cgo && tspi // +build linux,!gofuzz,cgo,tspi package attest import ( "crypto" "crypto/x509" "encoding/binary" "fmt" "os" "github.com/google/go-tspi/attestation" "github.com/google/go-tspi/tspi" "github.com/google/go-tspi/tspiconst" ) func init() { getTPM12Impl = getTPM12 } func getTPM12() (*TPM, error) { ctx, err := tspi.NewContext() if err != nil { return nil, err } if err = ctx.Connect(); err != nil { return nil, err } return &TPM{tpm: &trousersTPM{ctx: ctx}}, nil } // trousersTPM interfaces with a TPM 1.2 device via tcsd. type trousersTPM struct { ctx *tspi.Context } func (*trousersTPM) isTPMBase() {} func (t *trousersTPM) tpmVersion() TPMVersion { return TPMVersion12 } func (t *trousersTPM) close() error { return t.ctx.Close() } func readTPM12VendorAttributes(context *tspi.Context) (TCGVendorID, string, error) { // TPM 1.2 doesn't seem to store vendor data (other than unique ID) vendor, err := context.GetCapability(tspiconst.TSS_TPMCAP_PROPERTY, 4, tspiconst.TSS_TPMCAP_PROP_MANUFACTURER) if err != nil { return TCGVendorID(0), "", fmt.Errorf("tspi::Context::GetCapability failed: %v", err) } if len(vendor) > 4 { return TCGVendorID(0), "", fmt.Errorf("expecting at most 32-bit VendorID, got %d-bit ID instead", len(vendor)*8) } vendorID := TCGVendorID(binary.BigEndian.Uint32(vendor)) return vendorID, vendorID.String(), nil } // Info returns information about the TPM. func (t *trousersTPM) info() (*TPMInfo, error) { tInfo := TPMInfo{ Version: TPMVersion12, Interface: TPMInterfaceDaemonManaged, } var err error if tInfo.Manufacturer, tInfo.VendorInfo, err = readTPM12VendorAttributes(t.ctx); err != nil { return nil, err } return &tInfo, nil } func readEKCertFromNVRAM12(ctx *tspi.Context) (*x509.Certificate, error) { ekCert, err := attestation.GetEKCert(ctx) if err != nil { return nil, fmt.Errorf("reading EK cert: %v", err) } return ParseEKCertificate(ekCert) } func (t *trousersTPM) ekCertificates() ([]EK, error) { cert, err := readEKCertFromNVRAM12(t.ctx) if err != nil { return nil, fmt.Errorf("readEKCertFromNVRAM failed: %v", err) } return []EK{ {Public: crypto.PublicKey(cert.PublicKey), Certificate: cert}, }, nil } func (t *trousersTPM) eks() ([]EK, error) { return t.ekCertificates() } func (t *trousersTPM) newKey(*AK, *KeyConfig) (*Key, error) { return nil, fmt.Errorf("not implemented") } func (t *trousersTPM) loadKey(opaqueBlob []byte) (*Key, error) { return nil, fmt.Errorf("not implemented") } func (t *trousersTPM) loadKeyWithParent(opaqueBlob []byte, parent ParentKeyConfig) (*Key, error) { return nil, fmt.Errorf("not implemented") } func (t *trousersTPM) newAK(opts *AKConfig) (*AK, error) { pub, blob, err := attestation.CreateAIK(t.ctx) if err != nil { return nil, fmt.Errorf("CreateAIK failed: %v", err) } return &AK{ak: newTrousersKey12(blob, pub)}, nil } func (t *trousersTPM) loadAK(opaqueBlob []byte) (*AK, error) { sKey, err := deserializeKey(opaqueBlob, TPMVersion12) if err != nil { return nil, fmt.Errorf("deserializeKey() failed: %v", err) } if sKey.Encoding != keyEncodingEncrypted { return nil, fmt.Errorf("unsupported key encoding: %x", sKey.Encoding) } return &AK{ak: newTrousersKey12(sKey.Blob, sKey.Public)}, nil } func (t *trousersTPM) loadAKWithParent(opaqueBlob []byte, parent ParentKeyConfig) (*AK, error) { return nil, fmt.Errorf("not implemented") } // allPCRs12 returns a map of all the PCR values on the TPM func allPCRs12(ctx *tspi.Context) (map[uint32][]byte, error) { tpm := ctx.GetTPM() PCRlist, err := tpm.GetPCRValues() if err != nil { return nil, fmt.Errorf("failed to read PCRs: %v", err) } PCRs := make(map[uint32][]byte) for i := 0; i < len(PCRlist); i++ { PCRs[(uint32)(i)] = PCRlist[i] } return PCRs, nil } func (t *trousersTPM) pcrs(alg HashAlg) ([]PCR, error) { if alg != HashSHA1 { return nil, fmt.Errorf("non-SHA1 algorithm %v is not supported on TPM 1.2", alg) } PCRs, err := allPCRs12(t.ctx) if err != nil { return nil, fmt.Errorf("failed to read PCRs: %v", err) } out := make([]PCR, len(PCRs)) for index, digest := range PCRs { out[int(index)] = PCR{ Index: int(index), Digest: digest, DigestAlg: alg.cryptoHash(), } } return out, nil } func (t *trousersTPM) measurementLog() ([]byte, error) { return os.ReadFile("/sys/kernel/security/tpm0/binary_bios_measurements") } go-attestation-0.5.1/attest/tpm_fake.go000066400000000000000000000011251452320553600201040ustar00rootroot00000000000000package attest import ( "io" ) var ( testLog = []byte{0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x0, 0x0, 0x0, 0x53, 0x70, 0x65, 0x63, 0x20, 0x49, 0x44, 0x20, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x33, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x2, 0x1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x20, 0x0, 0x0} ) type fakeCmdChannel struct { io.ReadWriteCloser } // MeasurementLog implements CommandChannelTPM20. func (cc *fakeCmdChannel) MeasurementLog() ([]byte, error) { return testLog, nil } go-attestation-0.5.1/attest/tpm_linux.go000066400000000000000000000057511452320553600203460ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. //go:build linux && !gofuzz // +build linux,!gofuzz package attest import ( "errors" "fmt" "io" "os" "path" "strings" "github.com/google/go-tpm/legacy/tpm2" ) const ( tpmRoot = "/sys/class/tpm" ) // This will be initialized if we build with CGO (needed for TPM 1.2 support). var getTPM12Impl func() (*TPM, error) // InjectSimulatedTPMForTest returns a fake TPM that interfaces with // the provided simulated TPM. This method should be used for testing // only. func InjectSimulatedTPMForTest(rwc io.ReadWriteCloser) *TPM { return &TPM{tpm: &wrappedTPM20{ interf: TPMInterfaceCommandChannel, rwc: &fakeCmdChannel{rwc}, }} } func probeSystemTPMs() ([]probedTPM, error) { var tpms []probedTPM tpmDevs, err := os.ReadDir(tpmRoot) if err != nil && !os.IsNotExist(err) { return nil, err } if err == nil { for _, tpmDev := range tpmDevs { if strings.HasPrefix(tpmDev.Name(), "tpm") { tpm := probedTPM{ Path: path.Join(tpmRoot, tpmDev.Name()), } if _, err := os.Stat(path.Join(tpm.Path, "caps")); err != nil { if !os.IsNotExist(err) { return nil, err } tpm.Version = TPMVersion20 } else { tpm.Version = TPMVersion12 } tpms = append(tpms, tpm) } } } return tpms, nil } type linuxCmdChannel struct { io.ReadWriteCloser } // MeasurementLog implements CommandChannelTPM20. func (cc *linuxCmdChannel) MeasurementLog() ([]byte, error) { return os.ReadFile("/sys/kernel/security/tpm0/binary_bios_measurements") } func openTPM(tpm probedTPM) (*TPM, error) { switch tpm.Version { case TPMVersion12: if getTPM12Impl == nil { return nil, errors.New("support for Linux TPM 1.2 disabled (build with CGO to enable)") } return getTPM12Impl() case TPMVersion20: interf := TPMInterfaceDirect // If the TPM has a kernel-provided resource manager, we should // use that instead of communicating directly. devPath := path.Join("/dev", path.Base(tpm.Path)) f, err := os.ReadDir(path.Join(tpm.Path, "device", "tpmrm")) if err != nil { if !os.IsNotExist(err) { return nil, err } } else if len(f) > 0 { devPath = path.Join("/dev", f[0].Name()) interf = TPMInterfaceKernelManaged } rwc, err := tpm2.OpenTPM(devPath) if err != nil { return nil, err } return &TPM{tpm: &wrappedTPM20{ interf: interf, rwc: &linuxCmdChannel{rwc}, }}, nil default: return nil, fmt.Errorf("unsuported TPM version: %v", tpm.Version) } } go-attestation-0.5.1/attest/tpm_other.go000066400000000000000000000016631452320553600203260ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. //go:build gofuzz || (!linux && !windows) // +build gofuzz !linux,!windows package attest import ( "errors" ) var errUnsupported = errors.New("tpm operations not supported from given build parameters") func probeSystemTPMs() ([]probedTPM, error) { return nil, errUnsupported } func openTPM(tpm probedTPM) (*TPM, error) { return nil, errUnsupported } go-attestation-0.5.1/attest/tpm_test.go000066400000000000000000000034161452320553600201620ustar00rootroot00000000000000package attest import ( "crypto/rsa" "crypto/x509" "encoding/pem" "fmt" "testing" ) // Created by downloading the base64-url encoded PEM data from // https://ekop.intel.com/ekcertservice/WVEG2rRwkQ7m3RpXlUphgo6Y2HLxl18h6ZZkkOAdnBE%3D, // extracting its public key, and formatting it to PEM using // // openssl x509 -in ekcert.pem -pubkey // // This is the public key from the EK cert that's used for testing tpm2-tools: // https://github.com/tpm2-software/tpm2-tools/blob/master/test/integration/tests/getekcertificate.sh var testRSAKey = mustParseRSAKey(`-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwyDi8kSoYBqs8+AdJsZl JJk1Vi3h2hl+nn8HbEaWE8+2U+mOwsOG/B0TPyyMbMM4tzLwsgi9g4qHej5bvD4d QIToNcfIkGocBbTS0w/b68HbrZUPprFlvUtqhkYDFGFkwMT1nUiQEe8fko3upukA YfPTdeVkYnMVHvYiJSCYvhpKsB3AoSInxgn9rOsRWvQI1Gk6b0mRl3RpWwwSvBih /3EgpzN7L7XxlR2Lt/CU1bVUwRyVI7MHKf5keH0KE7nmMEiNq039hmNKUnDscvzF pE3GeajzKTjdgZfina6Dn1tMoPXeJ8lSLCPFThws5XhZUlEYvURwsYGA7veK5CZ7 zQIDAQAB -----END PUBLIC KEY-----`) func mustParseRSAKey(data string) *rsa.PublicKey { pub, err := parseRSAKey(data) if err != nil { panic(err) } return pub } func parseRSAKey(data string) (*rsa.PublicKey, error) { b, _ := pem.Decode([]byte(data)) if b == nil { return nil, fmt.Errorf("failed to parse PEM key") } pub, err := x509.ParsePKIXPublicKey(b.Bytes) if err != nil { return nil, fmt.Errorf("parsing public key: %v", err) } if rsaPub, ok := pub.(*rsa.PublicKey); ok { return rsaPub, nil } return nil, fmt.Errorf("expected *rsa.PublicKey, got %T", pub) } func TestIntelEKURL(t *testing.T) { want := "https://ekop.intel.com/ekcertservice/WVEG2rRwkQ7m3RpXlUphgo6Y2HLxl18h6ZZkkOAdnBE%3D" got := intelEKURL(testRSAKey) if got != want { t.Fatalf("intelEKURL(), got=%q, want=%q", got, want) } } go-attestation-0.5.1/attest/tpm_windows.go000066400000000000000000000260671452320553600207040ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. //go:build windows // +build windows package attest import ( "bytes" "crypto/aes" "crypto/cipher" "crypto/rand" "crypto/rsa" "encoding/binary" "errors" "fmt" "io" "math/big" tpm1 "github.com/google/go-tpm/tpm" tpmtbs "github.com/google/go-tpm/tpmutil/tbs" "golang.org/x/sys/windows" ) var wellKnownAuth [20]byte type windowsTPM struct { version TPMVersion pcp *winPCP } func (*windowsTPM) isTPMBase() {} func probeSystemTPMs() ([]probedTPM, error) { // Initialize Tbs.dll here so that it's linked only when TPM support is required. if tbs == nil { tbs = windows.MustLoadDLL("Tbs.dll") tbsGetDeviceInfo = tbs.MustFindProc("Tbsi_GetDeviceInfo") } // Windows systems appear to only support a single abstracted TPM. // If we fail to initialize the Platform Crypto Provider, we assume // a TPM is not present. pcp, err := openPCP() if err != nil { return nil, nil } defer pcp.Close() info, err := pcp.TPMInfo() if err != nil { return nil, fmt.Errorf("TPMInfo() failed: %v", err) } var out probedTPM out.Version, err = tbsConvertVersion(info.TBSInfo) if err != nil { return nil, fmt.Errorf("tbsConvertVersion(%v) failed: %v", info.TBSInfo.TPMVersion, err) } return []probedTPM{out}, nil } func tbsConvertVersion(info tbsDeviceInfo) (TPMVersion, error) { switch info.TPMVersion { case 1: return TPMVersion12, nil case 2: return TPMVersion20, nil default: return TPMVersionAgnostic, fmt.Errorf("TBSInfo.TPMVersion %d unsupported", info.TPMVersion) } } func openTPM(tpm probedTPM) (*TPM, error) { pcp, err := openPCP() if err != nil { return nil, fmt.Errorf("openPCP() failed: %v", err) } info, err := pcp.TPMInfo() if err != nil { return nil, fmt.Errorf("TPMInfo() failed: %v", err) } vers, err := tbsConvertVersion(info.TBSInfo) if err != nil { return nil, fmt.Errorf("tbsConvertVersion(%v) failed: %v", info.TBSInfo.TPMVersion, err) } return &TPM{tpm: &windowsTPM{ pcp: pcp, version: vers, }}, nil } func (t *windowsTPM) tpmVersion() TPMVersion { return t.version } func (t *windowsTPM) close() error { return t.pcp.Close() } func readTPM12VendorAttributes(tpm io.ReadWriter) (TCGVendorID, string, error) { vendor, err := tpm1.GetManufacturer(tpm) if err != nil { return TCGVendorID(0), "", fmt.Errorf("tpm1.GetCapability failed: %v", err) } vendorID := TCGVendorID(binary.BigEndian.Uint32(vendor)) return vendorID, vendorID.String(), nil } func (t *windowsTPM) info() (*TPMInfo, error) { tInfo := TPMInfo{ Version: t.version, Interface: TPMInterfaceKernelManaged, } tpm, err := t.pcp.TPMCommandInterface() if err != nil { return nil, err } switch t.version { case TPMVersion12: tInfo.Manufacturer, tInfo.VendorInfo, err = readTPM12VendorAttributes(tpm) case TPMVersion20: var t2Info tpm20Info t2Info, err = readTPM2VendorAttributes(tpm) tInfo.Manufacturer = t2Info.manufacturer tInfo.VendorInfo = t2Info.vendor tInfo.FirmwareVersionMajor = t2Info.fwMajor tInfo.FirmwareVersionMinor = t2Info.fwMinor default: return nil, fmt.Errorf("unsupported TPM version: %x", t.version) } if err != nil { return nil, err } return &tInfo, nil } func (t *windowsTPM) ekCertificates() ([]EK, error) { ekCerts, err := t.pcp.EKCerts() if err != nil { return nil, fmt.Errorf("could not read EKCerts: %v", err) } var eks []EK for _, cert := range ekCerts { eks = append(eks, EK{Certificate: cert, Public: cert.PublicKey}) } return eks, nil } func (t *windowsTPM) eks() ([]EK, error) { ekCerts, err := t.pcp.EKCerts() if err != nil { return nil, fmt.Errorf("could not read EKCerts: %v", err) } if len(ekCerts) > 0 { var eks []EK for _, cert := range ekCerts { eks = append(eks, EK{Certificate: cert, Public: cert.PublicKey}) } return eks, nil } pub, err := t.ekPub() if err != nil { return nil, fmt.Errorf("could not read ek public key from tpm: %v", err) } ek := EK{Public: pub} i, err := t.info() if err != nil { return nil, err } if i.Manufacturer.String() == manufacturerIntel { ek.CertificateURL = intelEKURL(pub) } return []EK{ek}, nil } func (t *windowsTPM) ekPub() (*rsa.PublicKey, error) { p, err := t.pcp.EKPub() if err != nil { return nil, fmt.Errorf("could not read ekpub: %v", err) } ekPub, err := decodeWindowsBcryptRSABlob(p) if err != nil { return nil, fmt.Errorf("could not decode ekpub: %v", err) } return ekPub, nil } type bcryptRSABlobHeader struct { Magic uint32 BitLength uint32 ExponentLen uint32 ModulusLen uint32 Prime1Len uint32 Prime2Len uint32 } func decodeWindowsBcryptRSABlob(b []byte) (*rsa.PublicKey, error) { var ( r = bytes.NewReader(b) header = &bcryptRSABlobHeader{} exp = make([]byte, 8) mod = []byte("") ) if err := binary.Read(r, binary.LittleEndian, header); err != nil { return nil, err } if header.Magic != 0x31415352 { // "RSA1" return nil, fmt.Errorf("invalid header magic %x", header.Magic) } if header.ExponentLen > 8 { return nil, errors.New("exponent too large") } if _, err := r.Read(exp[8-header.ExponentLen:]); err != nil { return nil, fmt.Errorf("failed to read public exponent: %v", err) } mod = make([]byte, header.ModulusLen) if n, err := r.Read(mod); n != int(header.ModulusLen) || err != nil { return nil, fmt.Errorf("failed to read modulus (%d, %v)", n, err) } return &rsa.PublicKey{ N: new(big.Int).SetBytes(mod), E: int(binary.BigEndian.Uint64(exp)), }, nil } func decryptCredential(secretKey, blob []byte) ([]byte, error) { var scheme uint32 symbuf := bytes.NewReader(blob) if err := binary.Read(symbuf, binary.BigEndian, &scheme); err != nil { return nil, fmt.Errorf("reading scheme: %v", err) } if scheme != 0x00000002 { return nil, fmt.Errorf("can only handle CBC schemes") } iv := make([]byte, 16) if err := binary.Read(symbuf, binary.BigEndian, &iv); err != nil { return nil, err } cipherText := make([]byte, len(blob)-20) if err := binary.Read(symbuf, binary.BigEndian, &cipherText); err != nil { return nil, fmt.Errorf("reading ciphertext: %v", err) } // Decrypt the credential. var ( block cipher.Block secret []byte err error ) block, err = aes.NewCipher(secretKey) if err != nil { return nil, fmt.Errorf("aes.NewCipher failed: %v", err) } secret = cipherText mode := cipher.NewCBCDecrypter(block, iv) mode.CryptBlocks(secret, cipherText) // Remove PKCS5 padding. padlen := int(secret[len(secret)-1]) secret = secret[:len(secret)-padlen] return secret, nil } func (t *windowsTPM) newAK(opts *AKConfig) (*AK, error) { nameHex := make([]byte, 5) if n, err := rand.Read(nameHex); err != nil || n != len(nameHex) { return nil, fmt.Errorf("rand.Read() failed with %d/%d bytes read and error: %v", n, len(nameHex), err) } name := fmt.Sprintf("ak-%x", nameHex) kh, err := t.pcp.NewAK(name) if err != nil { return nil, fmt.Errorf("pcp failed to mint attestation key: %v", err) } props, err := t.pcp.AKProperties(kh) if err != nil { closeNCryptObject(kh) return nil, fmt.Errorf("pcp failed to read attestation key properties: %v", err) } switch t.version { case TPMVersion12: return &AK{ak: newWindowsKey12(kh, name, props.RawPublic)}, nil case TPMVersion20: return &AK{ak: newWindowsKey20(kh, name, props.RawPublic, props.RawCreationData, props.RawAttest, props.RawSignature)}, nil default: return nil, fmt.Errorf("cannot handle TPM version: %v", t.version) } } func (t *windowsTPM) loadAK(opaqueBlob []byte) (*AK, error) { sKey, err := deserializeKey(opaqueBlob, t.version) if err != nil { return nil, fmt.Errorf("deserializeKey() failed: %v", err) } if sKey.Encoding != keyEncodingOSManaged { return nil, fmt.Errorf("unsupported key encoding: %x", sKey.Encoding) } hnd, err := t.pcp.LoadKeyByName(sKey.Name) if err != nil { return nil, fmt.Errorf("pcp failed to load key: %v", err) } switch t.version { case TPMVersion12: return &AK{ak: newWindowsKey12(hnd, sKey.Name, sKey.Public)}, nil case TPMVersion20: return &AK{ak: newWindowsKey20(hnd, sKey.Name, sKey.Public, sKey.CreateData, sKey.CreateAttestation, sKey.CreateSignature)}, nil default: return nil, fmt.Errorf("cannot handle TPM version: %v", t.version) } } func (t *windowsTPM) loadAKWithParent(opaqueBlob []byte, parent ParentKeyConfig) (*AK, error) { return nil, fmt.Errorf("not implemented") } func (t *windowsTPM) newKey(*AK, *KeyConfig) (*Key, error) { return nil, fmt.Errorf("not implemented") } func (t *windowsTPM) loadKey(opaqueBlob []byte) (*Key, error) { return nil, fmt.Errorf("not implemented") } func (t *windowsTPM) loadKeyWithParent(opaqueBlob []byte, parent ParentKeyConfig) (*Key, error) { return nil, fmt.Errorf("not implemented") } func allPCRs12(tpm io.ReadWriter) (map[uint32][]byte, error) { numPCRs := 24 out := map[uint32][]byte{} for pcr := 0; pcr < numPCRs; pcr++ { pcrval, err := tpm1.ReadPCR(tpm, uint32(pcr)) if err != nil { return nil, fmt.Errorf("tpm.ReadPCR() failed with err: %v", err) } out[uint32(pcr)] = pcrval } if len(out) != numPCRs { return nil, fmt.Errorf("failed to read all PCRs, only read %d", len(out)) } return out, nil } func (t *windowsTPM) pcrs(alg HashAlg) ([]PCR, error) { var PCRs map[uint32][]byte switch t.version { case TPMVersion12: if alg != HashSHA1 { return nil, fmt.Errorf("non-SHA1 algorithm %v is not supported on TPM 1.2", alg) } tpm, err := t.pcp.TPMCommandInterface() if err != nil { return nil, fmt.Errorf("TPMCommandInterface() failed: %v", err) } PCRs, err = allPCRs12(tpm) if err != nil { return nil, fmt.Errorf("failed to read PCRs: %v", err) } case TPMVersion20: tpm, err := t.pcp.TPMCommandInterface() if err != nil { return nil, fmt.Errorf("TPMCommandInterface() failed: %v", err) } PCRs, err = readAllPCRs20(tpm, alg.goTPMAlg()) if err != nil { return nil, fmt.Errorf("failed to read PCRs: %v", err) } default: return nil, fmt.Errorf("unsupported TPM version: %x", t.version) } out := make([]PCR, len(PCRs)) for index, digest := range PCRs { out[int(index)] = PCR{ Index: int(index), Digest: digest, DigestAlg: alg.cryptoHash(), } } return out, nil } func (t *windowsTPM) measurementLog() ([]byte, error) { context, err := tpmtbs.CreateContext(tpmtbs.TPMVersion20, tpmtbs.IncludeTPM20|tpmtbs.IncludeTPM12) if err != nil { return nil, err } defer context.Close() // Run command first with nil buffer to get required buffer size. logLen, err := context.GetTCGLog(nil) if err != nil { return nil, err } logBuffer := make([]byte, logLen) if _, err = context.GetTCGLog(logBuffer); err != nil { return nil, err } return logBuffer, nil } go-attestation-0.5.1/attest/vendors.go000066400000000000000000000027301452320553600200010ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package attest // TCGVendorID represents a unique TCG manufacturer code. // The canonical reference used is located at: // https://trustedcomputinggroup.org/wp-content/uploads/TCG-TPM-Vendor-ID-Registry-Version-1.01-Revision-1.00.pdf type TCGVendorID uint32 var vendors = map[TCGVendorID]string{ 1095582720: "AMD", 1096043852: "Atmel", 1112687437: "Broadcom", 1229081856: "IBM", 1213220096: "HPE", 1297303124: "Microsoft", 1229346816: "Infineon", 1229870147: "Intel", 1279610368: "Lenovo", 1314082080: "National Semiconductor", 1314150912: "Nationz", 1314145024: "Nuvoton Technology", 1363365709: "Qualcomm", 1397576515: "SMSC", 1398033696: "ST Microelectronics", 1397576526: "Samsung", 1397641984: "Sinosun", 1415073280: "Texas Instruments", 1464156928: "Winbond", 1380926275: "Fuzhou Rockchip", 1196379975: "Google", } func (id TCGVendorID) String() string { return vendors[id] } go-attestation-0.5.1/attest/win_events.go000066400000000000000000000654431452320553600205140ustar00rootroot00000000000000// Copyright 2020 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package attest import ( "bytes" "encoding/binary" "encoding/hex" "errors" "fmt" "io" "strings" "unicode/utf16" "github.com/google/go-attestation/attest/internal" ) type windowsEvent uint32 // SIPA event types const ( sipaTypeMask windowsEvent = 0x000f0000 sipaContainer windowsEvent = 0x00010000 sipaInformation windowsEvent = 0x00020000 sipaError windowsEvent = 0x00030000 sipaPreOsParameter windowsEvent = 0x00040000 sipaOSParameter windowsEvent = 0x00050000 sipaAuthority windowsEvent = 0x00060000 sipaLoadedModule windowsEvent = 0x00070000 sipaTrustPoint windowsEvent = 0x00080000 sipaELAM windowsEvent = 0x00090000 sipaVBS windowsEvent = 0x000a0000 trustBoundary windowsEvent = 0x40010001 elamAggregation windowsEvent = 0x40010002 loadedModuleAggregation windowsEvent = 0x40010003 trustpointAggregation windowsEvent = 0xC0010004 ksrAggregation windowsEvent = 0x40010005 ksrSignedMeasurementAggregation windowsEvent = 0x40010006 information windowsEvent = 0x00020001 bootCounter windowsEvent = 0x00020002 transferControl windowsEvent = 0x00020003 applicationReturn windowsEvent = 0x00020004 bitlockerUnlock windowsEvent = 0x00020005 eventCounter windowsEvent = 0x00020006 counterID windowsEvent = 0x00020007 morBitNotCancelable windowsEvent = 0x00020008 applicationSVN windowsEvent = 0x00020009 svnChainStatus windowsEvent = 0x0002000A morBitAPIStatus windowsEvent = 0x0002000B bootDebugging windowsEvent = 0x00040001 bootRevocationList windowsEvent = 0x00040002 osKernelDebug windowsEvent = 0x00050001 codeIntegrity windowsEvent = 0x00050002 testSigning windowsEvent = 0x00050003 dataExecutionPrevention windowsEvent = 0x00050004 safeMode windowsEvent = 0x00050005 winPE windowsEvent = 0x00050006 physicalAddressExtension windowsEvent = 0x00050007 osDevice windowsEvent = 0x00050008 systemRoot windowsEvent = 0x00050009 hypervisorLaunchType windowsEvent = 0x0005000A hypervisorPath windowsEvent = 0x0005000B hypervisorIOMMUPolicy windowsEvent = 0x0005000C hypervisorDebug windowsEvent = 0x0005000D driverLoadPolicy windowsEvent = 0x0005000E siPolicy windowsEvent = 0x0005000F hypervisorMMIONXPolicy windowsEvent = 0x00050010 hypervisorMSRFilterPolicy windowsEvent = 0x00050011 vsmLaunchType windowsEvent = 0x00050012 osRevocationList windowsEvent = 0x00050013 vsmIDKInfo windowsEvent = 0x00050020 flightSigning windowsEvent = 0x00050021 pagefileEncryptionEnabled windowsEvent = 0x00050022 vsmIDKSInfo windowsEvent = 0x00050023 hibernationDisabled windowsEvent = 0x00050024 dumpsDisabled windowsEvent = 0x00050025 dumpEncryptionEnabled windowsEvent = 0x00050026 dumpEncryptionKeyDigest windowsEvent = 0x00050027 lsaISOConfig windowsEvent = 0x00050028 noAuthority windowsEvent = 0x00060001 authorityPubKey windowsEvent = 0x00060002 filePath windowsEvent = 0x00070001 imageSize windowsEvent = 0x00070002 hashAlgorithmID windowsEvent = 0x00070003 authenticodeHash windowsEvent = 0x00070004 authorityIssuer windowsEvent = 0x00070005 authoritySerial windowsEvent = 0x00070006 imageBase windowsEvent = 0x00070007 authorityPublisher windowsEvent = 0x00070008 authoritySHA1Thumbprint windowsEvent = 0x00070009 imageValidated windowsEvent = 0x0007000A moduleSVN windowsEvent = 0x0007000B quote windowsEvent = 0x80080001 quoteSignature windowsEvent = 0x80080002 aikID windowsEvent = 0x80080003 aikPubDigest windowsEvent = 0x80080004 elamKeyname windowsEvent = 0x00090001 elamConfiguration windowsEvent = 0x00090002 elamPolicy windowsEvent = 0x00090003 elamMeasured windowsEvent = 0x00090004 vbsVSMRequired windowsEvent = 0x000A0001 vbsSecurebootRequired windowsEvent = 0x000A0002 vbsIOMMURequired windowsEvent = 0x000A0003 vbsNXRequired windowsEvent = 0x000A0004 vbsMSRFilteringRequired windowsEvent = 0x000A0005 vbsMandatoryEnforcement windowsEvent = 0x000A0006 vbsHVCIPolicy windowsEvent = 0x000A0007 vbsMicrosoftBootChainRequired windowsEvent = 0x000A0008 ksrSignature windowsEvent = 0x000B0001 ) type WinCSPAlg uint32 // Valid CSP Algorithm IDs. const ( WinAlgMD4 WinCSPAlg = 0x02 WinAlgMD5 WinCSPAlg = 0x03 WinAlgSHA1 WinCSPAlg = 0x04 WinAlgSHA256 WinCSPAlg = 0x0c WinAlgSHA384 WinCSPAlg = 0x0d WinAlgSHA512 WinCSPAlg = 0x0e ) // BitlockerStatus describes the status of BitLocker on a Windows system. type BitlockerStatus uint8 // Valid BitlockerStatus values. const ( BitlockerStatusCached = 0x01 BitlockerStatusMedia = 0x02 BitlockerStatusTPM = 0x04 BitlockerStatusPin = 0x10 BitlockerStatusExternal = 0x20 BitlockerStatusRecovery = 0x40 ) // Ternary describes a boolean value that can additionally be unknown. type Ternary uint8 // Valid Ternary values. const ( TernaryUnknown Ternary = iota TernaryTrue TernaryFalse ) // WinEvents describes information from the event log recorded during // bootup of Microsoft Windows. type WinEvents struct { // ColdBoot is set to true if the system was not resuming from hibernation. ColdBoot bool // BootCount contains the value of the monotonic boot counter. This // value is not set for TPM 1.2 devices and some TPMs with buggy // implementations of monotonic counters. BootCount uint64 // LoadedModules contains authenticode hashes for binaries which // were loaded during boot. LoadedModules map[string]WinModuleLoad // ELAM describes the configuration of each Early Launch AntiMalware driver, // for each AV Vendor key. ELAM map[string]WinELAM // BootDebuggingEnabled is true if boot debugging was ever reported // as enabled. BootDebuggingEnabled bool // KernelDebugEnabled is true if kernel debugging was recorded as // enabled at any point during boot. KernelDebugEnabled bool // DEPEnabled is true if NX (Data Execution Prevention) was consistently // reported as enabled. DEPEnabled Ternary // CodeIntegrityEnabled is true if code integrity was consistently // reported as enabled. CodeIntegrityEnabled Ternary // TestSigningEnabled is true if test-mode signature verification was // ever reported as enabled. TestSigningEnabled bool // BitlockerUnlocks reports the bitlocker status for every instance of // a disk unlock, where bitlocker was used to secure the disk. BitlockerUnlocks []BitlockerStatus } // WinModuleLoad describes a module which was loaded while // Windows booted. type WinModuleLoad struct { // FilePath represents the path from which the module was loaded. This // information is not always present. FilePath string // AuthenticodeHash contains the authenticode hash of the binary // blob which was loaded. AuthenticodeHash []byte // ImageBase describes all the addresses to which the the blob was loaded. ImageBase []uint64 // ImageSize describes the size of the image in bytes. This information // is not always present. ImageSize uint64 // HashAlgorithm describes the hash algorithm used. HashAlgorithm WinCSPAlg // ImageValidated is set if the post-boot loader validated the image. ImageValidated bool // AuthorityIssuer identifies the issuer of the certificate which certifies // the signature on this module. AuthorityIssuer string // AuthorityPublisher identifies the publisher of the certificate which // certifies the signature on this module. AuthorityPublisher string // AuthoritySerial contains the serial of the certificate certifying this // module. AuthoritySerial []byte // AuthoritySHA1 is the SHA1 hash of the certificate thumbprint. AuthoritySHA1 []byte } // WinELAM describes the configuration of an Early Launch AntiMalware driver. // These values represent the 3 measured registry values stored in the ELAM // hive for the driver. type WinELAM struct { Measured []byte Config []byte Policy []byte } // ParseWinEvents parses a series of events to extract information about // the bringup of Microsoft Windows. This information is not trustworthy // unless the integrity of platform & bootloader events has already been // established. func ParseWinEvents(events []Event) (*WinEvents, error) { var ( out = WinEvents{ LoadedModules: map[string]WinModuleLoad{}, ELAM: map[string]WinELAM{}, } seenSeparator struct { PCR12 bool PCR13 bool } ) for _, e := range events { if e.Index != 12 && e.Index != 13 { continue } et, err := internal.UntrustedParseEventType(uint32(e.Type)) if err != nil { return nil, fmt.Errorf("unrecognised event type: %v", err) } digestVerify := e.digestEquals(e.Data) switch e.Index { case 12: // 'early boot' events switch et { case internal.EventTag: if seenSeparator.PCR12 { continue } s, err := internal.ParseTaggedEventData(e.Data) if err != nil { return nil, fmt.Errorf("invalid tagged event structure at event %d: %w", e.sequence, err) } if digestVerify != nil { return nil, fmt.Errorf("invalid digest for tagged event %d: %w", e.sequence, digestVerify) } if err := out.readWinEventBlock(s, e.Index); err != nil { return nil, fmt.Errorf("invalid SIPA events in event %d: %w", e.sequence, err) } case internal.Separator: if seenSeparator.PCR12 { return nil, fmt.Errorf("duplicate WBCL separator at event %d", e.sequence) } seenSeparator.PCR12 = true if !bytes.Equal(e.Data, []byte("WBCL")) { return nil, fmt.Errorf("invalid WBCL separator data at event %d: %v", e.sequence, e.Data) } if digestVerify != nil { return nil, fmt.Errorf("invalid separator digest at event %d: %v", e.sequence, digestVerify) } default: return nil, fmt.Errorf("unexpected (PCR12) event type: %v", et) } case 13: // Post 'early boot' events switch et { case internal.EventTag: if seenSeparator.PCR13 { continue } s, err := internal.ParseTaggedEventData(e.Data) if err != nil { return nil, fmt.Errorf("invalid tagged event structure at event %d: %w", e.sequence, err) } if digestVerify != nil { return nil, fmt.Errorf("invalid digest for tagged event %d: %w", e.sequence, digestVerify) } if err := out.readWinEventBlock(s, e.Index); err != nil { return nil, fmt.Errorf("invalid SIPA events in event %d: %w", e.sequence, err) } case internal.Separator: if seenSeparator.PCR13 { return nil, fmt.Errorf("duplicate WBCL separator at event %d", e.sequence) } seenSeparator.PCR13 = true if !bytes.Equal(e.Data, []byte("WBCL")) { return nil, fmt.Errorf("invalid WBCL separator data at event %d: %v", e.sequence, e.Data) } if digestVerify != nil { return nil, fmt.Errorf("invalid separator digest at event %d: %v", e.sequence, digestVerify) } default: return nil, fmt.Errorf("unexpected (PCR13) event type: %v", et) } } } return &out, nil } type microsoftEventHeader struct { Type windowsEvent Size uint32 } // unknownSIPAEvent is returned by parseSIPAEvent if the event type is // not handled. Unlike other events in the TCG log, it is safe to skip // unhandled SIPA events, as they are embedded within EventTag structures, // and these structures should match the event digest. var unknownSIPAEvent = errors.New("unknown event") func (w *WinEvents) readBooleanInt64Event(header microsoftEventHeader, r *bytes.Reader) error { if header.Size != 8 { return fmt.Errorf("payload was %d bytes, want 8", header.Size) } var num uint64 if err := binary.Read(r, binary.LittleEndian, &num); err != nil { return fmt.Errorf("reading u64: %w", err) } isSet := num != 0 switch header.Type { // Boolean signals that latch off if the are ever false (ie: attributes // that represent a stronger security state when set). case dataExecutionPrevention: if isSet && w.DEPEnabled == TernaryUnknown { w.DEPEnabled = TernaryTrue } else if !isSet { w.DEPEnabled = TernaryFalse } } return nil } func (w *WinEvents) readBooleanByteEvent(header microsoftEventHeader, r *bytes.Reader) error { if header.Size != 1 { return fmt.Errorf("payload was %d bytes, want 1", header.Size) } var b byte if err := binary.Read(r, binary.LittleEndian, &b); err != nil { return fmt.Errorf("reading byte: %w", err) } isSet := b != 0 switch header.Type { // Boolean signals that latch on if they are ever true (ie: attributes // that represent a weaker security state when set). case osKernelDebug: w.KernelDebugEnabled = w.KernelDebugEnabled || isSet case bootDebugging: w.BootDebuggingEnabled = w.BootDebuggingEnabled || isSet case testSigning: w.TestSigningEnabled = w.TestSigningEnabled || isSet // Boolean signals that latch off if the are ever false (ie: attributes // that represent a stronger security state when set). case codeIntegrity: if isSet && w.CodeIntegrityEnabled == TernaryUnknown { w.CodeIntegrityEnabled = TernaryTrue } else if !isSet { w.CodeIntegrityEnabled = TernaryFalse } } return nil } func (w *WinEvents) readUint32(header microsoftEventHeader, r io.Reader) (uint32, error) { if header.Size != 4 { return 0, fmt.Errorf("integer size not uint32 (%d bytes)", header.Size) } data := make([]uint8, header.Size) if err := binary.Read(r, binary.LittleEndian, &data); err != nil { return 0, fmt.Errorf("reading u32: %w", err) } i := binary.LittleEndian.Uint32(data) return i, nil } func (w *WinEvents) readUint64(header microsoftEventHeader, r io.Reader) (uint64, error) { if header.Size != 8 { return 0, fmt.Errorf("integer size not uint64 (%d bytes)", header.Size) } data := make([]uint8, header.Size) if err := binary.Read(r, binary.LittleEndian, &data); err != nil { return 0, fmt.Errorf("reading u64: %w", err) } i := binary.LittleEndian.Uint64(data) return i, nil } func (w *WinEvents) readBootCounter(header microsoftEventHeader, r *bytes.Reader) error { i, err := w.readUint64(header, r) if err != nil { return fmt.Errorf("boot counter: %v", err) } if w.BootCount > 0 && w.BootCount != i { return fmt.Errorf("conflicting values for boot counter: %d != %d", i, w.BootCount) } w.BootCount = i return nil } func (w *WinEvents) readTransferControl(header microsoftEventHeader, r *bytes.Reader) error { i, err := w.readUint32(header, r) if err != nil { return fmt.Errorf("transfer control: %v", err) } // A transferControl event with a value of 1 indicates that bootmngr // launched WinLoad. A different (unknown) value is set if WinResume // is launched. w.ColdBoot = i == 0x1 return nil } func (w *WinEvents) readBitlockerUnlock(header microsoftEventHeader, r *bytes.Reader, pcr int) error { if header.Size > 8 { return fmt.Errorf("bitlocker data too large (%d bytes)", header.Size) } data := make([]uint8, header.Size) if err := binary.Read(r, binary.LittleEndian, &data); err != nil { return fmt.Errorf("reading u%d: %w", header.Size<<8, err) } i, n := binary.Uvarint(data) if n <= 0 { return fmt.Errorf("reading u%d: invalid varint", header.Size<<8) } if pcr == 13 { // The bitlocker status is duplicated across both PCRs. As such, // we prefer the earlier one, and bail here to prevent duplicate // records. return nil } w.BitlockerUnlocks = append(w.BitlockerUnlocks, BitlockerStatus(i)) return nil } func (w *WinEvents) parseImageValidated(header microsoftEventHeader, r io.Reader) (bool, error) { if header.Size != 1 { return false, fmt.Errorf("payload was %d bytes, want 1", header.Size) } var num byte if err := binary.Read(r, binary.LittleEndian, &num); err != nil { return false, fmt.Errorf("reading u8: %w", err) } return num == 1, nil } func (w *WinEvents) parseHashAlgID(header microsoftEventHeader, r io.Reader) (WinCSPAlg, error) { i, err := w.readUint32(header, r) if err != nil { return 0, fmt.Errorf("hash algorithm ID: %v", err) } switch alg := WinCSPAlg(i & 0xff); alg { case WinAlgMD4, WinAlgMD5, WinAlgSHA1, WinAlgSHA256, WinAlgSHA384, WinAlgSHA512: return alg, nil default: return 0, fmt.Errorf("unknown algorithm ID: %x", i) } } func (w *WinEvents) parseAuthoritySerial(header microsoftEventHeader, r io.Reader) ([]byte, error) { if header.Size > 128 { return nil, fmt.Errorf("authority serial is too long (%d bytes)", header.Size) } data := make([]byte, header.Size) if err := binary.Read(r, binary.LittleEndian, &data); err != nil { return nil, fmt.Errorf("reading bytes: %w", err) } return data, nil } func (w *WinEvents) parseAuthoritySHA1(header microsoftEventHeader, r io.Reader) ([]byte, error) { if header.Size > 20 { return nil, fmt.Errorf("authority thumbprint is too long (%d bytes)", header.Size) } data := make([]byte, header.Size) if err := binary.Read(r, binary.LittleEndian, &data); err != nil { return nil, fmt.Errorf("reading bytes: %w", err) } return data, nil } func (w *WinEvents) parseImageBase(header microsoftEventHeader, r io.Reader) (uint64, error) { if header.Size != 8 { return 0, fmt.Errorf("payload was %d bytes, want 8", header.Size) } var num uint64 if err := binary.Read(r, binary.LittleEndian, &num); err != nil { return 0, fmt.Errorf("reading u64: %w", err) } return num, nil } func (w *WinEvents) parseAuthenticodeHash(header microsoftEventHeader, r io.Reader) ([]byte, error) { if header.Size > 32 { return nil, fmt.Errorf("authenticode hash data exceeds the size of any valid hash (%d bytes)", header.Size) } data := make([]byte, header.Size) if err := binary.Read(r, binary.LittleEndian, &data); err != nil { return nil, fmt.Errorf("reading bytes: %w", err) } return data, nil } func (w *WinEvents) readLoadedModuleAggregation(rdr *bytes.Reader, header microsoftEventHeader) error { var ( r = &io.LimitedReader{R: rdr, N: int64(header.Size)} codeHash []byte imgBase, imgSize uint64 fPath string algID WinCSPAlg imgValidated bool aIssuer, aPublisher string aSerial, aSHA1 []byte ) for r.N > 0 { var h microsoftEventHeader if err := binary.Read(r, binary.LittleEndian, &h); err != nil { return fmt.Errorf("parsing LMA sub-event: %v", err) } if int64(h.Size) > r.N { return fmt.Errorf("LMA sub-event is larger than available data: %d > %d", h.Size, r.N) } var err error switch h.Type { case imageBase: if imgBase != 0 { return errors.New("duplicate image base data in LMA event") } if imgBase, err = w.parseImageBase(h, r); err != nil { return err } case authenticodeHash: if codeHash != nil { return errors.New("duplicate authenticode hash structure in LMA event") } if codeHash, err = w.parseAuthenticodeHash(h, r); err != nil { return err } case filePath: if fPath != "" { return errors.New("duplicate file path in LMA event") } if fPath, err = w.parseUTF16(h, r); err != nil { return err } case imageSize: if imgSize != 0 { return errors.New("duplicate image size in LMA event") } if imgSize, err = w.readUint64(h, r); err != nil { return err } case hashAlgorithmID: if algID != 0 { return errors.New("duplicate hash algorithm ID in LMA event") } if algID, err = w.parseHashAlgID(h, r); err != nil { return err } case imageValidated: if imgValidated { return errors.New("duplicate image validated field in LMA event") } if imgValidated, err = w.parseImageValidated(h, r); err != nil { return err } case authorityIssuer: if aIssuer != "" { return errors.New("duplicate authority issuer in LMA event") } if aIssuer, err = w.parseUTF16(h, r); err != nil { return err } case authorityPublisher: if aPublisher != "" { return errors.New("duplicate authority publisher in LMA event") } if aPublisher, err = w.parseUTF16(h, r); err != nil { return err } case authoritySerial: if aSerial != nil { return errors.New("duplicate authority serial in LMA event") } if aSerial, err = w.parseAuthoritySerial(h, r); err != nil { return err } case authoritySHA1Thumbprint: if aSHA1 != nil { return errors.New("duplicate authority SHA1 thumbprint in LMA event") } if aSHA1, err = w.parseAuthoritySHA1(h, r); err != nil { return err } case moduleSVN: // Ignore - consume value. b := make([]byte, h.Size) if err := binary.Read(r, binary.LittleEndian, &b); err != nil { return err } default: return fmt.Errorf("unknown event in LMA aggregation: %v", h.Type) } } var iBase []uint64 if imgBase != 0 { iBase = []uint64{imgBase} } l := WinModuleLoad{ FilePath: fPath, AuthenticodeHash: codeHash, ImageBase: iBase, ImageSize: imgSize, ImageValidated: imgValidated, HashAlgorithm: algID, AuthorityIssuer: aIssuer, AuthorityPublisher: aPublisher, AuthoritySerial: aSerial, AuthoritySHA1: aSHA1, } hashHex := hex.EncodeToString(l.AuthenticodeHash) l.ImageBase = append(l.ImageBase, w.LoadedModules[hashHex].ImageBase...) w.LoadedModules[hashHex] = l return nil } // parseUTF16 decodes data representing a UTF16 string. It is assumed the // caller has validated that the data size is within allowable bounds. func (w *WinEvents) parseUTF16(header microsoftEventHeader, r io.Reader) (string, error) { data := make([]uint16, header.Size/2) if err := binary.Read(r, binary.LittleEndian, &data); err != nil { return "", err } return strings.TrimSuffix(string(utf16.Decode(data)), "\x00"), nil } func (w *WinEvents) readELAMAggregation(rdr io.Reader, header microsoftEventHeader) error { var ( r = &io.LimitedReader{R: rdr, N: int64(header.Size)} driverName string measured []byte policy []byte config []byte ) for r.N > 0 { var h microsoftEventHeader if err := binary.Read(r, binary.LittleEndian, &h); err != nil { return fmt.Errorf("parsing ELAM aggregation sub-event: %v", err) } if int64(h.Size) > r.N { return fmt.Errorf("ELAM aggregation sub-event is larger than available data: %d > %d", h.Size, r.N) } var err error switch h.Type { case elamAggregation: w.readELAMAggregation(r, h) if r.N == 0 { return nil } case elamKeyname: if driverName != "" { return errors.New("duplicate driver name in ELAM aggregation event") } if driverName, err = w.parseUTF16(h, r); err != nil { return fmt.Errorf("parsing ELAM driver name: %v", err) } case elamMeasured: if measured != nil { return errors.New("duplicate measured data in ELAM aggregation event") } measured = make([]byte, h.Size) if err := binary.Read(r, binary.LittleEndian, &measured); err != nil { return fmt.Errorf("reading ELAM measured value: %v", err) } case elamPolicy: if policy != nil { return errors.New("duplicate policy data in ELAM aggregation event") } policy = make([]byte, h.Size) if err := binary.Read(r, binary.LittleEndian, &policy); err != nil { return fmt.Errorf("reading ELAM policy value: %v", err) } case elamConfiguration: if config != nil { return errors.New("duplicate config data in ELAM aggregation event") } config = make([]byte, h.Size) if err := binary.Read(r, binary.LittleEndian, &config); err != nil { return fmt.Errorf("reading ELAM config value: %v", err) } default: return fmt.Errorf("unknown event in LMA aggregation: %v", h.Type) } } if driverName == "" { return errors.New("ELAM driver name not specified") } w.ELAM[driverName] = WinELAM{ Measured: measured, Config: config, Policy: policy, } return nil } func (w *WinEvents) readSIPAEvent(r *bytes.Reader, pcr int) error { var header microsoftEventHeader if err := binary.Read(r, binary.LittleEndian, &header); err != nil { return err } switch header.Type { case elamAggregation: return w.readELAMAggregation(r, header) case loadedModuleAggregation: return w.readLoadedModuleAggregation(r, header) case bootCounter: return w.readBootCounter(header, r) case bitlockerUnlock: return w.readBitlockerUnlock(header, r, pcr) case transferControl: return w.readTransferControl(header, r) case osKernelDebug, codeIntegrity, bootDebugging, testSigning: // Parse boolean values. return w.readBooleanByteEvent(header, r) case dataExecutionPrevention: // Parse booleans represented as uint64's. return w.readBooleanInt64Event(header, r) default: // Event type was not handled, consume the data. if int(header.Size) > r.Len() { return fmt.Errorf("event data len (%d bytes) larger than event length (%d bytes)", header.Size, r.Len()) } tmp := make([]byte, header.Size) if err := binary.Read(r, binary.LittleEndian, &tmp); err != nil { return fmt.Errorf("reading unknown data section of length %d: %w", header.Size, err) } return unknownSIPAEvent } } // readWinEventBlock extracts boot configuration from SIPA events contained in // the given tagged event. func (w *WinEvents) readWinEventBlock(evt *internal.TaggedEventData, pcr int) error { r := bytes.NewReader(evt.Data) // All windows information should be sub events in an enclosing SIPA // container event. if (windowsEvent(evt.ID) & sipaTypeMask) != sipaContainer { return fmt.Errorf("expected container event, got %v", windowsEvent(evt.ID)) } for r.Len() > 0 { if err := w.readSIPAEvent(r, pcr); err != nil { if errors.Is(err, unknownSIPAEvent) { // Unknown SIPA events are okay as all TCG events are verifiable. continue } return err } } return nil } go-attestation-0.5.1/attest/win_events_test.go000066400000000000000000000121231452320553600215360ustar00rootroot00000000000000// Copyright 2020 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package attest import ( "encoding/json" "os" "testing" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" ) func TestParseWinEvents(t *testing.T) { want := &WinEvents{ ColdBoot: true, BootCount: 4, DEPEnabled: TernaryTrue, CodeIntegrityEnabled: TernaryTrue, BitlockerUnlocks: []BitlockerStatus{0, 0}, LoadedModules: map[string]WinModuleLoad{ "0fdce7d71936f79445e7d2c84cbeb97c948d3730e0b839166b0a4e625c2d4547": { FilePath: `\Windows\System32\drivers\vioscsi.sys`, ImageBase: []uint64{81416192}, ImageSize: uint64(86016), HashAlgorithm: WinAlgSHA256, ImageValidated: true, AuthorityIssuer: "Microsoft Windows Third Party Component CA 2014", AuthorityPublisher: "Microsoft Windows Hardware Compatibility Publisher", AuthoritySerial: []uint8{ 0x33, 0x00, 0x00, // |3..| 0x00, 0x25, 0x3a, 0x27, 0x38, 0x69, 0x0a, 0x34, 0x51, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, // -|.%:'8i.4Q......%| }, AuthoritySHA1: []uint8{ 0x26, 0x29, 0xe8, 0x6a, 0xae, 0x6e, 0xb9, 0xc9, 0xad, 0xcc, 0x1c, 0x54, 0x8d, 0x60, 0x1a, 0x50, 0xfd, 0x96, 0x92, 0x7a, }, AuthenticodeHash: []byte{15, 220, 231, 215, 25, 54, 247, 148, 69, 231, 210, 200, 76, 190, 185, 124, 148, 141, 55, 48, 224, 184, 57, 22, 107, 10, 78, 98, 92, 45, 69, 71}, }, "055a36a9921b98cc04042ca95249c7eca655536868dafcec7508947ebe5e71f4": { FilePath: `\Windows\System32\Drivers\ksecpkg.sys`, ImageBase: []uint64{82952192}, ImageSize: uint64(204800), HashAlgorithm: WinAlgSHA256, ImageValidated: true, AuthorityIssuer: "Microsoft Windows Production PCA 2011", AuthorityPublisher: "Microsoft Windows", AuthoritySerial: []uint8{ 0x33, 0x00, 0x00, 0x01, 0xc4, 0x22, 0xb2, 0xf7, 0x9b, 0x79, 0x3d, 0xac, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, }, AuthoritySHA1: []uint8{ 0xae, 0x9c, 0x1a, 0xe5, 0x47, 0x63, 0x82, 0x2e, 0xec, 0x42, 0x47, 0x49, 0x83, 0xd8, 0xb6, 0x35, 0x11, 0x6c, 0x84, 0x52, }, AuthenticodeHash: []byte{5, 90, 54, 169, 146, 27, 152, 204, 4, 4, 44, 169, 82, 73, 199, 236, 166, 85, 83, 104, 104, 218, 252, 236, 117, 8, 148, 126, 190, 94, 113, 244}, }, "2bedd1589410b6fa13c82f35db735025b6a160595922750248771f5abd0fee58": { FilePath: `\Windows\System32\drivers\volmgrx.sys`, ImageBase: []uint64{80875520}, ImageSize: uint64(405504), HashAlgorithm: WinAlgSHA256, ImageValidated: true, AuthorityIssuer: "Microsoft Windows Production PCA 2011", AuthorityPublisher: "Microsoft Windows", AuthoritySerial: []uint8{ 0x33, 0x00, 0x00, 0x01, 0xc4, 0x22, 0xb2, 0xf7, 0x9b, 0x79, 0x3d, 0xac, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, }, AuthoritySHA1: []uint8{ 0xae, 0x9c, 0x1a, 0xe5, 0x47, 0x63, 0x82, 0x2e, 0xec, 0x42, 0x47, 0x49, 0x83, 0xd8, 0xb6, 0x35, 0x11, 0x6c, 0x84, 0x52, }, AuthenticodeHash: []byte{43, 237, 209, 88, 148, 16, 182, 250, 19, 200, 47, 53, 219, 115, 80, 37, 182, 161, 96, 89, 89, 34, 117, 2, 72, 119, 31, 90, 189, 15, 238, 88}, }, }, ELAM: map[string]WinELAM{ "Windows Defender": {Measured: []byte{0x06, 0x7d, 0x5b, 0x9d, 0xc5, 0x62, 0x7f, 0x97, 0xdc, 0xf3, 0xfe, 0xff, 0x60, 0x2a, 0x34, 0x2e, 0xd6, 0x98, 0xd2, 0xcc}}, }, } data, err := os.ReadFile("testdata/windows_gcp_shielded_vm.json") if err != nil { t.Fatalf("reading test data: %v", err) } var dump Dump if err := json.Unmarshal(data, &dump); err != nil { t.Fatalf("parsing test data: %v", err) } el, err := ParseEventLog(dump.Log.Raw) if err != nil { t.Fatalf("parsing event log: %v", err) } events, err := el.Verify(dump.Log.PCRs) if err != nil { t.Fatalf("validating event log: %v", err) } winState, err := ParseWinEvents(events) if err != nil { t.Fatalf("ExtractSecurebootState() failed: %v", err) } // Theres way too many modules to cross-check by hand, so we filter it down // to a manageable number. keep := map[string]bool{ "0fdce7d71936f79445e7d2c84cbeb97c948d3730e0b839166b0a4e625c2d4547": true, "055a36a9921b98cc04042ca95249c7eca655536868dafcec7508947ebe5e71f4": true, "2bedd1589410b6fa13c82f35db735025b6a160595922750248771f5abd0fee58": true, } for k := range winState.LoadedModules { if _, keep := keep[k]; !keep { delete(winState.LoadedModules, k) } } if diff := cmp.Diff(winState, want, cmpopts.IgnoreUnexported(WinEvents{})); diff != "" { t.Errorf("Unexpected WinEvents (+got, -want):\n%s", diff) } } go-attestation-0.5.1/attest/wrapped_tpm20.go000066400000000000000000000477061452320553600210210ustar00rootroot00000000000000// Copyright 2020 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package attest import ( "bytes" "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rsa" "encoding/asn1" "errors" "fmt" "io" "math/big" "github.com/google/go-tpm/legacy/tpm2" "github.com/google/go-tpm/tpmutil" ) // wrappedTPM20 interfaces with a TPM 2.0 command channel. type wrappedTPM20 struct { interf TPMInterface rwc CommandChannelTPM20 tpmRSAEkTemplate *tpm2.Public tpmECCEkTemplate *tpm2.Public } func (t *wrappedTPM20) rsaEkTemplate() tpm2.Public { if t.tpmRSAEkTemplate != nil { return *t.tpmRSAEkTemplate } nonce, err := tpm2.NVReadEx(t.rwc, nvramRSAEkNonceIndex, tpm2.HandleOwner, "", 0) if err != nil { t.tpmRSAEkTemplate = &defaultRSAEKTemplate // No nonce, use the default template } else { template := defaultRSAEKTemplate copy(template.RSAParameters.ModulusRaw, nonce) t.tpmRSAEkTemplate = &template } return *t.tpmRSAEkTemplate } func (t *wrappedTPM20) eccEkTemplate() tpm2.Public { if t.tpmECCEkTemplate != nil { return *t.tpmECCEkTemplate } nonce, err := tpm2.NVReadEx(t.rwc, nvramECCEkNonceIndex, tpm2.HandleOwner, "", 0) if err != nil { t.tpmECCEkTemplate = &defaultECCEKTemplate // No nonce, use the default template } else { template := defaultECCEKTemplate copy(template.ECCParameters.Point.XRaw, nonce) t.tpmECCEkTemplate = &template } return *t.tpmECCEkTemplate } func (t *wrappedTPM20) tpmVersion() TPMVersion { return TPMVersion20 } func (t *wrappedTPM20) close() error { return t.rwc.Close() } // Info returns information about the TPM. func (t *wrappedTPM20) info() (*TPMInfo, error) { var ( tInfo = TPMInfo{ Version: TPMVersion20, Interface: t.interf, } t2Info tpm20Info err error ) if t2Info, err = readTPM2VendorAttributes(t.rwc); err != nil { return nil, err } tInfo.Manufacturer = t2Info.manufacturer tInfo.VendorInfo = t2Info.vendor tInfo.FirmwareVersionMajor = t2Info.fwMajor tInfo.FirmwareVersionMinor = t2Info.fwMinor return &tInfo, nil } // Return value: handle, whether we generated a new one, error. func (t *wrappedTPM20) getEndorsementKeyHandle(ek *EK) (tpmutil.Handle, bool, error) { var ekHandle tpmutil.Handle var ekTemplate tpm2.Public if ek == nil { // The default is RSA for backward compatibility. ekHandle = commonRSAEkEquivalentHandle ekTemplate = t.rsaEkTemplate() } else { ekHandle = ek.handle if ekHandle == 0 { // Assume RSA EK handle if it was not provided. ekHandle = commonRSAEkEquivalentHandle } switch pub := ek.Public.(type) { case *rsa.PublicKey: ekTemplate = t.rsaEkTemplate() case *ecdsa.PublicKey: ekTemplate = t.eccEkTemplate() default: return 0, false, fmt.Errorf("unsupported public key type %T", pub) } } _, _, _, err := tpm2.ReadPublic(t.rwc, ekHandle) if err == nil { // Found the persistent handle, assume it's the key we want. return ekHandle, false, nil } rerr := err // Preserve this failure for later logging, if needed keyHnd, _, err := tpm2.CreatePrimary(t.rwc, tpm2.HandleEndorsement, tpm2.PCRSelection{}, "", "", ekTemplate) if err != nil { return 0, false, fmt.Errorf("ReadPublic failed (%v), and then CreatePrimary failed: %v", rerr, err) } defer tpm2.FlushContext(t.rwc, keyHnd) err = tpm2.EvictControl(t.rwc, "", tpm2.HandleOwner, keyHnd, ekHandle) if err != nil { return 0, false, fmt.Errorf("EvictControl failed: %v", err) } return ekHandle, true, nil } // Return value: handle, whether we generated a new one, error func (t *wrappedTPM20) getStorageRootKeyHandle(parent ParentKeyConfig) (tpmutil.Handle, bool, error) { srkHandle := parent.Handle _, _, _, err := tpm2.ReadPublic(t.rwc, srkHandle) if err == nil { // Found the persistent handle, assume it's the key we want. return srkHandle, false, nil } rerr := err // Preserve this failure for later logging, if needed var srkTemplate tpm2.Public switch parent.Algorithm { case RSA: srkTemplate = defaultRSASRKTemplate case ECDSA: srkTemplate = defaultECCSRKTemplate default: return 0, false, fmt.Errorf("unsupported SRK algorithm: %v", parent.Algorithm) } keyHnd, _, err := tpm2.CreatePrimary(t.rwc, tpm2.HandleOwner, tpm2.PCRSelection{}, "", "", srkTemplate) if err != nil { return 0, false, fmt.Errorf("ReadPublic failed (%v), and then CreatePrimary failed: %v", rerr, err) } defer tpm2.FlushContext(t.rwc, keyHnd) err = tpm2.EvictControl(t.rwc, "", tpm2.HandleOwner, keyHnd, srkHandle) if err != nil { return 0, false, fmt.Errorf("EvictControl failed: %v", err) } return srkHandle, true, nil } func (t *wrappedTPM20) ekCertificates() ([]EK, error) { var res []EK if rsaCert, err := readEKCertFromNVRAM20(t.rwc, nvramRSACertIndex); err == nil { res = append(res, EK{Public: crypto.PublicKey(rsaCert.PublicKey), Certificate: rsaCert, handle: commonRSAEkEquivalentHandle}) } if eccCert, err := readEKCertFromNVRAM20(t.rwc, nvramECCCertIndex); err == nil { res = append(res, EK{Public: crypto.PublicKey(eccCert.PublicKey), Certificate: eccCert, handle: commonECCEkEquivalentHandle}) } return res, nil } func (t *wrappedTPM20) eks() ([]EK, error) { if cert, err := readEKCertFromNVRAM20(t.rwc, nvramRSACertIndex); err == nil { return []EK{ {Public: crypto.PublicKey(cert.PublicKey), Certificate: cert, handle: commonRSAEkEquivalentHandle}, }, nil } // Attempt to create an EK. ekHnd, _, err := tpm2.CreatePrimary(t.rwc, tpm2.HandleEndorsement, tpm2.PCRSelection{}, "", "", t.rsaEkTemplate()) if err != nil { return nil, fmt.Errorf("EK CreatePrimary failed: %v", err) } defer tpm2.FlushContext(t.rwc, ekHnd) pub, _, _, err := tpm2.ReadPublic(t.rwc, ekHnd) if err != nil { return nil, fmt.Errorf("EK ReadPublic failed: %v", err) } if pub.RSAParameters == nil { return nil, errors.New("ECC EK not yet supported") } i, err := t.info() if err != nil { return nil, fmt.Errorf("Retrieving TPM info failed: %v", err) } ekPub := &rsa.PublicKey{ E: int(pub.RSAParameters.Exponent()), N: pub.RSAParameters.Modulus(), } var certificateURL string if i.Manufacturer.String() == manufacturerIntel { certificateURL = intelEKURL(ekPub) } return []EK{ { Public: ekPub, CertificateURL: certificateURL, handle: commonRSAEkEquivalentHandle, }, }, nil } func (t *wrappedTPM20) newAK(opts *AKConfig) (*AK, error) { var parent ParentKeyConfig if opts != nil && opts.Parent != nil { parent = *opts.Parent } else { parent = defaultParentConfig } srk, _, err := t.getStorageRootKeyHandle(parent) if err != nil { return nil, fmt.Errorf("failed to get SRK handle: %v", err) } blob, pub, creationData, creationHash, tix, err := tpm2.CreateKey(t.rwc, srk, tpm2.PCRSelection{}, "", "", akTemplate) if err != nil { return nil, fmt.Errorf("CreateKeyEx() failed: %v", err) } keyHandle, _, err := tpm2.Load(t.rwc, srk, "", pub, blob) if err != nil { return nil, fmt.Errorf("Load() failed: %v", err) } // If any errors occur, free the AK's handle. defer func() { if err != nil { tpm2.FlushContext(t.rwc, keyHandle) } }() // We can only certify the creation immediately afterwards, so we cache the result. attestation, sig, err := tpm2.CertifyCreation(t.rwc, "", keyHandle, keyHandle, nil, creationHash, tpm2.SigScheme{Alg: tpm2.AlgRSASSA, Hash: tpm2.AlgSHA256, Count: 0}, tix) if err != nil { return nil, fmt.Errorf("CertifyCreation failed: %v", err) } return &AK{ak: newWrappedAK20(keyHandle, blob, pub, creationData, attestation, sig)}, nil } func (t *wrappedTPM20) newKey(ak *AK, opts *KeyConfig) (*Key, error) { k, ok := ak.ak.(*wrappedKey20) if !ok { return nil, fmt.Errorf("expected *wrappedKey20, got: %T", k) } parent, blob, pub, creationData, err := createKey(t, opts) if err != nil { return nil, fmt.Errorf("cannot create key: %v", err) } keyHandle, _, err := tpm2.Load(t.rwc, parent, "", pub, blob) if err != nil { return nil, fmt.Errorf("Load() failed: %v", err) } // If any errors occur, free the handle. defer func() { if err != nil { tpm2.FlushContext(t.rwc, keyHandle) } }() // Certify application key by AK cp, err := k.certify(t, keyHandle) if err != nil { return nil, fmt.Errorf("ak.Certify() failed: %v", err) } if !bytes.Equal(pub, cp.Public) { return nil, fmt.Errorf("certified incorrect key, expected: %v, certified: %v", pub, cp.Public) } // Pack the raw structure into a TPMU_SIGNATURE. tpmPub, err := tpm2.DecodePublic(pub) if err != nil { return nil, fmt.Errorf("decode public key: %v", err) } pubKey, err := tpmPub.Key() if err != nil { return nil, fmt.Errorf("access public key: %v", err) } return &Key{key: newWrappedKey20(keyHandle, blob, pub, creationData, cp.CreateAttestation, cp.CreateSignature), pub: pubKey, tpm: t}, nil } func createKey(t *wrappedTPM20, opts *KeyConfig) (tpmutil.Handle, []byte, []byte, []byte, error) { var parent ParentKeyConfig if opts != nil && opts.Parent != nil { parent = *opts.Parent } else { parent = defaultParentConfig } srk, _, err := t.getStorageRootKeyHandle(parent) if err != nil { return 0, nil, nil, nil, fmt.Errorf("failed to get SRK handle: %v", err) } tmpl, err := templateFromConfig(opts) if err != nil { return 0, nil, nil, nil, fmt.Errorf("incorrect key options: %v", err) } blob, pub, creationData, _, _, err := tpm2.CreateKey(t.rwc, srk, tpm2.PCRSelection{}, "", "", tmpl) if err != nil { return 0, nil, nil, nil, fmt.Errorf("CreateKey() failed: %v", err) } return srk, blob, pub, creationData, err } func templateFromConfig(opts *KeyConfig) (tpm2.Public, error) { var tmpl tpm2.Public switch opts.Algorithm { case RSA: tmpl = rsaKeyTemplate if opts.Size < 0 || opts.Size > 65535 { // basic sanity check return tmpl, fmt.Errorf("incorrect size parameter") } tmpl.RSAParameters.KeyBits = uint16(opts.Size) case ECDSA: tmpl = ecdsaKeyTemplate switch opts.Size { case 256: tmpl.NameAlg = tpm2.AlgSHA256 tmpl.ECCParameters.Sign.Hash = tpm2.AlgSHA256 tmpl.ECCParameters.CurveID = tpm2.CurveNISTP256 tmpl.ECCParameters.Point = tpm2.ECPoint{ XRaw: make([]byte, 32), YRaw: make([]byte, 32), } case 384: tmpl.NameAlg = tpm2.AlgSHA384 tmpl.ECCParameters.Sign.Hash = tpm2.AlgSHA384 tmpl.ECCParameters.CurveID = tpm2.CurveNISTP384 tmpl.ECCParameters.Point = tpm2.ECPoint{ XRaw: make([]byte, 48), YRaw: make([]byte, 48), } case 521: tmpl.NameAlg = tpm2.AlgSHA512 tmpl.ECCParameters.Sign.Hash = tpm2.AlgSHA512 tmpl.ECCParameters.CurveID = tpm2.CurveNISTP521 tmpl.ECCParameters.Point = tpm2.ECPoint{ XRaw: make([]byte, 65), YRaw: make([]byte, 65), } default: return tmpl, fmt.Errorf("unsupported key size: %v", opts.Size) } default: return tmpl, fmt.Errorf("unsupported algorithm type: %q", opts.Algorithm) } return tmpl, nil } func (t *wrappedTPM20) deserializeAndLoad(opaqueBlob []byte, parent ParentKeyConfig) (tpmutil.Handle, *serializedKey, error) { sKey, err := deserializeKey(opaqueBlob, TPMVersion20) if err != nil { return 0, nil, fmt.Errorf("deserializeKey() failed: %v", err) } if sKey.Encoding != keyEncodingEncrypted { return 0, nil, fmt.Errorf("unsupported key encoding: %x", sKey.Encoding) } srk, _, err := t.getStorageRootKeyHandle(parent) if err != nil { return 0, nil, fmt.Errorf("failed to get SRK handle: %v", err) } var hnd tpmutil.Handle if hnd, _, err = tpm2.Load(t.rwc, srk, "", sKey.Public, sKey.Blob); err != nil { return 0, nil, fmt.Errorf("Load() failed: %v", err) } return hnd, sKey, nil } func (t *wrappedTPM20) loadAK(opaqueBlob []byte) (*AK, error) { return t.loadAKWithParent(opaqueBlob, defaultParentConfig) } func (t *wrappedTPM20) loadAKWithParent(opaqueBlob []byte, parent ParentKeyConfig) (*AK, error) { hnd, sKey, err := t.deserializeAndLoad(opaqueBlob, parent) if err != nil { return nil, fmt.Errorf("cannot load attestation key: %v", err) } return &AK{ak: newWrappedAK20(hnd, sKey.Blob, sKey.Public, sKey.CreateData, sKey.CreateAttestation, sKey.CreateSignature)}, nil } func (t *wrappedTPM20) loadKey(opaqueBlob []byte) (*Key, error) { return t.loadKeyWithParent(opaqueBlob, defaultParentConfig) } func (t *wrappedTPM20) loadKeyWithParent(opaqueBlob []byte, parent ParentKeyConfig) (*Key, error) { hnd, sKey, err := t.deserializeAndLoad(opaqueBlob, parent) if err != nil { return nil, fmt.Errorf("cannot load signing key: %v", err) } tpmPub, err := tpm2.DecodePublic(sKey.Public) if err != nil { return nil, fmt.Errorf("decode public blob: %v", err) } pub, err := tpmPub.Key() if err != nil { return nil, fmt.Errorf("access public key: %v", err) } return &Key{key: newWrappedKey20(hnd, sKey.Blob, sKey.Public, sKey.CreateData, sKey.CreateAttestation, sKey.CreateSignature), pub: pub, tpm: t}, nil } func (t *wrappedTPM20) pcrs(alg HashAlg) ([]PCR, error) { PCRs, err := readAllPCRs20(t.rwc, alg.goTPMAlg()) if err != nil { return nil, fmt.Errorf("failed to read PCRs: %v", err) } out := make([]PCR, len(PCRs)) for index, digest := range PCRs { out[int(index)] = PCR{ Index: int(index), Digest: digest, DigestAlg: alg.cryptoHash(), } } return out, nil } func (t *wrappedTPM20) measurementLog() ([]byte, error) { return t.rwc.MeasurementLog() } // wrappedKey20 represents a key manipulated through a *wrappedTPM20. type wrappedKey20 struct { hnd tpmutil.Handle blob []byte public []byte // used by both TPM1.2 and 2.0 createData []byte createAttestation []byte createSignature []byte } func newWrappedAK20(hnd tpmutil.Handle, blob, public, createData, createAttestation, createSig []byte) ak { return &wrappedKey20{ hnd: hnd, blob: blob, public: public, createData: createData, createAttestation: createAttestation, createSignature: createSig, } } func newWrappedKey20(hnd tpmutil.Handle, blob, public, createData, createAttestation, createSig []byte) key { return &wrappedKey20{ hnd: hnd, blob: blob, public: public, createData: createData, createAttestation: createAttestation, createSignature: createSig, } } func (k *wrappedKey20) marshal() ([]byte, error) { return (&serializedKey{ Encoding: keyEncodingEncrypted, TPMVersion: TPMVersion20, Blob: k.blob, Public: k.public, CreateData: k.createData, CreateAttestation: k.createAttestation, CreateSignature: k.createSignature, }).Serialize() } func (k *wrappedKey20) close(t tpmBase) error { tpm, ok := t.(*wrappedTPM20) if !ok { return fmt.Errorf("expected *wrappedTPM20, got %T", t) } return tpm2.FlushContext(tpm.rwc, k.hnd) } func (k *wrappedKey20) activateCredential(tb tpmBase, in EncryptedCredential, ek *EK) ([]byte, error) { t, ok := tb.(*wrappedTPM20) if !ok { return nil, fmt.Errorf("expected *wrappedTPM20, got %T", tb) } if len(in.Credential) < 2 { return nil, fmt.Errorf("malformed credential blob") } credential := in.Credential[2:] if len(in.Secret) < 2 { return nil, fmt.Errorf("malformed encrypted secret") } secret := in.Secret[2:] ekHnd, _, err := t.getEndorsementKeyHandle(ek) if err != nil { return nil, err } sessHandle, _, err := tpm2.StartAuthSession( t.rwc, tpm2.HandleNull, /*tpmKey*/ tpm2.HandleNull, /*bindKey*/ make([]byte, 16), /*nonceCaller*/ nil, /*secret*/ tpm2.SessionPolicy, tpm2.AlgNull, tpm2.AlgSHA256) if err != nil { return nil, fmt.Errorf("creating session: %v", err) } defer tpm2.FlushContext(t.rwc, sessHandle) if _, _, err := tpm2.PolicySecret(t.rwc, tpm2.HandleEndorsement, tpm2.AuthCommand{Session: tpm2.HandlePasswordSession, Attributes: tpm2.AttrContinueSession}, sessHandle, nil, nil, nil, 0); err != nil { return nil, fmt.Errorf("tpm2.PolicySecret() failed: %v", err) } return tpm2.ActivateCredentialUsingAuth(t.rwc, []tpm2.AuthCommand{ {Session: tpm2.HandlePasswordSession, Attributes: tpm2.AttrContinueSession}, {Session: sessHandle, Attributes: tpm2.AttrContinueSession}, }, k.hnd, ekHnd, credential, secret) } func (k *wrappedKey20) certify(tb tpmBase, handle interface{}) (*CertificationParameters, error) { t, ok := tb.(*wrappedTPM20) if !ok { return nil, fmt.Errorf("expected *wrappedTPM20, got %T", tb) } hnd, ok := handle.(tpmutil.Handle) if !ok { return nil, fmt.Errorf("expected tpmutil.Handle, got %T", handle) } scheme := tpm2.SigScheme{ Alg: tpm2.AlgRSASSA, Hash: tpm2.AlgSHA256, } return certify(t.rwc, hnd, k.hnd, scheme) } func (k *wrappedKey20) quote(tb tpmBase, nonce []byte, alg HashAlg, selectedPCRs []int) (*Quote, error) { t, ok := tb.(*wrappedTPM20) if !ok { return nil, fmt.Errorf("expected *wrappedTPM20, got %T", tb) } return quote20(t.rwc, k.hnd, tpm2.Algorithm(alg), nonce, selectedPCRs) } func (k *wrappedKey20) attestationParameters() AttestationParameters { return AttestationParameters{ Public: k.public, CreateData: k.createData, CreateAttestation: k.createAttestation, CreateSignature: k.createSignature, } } func (k *wrappedKey20) certificationParameters() CertificationParameters { return CertificationParameters{ Public: k.public, CreateAttestation: k.createAttestation, CreateSignature: k.createSignature, } } func (k *wrappedKey20) sign(tb tpmBase, digest []byte, pub crypto.PublicKey, opts crypto.SignerOpts) ([]byte, error) { t, ok := tb.(*wrappedTPM20) if !ok { return nil, fmt.Errorf("expected *wrappedTPM20, got %T", tb) } switch p := pub.(type) { case *ecdsa.PublicKey: return signECDSA(t.rwc, k.hnd, digest, p.Curve) case *rsa.PublicKey: return signRSA(t.rwc, k.hnd, digest, opts) } return nil, fmt.Errorf("unsupported signing key type: %T", pub) } func signECDSA(rw io.ReadWriter, key tpmutil.Handle, digest []byte, curve elliptic.Curve) ([]byte, error) { // https://cs.opensource.google/go/go/+/refs/tags/go1.19.2:src/crypto/ecdsa/ecdsa.go;l=181 orderBits := curve.Params().N.BitLen() orderBytes := (orderBits + 7) / 8 if len(digest) > orderBytes { digest = digest[:orderBytes] } ret := new(big.Int).SetBytes(digest) excess := len(digest)*8 - orderBits if excess > 0 { ret.Rsh(ret, uint(excess)) } // call ret.FillBytes() here instead of ret.Bytes() to preserve leading zeroes // that may have been dropped when converting the digest to an integer digest = ret.FillBytes(digest) sig, err := tpm2.Sign(rw, key, "", digest, nil, nil) if err != nil { return nil, fmt.Errorf("cannot sign: %v", err) } if sig.ECC == nil { return nil, fmt.Errorf("expected ECDSA signature, got: %v", sig.Alg) } return asn1.Marshal(struct { R *big.Int S *big.Int }{sig.ECC.R, sig.ECC.S}) } func signRSA(rw io.ReadWriter, key tpmutil.Handle, digest []byte, opts crypto.SignerOpts) ([]byte, error) { h, err := tpm2.HashToAlgorithm(opts.HashFunc()) if err != nil { return nil, fmt.Errorf("incorrect hash algorithm: %v", err) } scheme := &tpm2.SigScheme{ Alg: tpm2.AlgRSASSA, Hash: h, } if pss, ok := opts.(*rsa.PSSOptions); ok { if pss.SaltLength != rsa.PSSSaltLengthAuto && pss.SaltLength != len(digest) { return nil, fmt.Errorf("PSS salt length %d is incorrect, expected rsa.PSSSaltLengthAuto or %d", pss.SaltLength, len(digest)) } scheme.Alg = tpm2.AlgRSAPSS } sig, err := tpm2.Sign(rw, key, "", digest, nil, scheme) if err != nil { return nil, fmt.Errorf("cannot sign: %v", err) } if sig.RSA == nil { return nil, fmt.Errorf("expected RSA signature, got: %v", sig.Alg) } return sig.RSA.Signature, nil } func (k *wrappedKey20) decrypt(tb tpmBase, ctxt []byte) ([]byte, error) { return nil, fmt.Errorf("not implemented") } func (k *wrappedKey20) blobs() ([]byte, []byte, error) { return k.public, k.blob, nil } go-attestation-0.5.1/attributecert/000077500000000000000000000000001452320553600173455ustar00rootroot00000000000000go-attestation-0.5.1/attributecert/attributecert.go000066400000000000000000000641451452320553600225670ustar00rootroot00000000000000// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2019 Google, LLC. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package attributecert parses X.509-encoded attribute certificates. package attributecert import ( "bytes" "crypto" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "errors" "fmt" "math/big" "time" "github.com/google/go-attestation/oid" ) var ( oidExtensionAuthorityKeyIdentifier = []int{2, 5, 29, 35} oidAuthorityInfoAccess = []int{1, 3, 6, 1, 5, 5, 7, 1, 1} oidCpsCertificatePolicy = []int{1, 3, 6, 1, 5, 5, 7, 2, 1} oidAuthorityInfoAccessOcsp = []int{1, 3, 6, 1, 5, 5, 7, 48, 1} oidAuthorityInfoAccessIssuers = []int{1, 3, 6, 1, 5, 5, 7, 48, 2} oidTcgCertificatePolicy = []int{1, 2, 840, 113741, 1, 5, 2, 4} oidAttributeUserNotice = []int{1, 3, 6, 1, 5, 5, 7, 2, 2} oidTcgPlatformManufacturerStrV1 = []int{2, 23, 133, 2, 4} oidTcgPlatformModelV1 = []int{2, 23, 133, 2, 5} oidTcgPlatformVersionV1 = []int{2, 23, 133, 2, 6} ) var ( oidSignatureRSASha1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10} oidSignatureRSASha256 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112} oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1} oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3} oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8} ) var signatureAlgorithmDetails = []struct { algo x509.SignatureAlgorithm name string oid asn1.ObjectIdentifier pubKeyAlgo x509.PublicKeyAlgorithm hash crypto.Hash }{ {x509.SHA1WithRSA, "SHA1-RSA", oidSignatureRSASha1, x509.RSA, crypto.SHA1}, {x509.SHA256WithRSA, "SHA256-RSA", oidSignatureRSASha256, x509.RSA, crypto.SHA256}, {x509.SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA256}, {x509.SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA384}, {x509.SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA512}, {x509.PureEd25519, "Ed25519", oidSignatureEd25519, x509.Ed25519, crypto.Hash(0) /* no pre-hashing */}, } // pssParameters reflects the parameters in an AlgorithmIdentifier that // specifies RSA PSS. See RFC 3447, Appendix A.2.3. type pssParameters struct { // The following three fields are not marked as // optional because the default values specify SHA-1, // which is no longer suitable for use in signatures. Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"` MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"` SaltLength int `asn1:"explicit,tag:2"` TrailerField int `asn1:"optional,explicit,tag:3,default:1"` } func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) x509.SignatureAlgorithm { if ai.Algorithm.Equal(oidSignatureEd25519) { // RFC 8410, Section 3 // > For all of the OIDs, the parameters MUST be absent. if len(ai.Parameters.FullBytes) != 0 { return x509.UnknownSignatureAlgorithm } } if !ai.Algorithm.Equal(oidSignatureRSAPSS) { for _, details := range signatureAlgorithmDetails { if ai.Algorithm.Equal(details.oid) { return details.algo } } return x509.UnknownSignatureAlgorithm } // RSA PSS is special because it encodes important parameters // in the Parameters. var params pssParameters if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, ¶ms); err != nil { return x509.UnknownSignatureAlgorithm } var mgf1HashFunc pkix.AlgorithmIdentifier if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil { return x509.UnknownSignatureAlgorithm } // PSS is greatly overburdened with options. This code forces them into // three buckets by requiring that the MGF1 hash function always match the // message hash function (as recommended in RFC 3447, Section 8.1), that the // salt length matches the hash length, and that the trailer field has the // default value. if (len(params.Hash.Parameters.FullBytes) != 0 && !bytes.Equal(params.Hash.Parameters.FullBytes, asn1.NullBytes)) || !params.MGF.Algorithm.Equal(oidMGF1) || !mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) || (len(mgf1HashFunc.Parameters.FullBytes) != 0 && !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1.NullBytes)) || params.TrailerField != 1 { return x509.UnknownSignatureAlgorithm } switch { case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32: return x509.SHA256WithRSAPSS case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48: return x509.SHA384WithRSAPSS case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64: return x509.SHA512WithRSAPSS } return x509.UnknownSignatureAlgorithm } // RFC 5280 4.2.2.1 type authorityInfoAccess struct { Method asn1.ObjectIdentifier Location asn1.RawValue } // RFC 5280 4.2.1.1 type authKeyID struct { ID []byte `asn1:"optional,tag:0"` IssuerName asn1.RawValue `asn1:"set,optional,tag:1"` SerialNumber *big.Int `asn1:"optional,tag:2"` } // RFC 5280 4.2.1.4 type cpsPolicy struct { ID asn1.ObjectIdentifier Value string } // RFC 5280 4.2.1.4 type policyInformation struct { Raw asn1.RawContent ID asn1.ObjectIdentifier Policy asn1.RawValue } // RFC 5280 4.1.2.5 type validity struct { NotBefore, NotAfter time.Time } // RFC 5280 4.2.1.4 type noticeReference struct { Organization string NoticeNumbers []int } // RFC 5280 4.2.1.4 type userNotice struct { NoticeRef noticeReference `asn1:"optional"` ExplicitText string `asn1:"optional"` } // RFC 5755 4.1 type objectDigestInfo struct { DigestedObjectType asn1.Enumerated OtherObjectTypeID asn1.ObjectIdentifier DigestAlgorithm pkix.AlgorithmIdentifier ObjectDigest asn1.BitString } // RFC 5755 4.1 type attCertIssuer struct { IssuerName asn1.RawValue `asn1:"set,optional"` BaseCertificateID issuerSerial `asn1:"optional,tag:0"` ObjectDigestInfo objectDigestInfo `asn1:"optional,tag:1"` } // RFC 5755 4.1 type issuerSerial struct { Raw asn1.RawContent Issuer asn1.RawValue Serial *big.Int IssuerUID asn1.BitString `asn1:"optional"` } // RFC 5755 4.1 type holder struct { Raw asn1.RawContent BaseCertificateID issuerSerial `asn1:"optional,tag:0"` EntityName pkix.Extension `asn1:"optional,tag:1"` ObjectDigestInfo objectDigestInfo `asn1:"optional,tag:2"` } // RFC 5755 4.1 type attribute struct { ID asn1.ObjectIdentifier RawValues []asn1.RawValue `asn1:"set"` } // RFC 5755 4.1 type tbsAttributeCertificate struct { Raw asn1.RawContent Version int Holder holder Issuer attCertIssuer `asn1:"tag:0"` SignatureAlgorithm pkix.AlgorithmIdentifier SerialNumber *big.Int Validity validity Attributes []attribute IssuerUniqueID asn1.BitString `asn1:"optional"` Extensions []pkix.Extension `asn1:"optional"` } type attributeCertificate struct { Raw asn1.RawContent TBSAttributeCertificate tbsAttributeCertificate SignatureAlgorithm pkix.AlgorithmIdentifier SignatureValue asn1.BitString } type Certholder struct { Issuer pkix.Name Serial *big.Int } type Component struct { Manufacturer string Model string Serial string Revision string ManufacturerID int FieldReplaceable bool Addresses []ComponentAddress } type AttributeCertificate struct { Raw []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature). RawTBSAttributeCertificate []byte // Certificate part of raw ASN.1 DER content. Signature []byte SignatureAlgorithm x509.SignatureAlgorithm Version int SerialNumber *big.Int Holder Certholder Issuer pkix.Name Subject pkix.Name NotBefore, NotAfter time.Time // Validity bounds. TCGPlatformSpecification TCGPlatformSpecification TBBSecurityAssertions TBBSecurityAssertions PlatformManufacturer string PlatformModel string PlatformVersion string PlatformSerial string CredentialSpecification string UserNotice userNotice Components []Component Properties []Property PropertiesURI string } // ParseAttributeCertificate parses a single attribute certificate from the // given ASN.1 DER data. func ParseAttributeCertificate(asn1Data []byte) (*AttributeCertificate, error) { var cert attributeCertificate rest, err := asn1.Unmarshal(asn1Data, &cert) if err != nil { return nil, err } else if len(rest) != 0 { return nil, asn1.SyntaxError{Msg: "attributecert: trailing data"} } return parseAttributeCertificate(&cert) } type PlatformDataSequence []PlatformDataSET type PlatformDataSET []pkix.AttributeTypeAndValue type TCGData struct { ID asn1.ObjectIdentifier Data string } type TCGDirectoryEntry struct { ID asn1.ObjectIdentifier Data asn1.RawValue } type TCGSpecificationVersion struct { MajorVersion int MinorVersion int Revision int } type TCGPlatformSpecification struct { Version TCGSpecificationVersion } type TCGCredentialSpecification struct { Version TCGSpecificationVersion } type TCGCredentialType struct { CertificateType asn1.ObjectIdentifier } type FipsLevel struct { Version string Level asn1.Enumerated Plus bool `asn1:"optional,default=false"` } type CommonCriteriaMeasures struct { Version string AssuranceLevel asn1.Enumerated EvaluationStatus asn1.Enumerated Plus bool StrengthOfFunction asn1.Enumerated `asn1:"optional,tag:0"` ProfileOid asn1.ObjectIdentifier `asn1:"optional,tag:1"` ProfileURI string `asn1:"optional,tag:2"` TargetOid asn1.ObjectIdentifier `asn1:"optional,tag:3"` TargetURI asn1.ObjectIdentifier `asn1:"optional,tag:4"` } type TBBSecurityAssertions struct { Version int `asn1:"optional,default=0"` CcInfo CommonCriteriaMeasures `asn1:"optional,tag:0"` FipsLevel FipsLevel `asn1:"optional,tag:1"` RtmType asn1.Enumerated `asn1:"optional,tag:2"` Iso9000Certified bool `asn1:"optional,default=false"` Iso9000URI string `asn1:"optional"` } // Certificates with this information in the SDA region appear to fail to // tag the optional fields type CommonCriteriaMeasures_sda struct { Version string AssuranceLevel asn1.Enumerated EvaluationStatus asn1.Enumerated Plus bool `asn1:"optional,default=false"` StrengthOfFunction asn1.Enumerated `asn1:"optional"` ProfileOid asn1.ObjectIdentifier `asn1:"optional"` ProfileURI string `asn1:"optional"` TargetOid asn1.ObjectIdentifier `asn1:"optional"` TargetURI asn1.ObjectIdentifier `asn1:"optional"` } type TBBSecurityAssertions_sda struct { Version int CcInfo CommonCriteriaMeasures_sda `asn1:"optional"` FipsLevel FipsLevel `asn1:"optional"` RtmType asn1.Enumerated `asn1:"optional"` Iso9000Certified bool `asn1:"optional"` Iso9000URI string `asn1:"optional"` } type Property struct { PropertyName string PropertyValue string Status asn1.Enumerated `asn1:"optional,tag:0"` } type AttributeCertificateIdentifier struct { HashAlgorithm pkix.AlgorithmIdentifier HashOverSignatureValue string } type CertificateIdentifier struct { AttributeCertIdentifier AttributeCertificateIdentifier `asn1:"optional,tag:0"` GenericCertIdientifier issuerSerial `asn1:"optional,tag:1"` } type ComponentAddress struct { AddressType asn1.ObjectIdentifier AddressValue string } type ComponentClass struct { ComponentClassRegistry asn1.ObjectIdentifier ComponentClassValue []byte } type ComponentIdentifierV2 struct { ComponentClass ComponentClass ComponentManufacturer string ComponentModel string ComponentSerial string `asn1:"optional,utf8,tag:0"` ComponentRevision string `asn1:"optional,utf8,tag:1"` ComponentManufacturerID int `asn1:"optional,tag:2"` FieldReplaceable bool `asn1:"optional,tag:3"` ComponentAddresses []ComponentAddress `asn1:"optional,tag:4"` ComponentPlatformCert CertificateIdentifier `asn1:"optional,tag:5"` ComponentPlatformCertURI string `asn1:"optional,tag:6"` Status asn1.Enumerated `asn1:"optional,tag:7"` } type URIReference struct { UniformResourceIdentifier string HashAlgorithm pkix.AlgorithmIdentifier `asn1:"optional"` HashValue string `asn1:"optional"` } type PlatformConfigurationV2 struct { ComponentIdentifiers []ComponentIdentifierV2 `asn1:"optional,tag:0"` ComponentIdentifiersURI URIReference `asn1:"optional,tag:1"` PlatformProperties []Property `asn1:"optional,tag:2"` PlatformPropertiesURI URIReference `asn1:"optional,tag:3"` } type PlatformConfigurationV2Workaround struct { ComponentIdentifiers []ComponentIdentifierV2 `asn1:"optional,tag:0"` ComponentIdentifiersURI URIReference `asn1:"optional,tag:1"` PlatformProperty Property `asn1:"optional,tag:2"` PlatformPropertiesURI URIReference `asn1:"optional,tag:3"` } type ComponentIdentifierV1 struct { ComponentClass []byte `asn1:"optional"` ComponentManufacturer string ComponentModel string ComponentSerial string `asn1:"optional,utf8,tag:0"` ComponentRevision string `asn1:"optional,utf8,tag:1"` ComponentManufacturerID int `asn1:"optional,tag:2"` FieldReplaceable bool `asn1:"optional,tag:3"` ComponentAddresses []ComponentAddress `asn1:"optional,tag:4"` } type PlatformConfigurationV1 struct { ComponentIdentifiers []ComponentIdentifierV1 `asn1:"optional,tag:0"` PlatformProperties []Property `asn1:"optional,tag:1"` PlatformPropertiesURI URIReference `asn1:"optional,tag:2"` } func unmarshalSAN(v asn1.RawValue) ([]pkix.AttributeTypeAndValue, error) { if v.Tag == asn1.TagSet { var e pkix.AttributeTypeAndValue if _, err := asn1.Unmarshal(v.Bytes, &e); err != nil { return nil, err } return []pkix.AttributeTypeAndValue{e}, nil } else if v.Tag == asn1.TagOctetString { var attributes []pkix.AttributeTypeAndValue var platformData PlatformDataSequence rest, err := asn1.Unmarshal(v.Bytes, &platformData) if err != nil { return nil, err } else if len(rest) != 0 { return nil, errors.New("attributecert: trailing data after X.509 subject") } for _, e := range platformData { for _, e2 := range e { attributes = append(attributes, e2) } } return attributes, nil } return nil, fmt.Errorf("attributecert: unexpected SAN type %v", v.Tag) } func parseAttributeCertificate(in *attributeCertificate) (*AttributeCertificate, error) { out := &AttributeCertificate{ Raw: in.Raw, RawTBSAttributeCertificate: in.TBSAttributeCertificate.Raw, Signature: in.SignatureValue.RightAlign(), SignatureAlgorithm: getSignatureAlgorithmFromAI(in.TBSAttributeCertificate.SignatureAlgorithm), Version: in.TBSAttributeCertificate.Version + 1, SerialNumber: in.TBSAttributeCertificate.SerialNumber, } var v asn1.RawValue if _, err := asn1.Unmarshal(in.TBSAttributeCertificate.Issuer.IssuerName.Bytes, &v); err != nil { return nil, err } var issuer pkix.RDNSequence if rest, err := asn1.Unmarshal(v.Bytes, &issuer); err != nil { return nil, err } else if len(rest) != 0 { return nil, errors.New("attributecert: trailing data after X.509 subject") } out.Issuer.FillFromRDNSequence(&issuer) if _, err := asn1.Unmarshal(in.TBSAttributeCertificate.Holder.BaseCertificateID.Issuer.Bytes, &v); err != nil { return nil, err } var holder pkix.RDNSequence if rest, err := asn1.Unmarshal(v.Bytes, &holder); err != nil { return nil, err } else if len(rest) != 0 { return nil, errors.New("attributecert: trailing data after X.509 subject") } out.Holder.Issuer.FillFromRDNSequence(&holder) out.Holder.Serial = in.TBSAttributeCertificate.Holder.BaseCertificateID.Serial out.NotBefore = in.TBSAttributeCertificate.Validity.NotBefore out.NotAfter = in.TBSAttributeCertificate.Validity.NotAfter for _, attribute := range in.TBSAttributeCertificate.Attributes { switch { case attribute.ID.Equal(oidAttributeUserNotice): if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &out.UserNotice); err != nil { return nil, err } case attribute.ID.Equal(oid.TCGPlatformSpecification): if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &out.TCGPlatformSpecification); err != nil { return nil, err } case attribute.ID.Equal(oid.TBBSecurityAssertions): if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &out.TBBSecurityAssertions); err != nil { return nil, err } case attribute.ID.Equal(oid.TCGCredentialSpecification): var credentialSpecification TCGCredentialSpecification if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &credentialSpecification); err != nil { var credentialSpecification TCGSpecificationVersion if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &credentialSpecification); err != nil { return nil, err } } case attribute.ID.Equal(oid.TCGCredentialType): var credentialType TCGCredentialType if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &credentialType); err != nil { return nil, err } case attribute.ID.Equal(oid.PlatformConfigurationV1): var platformConfiguration PlatformConfigurationV1 if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &platformConfiguration); err != nil { return nil, err } for _, component := range platformConfiguration.ComponentIdentifiers { t := Component{ Manufacturer: component.ComponentManufacturer, Model: component.ComponentModel, Serial: component.ComponentSerial, Revision: component.ComponentRevision, ManufacturerID: component.ComponentManufacturerID, FieldReplaceable: component.FieldReplaceable, Addresses: component.ComponentAddresses, } out.Components = append(out.Components, t) } out.Properties = platformConfiguration.PlatformProperties out.PropertiesURI = platformConfiguration.PlatformPropertiesURI.UniformResourceIdentifier case attribute.ID.Equal(oid.PlatformConfigurationV2): var platformConfiguration PlatformConfigurationV2 if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &platformConfiguration); err != nil { var workaround PlatformConfigurationV2Workaround if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &workaround); err != nil { return nil, err } platformConfiguration.ComponentIdentifiers = workaround.ComponentIdentifiers platformConfiguration.ComponentIdentifiersURI = workaround.ComponentIdentifiersURI platformConfiguration.PlatformProperties = append(platformConfiguration.PlatformProperties, workaround.PlatformProperty) platformConfiguration.PlatformPropertiesURI = workaround.PlatformPropertiesURI } for _, component := range platformConfiguration.ComponentIdentifiers { t := Component{ Manufacturer: component.ComponentManufacturer, Model: component.ComponentModel, Serial: component.ComponentSerial, Revision: component.ComponentRevision, ManufacturerID: component.ComponentManufacturerID, FieldReplaceable: component.FieldReplaceable, Addresses: component.ComponentAddresses, } out.Components = append(out.Components, t) } out.Properties = platformConfiguration.PlatformProperties out.PropertiesURI = platformConfiguration.PlatformPropertiesURI.UniformResourceIdentifier case attribute.ID.Equal(oid.PlatformConfigURI): var platformConfigurationURI URIReference if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &platformConfigurationURI); err != nil { return nil, err } default: return nil, fmt.Errorf("attributecert: unknown attribute %v", attribute.ID) } } for _, extension := range in.TBSAttributeCertificate.Extensions { switch { case extension.Id.Equal(oid.SubjectAltName): var seq asn1.RawValue rest, err := asn1.Unmarshal(extension.Value, &seq) if err != nil { return nil, err } else if len(rest) != 0 { return nil, errors.New("attributecert: trailing data after X.509 extension") } rest = seq.Bytes for len(rest) > 0 { var v asn1.RawValue rest, err = asn1.Unmarshal(rest, &v) if err != nil { return nil, err } tcgdata, err := unmarshalSAN(v) if err != nil { return nil, fmt.Errorf("attributecert: failed to unmarshal SAN: %v", err) } for _, e := range tcgdata { switch { case e.Type.Equal(oidTcgPlatformManufacturerStrV1): out.PlatformManufacturer = e.Value.(string) case e.Type.Equal(oidTcgPlatformModelV1): out.PlatformModel = e.Value.(string) case e.Type.Equal(oidTcgPlatformVersionV1): out.PlatformVersion = e.Value.(string) case e.Type.Equal(oid.TCGCredentialSpecification): // This OID appears to be misused in this context out.PlatformSerial = e.Value.(string) case e.Type.Equal(oid.PlatformManufacturerStr): out.PlatformManufacturer = e.Value.(string) case e.Type.Equal(oid.PlatformManufacturerID): // We can't parse these out at present break case e.Type.Equal(oid.PlatformModel): out.PlatformModel = e.Value.(string) case e.Type.Equal(oid.PlatformVersion): out.PlatformVersion = e.Value.(string) case e.Type.Equal(oid.PlatformSerial): out.PlatformSerial = e.Value.(string) default: return nil, fmt.Errorf("attributecert: unhandled attribute: %v", e.Type) } } } case extension.Id.Equal(oid.SubjectDirectoryAttributes): var seq asn1.RawValue rest, err := asn1.Unmarshal(extension.Value, &seq) if err != nil { return nil, err } else if len(rest) != 0 { return nil, errors.New("attributecert: trailing data after X.509 extension") } rest = seq.Bytes for len(rest) > 0 { var e TCGDirectoryEntry rest, err = asn1.Unmarshal(rest, &e) if err != nil { return nil, err } switch { case e.ID.Equal(oid.TCGPlatformSpecification): var platformSpecification TCGPlatformSpecification _, err := asn1.Unmarshal(e.Data.Bytes, &platformSpecification) if err != nil { return nil, err } out.TCGPlatformSpecification = platformSpecification case e.ID.Equal(oid.TBBSecurityAssertions): var securityAssertions TBBSecurityAssertions_sda _, err := asn1.Unmarshal(e.Data.Bytes, &securityAssertions) if err != nil { return nil, err } out.TBBSecurityAssertions.Version = securityAssertions.Version out.TBBSecurityAssertions.CcInfo = CommonCriteriaMeasures(securityAssertions.CcInfo) out.TBBSecurityAssertions.FipsLevel = securityAssertions.FipsLevel out.TBBSecurityAssertions.RtmType = securityAssertions.RtmType out.TBBSecurityAssertions.Iso9000Certified = securityAssertions.Iso9000Certified out.TBBSecurityAssertions.Iso9000URI = securityAssertions.Iso9000URI default: return nil, fmt.Errorf("attributecert: unhandled TCG directory attribute: %v", e.ID) } } case extension.Id.Equal(oid.CertificatePolicies): var policies []policyInformation _, err := asn1.Unmarshal(extension.Value, &policies) if err != nil { return nil, err } for _, policy := range policies { if policy.ID.Equal(oidTcgCertificatePolicy) { var subpolicies []policyInformation _, err := asn1.Unmarshal(policy.Policy.FullBytes, &subpolicies) if err != nil { return nil, err } for _, subpolicy := range subpolicies { switch { case subpolicy.ID.Equal(oidCpsCertificatePolicy): var cpsPolicy cpsPolicy _, err := asn1.Unmarshal(subpolicy.Raw, &cpsPolicy) if err != nil { return nil, err } case subpolicy.ID.Equal(oidAttributeUserNotice): var userNotice string _, err := asn1.Unmarshal(subpolicy.Policy.Bytes, &userNotice) if err != nil { return nil, err } default: return nil, fmt.Errorf("attributecert: unhandled certificate policy: %v", subpolicy.ID) } } } } case extension.Id.Equal(oidExtensionAuthorityKeyIdentifier): var a authKeyID _, err := asn1.Unmarshal(extension.Value, &a) if err != nil { return nil, err } case extension.Id.Equal(oidAuthorityInfoAccess): var aia []authorityInfoAccess _, err := asn1.Unmarshal(extension.Value, &aia) if err != nil { return nil, err } for _, v := range aia { if v.Method.Equal(oidAuthorityInfoAccessOcsp) { //TODO } else if v.Method.Equal(oidAuthorityInfoAccessIssuers) { //TODO } else { return nil, fmt.Errorf("attributecert: unhandled Authority Info Access type %v", v.Method) } } default: return nil, fmt.Errorf("attributecert: unknown extension ID %v", extension.Id) } } return out, nil } // CheckSignatureFrom verifies that the signature on c is a valid signature // from parent. func (c *AttributeCertificate) CheckSignatureFrom(parent *x509.Certificate) error { if parent.KeyUsage != 0 && parent.KeyUsage&x509.KeyUsageCertSign == 0 { return x509.ConstraintViolationError{} } if parent.PublicKeyAlgorithm == x509.UnknownPublicKeyAlgorithm { return x509.ErrUnsupportedAlgorithm } // TODO(agl): don't ignore the path length constraint. return parent.CheckSignature(c.SignatureAlgorithm, c.RawTBSAttributeCertificate, c.Signature) } go-attestation-0.5.1/attributecert/attributecert_test.go000066400000000000000000000050731452320553600236210ustar00rootroot00000000000000// Copyright 2019 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. package attributecert import ( "crypto/x509" "encoding/json" "os" "reflect" "strings" "testing" ) func TestVerifyAttributeCert(t *testing.T) { testfiles := [...]string{"testdata/Intel_nuc_pc2.cer", "testdata/Intel_nuc_pc.cer", "testdata/Intel_pc2.cer", "testdata/Intel_pc3.cer", } data, err := os.ReadFile("testdata/IntelSigningKey_20April2017.cer") if err != nil { t.Fatalf("failed to read Intel intermediate certificate: %v", err) } cert, err := x509.ParseCertificate(data) if err != nil { t.Fatalf("failed to parse Intel intermediate certificate: %v", err) } for _, filename := range testfiles { data, err = os.ReadFile(filename) if err != nil { t.Fatalf("failed to read %s: %v", filename, err) } attributecert, err := ParseAttributeCertificate(data) if err != nil { t.Fatalf("failed to parse %s: %v", filename, err) } err = attributecert.CheckSignatureFrom(cert) if err != nil { t.Fatalf("failed to verify signature on %s: %v", filename, err) } } } func TestParseAttributeCerts(t *testing.T) { files, err := os.ReadDir("testdata") if err != nil { t.Fatalf("failed to read test dir: %v", err) } for _, file := range files { if strings.Contains(file.Name(), "Signing") { continue } if strings.HasSuffix(file.Name(), ".json") { continue } filename := "testdata/" + file.Name() jsonfile := filename + ".json" data, err := os.ReadFile(filename) if err != nil { t.Fatalf("failed to read test data %s: %v", filename, err) } got, err := ParseAttributeCertificate(data) if err != nil { t.Fatalf("failed to parse test data %s: %v", filename, err) } jsondata, err := os.ReadFile(jsonfile) if err != nil { t.Fatalf("failed to read json test data %s: %v", jsonfile, err) } var want AttributeCertificate if err := json.Unmarshal(jsondata, &want); err != nil { t.Fatalf("failed to unmarshal file %s: %v", filename, err) } if !reflect.DeepEqual(&want, got) { t.Fatalf("%s fails to match test data", filename) } } } go-attestation-0.5.1/attributecert/testdata/000077500000000000000000000000001452320553600211565ustar00rootroot00000000000000go-attestation-0.5.1/attributecert/testdata/IntelSigningKey_20April2017.cer000066400000000000000000000016631452320553600265250ustar00rootroot000000000000000‚¯0‚— %P§0  *†H†÷ 0‡1 0 UUS1 0 UCA10U Santa Clara10U Intel Corporation1!0U Transparent Supply Chain10U www.intel.com0 170419000210Z 371031000210Z0‡1 0 UUS1 0 UCA10U Santa Clara10U Intel Corporation1!0U Transparent Supply Chain10U www.intel.com0‚"0  *†H†÷ ‚0‚ ‚£°®ñîXªAoÑžcI˜w>V¼M¿G6ùe3Ð k­S)RöÉhÚ ÇŽÞ¿Ð˜¾Œn%M-ô˜Ì›hµ»£¥éYJç ª¿êÉ+ä¯"“Rä±î푬…຃עåL€&R´)¦Û¬H­¤µÒ¬ËÌ¡6æù¶,Ð=}Ž:‡ÚÎOrà™_ÄIM_-eÞuP±a—îô¬Œcñn^eÏüêÿq[uç צ[Ì%|6ÂE(ðo|«'ƒ9Ûák†8ôÛ0–¬”p%“éøl{rôƒ‹ëÛá„ZWh9»b·ÛÝ=G Ë1“bi{ÎBYÚü†t6'×A£!00U!0ítv42p„ð'•ßg‹×s0  *†H†÷ ‚8§áˆå.‡IXP¼2¨¢µ$æp´14[[Á¸ºð ¨| On s—µóN¡Yvä·¡¨îæ.4•&ÅšžÕÚ°Bޝ–é¿3NKƒó»¾wJÆr¬³óÞO˜ÌÊ2x·MCr„›f™/PQ–cl¡gO‡šXæãû†ë#˫ӡ@~®QµíŽÐ¥.%;AÁ7ö¯ó^²®ë4@¶¡‚aƒñS’jk¶âßA‘Êl“© ;‡Ë ð™Ã"vüÉþÉ#ßáº^¨zI2)ç¼ÅT¯éójË wþëb÷y£åzZÜídŸ³ ÊÛ-{ïv1]¾‡p™go-attestation-0.5.1/attributecert/testdata/Intel_nuc1.cer000066400000000000000000000035531452320553600236600ustar00rootroot000000000000000‚g0‚Ï0• ’0‰¤†0ƒ1 0 UDE1!0U Infineon Technologies AG10U OPTIGA(TM) TPM2.01503U ,Infineon OPTIGA(TM) RSA Manufacturing CA 022{kä ¥0¢¤Ÿ0œ1 0 UUS1 0 U CA10U Santa Clara10U Intel Corporation1604U -Transparent Supply Chain Issuing CA IKGF_TEST10U www.intel.com0  *†H†÷  E`àHÁJ/IôKé-¿° €¸Iÿ0"20181006210933Z20320531102302Z0‚y0g100 0g1 0g0g1 0 0  0g1 0 ‚0‚Íg1‚À0‚¼ ‚90< Intel(R) Corporation Core i5€X23983922.6‚343ƒÿ08 Samsung M471A5143EB0-CPB€ABC459893.1‚196ƒ0H Not Specified KINGSTON SA400S3€50026B777805270B609.0‚196ƒ0u Intel Corporation Ethernet Connection I219-LM€8c:0f:6f:72:c6:c521.0‚343ƒÿ¤0g 8c:0f:6f:72:c6:c5¡>0 AMT true0 vPro Enabled true0 DropShip Enabled false¢=;https://www.platformmfg.com/platforproperties/493894384.htm0Fg1<0:8https://www.platformmfg.com/platformconfig/478748738.xml0‚Â0©U ¡0ž0› *†H†øM0Œ0Z+Nhttps://trustedservices.intel.com/content/TSC/certs/TSCcertPolicyStatement.pdf0.+0" TCG Trusted Platform Endorsement0†U0}¤{0y10g Intel Corporation10g NUC7i5DNHE10g J71739-4011(0&g DW1600420300110_BTDN732000QM0U#0€<¹ûc¥<¥|k‡C39ñܨû¤0j+^0\0Z+0†Nhttps://trustedservices.intel.com/content/TSC/certs/TSC_IssuingCAIKGF_TEST.cer0  *†H†÷  ‚| zZû»ÀáïÕfÝG"ï09Õã¥×©£EJ®­”ÖwLÑÌJÚ¡aû?§»Ðä6Â+’æÓà·# 8.€ã:íÕ¼/²x×õ€êÜ2âEÙ¯ëã·‰›£"yÜCˆtÆKÍizCl5º£Æu—á¨ílõ oÐÿ”>Õ'°|âÇÆ@L÷Èl•gC¢éØè> –¤±¦ÑNéE¨ÅÔåå` ·þĨÆ>k¹ @Þ‘ùFBõâ|ª1"NL`V²V­åd(%5šÜ³óÝù}Ðûg|ÀþCøe:€MDÖlÇCÇÑ#W¢^3—bΫ¤×âÅûWí.+o?™Që¿ Ec­Mvy˜ëîØ›®2Ã=ÛbW€Î{ðH·Í;vcèʦ›M4Ï¥°ÐtƒSÔÚ½<š%kD8ÎúGiFd6޼þvæ¨LT£ÎômföS½{Y!Œ1?žáÚ³Š†©­KSÙY®&ÊA¯¥lx“€¾¨Ž€zêÓxgo-attestation-0.5.1/attributecert/testdata/Intel_nuc1.cer.json000066400000000000000000000274741452320553600246400ustar00rootroot00000000000000{ "Raw": "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", "RawTBSAttributeCertificate": "MIIFzwIBATCBlaCBkjCBiaSBhjCBgzELMAkGA1UEBhMCREUxITAfBgNVBAoMGEluZmluZW9uIFRlY2hub2xvZ2llcyBBRzEaMBgGA1UECwwRT1BUSUdBKFRNKSBUUE0yLjAxNTAzBgNVBAMMLEluZmluZW9uIE9QVElHQShUTSkgUlNBIE1hbnVmYWN0dXJpbmcgQ0EgMDIyAgR7B2vkoIGlMIGipIGfMIGcMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExFDASBgNVBAcMC1NhbnRhIENsYXJhMRowGAYDVQQKDBFJbnRlbCBDb3Jwb3JhdGlvbjE2MDQGA1UECwwtVHJhbnNwYXJlbnQgU3VwcGx5IENoYWluIElzc3VpbmcgQ0EgSUtHRl9URVNUMRYwFAYDVQQDDA13d3cuaW50ZWwuY29tMA0GCSqGSIb3DQEBCwUAAhRFYOBIwUovSfRL6S2/GbAJgLhJ/zAiGA8yMDE4MTAwNjIxMDkzM1oYDzIwMzIwNTMxMTAyMzAyWjCCAnkwHAYFZ4EFAhExEzARMAkCAQICAQACAQEEBAAAAAEwEgYFZ4EFAhkxCTAHBgVngQUIAjAWBgVngQUCFzENMAswCQIBAQIBAQIBCTAUBgVngQUCEzELMAkCAQCCAQMBAQAwggHNBgdngQUFAQcBMYIBwDCCAbygggE5MDwEBAEAAAAMFEludGVsKFIpIENvcnBvcmF0aW9uDAdDb3JlIGk1gAhYMjM5ODM5MoEDMi42ggMzNDODAf8wOAQEAwAAAAwHU2Ftc3VuZwwQTTQ3MUE1MTQzRUIwLUNQQoAIQUJDNDU5ODmBAzMuMYIDMTk2gwEAMEgEBAMAAAAMDU5vdCBTcGVjaWZpZWQMEEtJTkdTVE9OIFNBNDAwUzOAEDUwMDI2Qjc3NzgwNTI3MEKBBTYwOS4wggMxOTaDAQAwdQQEBAAAAAwRSW50ZWwgQ29ycG9yYXRpb24MG0V0aGVybmV0IENvbm5lY3Rpb24gSTIxOS1MTYAROGM6MGY6NmY6NzI6YzY6YzWBBDIxLjCCAzM0M4MB/6QcMBoGBWeBBREBDBE4YzowZjo2Zjo3MjpjNjpjNaE+MAsMA0FNVAwEdHJ1ZTAUDAx2UHJvIEVuYWJsZWQMBHRydWUwGQwQRHJvcFNoaXAgRW5hYmxlZAwFZmFsc2WiPRY7aHR0cHM6Ly93d3cucGxhdGZvcm1tZmcuY29tL3BsYXRmb3Jwcm9wZXJ0aWVzLzQ5Mzg5NDM4NC5odG0wRgYGZ4EFBQEDMTwwOhY4aHR0cHM6Ly93d3cucGxhdGZvcm1tZmcuY29tL3BsYXRmb3JtY29uZmlnLzQ3ODc0ODczOC54bWwwggHCMIGpBgNVHSAEgaEwgZ4wgZsGCiqGSIb4TQEFAgQwgYwwWgYIKwYBBQUHAgEWTmh0dHBzOi8vdHJ1c3RlZHNlcnZpY2VzLmludGVsLmNvbS9jb250ZW50L1RTQy9jZXJ0cy9UU0NjZXJ0UG9saWN5U3RhdGVtZW50LnBkZjAuBggrBgEFBQcCAjAiDCBUQ0cgVHJ1c3RlZCBQbGF0Zm9ybSBFbmRvcnNlbWVudDCBhgYDVR0RBH8wfaR7MHkxHTAbBgZngQUFAQEMEUludGVsIENvcnBvcmF0aW9uMRYwFAYGZ4EFBQEEDApOVUM3aTVETkhFMRYwFAYGZ4EFBQEFDApKNzE3MzktNDAxMSgwJgYGZ4EFBQEGDBxEVzE2MDA0MjAzMDAxMTBfQlRETjczMjAwMFFNMB8GA1UdIwQYMBaAFDwGuftjpTylfGuHQzM58dyoB/ukMGoGCCsGAQUFBwEBBF4wXDBaBggrBgEFBQcwAoZOaHR0cHM6Ly90cnVzdGVkc2VydmljZXMuaW50ZWwuY29tL2NvbnRlbnQvVFNDL2NlcnRzL1RTQ19Jc3N1aW5nQ0FJS0dGX1RFU1QuY2Vy", "Signature": "fKB6Wvu7wOGQ7xTVZt1HIu8wOQIF1eOlndepo0VKrg6tlNZ3TNHMSgLaoWH7P42nu43Q5DbCK5IA5tMI4LcjCjgugOM6Gu2N1bwvsnjX9YDq3DLiFEXZGq/r47cYiZujInncQ4h0xkvNFml6Q2yNNbqjxnWXAeGoHO1s9Qtv0P+UPtUnsHzix8ZATPfIbJURZ0Oi6djojT4LlqSxptFO6UWoxdTl5WCgFbf+xKjGPmu5DEDekflGQvUU4nyqMSJOTGBWslatAOVkKCU1mtyz8935fdD7Z3zA/kP4ZRw6whWATUQa1mzHQ8fRI1eiXjOXYs6rpNfixftX7S4rbz+ZURLrvwxFY5CtTRl2eZjr7tgXm64ywz1/22JXAYDOe/BIt807dmPoyhamm000z6Ww0HSDU9TavTyakCVrRDjO+kdpfwZGZDaOvP525qhMVKPO9G1m9lO9e1khjJAxP57h2rOKhhSprUsfU9lZriYGygJBr6VseJOAvqiOgHrq0xd4", "SignatureAlgorithm": 4, "Version": 2, "SerialNumber": 396080772635209191883026258511591308753565665791, "Holder": { "Issuer": { "Country": [ "DE" ], "Organization": [ "Infineon Technologies AG" ], "OrganizationalUnit": [ "OPTIGA(TM) TPM2.0" ], "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "Infineon OPTIGA(TM) RSA Manufacturing CA 022", "Names": [ { "Type": [ 2, 5, 4, 6 ], "Value": "DE" }, { "Type": [ 2, 5, 4, 10 ], "Value": "Infineon Technologies AG" }, { "Type": [ 2, 5, 4, 11 ], "Value": "OPTIGA(TM) TPM2.0" }, { "Type": [ 2, 5, 4, 3 ], "Value": "Infineon OPTIGA(TM) RSA Manufacturing CA 022" } ], "ExtraNames": null }, "Serial": 2064083940 }, "Issuer": { "Country": [ "US" ], "Organization": [ "Intel Corporation" ], "OrganizationalUnit": [ "Transparent Supply Chain Issuing CA IKGF_TEST" ], "Locality": [ "Santa Clara" ], "Province": [ "CA" ], "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "www.intel.com", "Names": [ { "Type": [ 2, 5, 4, 6 ], "Value": "US" }, { "Type": [ 2, 5, 4, 8 ], "Value": "CA" }, { "Type": [ 2, 5, 4, 7 ], "Value": "Santa Clara" }, { "Type": [ 2, 5, 4, 10 ], "Value": "Intel Corporation" }, { "Type": [ 2, 5, 4, 11 ], "Value": "Transparent Supply Chain Issuing CA IKGF_TEST" }, { "Type": [ 2, 5, 4, 3 ], "Value": "www.intel.com" } ], "ExtraNames": null }, "Subject": { "Country": null, "Organization": null, "OrganizationalUnit": null, "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "", "Names": null, "ExtraNames": null }, "NotBefore": "2018-10-06T21:09:33Z", "NotAfter": "2032-05-31T10:23:02Z", "TCGPlatformSpecification": { "Version": { "MajorVersion": 2, "MinorVersion": 0, "Revision": 1 } }, "TBBSecurityAssertions": { "Version": 0, "CcInfo": { "Version": "", "AssuranceLevel": 0, "EvaluationStatus": 0, "Plus": false, "StrengthOfFunction": 0, "ProfileOid": null, "ProfileURI": "", "TargetOid": null, "TargetURI": null }, "FipsLevel": { "Version": "", "Level": 0, "Plus": false }, "RtmType": 3, "Iso9000Certified": false, "Iso9000URI": "" }, "PlatformManufacturer": "Intel Corporation", "PlatformModel": "NUC7i5DNHE", "PlatformVersion": "J71739-401", "PlatformSerial": "DW1600420300110_BTDN732000QM", "CredentialSpecification": "", "UserNotice": { "NoticeRef": { "Organization": "", "NoticeNumbers": null }, "ExplicitText": "" }, "Components": [ { "Manufacturer": "Intel(R) Corporation", "Model": "Core i5", "Serial": "X2398392", "Revision": "2.6", "ManufacturerID": 3355699, "FieldReplaceable": true, "Addresses": null }, { "Manufacturer": "Samsung", "Model": "M471A5143EB0-CPB", "Serial": "ABC45989", "Revision": "3.1", "ManufacturerID": 3225910, "FieldReplaceable": false, "Addresses": null }, { "Manufacturer": "Not Specified", "Model": "KINGSTON SA400S3", "Serial": "50026B777805270B", "Revision": "609.0", "ManufacturerID": 3225910, "FieldReplaceable": false, "Addresses": null }, { "Manufacturer": "Intel Corporation", "Model": "Ethernet Connection I219-LM", "Serial": "8c:0f:6f:72:c6:c5", "Revision": "21.0", "ManufacturerID": 3355699, "FieldReplaceable": true, "Addresses": [ { "AddressType": [ 2, 23, 133, 17, 1 ], "AddressValue": "8c:0f:6f:72:c6:c5" } ] } ], "Properties": [ { "PropertyName": "AMT", "PropertyValue": "true", "Status": 0 }, { "PropertyName": "vPro Enabled", "PropertyValue": "true", "Status": 0 }, { "PropertyName": "DropShip Enabled", "PropertyValue": "false", "Status": 0 } ], "PropertiesURI": "https://www.platformmfg.com/platforproperties/493894384.htm" }go-attestation-0.5.1/attributecert/testdata/Intel_nuc_pc.cer000066400000000000000000000014041452320553600242520ustar00rootroot000000000000000‚0‚è00 .0¤010U STMicro+ÏOùû2߉íSU lÏžäÈkjÝ 0¤Š0‡1 0 UUS1 0 U CA10U Santa Clara10U Intel Corporation1!0U Transparent Supply Chain10U www.intel.com0  *†H†÷ BО „xÖ÷BýÒ£â¢@†oˆP0"20170315210830Z20301231235959Z010g100  10g1 0 ‚0¡0MU ÿC0A0? *†H†øM010/+0# !TCPA Trusted Platform Endorsement0PUÿF0D¤B0@10g Intel10g DE3815TYKH10g H26998-4020  *†H†÷ ‚\ðøèÌYËKЕ$;〃YD½ç­Fsb 3Aj]Æ‹¦àÐ$Ö¼üœÎß6"s:4‚Z¯äÀ#rº¡=×Qäþ[õz¶å®\è ©Àê6z4®tÈ63—bYn­\Ôè9õÓ×õ5¿›Öd'X"pŤ­¦ï8ÚAù úš²DjPcŽæub;¦4÷ŠsÁ?Ù§å¶ €£Pp …|8ήàg¨•ºOªuŠÿƒì­Bkøž†ÔYÀSç’u[ð…¯ød0Ùg7Ì¿+â×ZMâܳ¹bcͺŒì;&<{;E˜rvï´A¶ ‡§U#™0¸ƒÙÏ…JôNÀºÙqŠiؘ2P]%@6k^z4`µ&v&ÄŸ–~¡5H´›1JršÄ2 Ð[Žh¹Æ.!ð¯à¾"° ;õ¤:¢0‚&00 .0¤010U STMicroNÀÃËßž—¡AEF‹ c=ç ’0¤Œ0‰10U www.intel.com10U TrustedSupplyChain10U Intel Corporation10U Santa Clara10U California1 0 UUS0  *†H†÷ 0"20160122210200Z20170122210200Z0N0L+1@0>0 Credential Type Label0 !TCPA Trusted Platform Endorsement0Ó0_UX0V10g Intel10g S2600KP10g H76962-35010g BQKP528406780pU i0g0g100  10Jg1A0?0 CC Version    ÿURL to iso9000 certificate0  *†H†÷ ‚B_k"ìle=£„£¹´ÙT¤_±Ñ9mš¾ržb™)|ûW©qU›²ž᪻õ霖í{SÎ?Lq¨‰è“ŠÀ_ “k~‡SagIÛdv„Ý.C o³¶/(dé›~ÂÒ`RŒNM³Ça{Ã!ß_öË%{Þ”CË ŽÒ¹ï•‡,?®Zq•áiÑL½`QºîÔ‚å2,¥ Í™yïŒa˜È;§$:,y¹4k’«¸ÁN:éPÕë.#ËïI”šA7ëå-°ôÁèÝQ^Ÿð¢,èRú…Çd9ó‘èhtf ªžÑP£o²Š¶ø@üÆÍOoÿ²¨go-attestation-0.5.1/attributecert/testdata/Intel_pc1.cer.json000066400000000000000000000144531452320553600244460ustar00rootroot00000000000000{ "Raw": "MIIDPjCCAiYCAQEwMKAuMBakFDASMRAwDgYDVQQDDAdTVE1pY3JvAhROwMMWy99/A56XoUFFRosDIGM956CBkjCBj6SBjDCBiTEWMBQGA1UEAwwNd3d3LmludGVsLmNvbTEbMBkGA1UECwwSVHJ1c3RlZFN1cHBseUNoYWluMRowGAYDVQQKDBFJbnRlbCBDb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExEzARBgNVBAgMCkNhbGlmb3JuaWExCzAJBgNVBAYTAlVTMA0GCSqGSIb3DQEBBQUAAgEBMCIYDzIwMTYwMTIyMjEwMjAwWhgPMjAxNzAxMjIyMTAyMDBaME4wTAYIKwYBBQUHAgIxQDA+MBkMFUNyZWRlbnRpYWwgVHlwZSBMYWJlbDAADCFUQ1BBIFRydXN0ZWQgUGxhdGZvcm0gRW5kb3JzZW1lbnQwgdMwXwYDVR0RBFgwVjEQMA4GBWeBBQIEDAVJbnRlbDESMBAGBWeBBQIFDAdTMjYwMEtQMRUwEwYFZ4EFAgYMCkg3Njk2Mi0zNTAxFzAVBgVngQUCFwwMQlFLUDUyODQwNjc4MHAGA1UdCQRpMGcwGQYFZ4EFAhExEDAOMAkCAQECAQICAQEMATEwSgYFZ4EFAhMxQTA/AgEBMBgWCkNDIFZlcnNpb24KAQcKAQIBAQAKAQEKAQIBAf8WGlVSTCB0byBpc285MDAwIGNlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAA4IBAQBCX2siA+xsZR89o4QWo525tNlUpF+x0TltB5q+cp5imSl8+1epcVWbsp4T4aq79emcEZaP7XtTzj9McaiJ6JMWipDAXw8Nk2uNfodTHGFnSdtkdoTdLkMLb7O2LyhkB+mbfsLSCGBSjE5Ns8dhe8Mh3x4OX432Acsle96UHkPLCo7Sue8elYcsP65acZXhadFMBb1gUboa7tSC5TIspY0JzZl574wWYZjIO6ckOix5uTRrkqu4wU466VDV6y4jy+8fEkmBlJpBN+vlLbD0wejdUV6f8KIs6FL6hcdkjRYPOfOR6Gh0Zgt/qp7RUKNvAhCyirb4QPzGHYHNT2//EbKo", "RawTBSAttributeCertificate": "MIICJgIBATAwoC4wFqQUMBIxEDAOBgNVBAMMB1NUTWljcm8CFE7AwxbL338DnpehQUVGiwMgYz3noIGSMIGPpIGMMIGJMRYwFAYDVQQDDA13d3cuaW50ZWwuY29tMRswGQYDVQQLDBJUcnVzdGVkU3VwcGx5Q2hhaW4xGjAYBgNVBAoMEUludGVsIENvcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTETMBEGA1UECAwKQ2FsaWZvcm5pYTELMAkGA1UEBhMCVVMwDQYJKoZIhvcNAQEFBQACAQEwIhgPMjAxNjAxMjIyMTAyMDBaGA8yMDE3MDEyMjIxMDIwMFowTjBMBggrBgEFBQcCAjFAMD4wGQwVQ3JlZGVudGlhbCBUeXBlIExhYmVsMAAMIVRDUEEgVHJ1c3RlZCBQbGF0Zm9ybSBFbmRvcnNlbWVudDCB0zBfBgNVHREEWDBWMRAwDgYFZ4EFAgQMBUludGVsMRIwEAYFZ4EFAgUMB1MyNjAwS1AxFTATBgVngQUCBgwKSDc2OTYyLTM1MDEXMBUGBWeBBQIXDAxCUUtQNTI4NDA2NzgwcAYDVR0JBGkwZzAZBgVngQUCETEQMA4wCQIBAQIBAgIBAQwBMTBKBgVngQUCEzFBMD8CAQEwGBYKQ0MgVmVyc2lvbgoBBwoBAgEBAAoBAQoBAgEB/xYaVVJMIHRvIGlzbzkwMDAgY2VydGlmaWNhdGU=", "Signature": "Ql9rIgPsbGUfPaOEFqOdubTZVKRfsdE5bQeavnKeYpkpfPtXqXFVm7KeE+Gqu/XpnBGWj+17U84/THGoieiTFoqQwF8PDZNrjX6HUxxhZ0nbZHaE3S5DC2+zti8oZAfpm37C0ghgUoxOTbPHYXvDId8eDl+N9gHLJXvelB5DywqO0rnvHpWHLD+uWnGV4WnRTAW9YFG6Gu7UguUyLKWNCc2Zee+MFmGYyDunJDosebk0a5KruMFOOulQ1esuI8vvHxJJgZSaQTfr5S2w9MHo3VFen/CiLOhS+oXHZI0WDznzkehodGYLf6qe0VCjbwIQsoq2+ED8xh2BzU9v/xGyqA==", "SignatureAlgorithm": 3, "Version": 2, "SerialNumber": 1, "Holder": { "Issuer": { "Country": null, "Organization": null, "OrganizationalUnit": null, "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "STMicro", "Names": [ { "Type": [ 2, 5, 4, 3 ], "Value": "STMicro" } ], "ExtraNames": null }, "Serial": 449600017855339869538679649152375580078880538087 }, "Issuer": { "Country": [ "US" ], "Organization": [ "Intel Corporation" ], "OrganizationalUnit": [ "TrustedSupplyChain" ], "Locality": [ "Santa Clara" ], "Province": [ "California" ], "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "www.intel.com", "Names": [ { "Type": [ 2, 5, 4, 3 ], "Value": "www.intel.com" }, { "Type": [ 2, 5, 4, 11 ], "Value": "TrustedSupplyChain" }, { "Type": [ 2, 5, 4, 10 ], "Value": "Intel Corporation" }, { "Type": [ 2, 5, 4, 7 ], "Value": "Santa Clara" }, { "Type": [ 2, 5, 4, 8 ], "Value": "California" }, { "Type": [ 2, 5, 4, 6 ], "Value": "US" } ], "ExtraNames": null }, "Subject": { "Country": null, "Organization": null, "OrganizationalUnit": null, "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "", "Names": null, "ExtraNames": null }, "NotBefore": "2016-01-22T21:02:00Z", "NotAfter": "2017-01-22T21:02:00Z", "TCGPlatformSpecification": { "Version": { "MajorVersion": 1, "MinorVersion": 2, "Revision": 1 } }, "TBBSecurityAssertions": { "Version": 1, "CcInfo": { "Version": "CC Version", "AssuranceLevel": 7, "EvaluationStatus": 2, "Plus": false, "StrengthOfFunction": 1, "ProfileOid": null, "ProfileURI": "", "TargetOid": null, "TargetURI": null }, "FipsLevel": { "Version": "", "Level": 0, "Plus": false }, "RtmType": 2, "Iso9000Certified": true, "Iso9000URI": "URL to iso9000 certificate" }, "PlatformManufacturer": "Intel", "PlatformModel": "S2600KP", "PlatformVersion": "H76962-350", "PlatformSerial": "BQKP52840678", "CredentialSpecification": "", "UserNotice": { "NoticeRef": { "Organization": "Credential Type Label", "NoticeNumbers": [] }, "ExplicitText": "TCPA Trusted Platform Endorsement" }, "Components": null, "Properties": null, "PropertiesURI": "" }go-attestation-0.5.1/attributecert/testdata/Intel_pc2.cer000066400000000000000000000014041452320553600234670ustar00rootroot000000000000000‚0‚è00 .0¤010U STMicro…gÿ5yÒÔ”]õkmÇ 0¤Š0‡1 0 UUS1 0 U CA10U Santa Clara10U Intel Corporation1!0U Transparent Supply Chain10U www.intel.com0  *†H†÷ TÞëÊ"ó_]J]Y·ß} ªGéï0"20170323223433Z20301231235959Z010g100  10g1 0 ‚0¡0MU ÿC0A0? *†H†øM010/+0# !TCPA Trusted Platform Endorsement0PUÿF0D¤B0@10g Intel10g DE3815TYKH10g H26998-4020  *†H†÷ ‚g«û¹¨ÌåÚ¤Q— ÞÚeý}ý|Q¸B°3Ã-‚¬ ÁJHÞá`:Y9øG±• *Ë3û£[€,#&‰NÐ÷Ñ©Pç«ÞïИÁ(8¾´Y[Šk> ÑMNóÕ€¬Ák†T¶çC²¡Ð9u#‡ %êÃŒ˜ýV‡ïƒCëÀƒ8ŽÅ“fVw°XHÌ_«±æ\0ñß9WÒ—¾ zH‰§Yi´³Á¥-J×Û]†Õ…¥¢·qèì`m…£¦³4ˆü…΄´ ê{sçµk§94OËnzÝ`b?€òà!¦õˆ—W+â&b2b sjîng$»Ó:ø högo-attestation-0.5.1/attributecert/testdata/Intel_pc2.cer.json000066400000000000000000000141211452320553600244370ustar00rootroot00000000000000{ "Raw": "MIIDADCCAegCAQEwMKAuMBakFDASMRAwDgYDVQQDDAdTVE1pY3JvAhQHAIGFZ/81eRaQ0tQElF31aw5tx6CBkDCBjaSBijCBhzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRQwEgYDVQQHDAtTYW50YSBDbGFyYTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xITAfBgNVBAsMGFRyYW5zcGFyZW50IFN1cHBseSBDaGFpbjEWMBQGA1UEAwwNd3d3LmludGVsLmNvbTANBgkqhkiG9w0BAQUFAAIUVN7ryhYi819dSl1Zt999CapH6e8wIhgPMjAxNzAzMjMyMjM0MzNaGA8yMDMwMTIzMTIzNTk1OVowMTAZBgVngQUCETEQMA4wCQIBAQIBAgIBAQwBMTAUBgVngQUCEzELMAkCAQCCAQMBAQAwgaEwTQYDVR0gAQH/BEMwQTA/BgoqhkiG+E0BBQIEMDEwLwYIKwYBBQUHAgIwIwwhVENQQSBUcnVzdGVkIFBsYXRmb3JtIEVuZG9yc2VtZW50MFAGA1UdEQEB/wRGMESkQjBAMRAwDgYFZ4EFAgQMBUludGVsMRUwEwYFZ4EFAgUMCkRFMzgxNVRZS0gxFTATBgVngQUCBgwKSDI2OTk4LTQwMjANBgkqhkiG9w0BAQUFAAOCAQEAZ6v7uR4PBhyozOXapFEEl40QIN4R2mX9ff0OfFG4QhiwM8MtgqygwUpIw57hYDpZOfhHEbGVCSrLM/ujWxmAGQAsIyaJTtD30X+pBFDnq97v0JjBKDi+tFlbims+INEWTU7z1YCswWuGVLbnQ7Kh0Dl1I4cNASXqkMMZjByYH/1Wh++DQ+vAgziOxZMBZlZ3sFhIzF+rseZcMPEY3zkXV9KXvqAZekiJp1lptLPBpS1K19sRXYbVhROlEqK3cejsYG0EhaOmszSI/IXOhLQL6ntz57Vrpzk0T8tuet1gFmI/FoDy4CGm9YiBl1cr4iZiMmKgc2rubmcku9M6+KBo9g==", "RawTBSAttributeCertificate": "MIIB6AIBATAwoC4wFqQUMBIxEDAOBgNVBAMMB1NUTWljcm8CFAcAgYVn/zV5FpDS1ASUXfVrDm3HoIGQMIGNpIGKMIGHMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExFDASBgNVBAcMC1NhbnRhIENsYXJhMRowGAYDVQQKDBFJbnRlbCBDb3Jwb3JhdGlvbjEhMB8GA1UECwwYVHJhbnNwYXJlbnQgU3VwcGx5IENoYWluMRYwFAYDVQQDDA13d3cuaW50ZWwuY29tMA0GCSqGSIb3DQEBBQUAAhRU3uvKFiLzX11KXVm3330Jqkfp7zAiGA8yMDE3MDMyMzIyMzQzM1oYDzIwMzAxMjMxMjM1OTU5WjAxMBkGBWeBBQIRMRAwDjAJAgEBAgECAgEBDAExMBQGBWeBBQITMQswCQIBAIIBAwEBADCBoTBNBgNVHSABAf8EQzBBMD8GCiqGSIb4TQEFAgQwMTAvBggrBgEFBQcCAjAjDCFUQ1BBIFRydXN0ZWQgUGxhdGZvcm0gRW5kb3JzZW1lbnQwUAYDVR0RAQH/BEYwRKRCMEAxEDAOBgVngQUCBAwFSW50ZWwxFTATBgVngQUCBQwKREUzODE1VFlLSDEVMBMGBWeBBQIGDApIMjY5OTgtNDAy", "Signature": "Z6v7uR4PBhyozOXapFEEl40QIN4R2mX9ff0OfFG4QhiwM8MtgqygwUpIw57hYDpZOfhHEbGVCSrLM/ujWxmAGQAsIyaJTtD30X+pBFDnq97v0JjBKDi+tFlbims+INEWTU7z1YCswWuGVLbnQ7Kh0Dl1I4cNASXqkMMZjByYH/1Wh++DQ+vAgziOxZMBZlZ3sFhIzF+rseZcMPEY3zkXV9KXvqAZekiJp1lptLPBpS1K19sRXYbVhROlEqK3cejsYG0EhaOmszSI/IXOhLQL6ntz57Vrpzk0T8tuet1gFmI/FoDy4CGm9YiBl1cr4iZiMmKgc2rubmcku9M6+KBo9g==", "SignatureAlgorithm": 3, "Version": 2, "SerialNumber": 484526530336932890242076058223020130738509441519, "Holder": { "Issuer": { "Country": null, "Organization": null, "OrganizationalUnit": null, "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "STMicro", "Names": [ { "Type": [ 2, 5, 4, 3 ], "Value": "STMicro" } ], "ExtraNames": null }, "Serial": 39974218276442478052338187117424437099638975943 }, "Issuer": { "Country": [ "US" ], "Organization": [ "Intel Corporation" ], "OrganizationalUnit": [ "Transparent Supply Chain" ], "Locality": [ "Santa Clara" ], "Province": [ "CA" ], "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "www.intel.com", "Names": [ { "Type": [ 2, 5, 4, 6 ], "Value": "US" }, { "Type": [ 2, 5, 4, 8 ], "Value": "CA" }, { "Type": [ 2, 5, 4, 7 ], "Value": "Santa Clara" }, { "Type": [ 2, 5, 4, 10 ], "Value": "Intel Corporation" }, { "Type": [ 2, 5, 4, 11 ], "Value": "Transparent Supply Chain" }, { "Type": [ 2, 5, 4, 3 ], "Value": "www.intel.com" } ], "ExtraNames": null }, "Subject": { "Country": null, "Organization": null, "OrganizationalUnit": null, "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "", "Names": null, "ExtraNames": null }, "NotBefore": "2017-03-23T22:34:33Z", "NotAfter": "2030-12-31T23:59:59Z", "TCGPlatformSpecification": { "Version": { "MajorVersion": 1, "MinorVersion": 2, "Revision": 1 } }, "TBBSecurityAssertions": { "Version": 0, "CcInfo": { "Version": "", "AssuranceLevel": 0, "EvaluationStatus": 0, "Plus": false, "StrengthOfFunction": 0, "ProfileOid": null, "ProfileURI": "", "TargetOid": null, "TargetURI": null }, "FipsLevel": { "Version": "", "Level": 0, "Plus": false }, "RtmType": 3, "Iso9000Certified": false, "Iso9000URI": "" }, "PlatformManufacturer": "Intel", "PlatformModel": "DE3815TYKH", "PlatformVersion": "H26998-402", "PlatformSerial": "", "CredentialSpecification": "", "UserNotice": { "NoticeRef": { "Organization": "", "NoticeNumbers": null }, "ExplicitText": "" }, "Components": null, "Properties": null, "PropertiesURI": "" }go-attestation-0.5.1/attributecert/testdata/Intel_pc3.cer000066400000000000000000000014041452320553600234700ustar00rootroot000000000000000‚0‚è00 .0¤010U STMicroK˜.幑‹ØtÂY”…êÍÅÑÌ 0¤Š0‡1 0 UUS1 0 U CA10U Santa Clara10U Intel Corporation1!0U Transparent Supply Chain10U www.intel.com0  *†H†÷  +sýtcâfÂŒ¨˜Ppæ†wJI0"20170323223433Z20301231235959Z010g100  10g1 0 ‚0¡0MU ÿC0A0? *†H†øM010/+0# !TCPA Trusted Platform Endorsement0PUÿF0D¤B0@10g Intel10g DE3815TYKH10g H26998-4020  *†H†÷ ‚4/s«+‡ÞÊÕÇ—L6NJ«æª&h#= ˜R£å¶¼¶2ö6:] l£‚Q,(2гpÖ€DV­ó 4êJ‹¥V 9wг"~B ÷Hz±3îCÎn É‹áaß›úqa¤d‘E0Ë*/ ë>l·¹( kLÛœÙ¶Ç •õË«Ò%x Adea:‹êäª–Ý¿Ö £ÍüÐSé÷ §ÍÆšötăoj‡=]Hb”yªs¢uÉ"M@Ï}¦NWœ Ó'g,›$°cSÕLöŒ4¨“\lÞ<]GÓÏë~ÚQÝ1û·vÎá”ɳ;õìõv÷é„go-attestation-0.5.1/attributecert/testdata/Intel_pc3.cer.json000066400000000000000000000141211452320553600244400ustar00rootroot00000000000000{ "Raw": "MIIDADCCAegCAQEwMKAuMBakFDASMRAwDgYDVQQDDAdTVE1pY3JvAhRLmC6N5bmRi9h0wlmUhRPqzcXRzKCBkDCBjaSBijCBhzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRQwEgYDVQQHDAtTYW50YSBDbGFyYTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xITAfBgNVBAsMGFRyYW5zcGFyZW50IFN1cHBseSBDaGFpbjEWMBQGA1UEAwwNd3d3LmludGVsLmNvbTANBgkqhkiG9w0BAQUFAAIUDCtzGf10Y+JmwoyomFBw5oZ3SkkwIhgPMjAxNzAzMjMyMjM0MzNaGA8yMDMwMTIzMTIzNTk1OVowMTAZBgVngQUCETEQMA4wCQIBAQIBAgIBAQwBMTAUBgVngQUCEzELMAkCAQCCAQMBAQAwgaEwTQYDVR0gAQH/BEMwQTA/BgoqhkiG+E0BBQIEMDEwLwYIKwYBBQUHAgIwIwwhVENQQSBUcnVzdGVkIFBsYXRmb3JtIEVuZG9yc2VtZW50MFAGA1UdEQEB/wRGMESkQjBAMRAwDgYFZ4EFAgQMBUludGVsMRUwEwYFZ4EFAgUMCkRFMzgxNVRZS0gxFTATBgVngQUCBgwKSDI2OTk4LTQwMjANBgkqhkiG9w0BAQUFAAOCAQEAFzQvc6srAIcH3gjK1ceXTAA2AE5Kq+aqJmgjBD0LmFKj5ba8tjL2NjoCXQtso4JRLAQoFDLQs3DWgYBEVq3zCzTqSoulVhENOXfQGwWzIn5CDPdIerEz7kPObqDJi+EOYQHfm/pxYaRkkUUwyyovC+s+bLe5ECgWIGtM2xec2bbHC5X1y6vSJXgLf0FkZQ9hOovq5KqW3b/WCqPN/NAHU+n3Cginzcaa9nTEFYNvaoc9XUgYYgKUeapzonXJIk1AARXPHH2mTlecC9OdJ2caHyybJB2wY1PVTPaMNKiTXGzePF2dCEfTz+t+2lHdMfu3dgfO4ZTJszv17PV29+kEhA==", "RawTBSAttributeCertificate": "MIIB6AIBATAwoC4wFqQUMBIxEDAOBgNVBAMMB1NUTWljcm8CFEuYLo3luZGL2HTCWZSFE+rNxdHMoIGQMIGNpIGKMIGHMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExFDASBgNVBAcMC1NhbnRhIENsYXJhMRowGAYDVQQKDBFJbnRlbCBDb3Jwb3JhdGlvbjEhMB8GA1UECwwYVHJhbnNwYXJlbnQgU3VwcGx5IENoYWluMRYwFAYDVQQDDA13d3cuaW50ZWwuY29tMA0GCSqGSIb3DQEBBQUAAhQMK3MZ/XRj4mbCjKiYUHDmhndKSTAiGA8yMDE3MDMyMzIyMzQzM1oYDzIwMzAxMjMxMjM1OTU5WjAxMBkGBWeBBQIRMRAwDjAJAgEBAgECAgEBDAExMBQGBWeBBQITMQswCQIBAIIBAwEBADCBoTBNBgNVHSABAf8EQzBBMD8GCiqGSIb4TQEFAgQwMTAvBggrBgEFBQcCAjAjDCFUQ1BBIFRydXN0ZWQgUGxhdGZvcm0gRW5kb3JzZW1lbnQwUAYDVR0RAQH/BEYwRKRCMEAxEDAOBgVngQUCBAwFSW50ZWwxFTATBgVngQUCBQwKREUzODE1VFlLSDEVMBMGBWeBBQIGDApIMjY5OTgtNDAy", "Signature": "FzQvc6srAIcH3gjK1ceXTAA2AE5Kq+aqJmgjBD0LmFKj5ba8tjL2NjoCXQtso4JRLAQoFDLQs3DWgYBEVq3zCzTqSoulVhENOXfQGwWzIn5CDPdIerEz7kPObqDJi+EOYQHfm/pxYaRkkUUwyyovC+s+bLe5ECgWIGtM2xec2bbHC5X1y6vSJXgLf0FkZQ9hOovq5KqW3b/WCqPN/NAHU+n3Cginzcaa9nTEFYNvaoc9XUgYYgKUeapzonXJIk1AARXPHH2mTlecC9OdJ2caHyybJB2wY1PVTPaMNKiTXGzePF2dCEfTz+t+2lHdMfu3dgfO4ZTJszv17PV29+kEhA==", "SignatureAlgorithm": 3, "Version": 2, "SerialNumber": 69476848050263231802801623192911051516064254537, "Holder": { "Issuer": { "Country": null, "Organization": null, "OrganizationalUnit": null, "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "STMicro", "Names": [ { "Type": [ 2, 5, 4, 3 ], "Value": "STMicro" } ], "ExtraNames": null }, "Serial": 431568076532287953841340025336737925813510721996 }, "Issuer": { "Country": [ "US" ], "Organization": [ "Intel Corporation" ], "OrganizationalUnit": [ "Transparent Supply Chain" ], "Locality": [ "Santa Clara" ], "Province": [ "CA" ], "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "www.intel.com", "Names": [ { "Type": [ 2, 5, 4, 6 ], "Value": "US" }, { "Type": [ 2, 5, 4, 8 ], "Value": "CA" }, { "Type": [ 2, 5, 4, 7 ], "Value": "Santa Clara" }, { "Type": [ 2, 5, 4, 10 ], "Value": "Intel Corporation" }, { "Type": [ 2, 5, 4, 11 ], "Value": "Transparent Supply Chain" }, { "Type": [ 2, 5, 4, 3 ], "Value": "www.intel.com" } ], "ExtraNames": null }, "Subject": { "Country": null, "Organization": null, "OrganizationalUnit": null, "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "", "Names": null, "ExtraNames": null }, "NotBefore": "2017-03-23T22:34:33Z", "NotAfter": "2030-12-31T23:59:59Z", "TCGPlatformSpecification": { "Version": { "MajorVersion": 1, "MinorVersion": 2, "Revision": 1 } }, "TBBSecurityAssertions": { "Version": 0, "CcInfo": { "Version": "", "AssuranceLevel": 0, "EvaluationStatus": 0, "Plus": false, "StrengthOfFunction": 0, "ProfileOid": null, "ProfileURI": "", "TargetOid": null, "TargetURI": null }, "FipsLevel": { "Version": "", "Level": 0, "Plus": false }, "RtmType": 3, "Iso9000Certified": false, "Iso9000URI": "" }, "PlatformManufacturer": "Intel", "PlatformModel": "DE3815TYKH", "PlatformVersion": "H26998-402", "PlatformSerial": "", "CredentialSpecification": "", "UserNotice": { "NoticeRef": { "Organization": "", "NoticeNumbers": null }, "ExplicitText": "" }, "Components": null, "Properties": null, "PropertiesURI": "" }go-attestation-0.5.1/attributecert/testdata/Intel_pc4.cer000066400000000000000000000016221452320553600234730ustar00rootroot000000000000000‚Ž0‚÷00 .0¤010U STMicro…gÿ5yÒÔ”]õkmÇ 0¤Š0‡1 0 UUS1 0 U CA10U Santa Clara10U Intel Corporation1!0U Transparent Supply Chain10U www.intel.com0  *†H†÷ “Àû7$S<é<ɧþpAͶ0"20170421170529Z20301231235959Z010g100  10g1 0 ‚0‚¯0­U ÿ¢0Ÿ0œ *†H†øM00/+0# !TCPA Trusted Platform Endorsement0Z+Nhttps://trustedservices.intel.com/content/TSC/certs/TSCcertPolicyStatement.pdf0wUÿm0k¤i0g10g Intel10g DE3815TYKH10g H26998-4021%0#g G6YK42300C87,GETY421001GV0U#0€(Ó°èÿ$ŸöŒâ‹Å b®-úg‚0c+W0U0S+0†Ghttps://trustedservices.intel.com/content/TSC/certs/IntelSigningKey.cer0  *†H†÷ w£³ŒØ]à§òLèj;ƒÃq¸ê”8†<íÛDZjÕ“'{‚ç-·sÎÇb©o£m À¸{`{BˆóЏx´ 4!W–Æf"H³ã”Ô³fÀsè µ1ž†¯á{h“¤‡õüQ+^\u¼öo•t€ÄÛ8&ÆNAêgo-attestation-0.5.1/attributecert/testdata/Intel_pc4.cer.json000066400000000000000000000147451452320553600244550ustar00rootroot00000000000000{ "Raw": "MIIDjjCCAvcCAQEwMKAuMBakFDASMRAwDgYDVQQDDAdTVE1pY3JvAhQHAIGFZ/81eRaQ0tQElF31aw5tx6CBkDCBjaSBijCBhzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRQwEgYDVQQHDAtTYW50YSBDbGFyYTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xITAfBgNVBAsMGFRyYW5zcGFyZW50IFN1cHBseSBDaGFpbjEWMBQGA1UEAwwNd3d3LmludGVsLmNvbTANBgkqhkiG9w0BAQUFAAIUApPA+zckUw886Rk8yaf+cEEZzbYwIhgPMjAxNzA0MjExNzA1MjlaGA8yMDMwMTIzMTIzNTk1OVowMTAZBgVngQUCETEQMA4wCQIBAQIBAgIBAQwBMTAUBgVngQUCEzELMAkCAQCCAQMBAQAwggGvMIGtBgNVHSABAf8EgaIwgZ8wgZwGCiqGSIb4TQEFAgQwgY0wLwYIKwYBBQUHAgIwIwwhVENQQSBUcnVzdGVkIFBsYXRmb3JtIEVuZG9yc2VtZW50MFoGCCsGAQUFBwIBFk5odHRwczovL3RydXN0ZWRzZXJ2aWNlcy5pbnRlbC5jb20vY29udGVudC9UU0MvY2VydHMvVFNDY2VydFBvbGljeVN0YXRlbWVudC5wZGYwdwYDVR0RAQH/BG0wa6RpMGcxEDAOBgVngQUCBAwFSW50ZWwxFTATBgVngQUCBQwKREUzODE1VFlLSDEVMBMGBWeBBQIGDApIMjY5OTgtNDAyMSUwIwYGZ4EFBQEGDBlHNllLNDIzMDBDODcsR0VUWTQyMTAwMUdWMB8GA1UdIwQYMBaAFCjTsOj/JJ/2jAPii8UMYq4t+meCMGMGCCsGAQUFBwEBBFcwVTBTBggrBgEFBQcwAoZHaHR0cHM6Ly90cnVzdGVkc2VydmljZXMuaW50ZWwuY29tL2NvbnRlbnQvVFNDL2NlcnRzL0ludGVsU2lnbmluZ0tleS5jZXIwDQYJKoZIhvcNAQEFBQADgYEAd6OzjNhd4KfyTOhqO4PDcbjqlDiGPO3bBMexatWTJ3uC5y2Qt3POx2KpbwejbQrA7oGJurh7YHtCiPOKF7gbeLQdCYE0IVeWxh5mIkgIs+OUG9SPswBmwBFz6Ay1McW+hg6v4Xtok6SH9fxRK15cdbyP9m+VdBSAxNs4JsZOQeo=", "RawTBSAttributeCertificate": "MIIC9wIBATAwoC4wFqQUMBIxEDAOBgNVBAMMB1NUTWljcm8CFAcAgYVn/zV5FpDS1ASUXfVrDm3HoIGQMIGNpIGKMIGHMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExFDASBgNVBAcMC1NhbnRhIENsYXJhMRowGAYDVQQKDBFJbnRlbCBDb3Jwb3JhdGlvbjEhMB8GA1UECwwYVHJhbnNwYXJlbnQgU3VwcGx5IENoYWluMRYwFAYDVQQDDA13d3cuaW50ZWwuY29tMA0GCSqGSIb3DQEBBQUAAhQCk8D7NyRTDzzpGTzJp/5wQRnNtjAiGA8yMDE3MDQyMTE3MDUyOVoYDzIwMzAxMjMxMjM1OTU5WjAxMBkGBWeBBQIRMRAwDjAJAgEBAgECAgEBDAExMBQGBWeBBQITMQswCQIBAIIBAwEBADCCAa8wga0GA1UdIAEB/wSBojCBnzCBnAYKKoZIhvhNAQUCBDCBjTAvBggrBgEFBQcCAjAjDCFUQ1BBIFRydXN0ZWQgUGxhdGZvcm0gRW5kb3JzZW1lbnQwWgYIKwYBBQUHAgEWTmh0dHBzOi8vdHJ1c3RlZHNlcnZpY2VzLmludGVsLmNvbS9jb250ZW50L1RTQy9jZXJ0cy9UU0NjZXJ0UG9saWN5U3RhdGVtZW50LnBkZjB3BgNVHREBAf8EbTBrpGkwZzEQMA4GBWeBBQIEDAVJbnRlbDEVMBMGBWeBBQIFDApERTM4MTVUWUtIMRUwEwYFZ4EFAgYMCkgyNjk5OC00MDIxJTAjBgZngQUFAQYMGUc2WUs0MjMwMEM4NyxHRVRZNDIxMDAxR1YwHwYDVR0jBBgwFoAUKNOw6P8kn/aMA+KLxQxiri36Z4IwYwYIKwYBBQUHAQEEVzBVMFMGCCsGAQUFBzAChkdodHRwczovL3RydXN0ZWRzZXJ2aWNlcy5pbnRlbC5jb20vY29udGVudC9UU0MvY2VydHMvSW50ZWxTaWduaW5nS2V5LmNlcg==", "Signature": "d6OzjNhd4KfyTOhqO4PDcbjqlDiGPO3bBMexatWTJ3uC5y2Qt3POx2KpbwejbQrA7oGJurh7YHtCiPOKF7gbeLQdCYE0IVeWxh5mIkgIs+OUG9SPswBmwBFz6Ay1McW+hg6v4Xtok6SH9fxRK15cdbyP9m+VdBSAxNs4JsZOQeo=", "SignatureAlgorithm": 3, "Version": 2, "SerialNumber": 14713002128900822875530586530101450951391563190, "Holder": { "Issuer": { "Country": null, "Organization": null, "OrganizationalUnit": null, "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "STMicro", "Names": [ { "Type": [ 2, 5, 4, 3 ], "Value": "STMicro" } ], "ExtraNames": null }, "Serial": 39974218276442478052338187117424437099638975943 }, "Issuer": { "Country": [ "US" ], "Organization": [ "Intel Corporation" ], "OrganizationalUnit": [ "Transparent Supply Chain" ], "Locality": [ "Santa Clara" ], "Province": [ "CA" ], "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "www.intel.com", "Names": [ { "Type": [ 2, 5, 4, 6 ], "Value": "US" }, { "Type": [ 2, 5, 4, 8 ], "Value": "CA" }, { "Type": [ 2, 5, 4, 7 ], "Value": "Santa Clara" }, { "Type": [ 2, 5, 4, 10 ], "Value": "Intel Corporation" }, { "Type": [ 2, 5, 4, 11 ], "Value": "Transparent Supply Chain" }, { "Type": [ 2, 5, 4, 3 ], "Value": "www.intel.com" } ], "ExtraNames": null }, "Subject": { "Country": null, "Organization": null, "OrganizationalUnit": null, "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "", "Names": null, "ExtraNames": null }, "NotBefore": "2017-04-21T17:05:29Z", "NotAfter": "2030-12-31T23:59:59Z", "TCGPlatformSpecification": { "Version": { "MajorVersion": 1, "MinorVersion": 2, "Revision": 1 } }, "TBBSecurityAssertions": { "Version": 0, "CcInfo": { "Version": "", "AssuranceLevel": 0, "EvaluationStatus": 0, "Plus": false, "StrengthOfFunction": 0, "ProfileOid": null, "ProfileURI": "", "TargetOid": null, "TargetURI": null }, "FipsLevel": { "Version": "", "Level": 0, "Plus": false }, "RtmType": 3, "Iso9000Certified": false, "Iso9000URI": "" }, "PlatformManufacturer": "Intel", "PlatformModel": "DE3815TYKH", "PlatformVersion": "H26998-402", "PlatformSerial": "G6YK42300C87,GETY421001GV", "CredentialSpecification": "", "UserNotice": { "NoticeRef": { "Organization": "", "NoticeNumbers": null }, "ExplicitText": "" }, "Components": null, "Properties": null, "PropertiesURI": "" }go-attestation-0.5.1/attributecert/testdata/Intel_pc5.cer000066400000000000000000000016221452320553600234740ustar00rootroot000000000000000‚Ž0‚÷00 .0¤010U STMicroK˜.幑‹ØtÂY”…êÍÅÑÌ 0¤Š0‡1 0 UUS1 0 U CA10U Santa Clara10U Intel Corporation1!0U Transparent Supply Chain10U www.intel.com0  *†H†÷ A÷…f9YqËú•$`­;¬1Ǹ]/0"20170421170530Z20301231235959Z010g100  10g1 0 ‚0‚¯0­U ÿ¢0Ÿ0œ *†H†øM00/+0# !TCPA Trusted Platform Endorsement0Z+Nhttps://trustedservices.intel.com/content/TSC/certs/TSCcertPolicyStatement.pdf0wUÿm0k¤i0g10g Intel10g DE3815TYKH10g H26998-4021%0#g G6YK42300CB6,GETY421001600U#0€(Ó°èÿ$ŸöŒâ‹Å b®-úg‚0c+W0U0S+0†Ghttps://trustedservices.intel.com/content/TSC/certs/IntelSigningKey.cer0  *†H†÷ îi^¹´ ωøÙ’IC»Ç¨-‹º÷UÓ:ÎB’wºSé¯ ¿_ Ȇ÷¸a(ÌÐÍùˆúF›Ó—º–z^Ø™·™Ÿ¤7ôût‹uÅ z„­˜°ëŒ~u ü™ÚÛ 2ß'·O{¡V ¥l65GèA$å`·@·)2oÅgo-attestation-0.5.1/attributecert/testdata/Intel_pc5.cer.json000066400000000000000000000147471452320553600244600ustar00rootroot00000000000000{ "Raw": "MIIDjjCCAvcCAQEwMKAuMBakFDASMRAwDgYDVQQDDAdTVE1pY3JvAhRLmC6N5bmRi9h0wlmUhRPqzcXRzKCBkDCBjaSBijCBhzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRQwEgYDVQQHDAtTYW50YSBDbGFyYTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xITAfBgNVBAsMGFRyYW5zcGFyZW50IFN1cHBseSBDaGFpbjEWMBQGA1UEAwwNd3d3LmludGVsLmNvbTANBgkqhkiG9w0BAQUFAAIUQfeFZjlZccv6lSRgrTusMce4XS8wIhgPMjAxNzA0MjExNzA1MzBaGA8yMDMwMTIzMTIzNTk1OVowMTAZBgVngQUCETEQMA4wCQIBAQIBAgIBAQwBMTAUBgVngQUCEzELMAkCAQCCAQMBAQAwggGvMIGtBgNVHSABAf8EgaIwgZ8wgZwGCiqGSIb4TQEFAgQwgY0wLwYIKwYBBQUHAgIwIwwhVENQQSBUcnVzdGVkIFBsYXRmb3JtIEVuZG9yc2VtZW50MFoGCCsGAQUFBwIBFk5odHRwczovL3RydXN0ZWRzZXJ2aWNlcy5pbnRlbC5jb20vY29udGVudC9UU0MvY2VydHMvVFNDY2VydFBvbGljeVN0YXRlbWVudC5wZGYwdwYDVR0RAQH/BG0wa6RpMGcxEDAOBgVngQUCBAwFSW50ZWwxFTATBgVngQUCBQwKREUzODE1VFlLSDEVMBMGBWeBBQIGDApIMjY5OTgtNDAyMSUwIwYGZ4EFBQEGDBlHNllLNDIzMDBDQjYsR0VUWTQyMTAwMTYwMB8GA1UdIwQYMBaAFCjTsOj/JJ/2jAPii8UMYq4t+meCMGMGCCsGAQUFBwEBBFcwVTBTBggrBgEFBQcwAoZHaHR0cHM6Ly90cnVzdGVkc2VydmljZXMuaW50ZWwuY29tL2NvbnRlbnQvVFNDL2NlcnRzL0ludGVsU2lnbmluZ0tleS5jZXIwDQYJKoZIhvcNAQEFBQADgYEABe5pXrkWHLQMz4n42ZJJQwe7x6geLYuBuvdV0zrOQpJ3uhRT6QCvDAO/Hl8JyIb3uGEozNDN+Yj6RpvTl7qWegKPXh7YmbeZn6Q39Pt0i3XFCQF6EoStEJiw64x+dQ0W/Jna2wsy3ye3T3uhVg2lbDY1R+hBJOVgtx1Atykyb8U=", "RawTBSAttributeCertificate": "MIIC9wIBATAwoC4wFqQUMBIxEDAOBgNVBAMMB1NUTWljcm8CFEuYLo3luZGL2HTCWZSFE+rNxdHMoIGQMIGNpIGKMIGHMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExFDASBgNVBAcMC1NhbnRhIENsYXJhMRowGAYDVQQKDBFJbnRlbCBDb3Jwb3JhdGlvbjEhMB8GA1UECwwYVHJhbnNwYXJlbnQgU3VwcGx5IENoYWluMRYwFAYDVQQDDA13d3cuaW50ZWwuY29tMA0GCSqGSIb3DQEBBQUAAhRB94VmOVlxy/qVJGCtO6wxx7hdLzAiGA8yMDE3MDQyMTE3MDUzMFoYDzIwMzAxMjMxMjM1OTU5WjAxMBkGBWeBBQIRMRAwDjAJAgEBAgECAgEBDAExMBQGBWeBBQITMQswCQIBAIIBAwEBADCCAa8wga0GA1UdIAEB/wSBojCBnzCBnAYKKoZIhvhNAQUCBDCBjTAvBggrBgEFBQcCAjAjDCFUQ1BBIFRydXN0ZWQgUGxhdGZvcm0gRW5kb3JzZW1lbnQwWgYIKwYBBQUHAgEWTmh0dHBzOi8vdHJ1c3RlZHNlcnZpY2VzLmludGVsLmNvbS9jb250ZW50L1RTQy9jZXJ0cy9UU0NjZXJ0UG9saWN5U3RhdGVtZW50LnBkZjB3BgNVHREBAf8EbTBrpGkwZzEQMA4GBWeBBQIEDAVJbnRlbDEVMBMGBWeBBQIFDApERTM4MTVUWUtIMRUwEwYFZ4EFAgYMCkgyNjk5OC00MDIxJTAjBgZngQUFAQYMGUc2WUs0MjMwMENCNixHRVRZNDIxMDAxNjAwHwYDVR0jBBgwFoAUKNOw6P8kn/aMA+KLxQxiri36Z4IwYwYIKwYBBQUHAQEEVzBVMFMGCCsGAQUFBzAChkdodHRwczovL3RydXN0ZWRzZXJ2aWNlcy5pbnRlbC5jb20vY29udGVudC9UU0MvY2VydHMvSW50ZWxTaWduaW5nS2V5LmNlcg==", "Signature": "Be5pXrkWHLQMz4n42ZJJQwe7x6geLYuBuvdV0zrOQpJ3uhRT6QCvDAO/Hl8JyIb3uGEozNDN+Yj6RpvTl7qWegKPXh7YmbeZn6Q39Pt0i3XFCQF6EoStEJiw64x+dQ0W/Jna2wsy3ye3T3uhVg2lbDY1R+hBJOVgtx1Atykyb8U=", "SignatureAlgorithm": 3, "Version": 2, "SerialNumber": 376604304886647401292944510352953751207572692271, "Holder": { "Issuer": { "Country": null, "Organization": null, "OrganizationalUnit": null, "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "STMicro", "Names": [ { "Type": [ 2, 5, 4, 3 ], "Value": "STMicro" } ], "ExtraNames": null }, "Serial": 431568076532287953841340025336737925813510721996 }, "Issuer": { "Country": [ "US" ], "Organization": [ "Intel Corporation" ], "OrganizationalUnit": [ "Transparent Supply Chain" ], "Locality": [ "Santa Clara" ], "Province": [ "CA" ], "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "www.intel.com", "Names": [ { "Type": [ 2, 5, 4, 6 ], "Value": "US" }, { "Type": [ 2, 5, 4, 8 ], "Value": "CA" }, { "Type": [ 2, 5, 4, 7 ], "Value": "Santa Clara" }, { "Type": [ 2, 5, 4, 10 ], "Value": "Intel Corporation" }, { "Type": [ 2, 5, 4, 11 ], "Value": "Transparent Supply Chain" }, { "Type": [ 2, 5, 4, 3 ], "Value": "www.intel.com" } ], "ExtraNames": null }, "Subject": { "Country": null, "Organization": null, "OrganizationalUnit": null, "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "", "Names": null, "ExtraNames": null }, "NotBefore": "2017-04-21T17:05:30Z", "NotAfter": "2030-12-31T23:59:59Z", "TCGPlatformSpecification": { "Version": { "MajorVersion": 1, "MinorVersion": 2, "Revision": 1 } }, "TBBSecurityAssertions": { "Version": 0, "CcInfo": { "Version": "", "AssuranceLevel": 0, "EvaluationStatus": 0, "Plus": false, "StrengthOfFunction": 0, "ProfileOid": null, "ProfileURI": "", "TargetOid": null, "TargetURI": null }, "FipsLevel": { "Version": "", "Level": 0, "Plus": false }, "RtmType": 3, "Iso9000Certified": false, "Iso9000URI": "" }, "PlatformManufacturer": "Intel", "PlatformModel": "DE3815TYKH", "PlatformVersion": "H26998-402", "PlatformSerial": "G6YK42300CB6,GETY42100160", "CredentialSpecification": "", "UserNotice": { "NoticeRef": { "Organization": "", "NoticeNumbers": null }, "ExplicitText": "" }, "Components": null, "Properties": null, "PropertiesURI": "" }go-attestation-0.5.1/attributecert/testdata/lenovo.cer000066400000000000000000000024731452320553600231610ustar00rootroot000000000000000‚70‚Ÿ0s q0Y¤W0U1 0 UCH10U STMicroelectronics NV1&0$U STM TPM EK Intermediate CA 05¾¤ü1 q Ò+5ýº`L  ¥0¢¤Ÿ0œ1 0 UUS1 0 U CA10U Santa Clara10U Intel Corporation1604U -Transparent Supply Chain Issuing CA IKGF_TEST10U www.intel.com0  *†H†÷  aîöa†#-ñKö½”*íœïé0"20180915044509Z20270801040000Z0~0g100 0g1 0g0g1 0 0  0g1 0 ‚0g10¡ 0 AMT true0‚²0©U ¡0ž0› *†H†øM0Œ0Z+Nhttps://trustedservices.intel.com/content/TSC/certs/TSCcertPolicyStatement.pdf0.+0" TCG Trusted Platform Endorsement0wUp0n¤l0j10g LENOVO10g 20L7002BUS10g ThinkPad T480s1 0g PF0ZAQSW_L1HF7CS001A0U#0€<¹ûc¥<¥|k‡C39ñܨû¤0j+^0\0Z+0†Nhttps://trustedservices.intel.com/content/TSC/certs/TSC_IssuingCAIKGF_TEST.cer0  *†H†÷  ‚ìMz‚Rbôì(_At£‡Õ{‚]=^9Ä:@S^„‡w‡Ú]°ð‘ÎÜ­Ú~Ó¬lÖkC[þoãzHPrþúw~˜ÊË®`>&‘!)MÚ7 Ôðc'ÃðM‡ÐÍvM·^%º6Õÿ…YþF鱯íNU°Ü:û}e6v*ñÒZ[Í?+ŽŠï¿ÚÕs,…`½¨’ñ‡úaïÜø~W=C¿°Ü­Rum7’Uï•ê„I%Œ§ ¥;«Ä!u·LÂL®"šá•¤{ÂÊ7é}Þ§ÌElбOàÛ£ñâ0ó%[¦…øfhÜ£-zHŒ—l·ëÀM…î`p}˜w¿¯½ : 8”û¾Íþƒ…i=åµÃší4ã6…®S³UPÝfÄJ2 aí$ó;®XÒbD¿ÆÚhWßÉ]JXˆ\ÑìPªÇåíX¦õ=–_4T>ÓæIµ‚À ±Ž_S RÓ9i‡™‚â ^×ßaH°$}—Û4ÙËë]’™PÍgo-attestation-0.5.1/attributecert/testdata/lenovo.cer.json000066400000000000000000000205251452320553600241270ustar00rootroot00000000000000{ "Raw": "MIIFNzCCA58CAQEwc6BxMFmkVzBVMQswCQYDVQQGEwJDSDEeMBwGA1UECgwVU1RNaWNyb2VsZWN0cm9uaWNzIE5WMSYwJAYDVQQDDB1TVE0gVFBNIEVLIEludGVybWVkaWF0ZSBDQSAwNQIUHb4WpPwxCXEK0h8rNQ/9F7pgTAyggaUwgaKkgZ8wgZwxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEUMBIGA1UEBwwLU2FudGEgQ2xhcmExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0aW9uMTYwNAYDVQQLDC1UcmFuc3BhcmVudCBTdXBwbHkgQ2hhaW4gSXNzdWluZyBDQSBJS0dGX1RFU1QxFjAUBgNVBAMMDXd3dy5pbnRlbC5jb20wDQYJKoZIhvcNAQELBQACFGHu9mGGIwgt8Qh/S/a9lCrtnO/pMCIYDzIwMTgwOTE1MDQ0NTA5WhgPMjAyNzA4MDEwNDAwMDBaMH4wHAYFZ4EFAhExEzARMAkCAQICAQACAQEEBAAAAAEwEgYFZ4EFAhkxCTAHBgVngQUIAjAWBgVngQUCFzENMAswCQIBAQIBAQIBCTAUBgVngQUCEzELMAkCAQCCAQMBAQAwHAYHZ4EFBQEHATERMA+hDTALDANBTVQMBHRydWUwggGyMIGpBgNVHSAEgaEwgZ4wgZsGCiqGSIb4TQEFAgQwgYwwWgYIKwYBBQUHAgEWTmh0dHBzOi8vdHJ1c3RlZHNlcnZpY2VzLmludGVsLmNvbS9jb250ZW50L1RTQy9jZXJ0cy9UU0NjZXJ0UG9saWN5U3RhdGVtZW50LnBkZjAuBggrBgEFBQcCAjAiDCBUQ0cgVHJ1c3RlZCBQbGF0Zm9ybSBFbmRvcnNlbWVudDB3BgNVHREEcDBupGwwajESMBAGBmeBBQUBAQwGTEVOT1ZPMRYwFAYGZ4EFBQEEDAoyMEw3MDAyQlVTMRowGAYGZ4EFBQEFDA5UaGlua1BhZCBUNDgwczEgMB4GBmeBBQUBBgwUUEYwWkFRU1dfTDFIRjdDUzAwMUEwHwYDVR0jBBgwFoAUPAa5+2OlPKV8a4dDMznx3KgH+6QwagYIKwYBBQUHAQEEXjBcMFoGCCsGAQUFBzAChk5odHRwczovL3RydXN0ZWRzZXJ2aWNlcy5pbnRlbC5jb20vY29udGVudC9UU0MvY2VydHMvVFNDX0lzc3VpbmdDQUlLR0ZfVEVTVC5jZXIwDQYJKoZIhvcNAQELBQADggGBAB3sTQJ6FoJSYvTsKF9BdKOH1XsCgl09XjnEOkBTXoSHd4faXbDwkc7crdoTftOsbNZrQ1v+b+N6SFBy/vp3fpjKyxQZrmA+JpEhGSlN2jcHDNTwYyfD8E2H0M12TbdeJbo21f+FHVn+Rumxxu1OVbDcOvt9f2U2dirx0gZaW80/K46K77/a1XMaLIVgvaiS8Z0Qh/ph79z4flcUPUO/sNytUhURdW03klXvleqESRYljKeBC6U7q8QhdbdMwkyuByIDmuGVpHsEwso36X3eF6fMRWzQsU/g26Px4jB/8yVbpoX4Zmjcoy16SIwelx0cDmy36wMQwE2F7gdgcH0bmHe/r70NOgs4lPu+zQf+g4VpPeW1w5rtHjQO4zaFrlOzVVAE3WbESjIKYe0k8zuuWNISAmIOG0S/FcbaaFffyV1KWIhc0exQqsfl7Vim9T0fll80VD7T5km1gsAMsY5fUwtSgdM5aYeZguINXtffYUiwJBR9l9s02cvrHV2SmVDNgQ==", "RawTBSAttributeCertificate": "MIIDnwIBATBzoHEwWaRXMFUxCzAJBgNVBAYTAkNIMR4wHAYDVQQKDBVTVE1pY3JvZWxlY3Ryb25pY3MgTlYxJjAkBgNVBAMMHVNUTSBUUE0gRUsgSW50ZXJtZWRpYXRlIENBIDA1AhQdvhak/DEJcQrSHys1D/0XumBMDKCBpTCBoqSBnzCBnDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRQwEgYDVQQHDAtTYW50YSBDbGFyYTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xNjA0BgNVBAsMLVRyYW5zcGFyZW50IFN1cHBseSBDaGFpbiBJc3N1aW5nIENBIElLR0ZfVEVTVDEWMBQGA1UEAwwNd3d3LmludGVsLmNvbTANBgkqhkiG9w0BAQsFAAIUYe72YYYjCC3xCH9L9r2UKu2c7+kwIhgPMjAxODA5MTUwNDQ1MDlaGA8yMDI3MDgwMTA0MDAwMFowfjAcBgVngQUCETETMBEwCQIBAgIBAAIBAQQEAAAAATASBgVngQUCGTEJMAcGBWeBBQgCMBYGBWeBBQIXMQ0wCzAJAgEBAgEBAgEJMBQGBWeBBQITMQswCQIBAIIBAwEBADAcBgdngQUFAQcBMREwD6ENMAsMA0FNVAwEdHJ1ZTCCAbIwgakGA1UdIASBoTCBnjCBmwYKKoZIhvhNAQUCBDCBjDBaBggrBgEFBQcCARZOaHR0cHM6Ly90cnVzdGVkc2VydmljZXMuaW50ZWwuY29tL2NvbnRlbnQvVFNDL2NlcnRzL1RTQ2NlcnRQb2xpY3lTdGF0ZW1lbnQucGRmMC4GCCsGAQUFBwICMCIMIFRDRyBUcnVzdGVkIFBsYXRmb3JtIEVuZG9yc2VtZW50MHcGA1UdEQRwMG6kbDBqMRIwEAYGZ4EFBQEBDAZMRU5PVk8xFjAUBgZngQUFAQQMCjIwTDcwMDJCVVMxGjAYBgZngQUFAQUMDlRoaW5rUGFkIFQ0ODBzMSAwHgYGZ4EFBQEGDBRQRjBaQVFTV19MMUhGN0NTMDAxQTAfBgNVHSMEGDAWgBQ8Brn7Y6U8pXxrh0MzOfHcqAf7pDBqBggrBgEFBQcBAQReMFwwWgYIKwYBBQUHMAKGTmh0dHBzOi8vdHJ1c3RlZHNlcnZpY2VzLmludGVsLmNvbS9jb250ZW50L1RTQy9jZXJ0cy9UU0NfSXNzdWluZ0NBSUtHRl9URVNULmNlcg==", "Signature": "HexNAnoWglJi9OwoX0F0o4fVewKCXT1eOcQ6QFNehId3h9pdsPCRztyt2hN+06xs1mtDW/5v43pIUHL++nd+mMrLFBmuYD4mkSEZKU3aNwcM1PBjJ8PwTYfQzXZNt14lujbV/4UdWf5G6bHG7U5VsNw6+31/ZTZ2KvHSBlpbzT8rjorvv9rVcxoshWC9qJLxnRCH+mHv3Ph+VxQ9Q7+w3K1SFRF1bTeSVe+V6oRJFiWMp4ELpTurxCF1t0zCTK4HIgOa4ZWkewTCyjfpfd4Xp8xFbNCxT+Dbo/HiMH/zJVumhfhmaNyjLXpIjB6XHRwObLfrAxDATYXuB2BwfRuYd7+vvQ06CziU+77NB/6DhWk95bXDmu0eNA7jNoWuU7NVUATdZsRKMgph7STzO65Y0hICYg4bRL8VxtpoV9/JXUpYiFzR7FCqx+XtWKb1PR+WXzRUPtPmSbWCwAyxjl9TC1KB0zlph5mC4g1e199hSLAkFH2X2zTZy+sdXZKZUM2B", "SignatureAlgorithm": 4, "Version": 2, "SerialNumber": 559101144935189974234374230728606001993160126441, "Holder": { "Issuer": { "Country": [ "CH" ], "Organization": [ "STMicroelectronics NV" ], "OrganizationalUnit": null, "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "STM TPM EK Intermediate CA 05", "Names": [ { "Type": [ 2, 5, 4, 6 ], "Value": "CH" }, { "Type": [ 2, 5, 4, 10 ], "Value": "STMicroelectronics NV" }, { "Type": [ 2, 5, 4, 3 ], "Value": "STM TPM EK Intermediate CA 05" } ], "ExtraNames": null }, "Serial": 169799846553430907340671867860357675971057306636 }, "Issuer": { "Country": [ "US" ], "Organization": [ "Intel Corporation" ], "OrganizationalUnit": [ "Transparent Supply Chain Issuing CA IKGF_TEST" ], "Locality": [ "Santa Clara" ], "Province": [ "CA" ], "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "www.intel.com", "Names": [ { "Type": [ 2, 5, 4, 6 ], "Value": "US" }, { "Type": [ 2, 5, 4, 8 ], "Value": "CA" }, { "Type": [ 2, 5, 4, 7 ], "Value": "Santa Clara" }, { "Type": [ 2, 5, 4, 10 ], "Value": "Intel Corporation" }, { "Type": [ 2, 5, 4, 11 ], "Value": "Transparent Supply Chain Issuing CA IKGF_TEST" }, { "Type": [ 2, 5, 4, 3 ], "Value": "www.intel.com" } ], "ExtraNames": null }, "Subject": { "Country": null, "Organization": null, "OrganizationalUnit": null, "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "", "Names": null, "ExtraNames": null }, "NotBefore": "2018-09-15T04:45:09Z", "NotAfter": "2027-08-01T04:00:00Z", "TCGPlatformSpecification": { "Version": { "MajorVersion": 2, "MinorVersion": 0, "Revision": 1 } }, "TBBSecurityAssertions": { "Version": 0, "CcInfo": { "Version": "", "AssuranceLevel": 0, "EvaluationStatus": 0, "Plus": false, "StrengthOfFunction": 0, "ProfileOid": null, "ProfileURI": "", "TargetOid": null, "TargetURI": null }, "FipsLevel": { "Version": "", "Level": 0, "Plus": false }, "RtmType": 3, "Iso9000Certified": false, "Iso9000URI": "" }, "PlatformManufacturer": "LENOVO", "PlatformModel": "20L7002BUS", "PlatformVersion": "ThinkPad T480s", "PlatformSerial": "PF0ZAQSW_L1HF7CS001A", "CredentialSpecification": "", "UserNotice": { "NoticeRef": { "Organization": "", "NoticeNumbers": null }, "ExplicitText": "" }, "Components": null, "Properties": [ { "PropertyName": "AMT", "PropertyValue": "true", "Status": 0 } ], "PropertiesURI": "" }go-attestation-0.5.1/attributecert/testdata/plat_cert1.cer000066400000000000000000000026771452320553600237230ustar00rootroot000000000000000‚»0‚£0w u0Y¤W0U1&0$U STM TPM EK Intermediate CA 0210U STMicroelectronics NV1 0 UCHPF)˜9I2&T˜…R9„ˆ$"0 ( 0š¤—0”1 0 UUS1 0 U CA10U Santa Clara10U Intel Corporation1.0,U %Platform Attribute Certificate Issuer10U www.intel.com0  *†H†÷  `)gêy$ýîlÁP¹ƒw}By™0"20170820155344Z20200820155344Z0‚ß0g100 +0g1 0  0Çg1½0º t3.1  €*¢-+https://www.intel.com/protectionprofile.pdfƒ*¤$"https://www.intel.com/cctarget.pdf¡ 140-2 ‚*https://www.intel.com/isocertification.pdf0,g1"0 https://www.intel.com/PCRs.xml0°g1¤0¡ R0P Intel platform2018€ BQKP528406781.0‚+‚,ƒÿ¤0g 2.23.133.5.1.6¡0 vPro true0 AMT true¢.,https://www.intel.com/platformproperties.xml0‚W0|U u0s0q *†H†øM0c01+%https://www.intel.com/platcertcps.pdf0.+0" TCG Trusted Platform Endorsement0U#0€™“Ô9Ë2â«•÷7£·w)Ô¤9¶06+*0(0&+0†https://www.intel.com/ocsp0~Uw0u¤s0q10g Intel10g0 +‚W10g S2600KP10g H76962-35010g BQKP528406780  *†H†÷  ‚¡úºßR©:œxÙ}ê‰?a‡tÖÚ5ù°y»‡¢ºþfõ_éËþA˜ã'y,Ú%5ت…<Èi„‰K¹IL‰Ê€þ“e2¿œ©EDZŸÒü® LpÓQårˆ Ða]›f.¢÷ %¯k –ë[†@iÞк#ìé`à Íû}kÚW£Ž¬¿÷ê<¤3ø‡è_‹“B;¶¹i~>èÌMm+/r»RW_íO¶ø÷ÕB dçÃ9‡ˆaåkm’Ò¤ö¢Ö…Ý^}6Òˆº ž.NŒBwËë ²O܉Ø2áúrL¬;wºœ¼!¨xMº™HKzß\×OØÊ_ÍGèn¢¸cgo-attestation-0.5.1/attributecert/testdata/plat_cert1.cer.json000066400000000000000000000231171452320553600246630ustar00rootroot00000000000000{ "Raw": "MIIFuzCCBKMCAQEwd6B1MFmkVzBVMSYwJAYDVQQDDB1TVE0gVFBNIEVLIEludGVybWVkaWF0ZSBDQSAwMjEeMBwGA1UECgwVU1RNaWNyb2VsZWN0cm9uaWNzIE5WMQswCQYDVQQGEwJDSAIYUEYpmIE5STImCFSYGYVSORmEiCQiMCAooIGdMIGapIGXMIGUMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExFDASBgNVBAcMC1NhbnRhIENsYXJhMRowGAYDVQQKDBFJbnRlbCBDb3Jwb3JhdGlvbjEuMCwGA1UECwwlUGxhdGZvcm0gQXR0cmlidXRlIENlcnRpZmljYXRlIElzc3VlcjEWMBQGA1UEAwwNd3d3LmludGVsLmNvbTANBgkqhkiG9w0BAQsFAAIUYCln6nkk/e5swVC5HoN3fR9CeZkwIhgPMjAxNzA4MjAxNTUzNDRaGA8yMDIwMDgyMDE1NTM0NFowggHfMBwGBWeBBQIRMRMwETAJAgECAgEAAgErBAQAAAABMBQGBWeBBQIXMQswCQIBAQIBAAIBCzCBxwYFZ4EFAhMxgb0wgboCAQCgdBYDMy4xCgEHCgECAQEAgAEBgQUqAwQFBqItFitodHRwczovL3d3dy5pbnRlbC5jb20vcHJvdGVjdGlvbnByb2ZpbGUucGRmgwUqAwQFB6QkFiJodHRwczovL3d3dy5pbnRlbC5jb20vY2N0YXJnZXQucGRmoQ0WBTE0MC0yCgEEAQEAggEDAQEAFipodHRwczovL3d3dy5pbnRlbC5jb20vaXNvY2VydGlmaWNhdGlvbi5wZGYwLAYGZ4EFBQEDMSIwIBYeaHR0cHM6Ly93d3cuaW50ZWwuY29tL1BDUnMueG1sMIGwBgdngQUFAQcBMYGkMIGhoFIwUAwFSW50ZWwMDHBsYXRmb3JtMjAxOIAMQlFLUDUyODQwNjc4gQMxLjCCBysGAQQBgiyDAf+kGjAYBgZngQUFAQYMDjIuMjMuMTMzLjUuMS42oRswDAwEdlBybwwEdHJ1ZTALDANBTVQMBHRydWWiLhYsaHR0cHM6Ly93d3cuaW50ZWwuY29tL3BsYXRmb3JtcHJvcGVydGllcy54bWwwggFXMHwGA1UdIAR1MHMwcQYKKoZIhvhNAQUCBDBjMDEGCCsGAQUFBwIBFiVodHRwczovL3d3dy5pbnRlbC5jb20vcGxhdGNlcnRjcHMucGRmMC4GCCsGAQUFBwICMCIMIFRDRyBUcnVzdGVkIFBsYXRmb3JtIEVuZG9yc2VtZW50MB8GA1UdIwQYMBaAFJmT1DnLMuKrlfc3o7d3KRzUpDm2MDYGCCsGAQUFBwEBBCowKDAmBggrBgEFBQcwAYYaaHR0cHM6Ly93d3cuaW50ZWwuY29tL29jc3AwfgYDVR0RBHcwdaRzMHExETAPBgZngQUFAQEMBUludGVsMRUwEwYGZ4EFBQECMAkGBysGAQQBglcxEzARBgZngQUFAQQMB1MyNjAwS1AxFjAUBgZngQUFAQUMCkg3Njk2Mi0zNTAxGDAWBgZngQUFAQYMDEJRS1A1Mjg0MDY3ODANBgkqhkiG9w0BAQsFAAOCAQEAoRr6ut9SqTqceNl96ok/YQ4Xh3TW2jX5sHm7h6K6/mb1X+nLEP5BmAbjHCd5LNolNdiqhTyQyGmEiUu5SUyJyoCPAf6TZTK/nKlFx7Gf0vyuDExw01EX5XKIINBhXZtmLqL3DCWvawuWnetbhkBpH97QuiPs6WDDC837fWvaV6OOrBO/9+o8pDP4hwboX4uTQju2uWl+PujMTQVtfysbL3K7EVIZV1/tT7b494/VQglk58M5h4hh5WttktIdGaT2otaF3V59NtKIugmeLk6Mj0J3y+sgsk8S3InYMuH6ckysO3e6nA68Iah4TRe6mUhLet9c10/Yyl/NFkfobqK4Yw==", "RawTBSAttributeCertificate": "MIIEowIBATB3oHUwWaRXMFUxJjAkBgNVBAMMHVNUTSBUUE0gRUsgSW50ZXJtZWRpYXRlIENBIDAyMR4wHAYDVQQKDBVTVE1pY3JvZWxlY3Ryb25pY3MgTlYxCzAJBgNVBAYTAkNIAhhQRimYgTlJMiYIVJgZhVI5GYSIJCIwICiggZ0wgZqkgZcwgZQxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEUMBIGA1UEBwwLU2FudGEgQ2xhcmExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0aW9uMS4wLAYDVQQLDCVQbGF0Zm9ybSBBdHRyaWJ1dGUgQ2VydGlmaWNhdGUgSXNzdWVyMRYwFAYDVQQDDA13d3cuaW50ZWwuY29tMA0GCSqGSIb3DQEBCwUAAhRgKWfqeST97mzBULkeg3d9H0J5mTAiGA8yMDE3MDgyMDE1NTM0NFoYDzIwMjAwODIwMTU1MzQ0WjCCAd8wHAYFZ4EFAhExEzARMAkCAQICAQACASsEBAAAAAEwFAYFZ4EFAhcxCzAJAgEBAgEAAgELMIHHBgVngQUCEzGBvTCBugIBAKB0FgMzLjEKAQcKAQIBAQCAAQGBBSoDBAUGoi0WK2h0dHBzOi8vd3d3LmludGVsLmNvbS9wcm90ZWN0aW9ucHJvZmlsZS5wZGaDBSoDBAUHpCQWImh0dHBzOi8vd3d3LmludGVsLmNvbS9jY3RhcmdldC5wZGahDRYFMTQwLTIKAQQBAQCCAQMBAQAWKmh0dHBzOi8vd3d3LmludGVsLmNvbS9pc29jZXJ0aWZpY2F0aW9uLnBkZjAsBgZngQUFAQMxIjAgFh5odHRwczovL3d3dy5pbnRlbC5jb20vUENScy54bWwwgbAGB2eBBQUBBwExgaQwgaGgUjBQDAVJbnRlbAwMcGxhdGZvcm0yMDE4gAxCUUtQNTI4NDA2NziBAzEuMIIHKwYBBAGCLIMB/6QaMBgGBmeBBQUBBgwOMi4yMy4xMzMuNS4xLjahGzAMDAR2UHJvDAR0cnVlMAsMA0FNVAwEdHJ1ZaIuFixodHRwczovL3d3dy5pbnRlbC5jb20vcGxhdGZvcm1wcm9wZXJ0aWVzLnhtbDCCAVcwfAYDVR0gBHUwczBxBgoqhkiG+E0BBQIEMGMwMQYIKwYBBQUHAgEWJWh0dHBzOi8vd3d3LmludGVsLmNvbS9wbGF0Y2VydGNwcy5wZGYwLgYIKwYBBQUHAgIwIgwgVENHIFRydXN0ZWQgUGxhdGZvcm0gRW5kb3JzZW1lbnQwHwYDVR0jBBgwFoAUmZPUOcsy4quV9zejt3cpHNSkObYwNgYIKwYBBQUHAQEEKjAoMCYGCCsGAQUFBzABhhpodHRwczovL3d3dy5pbnRlbC5jb20vb2NzcDB+BgNVHREEdzB1pHMwcTERMA8GBmeBBQUBAQwFSW50ZWwxFTATBgZngQUFAQIwCQYHKwYBBAGCVzETMBEGBmeBBQUBBAwHUzI2MDBLUDEWMBQGBmeBBQUBBQwKSDc2OTYyLTM1MDEYMBYGBmeBBQUBBgwMQlFLUDUyODQwNjc4", "Signature": "oRr6ut9SqTqceNl96ok/YQ4Xh3TW2jX5sHm7h6K6/mb1X+nLEP5BmAbjHCd5LNolNdiqhTyQyGmEiUu5SUyJyoCPAf6TZTK/nKlFx7Gf0vyuDExw01EX5XKIINBhXZtmLqL3DCWvawuWnetbhkBpH97QuiPs6WDDC837fWvaV6OOrBO/9+o8pDP4hwboX4uTQju2uWl+PujMTQVtfysbL3K7EVIZV1/tT7b494/VQglk58M5h4hh5WttktIdGaT2otaF3V59NtKIugmeLk6Mj0J3y+sgsk8S3InYMuH6ckysO3e6nA68Iah4TRe6mUhLet9c10/Yyl/NFkfobqK4Yw==", "SignatureAlgorithm": 4, "Version": 2, "SerialNumber": 548986496904781841196662391040664879653735004569, "Holder": { "Issuer": { "Country": [ "CH" ], "Organization": [ "STMicroelectronics NV" ], "OrganizationalUnit": null, "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "STM TPM EK Intermediate CA 02", "Names": [ { "Type": [ 2, 5, 4, 3 ], "Value": "STM TPM EK Intermediate CA 02" }, { "Type": [ 2, 5, 4, 10 ], "Value": "STMicroelectronics NV" }, { "Type": [ 2, 5, 4, 6 ], "Value": "CH" } ], "ExtraNames": null }, "Serial": 1968314523106797630082411822510029384949550822072796586024 }, "Issuer": { "Country": [ "US" ], "Organization": [ "Intel Corporation" ], "OrganizationalUnit": [ "Platform Attribute Certificate Issuer" ], "Locality": [ "Santa Clara" ], "Province": [ "CA" ], "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "www.intel.com", "Names": [ { "Type": [ 2, 5, 4, 6 ], "Value": "US" }, { "Type": [ 2, 5, 4, 8 ], "Value": "CA" }, { "Type": [ 2, 5, 4, 7 ], "Value": "Santa Clara" }, { "Type": [ 2, 5, 4, 10 ], "Value": "Intel Corporation" }, { "Type": [ 2, 5, 4, 11 ], "Value": "Platform Attribute Certificate Issuer" }, { "Type": [ 2, 5, 4, 3 ], "Value": "www.intel.com" } ], "ExtraNames": null }, "Subject": { "Country": null, "Organization": null, "OrganizationalUnit": null, "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "", "Names": null, "ExtraNames": null }, "NotBefore": "2017-08-20T15:53:44Z", "NotAfter": "2020-08-20T15:53:44Z", "TCGPlatformSpecification": { "Version": { "MajorVersion": 2, "MinorVersion": 0, "Revision": 43 } }, "TBBSecurityAssertions": { "Version": 0, "CcInfo": { "Version": "3.1", "AssuranceLevel": 7, "EvaluationStatus": 2, "Plus": false, "StrengthOfFunction": 1, "ProfileOid": [ 1, 2, 3, 4, 5, 6 ], "ProfileURI": "", "TargetOid": null, "TargetURI": null }, "FipsLevel": { "Version": "140-2", "Level": 4, "Plus": false }, "RtmType": 3, "Iso9000Certified": false, "Iso9000URI": "https://www.intel.com/isocertification.pdf" }, "PlatformManufacturer": "Intel", "PlatformModel": "S2600KP", "PlatformVersion": "H76962-350", "PlatformSerial": "BQKP52840678", "CredentialSpecification": "", "UserNotice": { "NoticeRef": { "Organization": "", "NoticeNumbers": null }, "ExplicitText": "" }, "Components": [ { "Manufacturer": "Intel", "Model": "platform2018", "Serial": "BQKP52840678", "Revision": "1.0", "ManufacturerID": 12110025430499884, "FieldReplaceable": true, "Addresses": [ { "AddressType": [ 2, 23, 133, 5, 1, 6 ], "AddressValue": "2.23.133.5.1.6" } ] } ], "Properties": [ { "PropertyName": "vPro", "PropertyValue": "true", "Status": 0 }, { "PropertyName": "AMT", "PropertyValue": "true", "Status": 0 } ], "PropertiesURI": "https://www.intel.com/platformproperties.xml" }go-attestation-0.5.1/attributecert/testdata/plat_cert2.cer000066400000000000000000000025501452320553600237120ustar00rootroot000000000000000‚d0‚L0w u0Y¤W0U1&0$U STM TPM EK Intermediate CA 0210U STMicroelectronics NV1 0 UCHPF)˜9I2&T˜…R9„ˆ$"0 ( 0š¤—0”1 0 UUS1 0 U CA10U Santa Clara10U Intel Corporation1.0,U %Platform Attribute Certificate Issuer10U www.intel.com0  *†H†÷  `)gêy$ýîlÁP¹ƒw}By™0"20170820155344Z20200820155344Z0‚ˆ0g100 +0g1 0  0Çg1½0º t3.1  €*¢-+https://www.intel.com/protectionprofile.pdfƒ*¤$"https://www.intel.com/cctarget.pdf¡ 140-2 ‚*https://www.intel.com/isocertification.pdf0,g1"0 https://www.intel.com/PCRs.xml0Zg1O0M¡0 vPro true0 AMT true¢.,https://www.intel.com/platformproperties.xml0‚W0|U u0s0q *†H†øM0c01+%https://www.intel.com/platcertcps.pdf0.+0" TCG Trusted Platform Endorsement0U#0€™“Ô9Ë2â«•÷7£·w)Ô¤9¶06+*0(0&+0†https://www.intel.com/ocsp0~Uw0u¤s0q10g Intel10g0 +‚W10g S2600KP10g H76962-35010g BQKP528406780  *†H†÷  ‚–¬e$ü¦uÅßBÒÒÉvšíà ëÆ[ã8H«RSýTÛ˜ø†ˆïO­½”ÛÔ,õ¦Pz:Bh(í&߯iPù–¹àˆÅÕë€XÑ?~$MóØÇœn«¼ dðBþO8$~îbRÙú+÷#±ßª¯J[D˜Þ ƒç _™}tšA}ͿꅨLÜ'ArÏ¥ËõÖK2NN§<&FÞÑ#6¢ð>Ýn4dÏá%I ˆ²Å({é¡$"â\a:Ÿ«•â×}å®Þgo-attestation-0.5.1/attributecert/testdata/plat_cert3.cer.json000066400000000000000000000201051452320553600246570ustar00rootroot00000000000000{ "Raw": "MIIFHjCCBAYCAQEwd6B1MFmkVzBVMSYwJAYDVQQDDB1TVE0gVFBNIEVLIEludGVybWVkaWF0ZSBDQSAwMjEeMBwGA1UECgwVU1RNaWNyb2VsZWN0cm9uaWNzIE5WMQswCQYDVQQGEwJDSAIYUEYpmIE5STImCFSYGYVSORmEiCQiMCAooFgwVqRUMFIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQKDAVJbnRlbDEeMBwGA1UEAwwVSW50ZWwgSW50ZXJtZWRpYXRlIENBMRMwEQYDVQQIDApTb21lLVN0YXRlMA0GCSqGSIb3DQEBCwUAAhRgKWfqeST97mzBULkeg3d9H0J5mTAiGA8yMDE3MDgyMDE1NTM0NFoYDzIwMjAwODIwMTU1MzQ0WjCCAYgwHAYFZ4EFAhExEzARMAkCAQICAQACASsEBAAAAAEwFAYFZ4EFAhcxCzAJAgEBAgEAAgELMIHHBgVngQUCEzGBvTCBugIBAKB0FgMzLjEKAQcKAQIBAQCAAQGBBSoDBAUGoi0WK2h0dHBzOi8vd3d3LmludGVsLmNvbS9wcm90ZWN0aW9ucHJvZmlsZS5wZGaDBSoDBAUHpCQWImh0dHBzOi8vd3d3LmludGVsLmNvbS9jY3RhcmdldC5wZGahDRYFMTQwLTIKAQQBAQCCAQMBAQAWKmh0dHBzOi8vd3d3LmludGVsLmNvbS9pc29jZXJ0aWZpY2F0aW9uLnBkZjAsBgZngQUFAQMxIjAgFh5odHRwczovL3d3dy5pbnRlbC5jb20vUENScy54bWwwWgYHZ4EFBQEHATFPME2hGzAMDAR2UHJvDAR0cnVlMAsMA0FNVAwEdHJ1ZaIuFixodHRwczovL3d3dy5pbnRlbC5jb20vcGxhdGZvcm1wcm9wZXJ0aWVzLnhtbDCCAVcwfAYDVR0gBHUwczBxBgoqhkiG+E0BBQIEMGMwMQYIKwYBBQUHAgEWJWh0dHBzOi8vd3d3LmludGVsLmNvbS9wbGF0Y2VydGNwcy5wZGYwLgYIKwYBBQUHAgIwIgwgVENHIFRydXN0ZWQgUGxhdGZvcm0gRW5kb3JzZW1lbnQwHwYDVR0jBBgwFoAUmZPUOcsy4quV9zejt3cpHNSkObYwNgYIKwYBBQUHAQEEKjAoMCYGCCsGAQUFBzABhhpodHRwczovL3d3dy5pbnRlbC5jb20vb2NzcDB+BgNVHREEdzB1pHMwcTERMA8GBmeBBQUBAQwFSW50ZWwxFTATBgZngQUFAQIwCQYHKwYBBAGCVzETMBEGBmeBBQUBBAwHUzI2MDBLUDEWMBQGBmeBBQUBBQwKSDc2OTYyLTM1MDEYMBYGBmeBBQUBBgwMQlFLUDUyODQwNjc4MA0GCSqGSIb3DQEBCwUAA4IBAQCZKjzwWca3acJIj24JH7iLc/z70QGngQeA5ef2xPYlZq2c2e5PBiVSZndTKeX7cCDIF1EGPeuu7avJ6OdJc/OoSGwfHindkvlYWdnpihbnQ1Vevwojd+VZqaJYv25X47GYZahCST1G/fkI+rRzJL8/A7vM5MOGSEO/AW85ZKi+ih4hbECh+9RPn5JB6l4JHU/lCR2OzTfQ8P+/G8BDJpZc0EymMtU6shrpVa1QY8OHHb7vzuzSrdQYutqCywV2WhLML0AkB4PuOVCHC7CMBShJ8bavbJ2ajA+bxWOWdQAX7iYKU3k+JUkJiAayxSh7FumhJCLiXGE6n6uV4td95a7e", "RawTBSAttributeCertificate": "MIIEBgIBATB3oHUwWaRXMFUxJjAkBgNVBAMMHVNUTSBUUE0gRUsgSW50ZXJtZWRpYXRlIENBIDAyMR4wHAYDVQQKDBVTVE1pY3JvZWxlY3Ryb25pY3MgTlYxCzAJBgNVBAYTAkNIAhhQRimYgTlJMiYIVJgZhVI5GYSIJCIwICigWDBWpFQwUjELMAkGA1UEBhMCVVMxDjAMBgNVBAoMBUludGVsMR4wHAYDVQQDDBVJbnRlbCBJbnRlcm1lZGlhdGUgQ0ExEzARBgNVBAgMClNvbWUtU3RhdGUwDQYJKoZIhvcNAQELBQACFGApZ+p5JP3ubMFQuR6Dd30fQnmZMCIYDzIwMTcwODIwMTU1MzQ0WhgPMjAyMDA4MjAxNTUzNDRaMIIBiDAcBgVngQUCETETMBEwCQIBAgIBAAIBKwQEAAAAATAUBgVngQUCFzELMAkCAQECAQACAQswgccGBWeBBQITMYG9MIG6AgEAoHQWAzMuMQoBBwoBAgEBAIABAYEFKgMEBQaiLRYraHR0cHM6Ly93d3cuaW50ZWwuY29tL3Byb3RlY3Rpb25wcm9maWxlLnBkZoMFKgMEBQekJBYiaHR0cHM6Ly93d3cuaW50ZWwuY29tL2NjdGFyZ2V0LnBkZqENFgUxNDAtMgoBBAEBAIIBAwEBABYqaHR0cHM6Ly93d3cuaW50ZWwuY29tL2lzb2NlcnRpZmljYXRpb24ucGRmMCwGBmeBBQUBAzEiMCAWHmh0dHBzOi8vd3d3LmludGVsLmNvbS9QQ1JzLnhtbDBaBgdngQUFAQcBMU8wTaEbMAwMBHZQcm8MBHRydWUwCwwDQU1UDAR0cnVloi4WLGh0dHBzOi8vd3d3LmludGVsLmNvbS9wbGF0Zm9ybXByb3BlcnRpZXMueG1sMIIBVzB8BgNVHSAEdTBzMHEGCiqGSIb4TQEFAgQwYzAxBggrBgEFBQcCARYlaHR0cHM6Ly93d3cuaW50ZWwuY29tL3BsYXRjZXJ0Y3BzLnBkZjAuBggrBgEFBQcCAjAiDCBUQ0cgVHJ1c3RlZCBQbGF0Zm9ybSBFbmRvcnNlbWVudDAfBgNVHSMEGDAWgBSZk9Q5yzLiq5X3N6O3dykc1KQ5tjA2BggrBgEFBQcBAQQqMCgwJgYIKwYBBQUHMAGGGmh0dHBzOi8vd3d3LmludGVsLmNvbS9vY3NwMH4GA1UdEQR3MHWkczBxMREwDwYGZ4EFBQEBDAVJbnRlbDEVMBMGBmeBBQUBAjAJBgcrBgEEAYJXMRMwEQYGZ4EFBQEEDAdTMjYwMEtQMRYwFAYGZ4EFBQEFDApINzY5NjItMzUwMRgwFgYGZ4EFBQEGDAxCUUtQNTI4NDA2Nzg=", "Signature": "mSo88FnGt2nCSI9uCR+4i3P8+9EBp4EHgOXn9sT2JWatnNnuTwYlUmZ3Uynl+3AgyBdRBj3rru2ryejnSXPzqEhsHx4p3ZL5WFnZ6YoW50NVXr8KI3flWamiWL9uV+OxmGWoQkk9Rv35CPq0cyS/PwO7zOTDhkhDvwFvOWSovooeIWxAofvUT5+SQepeCR1P5Qkdjs030PD/vxvAQyaWXNBMpjLVOrIa6VWtUGPDhx2+787s0q3UGLragssFdloSzC9AJAeD7jlQhwuwjAUoSfG2r2ydmowPm8VjlnUAF+4mClN5PiVJCYgGssUoexbpoSQi4lxhOp+rleLXfeWu3g==", "SignatureAlgorithm": 4, "Version": 2, "SerialNumber": 548986496904781841196662391040664879653735004569, "Holder": { "Issuer": { "Country": [ "CH" ], "Organization": [ "STMicroelectronics NV" ], "OrganizationalUnit": null, "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "STM TPM EK Intermediate CA 02", "Names": [ { "Type": [ 2, 5, 4, 3 ], "Value": "STM TPM EK Intermediate CA 02" }, { "Type": [ 2, 5, 4, 10 ], "Value": "STMicroelectronics NV" }, { "Type": [ 2, 5, 4, 6 ], "Value": "CH" } ], "ExtraNames": null }, "Serial": 1968314523106797630082411822510029384949550822072796586024 }, "Issuer": { "Country": [ "US" ], "Organization": [ "Intel" ], "OrganizationalUnit": null, "Locality": null, "Province": [ "Some-State" ], "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "Intel Intermediate CA", "Names": [ { "Type": [ 2, 5, 4, 6 ], "Value": "US" }, { "Type": [ 2, 5, 4, 10 ], "Value": "Intel" }, { "Type": [ 2, 5, 4, 3 ], "Value": "Intel Intermediate CA" }, { "Type": [ 2, 5, 4, 8 ], "Value": "Some-State" } ], "ExtraNames": null }, "Subject": { "Country": null, "Organization": null, "OrganizationalUnit": null, "Locality": null, "Province": null, "StreetAddress": null, "PostalCode": null, "SerialNumber": "", "CommonName": "", "Names": null, "ExtraNames": null }, "NotBefore": "2017-08-20T15:53:44Z", "NotAfter": "2020-08-20T15:53:44Z", "TCGPlatformSpecification": { "Version": { "MajorVersion": 2, "MinorVersion": 0, "Revision": 43 } }, "TBBSecurityAssertions": { "Version": 0, "CcInfo": { "Version": "3.1", "AssuranceLevel": 7, "EvaluationStatus": 2, "Plus": false, "StrengthOfFunction": 1, "ProfileOid": [ 1, 2, 3, 4, 5, 6 ], "ProfileURI": "", "TargetOid": null, "TargetURI": null }, "FipsLevel": { "Version": "140-2", "Level": 4, "Plus": false }, "RtmType": 3, "Iso9000Certified": false, "Iso9000URI": "https://www.intel.com/isocertification.pdf" }, "PlatformManufacturer": "Intel", "PlatformModel": "S2600KP", "PlatformVersion": "H76962-350", "PlatformSerial": "BQKP52840678", "CredentialSpecification": "", "UserNotice": { "NoticeRef": { "Organization": "", "NoticeNumbers": null }, "ExplicitText": "" }, "Components": null, "Properties": [ { "PropertyName": "vPro", "PropertyValue": "true", "Status": 0 }, { "PropertyName": "AMT", "PropertyValue": "true", "Status": 0 } ], "PropertiesURI": "https://www.intel.com/platformproperties.xml" }go-attestation-0.5.1/ci/000077500000000000000000000000001452320553600150575ustar00rootroot00000000000000go-attestation-0.5.1/ci/gen_ekcert.go000066400000000000000000000045621452320553600175230ustar00rootroot00000000000000package main import ( "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/binary" "encoding/hex" "flag" "fmt" "math/big" "os" "os/exec" "strings" "time" ) func ekPub() *rsa.PublicKey { out, err := exec.Command("tpm_getpubek", "-z").Output() if err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } spl := strings.Split(string(out), "Public Key:") hexKey := strings.NewReplacer(" ", "", "\n", "", "\r", "", "\t", "").Replace(spl[1]) modBytes, err := hex.DecodeString(hexKey) if err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } return &rsa.PublicKey{ N: new(big.Int).SetBytes(modBytes), E: 65537, } } func generateCertificate(pub *rsa.PublicKey) []byte { priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) if err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Organization: []string{"Acme Co"}, }, NotBefore: time.Now(), NotAfter: time.Now().AddDate(1, 0, 0), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, } derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, pub, priv) if err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } return derBytes } func main() { flag.Parse() certBytes := generateCertificate(ekPub()) f, err := os.OpenFile("/tmp/ekcert", os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0755) if err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } // Write the header as documented in: TCG PC Specific Implementation // Specification, section 7.3.2. f.Write([]byte{0x10, 0x01, 0x00}) certLength := make([]byte, 2) binary.BigEndian.PutUint16(certLength, uint16(len(certBytes))) f.Write(certLength) f.Write(certBytes) f.Close() cmd := exec.Command("tpm_nvwrite", "-z", "-i", "268496896", "-f", "/tmp/ekcert") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } } go-attestation-0.5.1/ci/run.sh000077500000000000000000000007711452320553600162270ustar00rootroot00000000000000#!/bin/bash -e 1>&2 echo "----- WARNING: The TPM 1.2 simulator no longer builds with newer versions of openssl. These scripts are kept for posterity, but likely won't build on new OS versions. ----" export PROJECT_ROOT="$( pwd )" TMPDIR="$( mktemp -d )" SIM_DIR="${TMPDIR}/tpm12_sim" TEST_ROOT="${TMPDIR}/tests_base" mkdir -pv "${SIM_DIR}" ./ci/setup_tpm12_simulator.sh "${SIM_DIR}" ./ci/setup_tests_fs.sh "${TEST_ROOT}" go test -v ./... -- --testTPM12 ./ci/shutdown_tpm12_simulator.sh "${SIM_DIR}" go-attestation-0.5.1/ci/setup_tests_fs.sh000077500000000000000000000046771452320553600205060ustar00rootroot00000000000000#!/bin/bash # ############################################################################### # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ################################################################################ # # Sets up a root filesystem with files that symbolize the presence of a fake # hardware VM. This filesystem can be chrooted into to run tests. # USAGE: ./setup_tests_fs.sh set -e BASE_DIR="${1%/}" # Trim any trailing slash. setup_base () { if [[ ! -d "${BASE_DIR}" ]] && [[ -e "${BASE_DIR}" ]]; then >&2 echo "Error: '${BASE_DIR}' is not a directory." exit 1 fi if [[ ! -e "${BASE_DIR}" ]]; then mkdir -pv "${BASE_DIR}" else sudo umount ${BASE_DIR}/* || true rm -rfv ${BASE_DIR}/* fi } setup_mounts () { mkdir -v "${BASE_DIR}/bin" sudo mount --bind /bin "${BASE_DIR}/bin" mkdir -v "${BASE_DIR}/usr" sudo mount --bind /usr "${BASE_DIR}/usr" mkdir -v "${BASE_DIR}/var" sudo mount --bind /var "${BASE_DIR}/var" mkdir -v "${BASE_DIR}/tmp" sudo mount --bind /tmp "${BASE_DIR}/tmp" mkdir -v "${BASE_DIR}/lib" sudo mount --bind /lib "${BASE_DIR}/lib" mkdir -v "${BASE_DIR}/lib64" sudo mount --bind /lib64 "${BASE_DIR}/lib64" mkdir -v "${BASE_DIR}/dev" sudo mount --bind /dev "${BASE_DIR}/dev" mkdir -v "${BASE_DIR}/etc" sudo mount --bind /etc "${BASE_DIR}/etc" mkdir -v "${BASE_DIR}/opt" sudo mount --bind /opt "${BASE_DIR}/opt" mkdir -v "${BASE_DIR}/proc" sudo mount --bind /proc "${BASE_DIR}/proc" mkdir -v "${BASE_DIR}/root" sudo mount --bind /root "${BASE_DIR}/root" mkdir -v "${BASE_DIR}/run" sudo mount --bind /run "${BASE_DIR}/run" mkdir -v "${BASE_DIR}/home" sudo mount --bind /home "${BASE_DIR}/home" if [[ -d "/tmpfs" ]]; then mkdir -v "${BASE_DIR}/tmpfs" sudo mount --bind /tmpfs "${BASE_DIR}/tmpfs" fi } setup_sys_overlay () { mkdir -pv "${BASE_DIR}/sys/class/tpm/tpm0" touch "${BASE_DIR}/sys/class/tpm/tpm0/caps" } setup_base setup_mounts setup_sys_overlay go-attestation-0.5.1/ci/setup_tpm12_simulator.sh000077500000000000000000000064071452320553600217070ustar00rootroot00000000000000#!/bin/bash # ############################################################################### # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ################################################################################ # # Builds/installs a TPM 1.2 simulator + trousers, on a debian-based system. # USAGE: ./setup_tpm12_simulator.sh set -e SIMULATOR_TARBALL_URL="https://sourceforge.net/projects/ibmswtpm/files/tpm4769tar.gz/download" SIMULATOR_TAR_SHA256="bb0a3f8003ca8ba71eb4a0852f0eb35a112297e28fce8e166412d4b2202c5010" if [[ "${1}" == "" ]]; then >&2 echo "Error: Must specify the working directory as the first argument." exit 1 fi PROJECT_ROOT=$(pwd) BUILD_BASE="${1%/}" # Trim any trailing slash. SIMULATOR_SRC="${BUILD_BASE}/simulator" setup_build_base () { if [[ ! -d "${BUILD_BASE}" ]] && [[ -e "${BUILD_BASE}" ]]; then >&2 echo "Error: '${BUILD_BASE}' is not a directory." exit 1 fi if [[ ! -e "${BUILD_BASE}" ]]; then mkdir -pv "${BUILD_BASE}" fi sudo apt-get -y install libssl-dev build-essential make trousers libtool autoconf tpm-tools } fetch_simulator () { TARBALL="${BUILD_BASE}/sim.tar.gz" if [[ ! -f "${TARBALL}" ]]; then wget -q -O "${TARBALL}" "${SIMULATOR_TARBALL_URL}" fi HSH=$(sha256sum "${TARBALL}" | cut -d" " -f1) if [[ "${HSH}" != "${SIMULATOR_TAR_SHA256}" ]]; then >&2 echo "'${TARBALL}' does not match expected SHA256." >&2 echo "Got: ${HSH}" >&2 echo "Want: ${SIMULATOR_TAR_SHA256}" exit 2 fi mkdir -pv "${SIMULATOR_SRC}" tar -zxf "${TARBALL}" --directory "${SIMULATOR_SRC}" } build_simulator () { cp -v "${SIMULATOR_SRC}/tpm/makefile-tpm" "${SIMULATOR_SRC}/tpm/Makefile" cd "${SIMULATOR_SRC}/tpm" && make -j4 cd "${SIMULATOR_SRC}/libtpm" && ./autogen cd "${SIMULATOR_SRC}/libtpm" && ./configure cd "${SIMULATOR_SRC}/libtpm" && make -j4 } run_simulator () { mkdir -pv "${BUILD_BASE}/NVRAM" export TPM_PORT='6545' export TPM_PATH="${BUILD_BASE}/NVRAM" export TPM_SERVER_NAME='localhost' export TPM_SERVER_PORT='6545' ${SIMULATOR_SRC}/tpm/tpm_server & SIM_PID=$! echo "${SIM_PID}" > "${BUILD_BASE}/sim_pid" disown sleep 2 } setup_tpm () { echo "Initializing the TPM..." ${SIMULATOR_SRC}/libtpm/utils/tpminit echo "Starting the TPM..." ${SIMULATOR_SRC}/libtpm/utils/tpmbios -cs ${SIMULATOR_SRC}/libtpm/utils/tpminit ${SIMULATOR_SRC}/libtpm/utils/tpmbios -cs } run_tcsd () { export TCSD_TCP_DEVICE_PORT='6545' sudo -E -u tss -g tss /usr/sbin/tcsd -f -e & TCSD_PID=$! echo "${TCSD_PID}" > "${BUILD_BASE}/tcsd_pid" disown sleep 1 tpm_createek tpm_takeownership -yz tpm_nvdefine -i 268496896 -z -s 3800 -p OWNERWRITE go run -v "${PROJECT_ROOT}/ci/gen_ekcert.go" sleep 1 } setup_build_base fetch_simulator build_simulator run_simulator setup_tpm run_tcsd go-attestation-0.5.1/ci/shutdown_tpm12_simulator.sh000077500000000000000000000021671452320553600224210ustar00rootroot00000000000000#!/bin/bash # ############################################################################### # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ################################################################################ # # Stops the TPM 1.2 simulator + trousers from running. # USAGE: ./shutdown_tpm12_simulator.sh set -e if [[ "${1}" == "" ]]; then >&2 echo "Error: Must specify the working directory as the first argument." exit 1 fi BUILD_BASE="${1%/}" # Trim any trailing slash. sudo kill $(cat "${BUILD_BASE}/tcsd_pid") rm "${BUILD_BASE}/tcsd_pid" sudo kill $(cat "${BUILD_BASE}/sim_pid") rm "${BUILD_BASE}/sim_pid" go-attestation-0.5.1/docs/000077500000000000000000000000001452320553600154145ustar00rootroot00000000000000go-attestation-0.5.1/docs/credential-activation.md000066400000000000000000000072241452320553600222140ustar00rootroot00000000000000# Credential Activation Credential activation remotely proves a specific attestation key resides on the same TPM as a specific endorsement key. Because the endorsement key is the cryptographic identifier for a TPM (and by extension, the device), credential activation enables a remote system to establish trust in a new key, which can then be used to encrypt or attest on behalf of the device. Credential Activation is a poorly documented TPM concept. This document aims to explain how it works and what it is used for, without assuming any knowledge of the TCG specifications. ## Overview Abstractly: credential activation allows a remote party to verify one key is on the same TPM as another key, and that the key has a specific set of properties. The description in the first paragraph describes the activation of an attestation key with the endorsement key. While this is the most common use of credential activation, any two asymmetric key-pairs in the TPM can be used. ### How it works The credential activation procedure involves the remote end generating a specially-crafted, encrypted challenge for the TPM to process. The server generates this challenge based on knowledge of two TPM keys (specifically, their public keys and key properties), and the secret data it wishes to encrypt. This challenge can be decrypted by the TPM using the `ActivateCredential` command. Through this command, the user presents to the TPM: * The encrypted challenge generated by the server * A handle to the 1st key * A handle to the 2nd key If the keys and their properties are present on the TPM, and match exactly the keys the server used to generate the challenge, the TPM will decrypt the secret contained within, and return it as the response to the command. ## Why use credential activation? **TL;DR: Credential activation lets you trust a new key.** While devices are typically identified by the endorsement key burned into their TPM, key usage restrictions set on most endorsement keys mean they typically cannot be used for signing or attestation. As such a different key is needed. After the new key is generated on the TPM, the credential activation procedure allows you to prove that: * The new key has acceptable properties (ie: A key intended for attestation can only be used in attestation commands, and the key material cannot be exported). * The new key is present & on the same TPM as an endorsement key. Once credential activation completes successfully, the remote end can be sure of the properties of the key & which device it was generated for, and start trusting the use of the new key on behalf of the device. ## Detailed process ### Glossary **Activation key** - The first public key. Credential activation verifies that this key is resident on the TPM, *and it has a specific set of properties.* **Anchor key** - The second public key. Credential activation verifies this key is resident on the same TPM as the activation key. ### Sequence of operations ![sequence diagram](credential_activation.png) 1. The Client device informs the server of the public keys of both the anchor and activation key, as well as communicating the key properties of the activation key. 2. The server computes the activation challenge, as described below. This challenge is sent back to the client. 3. The Client invokes the `ActivateCredential` command, providing the encrypted challenge from the server, and handles to the two keys. 4. If the keys handles presented have public keys / properties matching those the server used when computing the challenge, the TPM will be able to decrypt and return the secret. ## Appendix: Generating the credential activation challenge TODO go-attestation-0.5.1/docs/credential_activation.png000066400000000000000000001222321452320553600224570ustar00rootroot00000000000000‰PNG  IHDR¦ó3^† IDATx^ì¸,E™¿_sZÌ⪨0¡« ¬9gÿ\A1ãªkÌêŠYÑÅœ0³æ´fYV]DÁœãª ׌üŸß¥›fΙž™ž9=Ýo=Ï}¸Ì©®®z¿šsû¯ªætX$  H@€$  H@[Hàt[xoo- H@€$  H@@1uH@€$  H@À–PL·¿7—€$  H@€$ ÅÔ9  H@€$  H@[J@1ÝRüÞ\€$  H@€Sç€$  H@€$  l)ÅtKñ{s H@€$  H@PL€$  H@€$°¥Ó-ÅïÍ%  H@€$  H@1uH@€$  H@À–PL·¿7—€$  H@€$ ÅÔ9  H@€$  H@[J@1ÝRüÞ\€$  H@€Sç€$  H@€$  l)ÅtKñ{s H@€$  H@PL€$  H@€$°¥Ó-ÅïÍ%  H@€$  H@1uH@€$  H@À–h+¦'mi/»¿ù5#»oÖûNà$8'ðë¾÷³Çýûýéàì=îŸ]“€$Ð袡‘¶ñ`à…#»Ã–€æ$ ˜Î ÎËÖ“€bºpÜÓ…Ú€$°ÓÅ‚¤˜.ÆÏ«%0J³ŠiÛú}…ù)à€Ó¾FhÉý:EL·Û~ó›%ßm@Íÿþ÷pöm‰RÅt@au(À†Š˜¾x ˜Z8ÅGÓÖ̬( TÚŠfµ”·mý¾VLû™õK1´b:'8/“€Ö”€b:WàÓ¹°y‘$°@[ÑTL0ƒ  ˜ÎFÅtNp^& ¬)Åt®À)¦saó" H@1uŒ€b:gÌÓ9Áy™$°¦Ó¹§˜Î…Í‹$ ÅÔ90>Šéœ1WLççeÀšPLç œb:6/’€SçÀø(¦sÆ\1œ—I@kJ@1+pŠé\ؼHPLã# ˜ÎsÅtNp^& ¬)Åt®À)¦saó" H@1uŒ€b:gÌÓ9Áy™$°¦Ó¹§˜Î…Í‹$ ÅÔ90>Šéœ1WLççeÀšPLç œb:6/’€SçÀø(¦sÆ\1œ—I@kJ@1+pŠé\ؼHPLã# ˜ÎsÅtNp^& ¬)Åt®À)¦saó" H@1uŒ€b:gÌÓ9Áy™$°¦Ó¹§˜Î…Í‹$ ÅÔ90>Šéœ1WLççeÀšPLç œb:6/’€–*¦ûO©1>pbíÿ_ܯüÿáÀõËß|xGǾI ïNײƒÕvÛúõfÏ ì=á~ÓÈè“í'»»ß.õ#¦·^ä·^J~¶p_Å´e­Æ¼bz—»Ü…£Ž:оð…\ùÊWæç?ÿ9øÀÈë»ØÅNEöÈ#äš×¼&ÓÄ´’ÝûÝï~\èBZztÞõ®wñ‡<„ïÿû³ßK1™WH@ëL`f1Ýcxõ«á>÷dzœ¶ß>ûÙuÆ0kßÓY‰Y_ø¶¢¹l1Möò1¥[g~ <·&¦Éº^¸x‘Üç.ÙU3¦ÎêVæӈ浮u-¾ò•¯p…+\aê}ÚŠéÔ†:® ˜v Ôæ$ !˜YLßô&øÍoàþ÷2–icSL§òçÀÆú(¦éí€6ÄôÀŽ%kz«’e}¬bêôž…À÷¹p³›Avfüú×sø»¿ƒg?’a=ýéá#=~ö³S_ó¾÷Á¾p²ìfyð9Î )ãßà'_{‘‹œúÚw¾óäkîyÏ¿µ·ÓNpÐAk~ùKxýëá€àÏžížÓ£«˜Ngd H`#}ÓðÀž,¿U¹îuá°Ã`»íàyú*¥Í=7Ÿ Š©o H`~}ÓdFŸ äTÞüi–JL÷-òšÅ',«˜ÎÿÑ]9˜&cz–³œ…·¼å-­xu!¦9é5¯y gÏGÝ¥$ÓúÇ?þ‘Ï}îs§ìu˜Þÿþ÷ßö§*9á7ËyñˆGœª¿Ši«ðYI@Ì%¦º3œûXظҕà»ß=ù'9¸=ÙÊ,µ­—Èi²—/}éß^­–òF>7*;ìpr5ÒùÍoÂGÀ{ÞÏxÆß®xÙËà^÷:uö6ÙÖÜs×]ák_›íž›OÅÔ·$0?¾ˆiýð£I£©‹iýçfLçý(¯œGL³”öýïÿ¶ÃÚ”.Äôž÷¼ç¶å»ïÉÆ&E1mëH@˜™ÀBbZÝí߀û7¨¶ýG³×ó\çšÞŸ6bšV’‘=ê(8äÈýrP|–óV嵯=9{›Ìê´Òöž·£˜NcìÏ% (¦ÎŽQ˜GL?ùÉOrÝë^—£>š,“VºÓ,å}ÜãÇ·¾õ­mß™ºQ™EL³ÇtŸ}öÙö=¬3÷˜ÎŒÌ $ µ&°°˜f Μ{âá5¯9™E2›ùŒ3Ës?üáÍù´•Ä|Ojö´¾îu°Ë.§Ð,å}ÚÓà2—9íKÍ´½§bºÖsÛÎK ·ÓކƎ-ƒÀÔÿøä¥¹w»¼ûݧŽCNóMŸN8"©9º 4eŸë§ròF­´½§b:¨¹î`$ЊioBaGVA`^1ÍÞÎn{ȯڪÌ"‰/xÜéNjþò—Ó""úô§Ãmnsò²Þ|5MšoE°íTÞ|EÍfûZ7³Ky‡õ6p4X-UˆéjG´ùÝ<•·OÑØ‚¾Ì+¦[ÐÕ~ÝR1íW<ì$°l3‹é²;´í+¦ë'{)~PLû{µ$Šéœ`Ó9Áy™$°¦Ó¹§˜Î…Í‹$ mS'¨(¦s†[1œ—I@kJ@1+pŠé\ؼHPLã# ˜ÎsÅtNp^& ¬)Åt®À)¦saó" H@1uŒ€b:gÌÓ9Áy™$°¦Ó¹§˜Î…Í‹$ ÅÔ90>Šéœ1WLççeÀšPLç œb:6/’€SçÀø(¦sÆ\1œ—I@kJ@1+pŠé\ؼHPLã# ˜ÎsÅtNp^& ¬)Åt®À)¦saó" H@1uŒ€b:gÌÓ9Áy™$°¦Ó¹§˜Î…Í‹$ ÅÔ90>Šéœ1WLççeÀšPLç œb:6/’€SçÀø(¦sÆ\1œ—I@kJ@1+pŠé\ؼHPLã# ˜ÎsÅtNp^& ¬)Åt®À)¦saó" H`.1 ¶kGe0Ž£=SÄ´ý%Ö<5ߟÎ. H@'PÄtà£\ÞðN1ÔåÝ–% ¡8]ËÔ²ÞºTSL×%R÷³Ïbú[`;àï€:w‡Í)¦´) H ·ÓÅB£˜.ÆÏ«%0JmÅtpŽv. »Šz ôŒ@夕£ö¬{vG€z@à߀}ý€ƒ{л  H Ši'mDPL;Áh#€M@1txœÆK@1oìyÿ(¦ý‹‰=’€$Ð7Šiß"b$ N(¦`´ tB@1í£H@4ÅtÐáup/Åt¼±wäý# ˜ö/&öH@ß(¦}‹ˆý‘€:! ˜v‚ÑF$Ð Å´Œ6" H`ÐÓA‡×ÁI`¼ÓñÆÞ‘÷€bÚ¿˜Ø# H@}# ˜ö-"öGè„€bÚ F‘@'ÓN0Úˆ$ APL^'ñPLÇ{GÞ?Šiÿbb$  ô€bÚ·ˆØ H Ši'mD³˜^ øðqàúÐܸ‘ƒ€¿öZò}¶ºù//-6êK8Wûá çtüàÀs–<À6ý_r:iþÕÀ½€ÿÙI‹Ó¹pT™ãŸœ^}¥5V5V:¨ßL1]1po' ¬†€bºÎÞEmŒYL<8paà§m€ÍYG1 îÀ-Zˆé¿_Žœ“Ûˆ ¦g,sùDà­À>m?¡Þ¹ãKߟÒΙý—5>xXàö›^š÷Tú·w‹¬jþ´èÊÚVQL×6tv\ØŒ€bêü@ŒYLÿøpOàÙS²|‹FL1]LLåßöú!ˆéMwùàåIÀÀ_ÛhÔ›ELç¼ÅÜ—Í"¦sßÄ O! ˜:$ APLVµ¦Æ*¦É \¹ˆéU€›4bIypàZ%«šþI¨û•×/$ ˜ìÞÍÊßÓl%¦ïž\ÈrÇ»¿¨Ý7Ë‹ŸD.’ùÊ2ã‡ßhôíÀîÀÓ€ç;Ÿnœ4Ã\¬ÄãN@ÆqþHûékU.Ù©»Õ^{p¹Òêå0K–îÒÀ?.´ÇoЯÍ2¦‰Éçk÷ÛH?&•iüÛ"iŠé=J<²û£µFv*1 ï_¯(ãMµ, OýÌŸÕ®Ëüùu™smû4k½d,ÏܧÜ;K¥›KkÏQú»g™×ÉŠ¾ãª2¡Ÿ?*¢[ïÓCʬ^»ð•Z…üŽÉÒí°¬Ï©—¹ll5gó¾|p›2§Ã.Ë·_Tk/sý&@¹/ðÊÚëmçO›÷\Þ¿Yªœ³î\˜}sÂûwÖX­S}Åt¢e_% ÖÓÖ¨¬(¥«˜æ<Ô—® üWÙZ—ÄHJ”³TðýE2¾ Ü8¬™<8ßµhÈ\ˆ@f‰p½äßô´ÙýÐÓÔÍž×̵|XQ•£Ëûá)µ×ò~¼Uy=²|GàåÀ®%6õ1<·´yïòbúÕüPfÚüiûžËû7s!*僣°É¾Õü^¨Þ¿mçØºÖSL×5rö[Ø”€bê‘@ŒULsØÎg‡—‡Ìd ¼ªšHJþ?dUÉ5¤êµd[’½ÉÃt–oTò`›ìböSV%¯]¸Cy!ÙÓˆWÚümy-Öœ—”åÆÕµÓGW(»ygT%¦W+<ªv¾¼½<ˆçµYÄ4Bi¨J²]»”ll³ŸÓÄ´ª‰™$¦mù·å“˜¿¸bùÀ"qMf½^’1 °síÅë–+¶«eɳ9É«–zû–¬z>´XVI72º}Ùš~¦¯I[>D‰0烇z6wRŸfYÊ[ý.™$¦×òAL¾Šp†A>DI¶ô‡S`D¬_X2ïõª³,åÝhþ´}Ï5ß«éGæx> ªÞ¿ËŠi_ÚULû û! tJ@1í§I`!cÓ<´'sõGàO…^²=Éð%;Y•Iû “éÊrÌêt؈GD,×73IÍ‡èæ©¼ÿ d¹a2°)Ï,Ó\RœLc2Rõe´ÕRÞ<ð/R*ñˆ(Ô— 'Õ1e‰oÊ,bÚ<•÷îå!>Ü›eQ1mË¿-£Ä<Ëo³6Ëwÿ}Â…Y*›oWûYþ];KÉìEêS²ô3Ò•G®>SÚ«K{Û~µ­—8EFS.ȼÉ{üe©w^ÎÉÀ7çÙ¤{t%¦i;K_“m ¿ «ú5Õý“¥Í{"âŸì{>Ȳñæ‰Ì]ˆiÛ÷ܤ=âÍ÷oÛ­k=Åt]#g¿% M (¦N ô‡ÀÅ4ËJ“M–«*»•嘑§,GLi+¦Yª‰ûË&amó`»ÑCòë€üÞŒàUeÙbÚ”áEÄôŸË’äd‡›¥ 1mÿí;.1Ïríd#É@&K^/ayºm‹F³t;K³_S–iç ¢Ÿ·¸nž*™#ÉîfÏq–W%Ëųì4ö”ˆi²÷7nq“.Å4™Û,‹¾^Yzž9œýÈõ’>¥ïùj ±O³×{•bÚ|ϵyÿ¶À¹ÖUÓµŸ—€6" ˜:7$ÐcÓHG²ƒõƒ^ª¯ØÈž»<”¦´Ó,‘̾Ìì…ËÒ×J›Û,+ÌË,O­2^ÙQŠÖÌ»ÓdŠ?X:ŸýsY>œƒd’©J‰¤e¬{Ԙײ'0‡0U%ÌÒN$¤*¹ ”ÌW“Ï¢bÚ–Ûw\=æOr Î5‡íd)oÊAWÓ–ÂF^ÓÈa–­fž,«d¯tö¹&S[ïWNçÍ2⸕’8’ÕN–|Ú2Ús•j²ì÷;S:¾ÙRÞ\ZeóÕ-9;ÙÐjÅBÕtd4K|Óç”Ìÿ/—¹ØÓxæU}%ÁF]Ül)o›÷\›÷ï²âÚ—vÓ¾DÂ~H@PL;ÅicXˆÀØÄ4Ðü¸yã£@lfÂÚˆi®Ëþ·<ç”Ñ”½|Y¾™ƒªÃXÚ<ØV±DrQÚ³\0§ûN:ü(BØÕRÞl“S\#ì*KU#RÕaPùYNÌdÿkrŠ,gß`SL#«i#'°fIföÇ&Séh–ˆi~–ç&^SÕßH,Úòoû&iÆ<ÙØì¿ôåôÝ”dÇ“EÍaT‘Ô,Ó E¼>Õ¸Q>ð8¦dXsÒl>Ù¨äTÜ0ϲÛÍ–…ot}D-ûY“‘¬—´™Oò³n”ïMõ¬åÙ°=gùà!¯×Kþ½Î)ÂÉæ¿ |‘%Ìù°¤Y¦‰i꿯œXœ=ò!P³dét:$[›Óœ³g5s-ÔKö‡ç=—÷@æQÞs“æX®Ùhþ´}ϵyÿnÚAüH1D„$Ð$ ˜:'$ÐcÓ,+ÍIªœððÁ:´HF¤£­˜æwZ%§Ú&‹öû"9´ZÜöÁ6ÙÒÔÍ×Å$s™ÓSóŸå õÒuÆ4¸ä!ÿêEb’a«Ÿ<‰É^ÚdsPT<ýD"šbúæ²?ðöEb³Ÿ°~€T}ŠìÍLI&/"8©l&¦mø·}Ç5c‰‹ìD`²'3±M‰ˆ>½|­I–õ&C™¹“¸4Kæ[ö†Õf_哘#b²ú Ìmûž"§™?Í’qåÙœ4œÍ ‰{„úË 9y¶Yò=¿Éœ'ÞÙ?ûØòD³^1ÍœÈ2Ý(™Ðf™ÿY±yøÝ²<ndžäýU/ឥÀùÐ ýOœ²÷wÖùÓæ=×öýÛ6VëXO1]ǨÙg H`*Åt*"+H`eÆ&¦+»&7Úèð£5éþZt3{&*YÇÍ:1de´E}# ˜ö-"öGè„€bÚ F‘@'ÓN0®m#ŠérB—%ãÉxgvöâ&“^íÞèŽÕɹ›eU—Ó[[•ÀtŠétFÖ€Ö€bº†A³Ëƒ% ˜6´­¦˜¶Â4s¥,‰Ía=9%wï {OgnÐ $°ÅÓ-€·—€–C@1]W[•À<Óy¨y$ qPLÇoG+ÑPLGjºÓ5’]”€$°ÅÓ-€·—€–C@1]W[•À<Óy¨y$ qPLÇoG+ÑPLGjºÓ5’]”€$°ÅÓ-€·—€–C@1]W[•À<Óy¨y$ qPLÇoG+ÑPLGjºÓ5’]”€$°ÅÓ-€·—€–C@1]W[•À<¶ZLÛ~]É^À›kœö{äBÀQ@®ûä<`Z^Ó¶ÿ-›Û’j—^\øpOàìÉ«{7þsÁ¶Ú^¾ª˜·íO½ÞÀ;ÊWÈÌs}—×ì¼øû.µ­¥èÃüQL—b—€¶ŠÀ´ÊUöë`à¢åûæVyoï%>X1­X]£|'ä´ß#gö^·DÐCÓ£^<¸p‡˜ø)p"ðV`ŸÚªø^øþ”vVóªé_¾§tZùàKÀ‘Ó*®àçŠé ·¸ÅºÍÅ´EP­" ¬i”«‘bºJÚÞ«†*¦«b½îbzàÏÀ%‹øÝ8¸Úo ¼ xð¤òáß_çlo1ós_6‹XÌ}“%\¨˜.êM®ÛüQLç²—H@ý' ˜ö?Föp<æÓêÁ6™°HÌNÀ€¾VC÷ _¯¬½–ŒÑ¡åõ¼\‰Ç€û×~<xË„0L˘>x~íº+éG³œ£ô}OàÂÀñå~ûÍú¦˜žÈÜ [?¨µwsà@à À÷ÊßßXûy$.™Ê¨½–ìã ×ÌØ·¶Õ¿^–™¾øðÎ"”m¯oÖK–úüÀ}€ŸÍåÔmøR–×ÛÿQÝúkÓbž9ž¬ù=ÊØªk <H6ö¤òbæÂƒ€Û;–þ?§d“«ëòú¤¥Î÷mÌõ,þ|­£™[O€z1ày@„>ñþxé×7juó>ÊRåÿî\æì7»¿˜1PM1=ðžò¾»+ð‡Z{ùp!ýÞ¾,óëÏ.qÎæ÷H²ì—þ©|h’L~Þõò ãxZy¿'&ŸnP‹åYË{,¼Î |x"ð¾ZC“~ÿäý–öó>¨—iïߪîopLÿòûå÷@2æU{]ÏŸÌïg{ùý“÷pæpÞ{õ. ä9,ïûël9Ó– ¬& ¬Åt½âeo‡M`^1}[‘™G•%›‘‘<àï TÙ±YÄ4ðÓ[ª²¤4PßmàŸ&¦ùý’,`ÄçWÀ$1ÍÃÿ'J½ˆI–XæÁ5èÙc9K©‹i$4û`ÏSJ#»U¹rY‚œ1¾·d$#ÞÙ‡ùîR)[ ²\õªEôóòm×ù¿©¾³² IDATY:6CÝ;–~ÿoÙ—{»"34qJÕ°¯ìÓï<$G"4UiË?ÙañЍ„o2K„ë¥M̳ç5±ŠìT%K˜#dO©½v)àVåõÄ/l^ìZ‹Iªg Ï-mÞ»\Ÿ~U‚[kþžd"ÚM1=ðÅ" ‘¡d¯Ÿ\>ÔÈü?¡41}ð„"±a“}‡ï/²5K¬êbš÷쀖 w=³žY„>ï‘»Õ>X9vIs6bš2ÖYÏ< ã7ÕVyïæ÷Eêæ}á«•}Ó×.n¤^$>1‹Œ}¦´U½ë¿2WóÁX>p«>Xjóþ­º1Í!êô!Û…òaÛ¯ï.æOšŒÈgû–Ø"©ù=|õÚ{%ãˆòaåw_æWx·-Ši[RÖ“€ÖŠ€bºVá²³'0¯˜æA?Y”¿>)qÉ*|¬¼6‹˜féh=“k# Ù'Z/ÓÄ´ª[k’˜&›ñâòàÙÌ*ÌîêÁöº%k‘ÙÔÌBäá1÷ªï·Œd„W”«’‡Çˆ\2)ù bvÿY;6Cý0J–îOåÃ…ß•kóðŸ,^úض$cÍ܈Ø=x pñš´Í–¥¼›Å<Œ3/sàOú•Ÿ2Ç"f?œ2¸Ä#Ùä|øR/³,ÅŒOÓÈRd5YÓMJ¤÷[ÀKÊœÊk¹W>¸¨ïýØDÆfÝ\‰i<’$#\_ePñç%~™»U ÃO_Òœ(ED3¶ª„üǪ’¹iÎêƒ_Nˆ_õ!ÏõJ–¹ªòºòÔÿ+/Tó«ùû'+?Þ^>HÕ¶ïßÔMŸüë”yÕÅü‰€~¹dÓ³¯;å,eŽçC­È}J„ôå–HòDvpDæÓI§z&+‘Oëó ™2‹˜FêK_lW2Võpt!¦Éd$[p“â\=ØF“¥Íƒò¤Cz²ì2Ë‘¿ª$»˜,J2*UÉd$(¯³d^’í¨K{Ý>¥‰ì)ÍRëd¤"¿y¨Ž,åÁ=rþ$[Ö¶D²"£¿)dŒ™c‰[–Z¦Ì¿+1Í}ƒ,™`fIu² ·˜0°diÃ%ýÉÞEà"¸zéB,žY2ä͹øÚ’ÕJ–2%÷ŠTç”éªD|²\8}¥DL“ÙχJY‘ðy™¶²l8™ïdlëYÔdx“áÏ©J—s6bšß-ùS•,ÁÎï• Ö^«–òÖ?Ô©3È2úô3ËyëýÏ …§ÖÞsíÏoy?g‹A5wÚ¼S7ï¡0®¤p£Øt1²<7Ûª÷[u¯Èi2ÊÇÄ-ïó¬È "é³ §˜Îò.³®$°6Óµ •.Å4ÙÂ<ôU{JÓ<4åwÅÝ1èJLsòì;ˆoõ`›½xYî·[É€Ö—ñæ6a“ŒEÄh³’“e³2ãÉ2féï.ôsRÉÌ%{’%€Ù÷›‡ødl#ÁÙ뛬X•ýnÓ…Ä+K<“}K¦·*ypβÓd¸R"¦mùw)¦ÉÜF¸“Eˇ‘›z60}Ëœ¨–©¸dSÓß,#]¥˜6çÿ2Ä4òáKÆ-\_†œLr>hʲòiËÛ»œ³“Ä´)“‰S1Í\gkˆiöÁg©t$3e#1m~0Ðöý›6W)¦a“¹q®6oPà僖Ä;K}¯ßؽY3ŠiKÈV“€Ö‹€bº^ñ²·Ã&0¯˜f¹]^«ƒWò÷ï”=]ÕWbDpr`O}_]^˵y˜ª?&Ã)JÉþ¹o—ÌÖ³ø»ÓÈn2 ÉÒN[Æ9-úõÛdŸ2†ßÍËy#@ɾ%ÃÓ܇ؼGä5Ù±0 «,;^F©/C®'J–6O†%|f)ÉìfIp²mõ%Ò‘öÈoNþM™…¸³W8ûý2¿6+›-åÍuéWâƒh"d‰G=ƒ:‘Ñ| ’>§„CÄ-¶4Å4žý*«¹Yß6[Ê›øf)o•õÊ=3ÿó¾©îÙµ˜V+"hy¿¾¡ì«¬Æ÷`2¦É6—ÓOgWs6bš÷P>D¨JúXÕ³ÛÓÄ´ZÊ›CÈ2'«’2Ç«,sõhþþÉRêÄ<™ò”YÞ¿mÅ´‹ù“¬~æk–ÛgîÎR’5ͼÌ~þ6E1mCÉ:ÀÚPL×.dvxÀæÓ|ïeÉÁ#Y˜å‘Y>q¬JvÓþíK6.Ë'#(Éœ5Å4‰œâšå¼y(MÆ0bÖÜ?V‰iÞSª=®Ím&)Éð$ƒ— aNÍÃYV“¡Ìë³”fÆ%"•6²/1Ë+ ÍI»YB—}k9l'™ÊìLÿëK˜sïDIÆyÒi®mæì´÷VÚÍû&¢›XU åC‰zi#¦´ü~j~]L|ªJõþmþþÉh‘¼ziûþm+¦]ÍŸ¬ÐÈ{6s/s)äd¾…_¾ª&%ñ˼Îʃ<ƒåÃ…ìeÏ\m‹bÚ–”õ$ µ" ˜®U¸ììÀ ,"¦ÉàXº'Œb¾'3ËÕ²èIwÉi2yÉvÕ¿J£ûÙ¢6'ÐvÎNã8ié´kùùF{Lis¨×*¦C¬ã’ÀÈ (¦#Ÿ¿WÓþ„#_¹“å’O*ßÛ™}o›•d×rØRuÚmFbOÆB`Ö9;‹b:ÐÖý\1Ý:öÞYX"Åt‰pmZ3PLg¶ÄêYÒ»GÙ£š¯ã˜÷û—ØE›–À©t=gÓþN0Å´¿±±gÀÓày©:&0˜vÜ›“€$ žPL{ »' ÌG@1›WI`ÓePµM H@Ã" ˜+žŽF(S§‚úC@1íO,ì‰$ ¾PLûû% ,D@1]ŸK SŠi§8mLÀ (¦ƒ «ƒ’€Sç€úC@1íO,ì‰$ ¾PLûû% ,D@1]ŸK SŠi§8mLÀ (¦ƒ «ƒ’€Sç€úC@1íO,ì‰$ ¾PLûû% ,D@1]ŸK SŠi§8mLÀ (¦ƒ «ƒ’€Sç€úC@1íO,ì‰$ ­ °;ð+àðMn®˜nEd¼§$°tŠéÒ{ ´& ˜¶FeE H@ƒ$pð¤"¦OÞ@PÓA†ÞAI@Š©s@ý! ˜ö'öDÀV¨Ä´ºw2§MAUL·"2ÞSX:Åt鈽ZPL[£²¢$ AhŠé$AULz% (¦Î ô‡@%¦'ŸèO·ì‰$  ¬ˆÀŽ@þlT’A=¸=°pðŠúåm$  ,€bºtÄÞ@­ TbÚú+J@Àè|¸œb:º¸;` ž€b:ø;À5"P‰éï[­Q¿íª$  tC`oàž4õZ K}쫘vÜV$ þPLû {"÷˜:$  Œ›À¤=¦•~¿ qé¸çˆ£—À` (¦ƒ ­[CŠéÍ.K@è@]L›BZÝF1í¸MI@ý! ˜ö'öDŠ©s@À¸ DLsøQþ[eH›DÓqÏG/ÁPLZ¶†Ó5 š]–€$°bŠéŠ{; H`5ÓÕpö.hC@1mCÉ:€ÆM@1wü½K@1lhØPL×0hvYÀŠ (¦+îí$ ÕPLWÃÙ»H  Å´ %ëH@7ÅtÜñwô,Åt°¡u`kH@1]àÙe H@+& ˜®¸·“€VC@1] gï"6Ó6”¬# H`ÜÓqÇßÑK`°ÓÁ†Ö­!Åt ƒf—%  ¬˜€bºbàÞNX Åt5œ½‹ÚPLÛP²Ž$ qPLÇG/ÁPLZ¶†Ó5 š]–€$°bŠéŠ{; H`5ÓÕpö.hC@1mCÉ:€ÆM@1wü½K@1lhØPL×0hvYÀŠ (¦+îí$ ÕPLWÃÙ»H  Å´ %ëH@7ÅtÜñwô,Åt°¡u`kH@1]àÙe H@+& ˜®¸·“€VC@1] gï"6Ó6”¬# H`ÜÓqÇßÑK`°ÓÁ†Ö­!Åt ƒf—%  ¬˜@×búp`ÏÁÛI`] ãûey¡SL—ÇÖ–%0+ÅtVbÖ—€$0>]‹éÁÀ>ãÃèˆ%0ï—žëJ/šJ@1ŠÈ XÅte¨½‘$ µ%°,1}.ð¶µ¥bÇ%°\)ïÅt‰œÓ%µi ÌH@1˜Õ%  ŒÀ²Ät? ÙS‹$pZ—¾(¦KœŠéáÚ´f$ ˜ÎÌê€FH@1aÐò–PLWÅt½…ZPL[‚²š$ PLG|‡¾eÓ WLWÙ[H %Å´%(«I@1ÅtÄÁwè[F@1]zÅt½…ZPL[‚²š$ PLG|‡¾eÓ WLWÙ[H %Å´%(«I@1ÅtÄÁwè[F@1]zÅt½…ZPL[‚²š$ PLG|‡¾eÓ WLWÙ[H %Å´%(«I@1¾ˆé]‡W~ |xðÞÇf(COwöèÉ€ndÞ_±Ìµyºõ à²åÂ'ÌØˆb:#°yª+¦óPó ,‡€bº®¶* H`Hú ¦ÿ<xðàÀ5€^ØçŽ.|Mú¼ªn®BLgáI¾;ð¯ÀI Bø p¤bº Å%]®˜. ¬ÍJ`ŠéмDÀÈlµ˜ž8ØxɳŸEŒÖx˜su½ob:× 6¸H1í’fÇm)¦µ9 ,@@1]ž—J@ ­Ó[”,éy€_Ma~=àÀ®À À»€‡¿)×]xðàñÀaÀ›€?n œTy'à~ÀµJv6×½³Ö‡ƒKÝ»Õ^Ëý/ì^{íàž¾ÿØ¡ñÚNÀAÀ €_¯/™¶?7êݹŒ+KEóleÍÛ瘓—žÜ8gg–ž¦Ïõ’åÓYNqí üH&»Î£MÿÏ<¸WÉF üøûÆRÞ<£¤^–÷žøð àgµN…Õ…€ÿÂäÂÀ7»¿˜ƒæËíÊuáþ <Ï<Èܸ<ð'à¥où{³(¦sLÊU]¢˜®Š´÷‘ÀtŠétFÖ€$0v[-¦ÙWúè".›Å"{ò¾ <xpAàUEdn].Œ¼ýðàSÀQÀ‹ÇŒQÓÏ1ý^¹&ýˆ|ý ´×VL#VëÈÒ¥ËõY" ®ÊÙ‹`¾ xV©ÿFàãeomUïÚ@d'r±ŽèEP¿0ÇDÍ’Õ0H{Ç~üO£½ˆi2×/*|#Õ?~]êµíÿ£J<#’ŸîXd#†UÆôjÀgkí¥ÞÛ‹åå¶bšºÓ–òî<°ÈWuËëùÜøCy1Bš o²ÂÃEJ>ãìNÛK1M68û.'•¶ýO¦øùåપ,Ѿ@MLÓ§/—lèOK¥d*³G÷¶ÀGËkÓ‹w¨uè¹å ¥úkmø×Ç”2’1ž”14öÈúyKÖ¶ùs3¦‹ÌÐ%_«˜.°ÍK`Šé °¬* H`¤¶ZL“1},°ýþɾ%‹Õ§d7“E}eMLÏTÿf9fä5%–¥¥•DV?«n,Z^Ê2Δ.ÅôeEÀ“­¬Jž›#d‘ÐHqJ¤:cI¦1Y߯+ÙÌY§h2ÌoÞD6ëíEL³Œ·’Âæ½Úô?K…“a'³Y•æÓdS“-®–`WõÂ"óá¥å…ˆi–ïUk+ñ¿ PeÉ«Mû` >žibšd‰ù.E‚¯Y²§Í{¦MÅtÖY¹ÂúŠé a{+ L! ˜:E$  H`­Ó,«ü’Q«ïlö{#1ý!=“YÖ[eLçÓ×–¥³ÕžÒ.Å4mg¹o2‚mJ2Œa“¾dyëõ,=ž¥DL#â÷ieš˜¶éÿÙÊ2áÄ!ûB«ÒÓdÈ#ÉjoV¶BL/R–WgoØe™wö´f«b:mõìçŠiÏbwFM@1uø¼$ V¶ZL³w1{³‡/Ë47*YÊ›ý›7ªUÈÞË q«/åm+¦·,¯4™½‡ß*ÙÊ,iMI²'³¾72¯e¿kýð£Ôdåð¦,/þ΄Ad)l!ºL〟6AJÖôhàqm*×êDÖ¯ZþÔ÷»Njfš˜¶íD.Ï죭Ê€œ¾\qÌRÞ¯7Ÿòu@³ˆé4þõ1o–1ÍéÐég²ØUI&=}ÅtÆ ¸ÕÕÓ­Ž€÷—Àß(¦Î H@˜F`«Å4ý‹ô$«–vsªnö\&C˜ cd.¥:ü(Ò˜²Ä3©½M©3kÆ4Ë€ïS–úæÐždòò=¤Uæ6?; œÎq»GYÞû± bšgà,c}fÙ#šþfÙî·Kß²D8ûYsšpÆ›lf²¢9u6Kv«’1_©ˆè_€ìCÍrÜ”ý¯³”ô!B›}·ÙË›’ÌRÕÜ¿^¦‰iÛþ'†‘»,×èç¤Ýœî›%¯uÁ¬æ¤àŒ+‡É©ÎÍ’q}¦|°’Ó‡ó§MIlòF2³ùÀŲŠé Ú¤æ$ ˜Î ÎË$  Œˆ@Ä4¸³dõa5 üb9D'Ë|«Y­]L¾Ê$_ñR;«˜æ—Œk2}9!6’T•ÈR¾Ò%{ \¾Ö&ÒœƒššÓ\“¯ŒIÿR'{F³w6[•ˆèÓ‹HG@óÕ(Y.š1TåŠeOi2¯y®ŽÜ½pÂ×»´¢ÉÐf)o¤*ýÊáDéCFª—ibšºmúŸSm#”a‘òáA8æ”ߺ˜&«=¿ù0àb%†‘èÛ—¯ªÉýfÓ6ü«ñn&¦‘ödçÓ×Ì«p ³G–Ó‘›Ü#¦Éü¦$C3ÚÅ´ ¥ë(¦ ôr tH@1í¦MI@(¾ˆé*ñntøÑ*ûà½ÆM@1]AüÓ@öhI@1m Êj€FL@1qðú–PLW€^1]do!–Ó– ¬& H`ÄÓß¡oÅtèÓ@öhI@1m Êj€FL`Œb:âp;ôžPLWÅt½…ZPL[‚²š$ PLG|‡¾eÓ WLWÙ[H %Å´%(«I@1ÅtÄÁwè[F@1]zÅt½…ZPL[‚²š$ PLG|‡¾eÓ WLWÙ[H %Å´%(«I@1ÅtÄÁwè[F@1]zÅt½…ZPL[‚²š$ ›˜¼xNÏbþt`gà¶=ë×fÝ9ø{`¯úœvŽ«µsCàð íæ^o®½Þ'÷˜ƒb: ­9ëöirì\8vÎñx™Ö™€bºÎѳï€VC`bú ’tH dÿ| 8²EÝE«ì^úµc‹†"byn}}‹º}©Ò¥˜ÖÇôàˆiUïÀ§€>¹Ç,qQLg¡5gÝ>MÅtÎ zÙ`(¦ƒ ¥‘€$°4cÓ¥œÐð,bºÊ~uu/Åt~’ŠéüìZ_©˜¶FeE ,€bºtÄÞ@ÀÚXµ˜žxp'àòÀŸÊÒÚ•¿×ÞØ¸ ,Z27+O½½×LˆÀNÀwj¯_ø|íÿ÷n\—e£_\{ý€dcÓÞwËëmûÿ}àâ{¼¸[ãµ_ç*¯½ØcÂxÎ Ü8/ðUà‰Àûju#Á/î <ªd_ÿ Ü 8jÎY:%¦ïž\ø$pàµ{^H|o${ü³²”úEô«‹Œižž]xžøHéCî]•ôÿBÀ¶éç7'ôÿìÀ JÿÓÖÑ@êÆ{®\k/ó$mÞøeÉ~$Í¢˜Î9)g¹L1…–u%°\ŠérùÚº$ !Xµ˜žx ðÞ"{»ïžRþ+¦Ùz×"‡‚ˆìÇkÐóÜ™ö" /^W~ö— 9cy-Kx³ä·)¦÷(²ᨮOÒ¿ÕÚkÛÿÔ»ð<àÒåú¿ùS/©—q<³ˆì$1}pí"ß+âô\à:ÀgJcÓˆí¿"¼a)¿Þµ ÿHX¸½x2pð1 q®J$ìV¥ÞñÀ—¶ÿféBLß œØÈ=#©ÙÃ{uàÄrÃô?’Dª§Ì±ìA~£ÿùÙ.ELÏVêDÆ#«?*mE^¿¼ xpžÂ!óõ¡ƨ˜Î1)g½D1•˜õ%°<ŠéòØÚ²$ ¡Xµ˜Nâ–ÌY2ɦ\ øŸ"3jz–=¦‘ØIb±Èá;éCÄ$’’maÉ>F´6+ÍþWugYÊL6±)¦9+%Ù×Èe2{U‰„Ÿøå…Ü+»}ļœ eÆšz³”¶ü#v—+ûA«öóZú|‡)7LÖ7âü² õÓè—K6ô§¥ýdº#¨9\ê£åµI}ð'õþ‡{„?ýM‰Tg~ܧÖ÷döó@î]•ëùPe»Z–¿ú™b:ËŒœ³®b:'8/“À(¦K€j“€F`+ÄôLEf’…Š\³dOo]ØîY–Až£–ÝÚ {bZ G$"rš%Ñ‘dP߸ù´þWÕ»Ó[ﲜ·žmÍݧ–%»¹_µ”7§ÛVå&%çYJ[þ“ö˜þkÉÒV±¬î› b^‹¸…i2¨ÏØàtäEÅ4ñˇ ¿i :ršìe–<§´í²­É´¦ÿa™åÊOjTÁNL~W»g¼(÷LÖýk¾(¦³ÌÈ9ë*¦s‚ó2 ,€bº¨6) H``V-¦)Ëq³góP ZšY©‹é€ˆé¤e¹Ít%¦9é5® /.b“LX½´éU¿+1ÍRç,!­‹é?—å³ÉN¦t-¦mø·»—%®ùšž?’e~Ó’Ä4‚˜¾U{w7z˶íØÿWÉç›>^=¡ß¯-ËwÛ~Ýbº‚_¤Šé { ´$ ˜¶e5 H@#&°j1Ý¿,WM©*yÐÏÔJLshP„5{³orZÉÁFWN«Xö£NZÊ[]š%¦‘ÒìùÌòÙÏ5ÚlÓÿê’ì1M¿ò50ÓÊ´¥¼ù:™úþÚHÝ9k̺Ó¶üÛŠ]dô+Àà „dœ³Ô6ñšô}²‹fL“•Íýn^DxQ1Í>ÕÈuö<×3¢õvóÆÓÊA]õ–6º·b:íÑÁÏÓ Ú„:" ˜vÒf$  ˜ÀªÅ4‡Íä„Ù,ÍÉ¥÷-Ù¾“‡ÿªd?_N°Í)¹(û&sO2š9d§^rRJêg¯j2ž}OéF{L«öQ–i&£›û5KÛþ纫–qsxRä9K—? œ0¡ÝÄ4U³wôúÀÝËiÃgêç@¤úáGY¢ÚÅRÞܳ ÿ¶bš%Ñ9±7±ÎD®T Êräf‰˜fïl²”9¨¨ïÔ¯¾Ç4’›Ò̬'㛥̉WæL–BçÝHrUÚö?’û‰‡*kÃ¥²÷·*ÉîW±¤æŽ ”}®ù¾Õ.V¶™ IDATfQL'@éú%Å´k¢¶'ù (¦ó³óJ H@c!°j1Häð˜òóëò°Ÿ“M \¶=Ï”yÀÏW–äëb²Ï3ÙË*'ÎÖã|=p‰²L4Ïœ˜:©LÓdn³\óá@Ø4KÛþW×åôßœ\qútO–²6Ëfb©zú„¯‹©„µzÉ þÏ„1Þxeíõ«Ÿ¯ýÆqð„ë®VÆx=à‚À7‡‡O¨Û•˜Þ¸w‰Õ9€ÿî7!«ìfx& ~à»À=ãJ&ò⾆k–s×˯€s•ÞìÑøybÿ ì³¼*ï~ܳöZ›þÒ¸&—ÿ¨dkë·ÎœÊ¬ÊFKÀ“õ~x™«?^<»1_ÛÌŸo«,€bº¨6) l=Åtëc`$PPLû3Þ ü¾ìћ֫ˆiä+‚ø€²Ì2ÂWß|d¡,ƒèTbYm]HüÓÆûË>Ös/nÜÓ+—%°‘¯÷‘Á·÷ÒïªD,"£Yž›6#Ißn V«wFà¹e)o/åƤäµÔKÉÞˆÒ$10GØÒ~þ}‰¬ß®ÔŸ »ÓHôw€£ì­|]Y¾zûÚý²4ŒžTdý×%žXü¶V/šþ>¸tyý¯@þÔKêe|Ï,"ÛÓü,¬_XþäÚó–~Ýøx­±6ý?=pà¥_?(ñIœê%÷Mß"è‘çIbzWàÅÀ?—8]½0{VcßpÛù3íýáÏ»' ˜vÏÔ% PL{» B@1íÏTø‡ÿ<¼O+ÓHg²œ¿Ü òÏo­ý<÷ÈËÇ—×"(‘Õì³ÿCy-YÇŸ4#m$ WÏ|&)¼N­ýˆÅ«€<ÄV%ÚHeýµül–=¦ÀÄ´9üìËM_/W²§õŸw%¦Í{îYd0’Z•HâÛŠðO‹ç,{LsT>„hŠiFˆ“OɇÉšï4¥“úŸKfYÊ»Ùðo¯-T]ÉÒœìsÊ,ó§ÅÛÄ*PL;„iS@(¦ý‰…=‘€bÚŸ9e·*¢8­WÓÄ´zè¿jÙ[ºQ{Yº+¥žU™$¦Éä¾ ,7ݬo³ˆEWbš¯×ypÙŸú™’íÍÒßìë\†˜fyqDû’À+ÊAUÉ`firSL#cŸ˜ÌOåÝ,cš[}°|mK2ÌÙ3|±Æ)¹mú¿ 1 ¿ì¹ÍòåüW1m1Q¶°Šbº…ð½µ$°<ŠéòØÚ²f% ˜ÎJlyõ“ýŒÄ$óÖ< ¨y×ibšýɘ¾º|/êF½ÎAotÍ41MÆ=8dßkÒj~ßiÛþçþÙ»›}£õ¬æFýš¶”÷ ÀSjç0¤~Ô\ÊÛ6ã>©?ï–€bÚ-O[“€zB@1íI ì†\ÊÛ»9ŒPí[Nn f™çQ%KWuxš˜¦Þ}Š,=®HJ– gOjöûå@›”³•¥Ÿ¨Ò“¥°Æ,­‹é?”½©9 6r‘=¨Éþ¥dåª~Í"¦9¡5™ÎÈn¤8§ð~xƒˆl¶Ç4}ù²T8Ë’]ú~“ ÙÊj)o–4§¤ÿ³–0üjÙ¿›“ó=³ÙË›“uÏR[:= ‡–=¼Ùwû¿…ožJŸë%™íÄøF%îÊ|8‘¥ØÍ2MLó}¢ùP"}‰ô×§J[mûŸºù÷:òÑMƸhök31ÍáGÎt•“ƒ‡ˆs–'Ó<Ïü™5nÖ_Œ€bº?¯–€zJ@1íi`ìÖ( ˜1íWØ#Yš¡Höì§%;—Šê'î¶ÓŒ,‡ÚDÔ"lÙš¥ÉTE «’½†//Y±Ï•trHRótÕÈRN¼HFì~<H&l±HÆ1"ž}š‘¶HiNùT6Ó|%K¾z$™Ò|eNd7'?xs£±JL«—³o¶:¡x–™{Dø#ÉÔæ$܈e>H8®ÖPöî&žÉ‚W§æÞ¿œ2ܼ_NNæ5²œqLúú™\3MLS'™}¶™C“ä»mÿÓV¾f&¹]Y¶üX ó£Y¦}ÿmƃ˜òFõu1Y¾^ÏÀÏòÁÆ,ñ²îâÓÅÚ‚$ÐCŠiƒb—FK@1mè¸$ ÖÓÖ¨¬( ¬Åt¢e_‡N@1z„Ÿ$ Å (¦‹3´ H ‡ÓÅ.–€b:ÚÐ;p H@­ (¦­QYQX'Šé:E˾€b:ô;> H@‹PLgh @ (¦= Š]-Åt´¡wà€ZPL[£²¢$°NÓuŠ–}:Åtèv|€' ˜.ÎÐ$ PL{»4ZŠéhCïÀ%  ´& ˜¶FeE H`(¦ë-û:tŠéÐ#ìø$  ,N@1]œ¡-H@=$ ˜ö0(vi´Óц¾÷ÿðÒògÑÎî¼¹ÖÈFÿå~÷+õþ ¸Á¢7öz „€b:@: HàÔSg„úC@1íO,ìÉ© t)¦UË×>Lûwè1À-S§¤N! ˜:$ A˜ö@°ÊAì\8v•7ö^è Å´'°§! ˜:)$ЊibaO$  (¦´) ,H@1] —ÏEàÀÀžÀ…ã·ûÕZ‹˜¾8p_ sõÀ>;^­\w=à‚À7‡‡OèYWÓ€ƒJFõ—ÀëËxþÜèÿ›€‹×*ã|ׄþ_ x °+pð5àÒÀÇ€ÖÚ»9p pà{åïáa‘À*(¦« ì=$ •PLWŽÜJ`CŠ©“cÕÎ|8CÈ/ç-ú¹†Ø]x.ð*àŠEÖnÖ¶s•×òïËÓ€Û•Õ0uQÌ%]ˆéÙ¯ožœ§óÇËxª®E¬#Ý{ï/‚úmàÖþgÌ ì|ÈžØìqô¦\¹,AÎþ×÷‘ñˆü½€w¯:€Þo”ÓQ†ÝAK`øÓáÇØ®Åt}b5”žÞx1¬ãÏ6TÄîPà Y¤æ!y£rÒîåJö´^¯ 1MÆ6™Ìk _·ÈævÀÊë鳯Ÿ©õÿÌÀ‹xFÐS¾<xC­ý·–1Õ³ÅO’E½ÎP&†ãè5Å´×á±sÀ¼ÓyÉyº' ˜vÏÔ7'ð"à²ÀM¦€š´Ç4ÙÄ,‡}NãÚ,‡¤¥Ý,ç½SÉ>ݨׅ˜¾¬d*Wk;ÿ®¥,ÇÍRÜ”¶ý? H¶õ‘ÀµW¾Sk?Ë“sŸj¯%ãüë’vÎI`ÙÓe¶} H`K(¦[‚Ý›J`"ÅÔ‰±jÓd3oÜ‘˜î<¸ìGý ðàÈ%ŠékËòÝÛvÔÿHu:ËŽ¿<ø`£í/ž·ê`y? Š©SA$ÅtauPkJ@1]ÓÀ­q·ï^¾›ôòÀ7G›Œcö«þ¦ìÉ|Oiëb@D.û5—‘1ÍrÚìc½L‹¥ÈÍïa”ñÍ2ÝÏ—ÃŒ6‘:Ù¯še»'­qìíúúPL×7vö\Ø„€bêô@(¦ý‰ÅXz’}•Gg-§éFÏ \¼¼^qh#¦©› é”å½9 )‡]©,Î!KõR-å=Syñ/@Ï÷˜Þ²du#‚'ÖêåDáìÍ º‘Ô¯Ùךƒšò©³ôÿüÀÏj”loJîw\Czÿ¡´ýö²ÿ4cÞHÿ¿1–‰ã8·”€bº¥ø½¹$°,Šé²ÈÚ®f' ˜ÎÎÌ+'Í×ÅÜ¡Ýÿï0£Ø¥ú Ë×­$Sú鲬7'×F.ß¼˜V/oôÖ¹öé¥ÒwË×·Ô›Šˆæç·)ËzsˆSjzÄýÏÝ5úùW K”ŸY{}—’©MÖ4blóS‡$-[ÀdŠ©3C$ÅtauPkJ@1]ÓÀÙíAØx_ÌÈtJ5ÊIÄù^Ö«b”bÓ!DÑ1H@§! ˜:)$ЊibaOÆGà¦%ãyMà{@þ}Œ¾¢|¥ÎAãCâˆ{J@1íi`ì–$°Åt1~^-. (¦]Ò´- ÌF ÿfOì½Ê>ÛìÍžÕ—ïž­)kK`©Ó¥âµq H`«(¦[EÞûJà´Sg…$  L# ˜N#äÏ% µ$ ˜®eØìô@ (¦ ¬Ã’€$Ð!Å´C˜6% ô‡€bÚŸXØ (¦Î H@˜F@1FÈŸK@kI@1]˰ÙéPLX‡% H CŠi‡0mJèÅ´?±°'PL€$0€b:?—€Ö’€bº–a³Ó% ˜4°K@‡ÓaÚ”$ЊibaO$ ˜:$  H`Åt!. ¬%Åt-Ãf§J@1h`–$  (¦´) H ?ÓþÄžH@1uH@À4Šé4Bþ\XKŠéZ†ÍN”@1Ýx°7Ч÷ï@Câ°$  ôŽ€bÚ»Ø! H  }z°=ظ(plƒ³ ¬ÍÄ´.¤Õ°úôþ]3ÔvWÀÚPL×6tv\ØŒ@ŸlSçêØ LÓIBª˜Ž}¦8~ H`ÌÓ1Gß±K`ÀÓס­º˜^©¶dw£ÜpíFh‡%  H`Qnì¼hc^/ H /Ó¾DÂ~H*1ýpfH@€6! ˜:=$ APLN³æêÓön\&í1Íé» jŸÞ¿ãŠ”£•€$°uÜcºuì½³$°D}z°õð£%ڦׂÀf§òNÔ>½×°”€$0Šé‚è$ ÓèÓƒ­bê ;6ßcZÔ>½Ç;Ç/ H`UÓU‘ö>ÀJ ôéÁV1]iè½Y ´ÓªÛÔCz8»$ H@Ë% ˜.—¯­K@[D@1Ý"ðÞVÌ"¦”€$ qPLÇwG-ÁPLb¸FÓ5 –]•€$°EÓ-ïm% åPL—Ë×Ö%0 ÅtZÖ•€$0NŠé8ãî¨%0xŠéàCì׈€bºFÁ²«€¶ˆ€bºE཭$°\ŠérùÚºf! ˜ÎB˺€ÆI@1gܵO`(bújà^À€ÿ\aÔŽÞœ¸ðcàà ¶ÝöòU‰iâxn _­2­ÜØxý´ŠS~–Ÿæyo)¦ Â÷r H@#  ˜Ž ÈQc$0ÏÃó²8Í+¦7ÞUDëIE.þº@'gÓn3ó¥]ˆéYã€ý—Ì܃î.裘v5:Å´+’¶# H@“(¦Î H`† ¦/ÎÜøÌ×''Dë~%›zà%Óy³ò÷TOVí5®Û øNíõ«Ÿ¯ýÿ~ÀÁë¾<¸öú?‘Þ´÷ÝòúY€w.ü©, ~Pù{uù÷‹7îñFàn×nX–è~¯ü=õªr‹’%=ð«)3ú@døiÀódj? Ü8©ví´{¦ê?/-ýúðà=@s)o›¶ÂðMÀE€k.LÔ3åéëÿLß}W6^‡s•×Þì1ẫ‰óõ€ ß,K¡çfQLù«ÒAI@è Å´7¡°#@—Ö]LÏP– F¢²ó#ÀW‡4 ehöUFøN_Dðãµza‘öŽ^¼®üì/€gùpJ–ð2ALïQölFšªëÓ‡]Ë>تÉÜï1@övFVóódŸ¼ vßÔ»]Y‚{éòz²ÂõÌð•ËÒxÚ‹L½¥ì½}w¹&ûJ ü}‹I¦©Á;iYn38]‰i%K?“|q‘çæ‰ÁY†šåÄYÆ{hYòz—"°³ŠéÊò߈àF%Yãÿ’ñûÅ”YÙFLÛÜ3Kd³D9‡TUe’˜¶i+×o…˜æ°¨ìÎþÔÏ”lo–q+¦½ýÕfÇ$  –€b:ØÐ:0 Œ›À:‹éµ‹Ô]¨,«¬"™¯AÙ·¶\5Ëz³ÇñŽ@·™Vr°Q–Ó6É™tÝFKy«ºÙï)œåàœÏ5‰ðdéhÄ­*ùNÖd4›bš=éWö5N*Y ›½—Ép6÷QVõ«%ÆÙÚý—›•6bÚæžÙo›Ã“"á9t*%ûd³/´~øQ›¶rí,bšûF›‡DM÷FKy³W5ù|OilJÉòðˆ´b:íÝäÏ%  H kŠi×DmOèuÓHÇU‹ðÕa^¢ˆh~V‰`3Šœ$ë•ïåtÝd4›—ƒƒRR?{=“ñÜè{J§‰iä._a“Œhî×,9T(û/“ÕÍ>ÎìÇ̒ݯ—Ãêõ3ž£ÊáI‘ç,ýÍÞÊJ¥œú›ïÏŒ|G<³‡3{&“%ÎI¸UIÖ6öpà}e¹ñõœÔ›C}ªÒFLÛÜólåà¤TY ›ØíÜÓ6m¥o³ˆiƘ˜GÖ#ʼnÁFßÕºÙÓ°L¦9u²,9HEªo|¢Ôj)o–h§´ÉÒWMø=¦½øµh'$  ôš€bÚëðØ9 H`^ë,¦ÉXEp²°Y"/¡d$S2ÎYN¬Í×ÅdŸg¤õŸ&|mJ0'üFpX2žõrë÷š&¦É|f¹q©y0OÚ‰¼d/j²¦Ù ú àGer®Y²§6ÈÈNöÐf<écU"«‘ˈXÚÎÏžZ–2×ÛŠt'³œ¯¨ùmùj›°Œ|U¥˜¦n›{fßlÆ™¯Ê ÷Ç›ðu1mÚšEL#ÛÉÄ&»þ¿EJsøÓ¤²™˜æ+ˆò½¯É”†{d7`äDå77«Ä´z9û~3ÚÅ´ %ëH@7ÅtÜñwô,uÓÁÅ–€b:ÚÐ;p H@­ (¦­QYQX'Šé:E˾€b:ô;> H@‹PLgh @ (¦= Š]-Åt´¡wà€ZPL[£²¢$°NÓuŠ–}:Åtèv|€' ˜.ÎÐ$ PL{»4ZŠéhCïÀ%  ´& ˜¶FeE H`(¦ë-û:tŠéÐ#ìø$  ,N@1]œ¡-H@=$ ˜ö0(vi´ÓцÞK@hM@1mÊŠÀ:PL×)ZöuèÓ¡GØñI@Xœ€bº8C[€zH@1íaPFÚ¥[‡çéø3lÅtÄÁwè€ZPL[‚²š$°^ÓõŠ×{«˜*¦CžßŽM@WÓ®HÚŽ$Ð+Ši¯Â1êÎ(¦Šé¨ß^@KŠiKPV“€Ö‹€bÚÏxÝx°pà»À=€Ï׺{=àÀ®À À»€‡¿)u®¼xðxà0àMÀ €Ÿ7N>  \¥Üï¶À}ê¿ï.íxp'àòÀŸ€w*¯ºö…rŸ‹×.\ú¶OõÞÀ“íÿþ£ü¿Kyá·ÀvýœšöJ€¶˜€bºÅðöÀr(¦ËáºH«·O*‚÷kàŠÀ—8YXR.|x*ð à‚À«€ŸÉ<¦DLÿ xð)à(àÅÀc€_7Ž(bz1à7×,By¯"½7+íEsí{‹(Gˆ#ÃO)²[ÓÈhÄóý@õÛ¥_‘㔫—{§o¹g¤øÕEÆSÅt‘÷×J@:Åtèv|)Å´Ľ xì&]{9p ঵:;ß®Q$4bz8p&à\ÀñÀ$Žë¡ IDATÎÀ×€c‹°æ>ɘ~¼æA%ÃyGà>¥N¤x£ò"à¼Àk’1$çΪ|¶lT½öÆÒ§J¢S/™Ø´§˜*¦ý{WÚ# H@ý! ˜ö'öDè€bÚ!Ìšº@Éz^øä&í}ºd.ÿµQç%‹úÊ’1˜ž±vÚk–àF^¿_²Ÿ‡1M½´õ``¯’ñL†ôrµ{DroììX²«Yf\̈éKËŸêÒŒ%ÙÕ´Ÿò¹"ßÖÚv©{L;x Ù„$ ÁPLb(qPLû÷JL³ôsˆéË>Íd,«ŒiWbš%¹É¬FD#´ßîR2¬³ŠiÄú=ÀÓÓSEÙ¯‹é×ûÑÞH@è#Å´Q±OÀÂÓ…vÞ@Ä/{3÷Û¤å,å½4p£ZË_/û7³Ÿ´k1ÝØ£ì;­n›}¡9¼hV1ÍuܪÖÿ,ÎaN.åu)oço*”€$0 Šé€‚éP$ ¿PLû7"ÉHf™k2Ÿÿ D:³/ô'¥»ÕáG¹hÉ‹ìܦÔéZLs"oú´g9<)'÷î^d8'üV¥ÍRÞ«Éšæð£œìAMöôôŠé¶–=•·ïK{$ H /Ó¾DÂ~H@PL;ÅÙYc9 7Ê\b”‘î_¾Ö¥ºÉõ_óÎòÕ09Å7¥k1ÍþÒdj#ιGNþðÈ"γˆiê&Cš¯‹ÉÁLÉx¦bª˜vö.²! H@Ã$ ˜3®ŽJ£' ˜Ž~  GÜcÚ£`Ø H@=% ˜ö40vKXŒ€bº?¯–@—Ó.iÚ–$ aPL‡WG%ÑPLG?Ð#Ši‚aW$  ô”€bÚÓÀØ- H`1Šébü¼Z]PL»¤i[€†I@1f\•FO@1ý@(¦= †]‘€$ÐSŠiOc·$ Å(¦‹ñój tI@1í’¦mI@&Åt˜quT=ÅtôS@=" ˜ö(vE@O (¦= ŒÝ’€# ˜.ÆÏ«%Ð%Å´Kš¶% H`˜ÓaÆÕQI`ôÓÑOôˆ€bÚ£`Ø H@=% ˜ö40vKXŒ€bº?¯–@—Ó.iÚ–$ aPL‡WG%ÑPLG?Ð#Ši‚aW$  ô”€bÚÓÀØ- H`1Šébü¼Z]PL»¤i[€†I@1f\•FO`ÝÄtoàIÀ%F9 ‘€b:Ĩ:& H@ÝPL»åik@O¬‹˜VBºcáÖ§~÷$”vcÓÑ!H@X2ÅtÉ€m^Ø}¼c€€‹ÇM!­(õ©ß[9ï:DŠé£ê˜$  tK@1í–§­I@=!Ð'Á«‹éMÊ’Ý*CÚÄÕ§~÷$”vcÓÑ!H@X2ÅtÉ€m^Ø}¼JLóßdM-+ßÛuðŽ[€6% ˜:A$ A裘¾Øs´”ÚPLÛq²–$ 1PLÇuÇ,裘&[zFààžÄ OýÁ4qˆ+"àRÞö6€Ö˜€bºÆÁ³ëÀÆú$x“?ÊÓI‚Ú§~;¿$ÐÅ´+’¶# H`¸ÓáÆÖ‘I`Ôú$x“Ä´ NSPûÔïQO ß)Å´Sœ6& H`ÓA†ÕAI@}¼ÍÄ´)¨ù‹†F@1ZD$ î (¦Ý3µE H ÖML{€Ì.H`iÓ¥¡µa H@ƒ! ˜&”D¨PLèÅ´?±°'€úJ@1íkdì—$°Åt!|^,N (¦â´1 H@ƒ$ ˜2¬JPLèÅ´?±°'€úJ@1íkdì—$°Åt!|^,N (¦â´1 H@ƒ$ ˜2¬JPLèÅ´?±°'€úJ@1íkdì—$°Åt!|^,N (¦â´1 H@ƒ$ ˜2¬JPLèÅ´?±°'€úJ@1íkdì—$°Åt!|^,N (¦â´1 H@ƒ$ ˜2¬JPLèÅ´?±°'€úJ@1íkdì—$°Åt!|^,N (¦â´1 H@ƒ$ ˜2¬JPLèÅ´?±°'€úJ@1íkdì—$°Åt!|^,N (¦â´1 H@ƒ$ ˜2¬JPLèÅ´?±°'€úJ@1íkdì—$°Åt!|^,N (¦â´1 H@ƒ$ ˜2¬Jƒ˜îSBý;àËÀAÀ¡†&·Î?ÓUVž…€b: -ëJ@'ÅtœqwÔ<1‰éµ€·ž<xÊ#ü…"Þ‘È.ËØÅt÷ÂuÇ.¡6ÚRL—צ%  „€b:@: HàÔÆ$¦W¾R†¿ð&`W "7¤¢˜.'šŠér¸Úª$  ÌF@1—µ% 5!0V1͸¿¼xh-V7®|¯üýbyCà ÀnÀ€ï÷>_«û 2ó4àù@2mŸnœœ8ØxGíº‡.Yê8¸p? ™ßiÿµëÒÎk&ôu'øÿí ¼}åœÿß )ÓˆFîÅŒBªIB1äÖ þ“»Ä¸EeÈ­r #w’j„H®ã¡DÓ`ÒLׄ˜I.¹N(Q¤ÿës~ÏÊj·ÏÙk¯³÷>k¯ý~^¯^²ÏZÏåý}Îi¿×÷yžÅw>ßØØ 8H›g \“ú^R®ùwà“åÿ·YÊ›v^„ï¦À/J]ohs–ü«¦›´y.°Å@_3/3áßs3¦ju€zH@1íaP’$‹*¦‰}ö˜Þ°ˆbþÿÖÀ—Šü}ø;àÀãck“%Kóù‹KÖõ×À퀯 ˆi¤7‚ûT r9­²¶¹ô­Àõ‹ÀV·F#ªÿR>¨Ä4Ò1M}Éç‘Îï—ëËHòéÀ¡À1åó?Lô½ç‘NŸ#W•Œÿ°\»pJiçÝÀ··Ücúà—À³€Ÿ7.íTí­ÿ¦1×Ý€×·,}ÿ&YÓIÒ´. H@ý$ ˜ö3®ŽJ O`‘Å4 Ýئ̂?"nUIV4µ»Õ>;øpÀˆÙ“Œf0Ù×HÙ°rgàóÀÊ5[_-Ù¹•*1(׳šß>\2·õºG-åý9ð4 ã­Ê犔¿ |làu€ì+­J2¶‡·Ó³€±§w-ø7m3 \Ê»ð.  H ÓN„ÁNH@“&°Èb:˜1ý6p3àÒädÊ’Íɾ)ÉnF^w¾8"ÕRÞºÔ»%ÒvD‘¾Êtൠ+1ÍçY~\•d0³8ÂX/+‰i8Ë€/Èö]£d…U*JÖ6òLjUVsøÑ½JÆ5uX„úø²T¹ª-ø7i³êŸb:é¿>Ö' H@m(¦m¨y$Ðy‹*¦ÕÓO—åª T–ľ±,×\.p•˜î |aDt›Šiö{F.w,¯µI6³¾tx91}gYº;¸Ïq%1½EY ¼]Ù[ºÜ²öãeì$Ä4u¬d‰p–Ä>û=jX þMÚTL;ÿgÌJ@X(ŠéB…ÛÁJ`q,ª˜>¬ì1 UeYgö>&ÙÉ–+9è(‡&åð •JS1ÍaBY¶›ë³‚”廯ž?0;+1Mv/r˜¾<·Ê” hN¸­—Ü”’Lêõ€§Ö.HY:œvr@Ò%elD·ª+ûY“5Í!K9ˆ)‚šÓ…#¶mÄ4' ‡}<ý9¨œ.œWø¬%ÿ¦1Oóã4àžåaFö&gÏo–EOª(¦“"i=€úK@1íol™šÀ"‰iì\N¢ÍÁGïùÈF,YÓì»<x“iëå>%ã È´×€Ž#¦¿ãʉ¯9u·^*1ýÇò™,‡Í5û' Cê]@¤5ý„f‰r½<´œê›Ó„³§6²ûäwºF`󺘂” ñ å•/mÄô5À£Ë«b"òÙgšŒmýTÞôo-ø7m3ý;¬œfœ‡÷œ’Æ“*Šé¤HZ$ þPLû&…&°b:Ždþ広e¹=¦ó0.û8Åt<^^- H` (¦‹uÇ,  ˜®]7(ËbsRî'ËëHòUÅtíb²Ö-+¦kÛ—€$Ð}Ši÷cd% ÓÐ&t˶eI럀¼?ôÈeê5c:!à¨æÜ²¯9'*+Ši‚d$  tœ€bÚñÙ= H Å´7ï’@ÕiÏÔ5(¨ŠiªÞ# H`±(¦‹oG+…! ˜.L¨h ¾†hPPÓÉ.H@è8Å´ã²{@;Ši;nÞ%6–{?n%¨yUQ^?s°q›¼G€zO@1í}ˆ “@Åt1#á¨%yW튩SA€V  ˜:=$ ^PL{V5§ÞSÞ÷jÆtNh·%  Ì€€b:È6! Ìž@ÅôfÀgÂ%0uË-åÍ!H9 é.åz l@À¼PLç=‚ö_J@1ubH`vÅ´Òì1Mñð£ÙÅ–$  Ì+Åt^#g¿%  (¦N ÌŽ@%¦ƒBZõ@1],lIÀ¼PLç5rö[PLè£Ë’Ý*C:Ø-Å´#²€:L@1íppìš$О€Óöì¼S“& ˜Nš¨õI@èÅ´1uD ˜: $ЊiwbaO$  t•€bÚÕÈØ/ H`UÓUáóf L”€b:QœV& H —Ó^†ÕAI@Š©s@Ý! ˜v'öD@W (¦]Œý’€VE@1]>o–ÀD (¦Åie€zI@1íeX”$ ˜:$ЊiwbaO$  t•€bÚÕÈØ/ H`UÓUáóf L”€b:QœV& H —Ó^†ÕAI@Š©s@Ý! ˜v'öD@W (¦]Œý’€VE@1]>o–ÀD (¦Åie€zI@1íeX”$ ˜:$ЊiwbaO$  t•€bÚÕÈØ/ H`UÓUáóf L”€b:QœV& H —Ó^†ÕAI@Š©s@Ý! ˜v'öD@W (¦]Œý’€VE@1]>o–ÀD (¦Åie€zI@1íeX”$ ˜:$ГÓü~oÑáÙ H@3#p!ðË™µ6Û†ÓÙò¶5 H`FÓ¶ 4 0i1­êkд—H@裀'öjDŒbÚÓÀ:, ,:ÅtÑg€ãïi‰éåÀy]¨}‘€$0%ù;º) ˜N °ÕJ@˜ÅtZd­W㘖˜þHÝ H@}'ðàmŠißÃìø$ >PLûUÇ4¯Óyœý–€ºB@1íJ$ì‡$ 1 (¦cór L‘€b:E¸V- ,Åt!Âì % >PLûUÇ4¯Óyœý–€ºB@1íJ$ì‡$ 1 (¦cór L‘€b:E¸V- ,Åt!Âì % >PLûUÇ4¯Óyœý–€ºB@1íJ$ì‡$ 1 (¦cór L‘€b:E¸V- ,Åt!Âì % >PLûUÇ4¯Óyœý–€ºB@1íJ$ì‡$ 1 (¦cór L‘ÀZˆé5Ç7~œ œ]Æúà}µqú»q#à4 ÷}qм¬zú2'ûí€ §³Ù¦óçÍÀSJÝÿÜcÌv¦uù!À Ë|žV+Õ{JaþÚ5hütàhà°)´½ ppà[¬_1 L«’€$0K£¾`β/?(_Œoüp– Û–:B`-Äô½ÀöÀÓ¯×îäóó¸Üø0êïF%»GçÏ€íƒÈÃÍgÐÖ¢5ñjànÀ?›?~ÕBÓù³?p¿9ÓJ¶nœÛ’ÓàmO¾œ:¡úÆ©f5b:Š…b:N$®|훀}€}§ôР}ϼSÀ*Œú‚¹ŠªÇ¾U1™7ôŒÀ¬Å4¢lÌí€o6`ÙT,T5ÑKÓ‰â¼ReþxΚh:Ó ÀžPŠé„@N¸ÅtÂ@­NèÅ´q°Y‹é+ûÛ4Ä?J,ž¼¡V×ío ©{Ë’áÌRÍ_ïþP»ö+%k{à.À{Ô—¬ÔŸ½§,Mn8¬+.KFðU…ɦÀ/€—o©U´{é{–¸V%Ù½÷ÉÕËß/,éõï¾D²,ú×%3%™Õ;ÁGÑʸÖ+{î£*¯,¡Ž}¢eê~<V%{…YöBfÏÞ_7¬ ËØ"¦îÈk„øûE ªº®\£Ä&^Q~qTÖBLÃ*?2ª~$öwv3à_–¯g/õ³K}y‘¥ì‘¼ì©M‰˜fom˜Q–Œ°ÌÙÄ *‰]æshd.†éåÀeýʃ‚ˆ|d?ö1eÉûC®‹(§d ï09¬ÄîŒò &1ÿÀ»Ë²ëjž5?‘íì¥Í~óŒáE@–ï×b¹hUÿÃ?pNö*©"Éãö¿Â§˜Žù‹à债B@1íJ$ì‡fŸ1ý\ùòüO áÓªšJ°‡‰i2ƒO¶ªµ¹S‘ÍkYˆéQ@–¬U%_Àó½þY~6©¥¼gÿ¼tMÅ4ùÎ!RË•dë²LvWà„®‹åPªz¶8_ä“ËþϪüuáqÉ2õUûD“­ÎC£Êq@bñ‚!®…˜&#›}ËÉ4Ó ‘Œp¯t*q„$˘“a̪ÕCòm ‡Â]Zû0B–ìe}Iq®É—ø¿òÐá“åDÝ,­­—H\ä;Y»Œ3ëd‡•®‰iú`‡_¤>ÇdP—“ñå¦w–mç´áÁLë;‹ð&s˜2ìTÞ°ÎÒÛ<`©ïÏ%cU_"cw-™ÕÄ+˪óû?¬ŒÓú©¶ëd’ë‚ÙdþTþdÔ“å­Ê¬÷˜¶í›bºÜŒ÷s H@' ˜v<@vo¡ÌZL³”6_ìsøQ“2 1Í—þ,wÌá•ÊZˆiú“%ˆ;”åÁÙCøé²¯êë8bº3ð…±Ê²ËˆéW¸.KBßX–+7‰S–æ&»—/èùé©gõRG–Tg¿hÆ“ÌaNø|ëÊ»(¦y€‘C»²ì4.’Al[–Óˆn¸eßfÊ01Mf:{†³d7ÿ[•QbñÊÕÜÞ‘Úœ&ýº)Ši“ù“åËéW2Ò]Ó&ý¯Ç^1÷7Áë%  t„€bÚ‘@Ø ¬ÁáGYqЏd™ì¨2 1ÍrÔ——}É*.WÆÓì1M­ž=5–&?OV+ψc%J‰ðå`™,c­J>Kæ³~øQd%{örhÍr%‡6å £d¬“]®$ šý¶‰W]F!Yè0Ž|&3º\ÉrãìÝMo°¬$¦Õ²Ñú’íê³ì3êþå]»y¿j2¿™¿Y†=n‰g™j–òfùkJöfv–®V™ùˆé ÿì_NIÖ?ŸgÔíÊÞÜ쯮UïWòÊœÊÙd¼S²,9ý˜VÆ´ÉüÉ\̲òüŽÿwE²­ÙÃÛf)ï(Ã^3,cÚ¤ÿuƊ鸿 ^/ H #ÓŽÂnH` Ä4Ðó¥/Ëþ’1Ëi± ,=­dPê©Ä4_ÞS–Ëò­´Ç4’ ÎÁ2‘ÔE–¾æ˜ðS•qÄ4Ë1Óß{–1DŠª6Æ™X‘†œP›“TshPN Îg¯ªD8òe=29Jv5‡åߺ˜F³ç1'éf¯ìÿ•u²2+U%{ ³dôŸKv6â™YsR%¡ÙC6‘׈XîO–-üsàMU²$4K|³W0™¯ˆW¤"Ÿg\UÉÞÔðŠ%»šåËY²9L¢WÓÔ—ñ$ÛWH”ºr¢ðJb:jþäTÞdð²´zØáAi7s'í&ÎĺIܫò¤9'Jg©ô¿”þ~”‹çŽ”,i¤8(ràT½ä¿©ášll²ÜÙ›šeë‘Ý”œªœ9Ÿ}Ö9Ý8ãÌ¿G ó ¡ßz«]ÊÛtþdÏn~ÿ#Ê™Gá›ùÿ¼–b:ŠES1mÚÿŠ™bÚdö{$ PL;»´°f½”7 óe8_®#GÉ8þ´dt"Tƒ¯z©Ä´ PöÙÕO¬­>_ILsMD4§¼&Ó˜ÌQ²z‘¸œŒZ•qÄ4÷$£“/Ô‘µÿòú&“*¯ÇÈ©¯‘̈d²Œa38Æ”SZÓïìÍÌ!B³Á×ÅDÐr$6k#'9u4§¬V%ŸG²rân$1ûA#¼9]5™·ªDô’iNÖ4B•ý9%6K«’yóYö[¦žH[ä:¯#©JîÍòä,‡ÍrÞHxØG¸ê{X«ëG‰i–‚‡}2ÊyuOâš…WÓQó'bZ\-—Œ_Xg®†çà«QšÄºº&ÙÒd>óº˜,ãÎ ‚, ÎI±UÉÏóà$¿‰U®DL#òÃöµæ•1yS²ÇYª›ŒtöüV%!òJ”k/åAA¤0Ë’ËjÅ4õ5™?Y–Yâ™KO_æDঌWbÑTL›ö¿ê“bÚ4:^' H cÓŽÄî,4µÓ…îàç–@öEç@ŽÔÒšÛÙñ‰PL'†ÒŠ$  Ì–€b:[Þ¶&•(¦Î ¬L K˜s‚q²¼É6fɬEuŠ©óAÀœPLç4pv»—Ó^†ÕAMˆ@µ6ûóŠ›ìÍ\é5;jÖj挀b:g³»€*Š©sAÝ! ˜v'öD˜OŠé|ÆÍ^K@X:£+%‡-äð•åTéJ?퇦E@1Yë•€…€bº(‘vœ@ï(¦½ ©šcŠéÏ®K@  ˜v" vBÀøÓñ™y‡¦E@1Yë•€…€bº(‘vœ@ï(¦½ ©šcŠéÏ®K@  ˜v" vBÀøÓñ™y‡¦E@1Ùþ×{p¯2Ìü]_oàÄÚÇï-?¿¼†ã|àßýìóOù[àlàÀƒÊg×~ü¸å˜8nüî#óR IDAT¸“b:ÝIZ«]1m‡ÚŒi;nÞ% H`Í (¦k; +tYL < ¸5,½f*K=ï\R‹_úÿš’ËRÒ§?ˆq–…<¸qYÎ÷òô¿~éEÀ£dsíï€'³ÍduÞ1džm |wJóïêÀ G•×`] |xÒ@{›¯î äžÏÏ\åÒÆ&Óº˜&#÷?CÄ4× <øðàÀ ˆi2³ÇÉú¼r€Ç~elœ <£ÈruY–½Ì«ê³­/—~e)Mù æxúúlà%Ëœ%Ñ‘õd’³|ú²RÉ7JFþmµJ#öüd«²=ð²Â;¿ YByrzíšdõ÷èÜÊ\ÕçúÏÇé~óûú@àæå÷öµÀáµ óùÿé@æu}ܹäïËï@Æ»>ð= KÊ«”J¼ïD&3o <™ßצãVL›’ò: H@# ˜v, vg¡ tULïZ²k‘Ã,ÿÌ—Ìj2õòÁòe3K̲w,’º°CíË{„á ¥ŽØ×€ë›©×1ÍÈ|1~kùRž}Ž¿®]Ô¤ÍüKŸóÅÿPà˜rÿ§8Û"p‘ùì«Ìþ¹¿n0 œ×¾Z$?â“e´‘¿aøf)m›2Ž˜F²0™ÐÛ—Ö–ò^ø"†Y›qDÎV³Çô>e¯k– ¾o`p{Ï)ò’yñ˜"Æ·~X®ÍƒŠ77)¼òqÄþÀ.µúšðoÂ6bäÈùieésöäþ¸pJ©¨‰˜nXöêFLßäE–S¿HYÕ§<عnÉR‡w~žLw%ÁMúžkÆé–mï |¼üþ>¬ô1õúïz~‡_W~×#)éW}ïrö&çaÓ‹K¼ó;›ù•¸æ÷:¥Ó<äÊCœ<ÈÚ«<´Êƒ‰êº¦c­®SLÇ%æõ€:B@1íH ì†ÊžÀÈH¾m<"•è& ±Ü~Ã&ÍDH“!ÊÔˆá°M&ëF倜\“}‹Ô|Iýl¹)b‘=ÉVfRë ‡dÔþe•mV·Ïr)odú¯K¨žU®%Y²Ha²¦Õ—ð|éÿð¯Eì›Ägðš&bš9™È¼ø"ð”š4WKy#¦ÿ¼ ˆæÃjÄôÓeL™O‘½Á’ äÓ€Ž˜ædã²U}G>{×ÀáGƒíf¹k²”ÙË]/yÈ“Œõjé§ÿ‘Ñü窔ÌÅ,§ÍïËà\Ì>ß<¨Z.«ŸƒŽ>5ä@³úøÓ&3pø5Ši{vÞ) t˜€bÚáàØµ…#ÐU1Íò¾ÛÍAY¢)È’Ì×¢”wgf‰n>Ï!IÙ˜Só…·*×,Ù®ü,àDns0еCdªkG‰i®kÒfU_%Bù2—rQNM,9´%¼;·8l¦ª+YÇìÌ~ÑŒ5šCzòyNa­¾øg gNÎ^Å<”ý´9 hV‡ û%›FÆ´Ó´—\³4§¶þw­O,¢ž‡Éginö¶†a=s›[rPRà‰ø ]~Þ„“?0ãˆ]õîØ‡”˜çDãdB“!®ŸÊ9Ï!JYŒnd<¿ù}¨—ü÷9×$³ž=Þ9œ(‡%åÁEÓ2Nÿÿ­ì‹N|"Y¶ßûˆvkª—œÐ xêÿ=pÇßó<€Éç08 ø¿2§³¸Ú§®˜6âU¯SLÛ³óN H ÃÓÇ®-®ŠiNÓŒ($s“¿…œn›WZÔKö‡eÏ]–Ø& ˜/ÕùÂ/êõ}ŒѼ.æËaIùÒšWÀ î=l"¦MÛL?³L4Ù«Hg²µÉVæ ÿ`ÉɸùRž/ÎmOÆÍþ×|™ÏÞÇŒ=•1ÿç@cáiÉëb’5̉ÅY–š“JÛ–.gL«1½¢,o¾ËÀ+{’I}^í„àœœW žØä¡œâ:ìU@Mùb<ŽØE³ì5™Äds€Ud³þº˜d!sT–#g9o^“ŸgÎåÁÄ`É+c²Ç3‡¡åÀ¥dW³g¹i§ÿ™‹ù=Ï2ýd<Ó§dr#ž9«^ò°*‡Tå¡@~óð)¿÷õ’,99íü݈P'^Õà Ŵi¯zbÚžwJ@& ˜v88vmátUL-Ynœ/Üùmé&<,É©¶9ä(YD‹*~ä\€$0§Ó9 œÝî%Å´aÍÞÿx/c7zf/n^–W'˘÷mf™«EuŠ©óAÀœPLç4pv»—Ó^†ÕAMˆ@µg7{ƒóŠ•¼ó4ïbµH@1uH@èÅ´At½! ˜ö&”DX#fL×¼ÍJ@X-Åtµ½_“# ˜NŽ¥5I@‹I@1]̸;j H ÓÑ!ô†€bÚ›P: H`(¦kÞf%  ¬–€bºZ‚Þ/ÉPL'ÇÒš$ Å$ ˜.fܵ$Њi‚èzC@1íM(ˆ$°FÓ5o³€VK@1]-Aï—Àä(¦“c9‰š6.n|k®a lüÈÿ?w ýy0ðfà†S¨Û*%Є€bÚ„’×H@è Å´ƒA±K K@1mè+ñ¼Å2’6 1¸ä}œ³,ÿ |x)ñ~µå{ZG1SLgUÛF@1u^H@˜SŠéœÎn÷’€b:Û°Ž’¬>‰é/€=O®ñ(fŠé*{ûª (¦«Fh€Ö†€bº6ÜmUÃ(¦³›GQ«·ø#঵* »;/»‘®ßÏÞQ»nà©ÀÃ˲ßKOòïUÉÒÙ,¥­—÷i1ìk®œ¼8n ®Ë—©»Íßþ&Ì*1½?ð:àÎÀÿNèË~À¾ÀfÀ™À3€3Z°È-áð,àÖ@Æv6p7à’m>»ÄúåÀJvû¿€{”,sþ÷Dà&ÀÏjõøÍÀ¼Êïôk€ÝõÊ}™õûREâö•rÆqmà0`ÿ–<ù6Åt‘£ïØ% ¹&ÐæËÉ´üƒò¥ðfÀ§ÕˆõJ ÃÓÙ'’p] ™Ä[ß/ÒqÙ1ä¼°HÅ^ÀAE¦.*×®_âÀ÷€m•e³o¬Õ—ëv^_ÚÌþTþwäoîZ$(â÷¨"‚‘±,Û­Ê_•‰?ø|ùÿ÷¸¥ ³ˆéû/ÏÎÞl ì\kpoà9¥O_+rѾm‹¿ÿáp<ðPà$ œ#¨½ziÚfÄô™E¨óÀ!ì²ôú¥²üw3ã:´ü“ópà|àÞ5Æùüƒ@pìSö+GR·vês-bš±'>á–²á”ö÷y»^1·ˆÙ_ H@µÿÀv†bÚ•Hص" ˜Î–ü¨e©ÕÏwN-]«>»ðõº{x‘•dòêe{Lóð.²ÑûÏZåÇü‡!ýŠD§íÏ®ñ(fi#Ùä¿+må³£Jߪæ<­ˆ[õÙçŠÐ¾`Ì>FHó ~²Â½MÛŒ˜Fš#Š¿\¦¾ôñAÀÊÏ#°ÉoY»>š9r#à§åód×s Vî­Ç"bzMà¾-÷þމ¬×—+¦½¯ƒ“€úLÀŒiŸ£ëØæ€b:Ûˆ’¬a{L¯üØ8½ÖÝk÷¶)ÙµÈl²§˜‚˜f™ì±@–ó&ãZ•,—}ÙÀräêg³ÓÁSyw)äÌZN¾p ÿa˜q%û;NÉ}oVÄö ’ž fUÆi³ZÊ›ìór%K¾óp òùmààãÀ+k7ä¡D–jgyo½DN“‘ §ªTKyÇ•òq8-ʵŠé¢DÚqJ@½# ˜ö.¤hŽ (¦³ Þ¤Ä4{ ³3"še¬ÕÒÚd §%¦Y*œ¥žu1ý'à%@2ªƒ¥KbšSÃh»²·tRQ¿>°kYœ¥²ÙüåRù8m6ÓT›åÃÙ7›½·yÐæ2œ9ù: ¨˜6€ÔðÅ´!(/“€$Ð5Ši×"b™€b:ÛèG~U–_~wHÓM3¦–Ãm²”´*ÙW™C}Å4{L³Ì·~ÈÒ¸£®–òæ]¤ÕžÑÔñ^à/‡´™ŸMJLG1v*ï`Æ4{U“1 £°›FIÖ4íT•2N›MÅ4ÚW•ìl2åYž[/ɦf_j–ç~fÄ ÓÉÍÅtr,­IÀL (¦3ÅmcX‘€b:Û ’¿¿.r‘=Š\\¶IOšŠiöæàžìuÌžÄ'•ýœ94é^CJ–0Y¶{–l^„&'ÑfYë8%‡%#¸©Îɾ¯-"Õ?ªêœ”˜ŽbÖDLÓ§'Gq̲ۜž›=ß)RÃ"‡Xݾˆè€÷•“’?\«¨i›MÅ4{B#ØYšþY†¤v8TîGLóZ ˆnj¬tØÓ(n}ý¹bÚ×È:. H ÷ÓÞ‡ØÎÅtŽ‚eW% NPL;;% H`4Åt4#¯À¬(¦³"m;@_ (¦}¬ã’€zO@1í}ˆàPLç(XvUè$Å´“a±S€FPLG3ò ÌŠ€b:+Ò¶# ô•€bÚ×È:. H ÷ÓÞ‡ØÎÅtŽ‚eW% NPL;;% H`4Åt4#¯À¬(¦³"m;@_ (¦}¬ã’€zO@1í}ˆàPLç(XvUè$Å´“a±S€FPLG3ò ÌŠÀ´Äô2àÄY Âv$  ¬!¼S6ï¶= xâöcšM¿ ØØÈ{‘-€zA@1íEDOLKL{‚ÇaH@hL@1mŒÊ %  tƒ€bÚ8Ø „À¤Åt}àÞ¢•€$°€~œÕÓq›1íi`–€bºè3Àñw‰À¤Å´Kc³/€$0Šéd8Z‹$Ð1ŠiÇbwš€bºÐáwð€PLaò" H`Þ(¦ó1ûÛgŠiŸ£ëØ$  L†€b:ŽÖ" tŒ€bÚ±€Ø…& ˜.tø¼$ FÓF˜¼H˜7Šé¼EÌþö™€bÚçè:6 H@“! ˜N†£µH@# ˜v, vg¡ (¦ ~/ H Å´&/’€æ€b:o³¿}& ˜ö9ºŽMÀd(¦“áh-@Ç(¦ ˆÝYhŠéB‡ßÁK@hD@1m„É‹$ y# ˜Î[ÄìoŸ (¦}Ž®c“€$0Šéd8Z‹$Ð1ŠiÇbwš€bºÐáwð€PLaò" H`Þ(¦ó1ûÛgŠiŸ£ëØ$  L†€b:ŽÖ" tŒ€bÚ±€Ø…& ˜.tø¼$ FÓF˜¼H˜7Šé¼EÌþö™€bÚçè:6 H@“! ˜N†£µH@# ˜v, vg¡ (¦ ~/ H Å´&/’€æ€b:o³¿}& ˜ö9ºŽMÀd(¦“áh-@Ç(¦ ˆÝYhŠéB‡ßÁK@hD@1m„É‹$ y# ˜Î[ÄìoŸ (¦}Ž®c“€$0Šéd8Z‹$Ð1MÅôøôûîÀµ€“K¦ÜÞ3€oM¹ «ï Ëa#à#ì¿‚õ¯ »l—] Ÿíbß_ ÜѾÙ- H@“"°7ðÀIU6áznlœ œ7áº'UÝ¿ÇNª2ë‘€ƒ@S1½¼g8vNíÙ˜N—Ã_¿npéš\’§2ë;­IëýÝÕÖɽE@Ÿ <µÏœòØþ8tÊmX½$Ð3ãŠéýç|üoþPLçöN˜4VbúèGóž·¾5üñp ð°‡Mºk]®O1írt웺Nàj ;X}Ãnz}½ÚM€ €íÓ‡´1Œ¾Ø xð``àœr}Ät7à-@þê¥äg7ž¤˜6Œ¢—ÑVLõ¨GqÚi§q衇²õÖ[óóŸÿœOúÓäóÍ7ßüJdO=õTvÜqGF‰i%»OyÊS¸Ñn4õè|ìcãÏxçž{îøm)¦ã3ó H`ž Œ-¦»ïo;<ñ‰pòɰÁ°ÙfpÆóŒaܾ+¦ãóz HàÏšŠæ´Å4ÙËýK·®ü8x]ML“u½+°E‘Ü×7.ÙU3¦ÎêFÚˆiDó.w¹ ßøÆ7¸ímo;²¦b:²¢ _ ˜N¨ÕI@}&0¶˜¾÷½ð›ßÀ^{õ˨±)¦£ùs H`y]ÓôöûÀ¡bú àæ%kºkɲ ˜:½Ç!ÐFL÷ßN8á¾üå$öG—QbzÈ!‡ðÌg>󊊾þõ¯s»ÛÝî*ŸsÎ9KΓO>™M7Ý”=ö؃ƒ:ˆk\ãW\{Ç;Þq)kû£ýˆSN9…ÿøÇ<øÁæðÿR}7¿ùÍùþ÷ókõçòèG?ziir£bÆ´&/’€zC`l1}Ýëà>÷ìÌøõ¯—çð¯y $úÞzpâ‰ðô§ÃÏ~vå{Ž;¾ò•u²›åÁ×¾6vì_ãßãëî½ÉM®|ïG?ºîž=÷üs}[n ‡¹ç—¿„w½ :þð‡ñÚ]Åt4#¯€–#Ð51Í7.KyÏ.ÏRÞˆé-{M“ºúŠbêä‡@1Ým·ÝØpà —ö‚6)£Ä4K|/»ì2~ûÛß²É&›0LL/¾øâ¥½«»ï¾;Ï}îs¹à‚ ˆHî¼óμá o¸’˜FF>úhvÝu×%AÝrË-9î¸ã¸ç=ïyÅuiïØce¿ýöã»ßýîÒçë­·ÞÒ?ŠbÚ“I@½!0¶˜nº)|ö³pýëë^G_|Uü l² ì³\pÁ:IÝj+Øa¸¬vGÄ4‹t>ÿyxÞóÖÕ³á†PíÆ¸ÚÕàœsàÐC×ý“r½ëÁùçýï½î¾”6‚³Ï†}^ýj¸îuá=ïY÷óÚ3Ò¥kGµ9:ºŠéhF^! ,G +bš‰~ü pÏÈßÇZ§+1}p>pb9 )׿ ¤†i<ühÁÚˆé½îu/¶Øb ÞžÍC Ê(1­ª¸è¢‹Øx㇊i2žGqguÖ-~á _X’Í /¼k]ëZKŸ'cú„'<}÷Ý÷Šë¶Ûn;÷¸Ç]é³üÐ¥¼ ‚ç%€Ö[LsS´ä¤ˆdðqƒãÿ3Òè׿9Và§Ù´Äº½¨Ô=hØV%’xÍkÂ}ï Ë¥÷‚¬»ïNwZw×SŸ ûíÉVeï½áiO['¿UÙi'8é$Øxcø}¾}•Ҥ͕'ˆbê/$О@WÄ4™ÑW9•7ÿ –JL÷)òšÅ'—‰ULÛÇáîl#¦É˜n°Á|àhÄkbš‘ÞñŽw°Qu—’Lë%—\™gžyÅ^׈é^{íµôOUrÂo–ó>ûÙϾRÓFáó" H@!ÐJL+t믷¿=|ï{ë~’ƒÛ“­ÌRÛz‰œ&{ùæ7ÿùÓj)oäs¹rÓ›®Ë F:¿ým8åøøÇᕯüóG ü•³·É¶¦Ím·…o~s¼6WžŠ©¿>@{]ÓúáGÃFSÓúÏ͘¶ýBÞÙFL³”öSŸúÔÒáGMÊ$ÄtÏ=÷\Z¾ûñ|ÃX¡(¦M"â5€Æ&°*1­ZûÖ·àMo‚jÛ1{=¯sÑýi"¦©%ÙÓNƒ£†´—ƒâ³œ·*ï|çºìm2«£JÓ6—¯G1ÅØŸK@ËPL E ˜~ñ‹_d§vâôÓO'ËdG•Iˆi–ò>ÿùÏç;ßùÎÒ;S—+ãˆiö˜î½÷ÞKïa»¸ÇtldÞ  Ì5U‹i¶ðç̹½ÞñŽu,’ÙÌ3Î,ÏýÌgVæÓTóžÔìi=æØf›« h–ò¾üåp«[]õ€¥Á4mS1ë¹mç%ÐYŠigCcǦA ˜¦}èC—ÞczØa‡±Í6Û,~›¥±Ûo¿ýÒ²Ùz©Äôå¸Ã«_=o@ºjYiiFŠgj$u«­¶Zzwêù矿ôŽÔªŒ#¦gœqÆRO:餥1ä”᪑¬Ó‘ˆ¼@è±Åtç×íÙÌ{Kó¿ÙgzÿûC]ÏÒªä0ô]vY·4ûæ1pì±WŽCNóMŸ.¼"©9º 4eŸë—ròF­4mS1íÕ\w0è Å´3¡°#³ ÐVL³·óàƒ^z½J2Ž7¸Á È^Î<ð*¯z©Ä´Ï~ðnš@e%1Í¥Ñ8€O|âKËz“9}Ä#Ák_›Wø®+ãˆi®ßgŸ}8æ˜cˆ,ï°Ãyä‘lžu_£Šb:Š?—€úE`l1}Ä#à…/„[ÜbÝëbò*—ì=ï¼+ƒÉ³Ê¼ò%Ëzóç7מ~:<ä!?µUGßøFxøÃ!ÿ©ù㯈ˆè+^|àºe½y5Mš8Š`éTÞ¼¢f¥£ÐÎÎ%IDAT}­+‡Ù¥¼ýú5p4˜-YˆélG´rkžÊÛ¥h¬A_ÚŠétµ[M*¦ÝЇ½‘€¦M`l1v‡æ£~Åt>âd/%ÐMŠi7ãb¯¦D@1m V1m ÎÛ$ 9% ˜¶ œbÚ ›7I@KS'ÂBPL[†[1m ÎÛ$ 9% ˜¶ œbÚ ›7I@Š©s`ñ(¦-c®˜¶çmÀœPL[N1m…Í›$ ÅÔ9°xÓ–1WL[‚ó6 H`N (¦­§˜¶ÂæM€bêX<Ši˘+¦-Áy›$0§ÓVSL[aó& H@1u,Å´eÌÓ–à¼M˜SŠi«À)¦­°y“$ ˜:€bÚ2æŠiKpÞ& Ì)Å´UàÓVؼIPL‹G@1msÅ´%8o“€攀bÚ*pŠi+lÞ$ (¦ÎÅ# ˜¶Œ¹bÚœ·I@sJ@1m8Å´6o’€SçÀâPL[Æ\1m ÎÛ$ 9% ˜¶ œbÚ ›7I@Š©s`ñ(¦-c®˜¶çmÀœPL[N1m…Í›$ Vbzüœs»3° °#pêœÅî· p…˜^ýê°Ë.-jXÐ[.» N<1ƒÿÝÕ`£¥à°% Å!PÄô¶Àæ‹3êUôlàû©å C]u•V  , «5éå ¯›—ËÓy‰Ô„ûy…˜N¸ÞªN1] `;T ,0"¦ L`uCWLWÇÏ»%°šŠéýzFçKÀ¯{6&‡Ó€Àå°>pï—zÉp—] –R§ H@=&`ªtuÁý&pÞêªðn H`Ñ4ÓEãâx%  H@€$  H`FÓ¶ H@€$  H@N@1ufH@€$  H@ÀšPL׿K@€$  H@€bê€$  H@€$ 5% ˜®)~—€$  H@€$ ÅÔ9  H@€$  H@kJ@1]Sü6. H@€$  H@Š©s@€$  H@€Ö”€bº¦øm\€$  H@€Sç€$  H@€$  ¬)ÅtMñÛ¸$  H@€$  (¦Î H@€$  H@XSŠéšâ·q H@€$  H@PL€$  H@€$°¦Ó5Åoã€$  H@€$ ˜:$  H@€$  H`M (¦kŠßÆ%  H@€$  Hàÿ™zˆñAIEND®B`‚go-attestation-0.5.1/docs/event-log-disclosure.md000066400000000000000000000176441452320553600220240ustar00rootroot00000000000000# Verifying TPM Boot Events and Untrusted Metadata This is a disclosure of a vulnerability report sent to the Trusted Computing Group. ## TPM boot logs TPMs are cryptographic hardware that, among other things, can be used to verify the boot state of a machine; that a machine booted a specific OS, enabled specific BIOS settings, and hasn’t had its bootchain tampered with. As a machine boots it records events, such as the bootloader hash and secure boot keys, in a structure called the Event Log. When an event is written to the log, its digest is also written to rolling hashes in the TPM called PCRs. PCR values can be attested remotely by the TPM and used to verify the log by replaying the log’s digests. If the replay matches the PCRs’ values the log hasn’t been tampered with. An Event Log is a series of events using the following format (the TPM 2.0 format is slightly different but functionally the same): ``` typedef struct tdTCG_PCR_EVENT { TCG_PCRINDEX PCRIndex; // PCRIndex event extended to TCG_EVENTTYPE EventType; // Type of event (see EFI specs) TCG_DIGEST Digest; // Value extended into PCRIndex UINT32 EventSize; // Size of the event data UINT8 Event[EventSize]; // The event data } TCG_PCR_EVENT; typedef UINT32 TCG_PCRINDEX; typedef UINT32 TCG_EVENTTYPE; typedef UINT8 TCG_DIGEST[20]; ``` \- [_TCG EFI Protocol Specification 5.1_][efi-spec-5_1] PCRIndex indicates which PCR was extended. The Digest is the value written to the PCR and is a hash of the Event.* EventType indicates what kind of data is being conveyed. * Except when the Digest is the value being communicated (the bootloader hash) or a hash of part of the event (some UEFI variables). [efi-spec-5_1]: https://trustedcomputinggroup.org/wp-content/uploads/EFI-Protocol-Specification-rev13-160330final.pdf#page=15 ## Event type and verification footguns To verify a machine’s state, it might seem reasonable to parse the Event Log, replay the Digests against the PCRs to verify it hasn’t been tampered with, then parse data from the log to get things like a machine’s secure boot settings. This is wrong. Replaying an Event Log only verifies a subset of the fields in an Event. Specifically, it only guarantees PCRIndex, Digest, and sometimes the event data, but __the EventType isn’t part of the Digest and can be freely modified by an attacker.__ Consider the following event log for secure boot entries (PCR[7]): ``` PCRIndex=7 EventType=EV_EFI_VARIABLE_DRIVER_CONFIG EventSize=53 PCRIndex=7 EventType=EV_EFI_VARIABLE_DRIVER_CONFIG EventSize=842 PCRIndex=7 EventType=EV_EFI_VARIABLE_DRIVER_CONFIG EventSize=1598 PCRIndex=7 EventType=EV_EFI_VARIABLE_DRIVER_CONFIG EventSize=4744 PCRIndex=7 EventType=EV_EFI_VARIABLE_DRIVER_CONFIG EventSize=3762 PCRIndex=7 EventType=EV_SEPARATOR EventSize=4 PCRIndex=7 EventType=EV_EFI_VARIABLE_AUTHORITY EventSize=1573 ``` To determine the secure boot state of a device, a parser might reasonably implement the following logic after verifying an event log: ``` for (event in events) { switch (event.type) { case EV_EFI_VARIABLE_AUTHORITY: // Parse EFI variable for secure boot state // ... case EV_EFI_VARIABLE_DRIVER_CONFIG: // ... case EV_SEPARATOR: // ... case /* more cases */: // ... default: // Ignore unknown event types continue; } } ``` Because of the “default†condition, an attacker can change all existing event log types to a type the parser doesn’t interpret, for example the reserved type EV_UNUSED, then append their own events and extend the PCRs: ```diff -PCRIndex=7 EventType=EV_EFI_VARIABLE_DRIVER_CONFIG EventSize=53 -PCRIndex=7 EventType=EV_EFI_VARIABLE_DRIVER_CONFIG EventSize=842 -PCRIndex=7 EventType=EV_EFI_VARIABLE_DRIVER_CONFIG EventSize=1598 -PCRIndex=7 EventType=EV_EFI_VARIABLE_DRIVER_CONFIG EventSize=4744 -PCRIndex=7 EventType=EV_EFI_VARIABLE_DRIVER_CONFIG EventSize=3762 -PCRIndex=7 EventType=EV_SEPARATOR EventSize=4 -PCRIndex=7 EventType=EV_EFI_VARIABLE_AUTHORITY EventSize=1573 +PCRIndex=7 EventType=EV_UNUSED EventSize=53 +PCRIndex=7 EventType=EV_UNUSED EventSize=842 +PCRIndex=7 EventType=EV_UNUSED EventSize=1598 +PCRIndex=7 EventType=EV_UNUSED EventSize=4744 +PCRIndex=7 EventType=EV_UNUSED EventSize=3762 +PCRIndex=7 EventType=EV_UNUSED EventSize=4 +PCRIndex=7 EventType=EV_UNUSED EventSize=1573 +PCRIndex=7 EventType=EV_EFI_VARIABLE_DRIVER_CONFIG EventSize=53 +PCRIndex=7 EventType=EV_EFI_VARIABLE_DRIVER_CONFIG EventSize=842 +PCRIndex=7 EventType=EV_EFI_VARIABLE_DRIVER_CONFIG EventSize=1598 +PCRIndex=7 EventType=EV_EFI_VARIABLE_DRIVER_CONFIG EventSize=4744 +PCRIndex=7 EventType=EV_EFI_VARIABLE_DRIVER_CONFIG EventSize=3762 +PCRIndex=7 EventType=EV_SEPARATOR EventSize=4 +PCRIndex=7 EventType=EV_EFI_VARIABLE_AUTHORITY EventSize=1573 ``` The PCR replay and TPM quote will match this event log, but the parser will skip over the legitimate values and use attacker supplied ones. Even if the parser exhaustively matches event types, an attacker can masquerade a required event as an optional one in hopes the parser will no-op. For example, consider the following bootloader entries (PCR [4]): ``` PCRIndex=4 EventType=EV_SEPARATOR EventSize=4 PCRIndex=4 EventType=EV_EFI_BOOT_SERVICES_APPLICATION EventSize=158 ``` In this case, an attacker can change the bootloader hash event type to an optional event type, then append their own hash. This is especially hard to detect because the Digest of EV_EFI_PLATFORM_FIRMWARE_BLOB and EV_EFI_BOOT_SERVICES_APPLICATION event types aren’t a hash of their event data, so an attacker can also modify the data to match the parser’s expectations too: ```diff PCRIndex=4 EventType=EV_SEPARATOR EventSize=4 -PCRIndex=4 EventType=EV_EFI_BOOT_SERVICES_APPLICATION EventSize=158 +PCRIndex=4 EventType=EV_EFI_PLATFORM_FIRMWARE_BLOB EventSize=124 +PCRIndex=4 EventType=EV_EFI_BOOT_SERVICES_APPLICATION EventSize=158 ``` ## Vulnerability report and outcome This issue was reported to the Trusted Computing Group on September 6th and eventually triaged by their Vulnerability Response Team. At the time of the report, there was no conical recommendations for how to verify an Event Log and there was no warning in the [Event Log spec][spec-event-logging] that fields are untrusted. The TCG noted that event data is meant for debugging, and that event digests (the values written to the PCRs) are the only fields that should be used for trust decisions. The TCG confirmed that guidance for verifying the Event Log is being drafted. Updated specifications, including a new document, the TCG Firmware Integrity Measurement Specification, have been [released for public review][spec-public-review].The guidance document will be available soon at the same location. The full 90-day disclosure deadline was requested to determine if other TCG members were vulnerable to this issue. This issue is a nice reminder that mixing trusted and untrusted data is a recipe for [implementation][saml-sig-wrapping] [vulnerabilities][jwt-header-none]. We plan to update our open source project [go-attestation][go-attestation] to better help users identify what can be used for trust decisions and what’s reserved for debugging. A special thanks to Amy Nelson, the PC Client Workgroup Chair, for being our point of contact through this process. [spec-event-logging]: https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClientSpecPlat_TPM_2p0_1p04_pub.pdf#page=90 [spec-event-logging-draft]: https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClient_PFP_r1p05_05_3feb20.pdf#page=89 [spec-public-review]: https://trustedcomputinggroup.org/specifications-public-review/ [saml-sig-wrapping]: https://www.usenix.org/system/files/conference/usenixsecurity12/sec12-final91-8-23-12.pdf [jwt-header-none]: https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/ [go-attestation]: https://github.com/google/go-attestation go-attestation-0.5.1/go.mod000066400000000000000000000005331452320553600155730ustar00rootroot00000000000000module github.com/google/go-attestation go 1.20 require ( github.com/google/go-cmp v0.6.0 github.com/google/go-tpm v0.9.0 github.com/google/go-tpm-tools v0.4.2 github.com/google/go-tspi v0.3.0 golang.org/x/sys v0.14.0 ) require ( github.com/google/certificate-transparency-go v1.1.2 // indirect golang.org/x/crypto v0.13.0 // indirect ) go-attestation-0.5.1/go.sum000066400000000000000000003602731452320553600156320ustar00rootroot00000000000000bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= bitbucket.org/creachadair/shell v0.0.6/go.mod h1:8Qqi/cYk7vPnsOePHroKXDJYmb5x7ENhtiFtfZq8K+M= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= cloud.google.com/go v0.92.2/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go v0.92.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/monitoring v0.1.0/go.mod h1:Hpm3XfzJv+UTiXzCG5Ffp0wijzHTC7Cv4eR7o3x/fEE= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/spanner v1.17.0/go.mod h1:+17t2ixFwRG4lWRwE+5kipDR9Ef07Jkmc8z0IbMDKUs= cloud.google.com/go/spanner v1.18.0/go.mod h1:LvAjUXPeJRGNuGpikMULjhLj/t9cRvdc+fxRoLiugXA= cloud.google.com/go/spanner v1.25.0/go.mod h1:kQUft3x355hzzaeFbObjsvkzZDgpDkesp3v75WBnI8w= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/trace v0.1.0/go.mod h1:wxEwsoeRVPbeSkt7ZC9nWCgmoKQRAoySN7XHW2AmI7g= code.gitea.io/sdk/gitea v0.11.3/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0= contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw= contrib.go.opencensus.io/exporter/stackdriver v0.13.5/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= contrib.go.opencensus.io/exporter/stackdriver v0.13.8/go.mod h1:huNtlWx75MwO7qMs0KrMxPZXzNNWebav1Sq/pm02JdQ= contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0= github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0= github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= github.com/apache/beam v2.28.0+incompatible/go.mod h1:/8NX3Qi8vGstDLLaeaU7+lzVEu/ACaQhYjeefzQ0y1o= github.com/apache/beam v2.32.0+incompatible/go.mod h1:/8NX3Qi8vGstDLLaeaU7+lzVEu/ACaQhYjeefzQ0y1o= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ= github.com/apex/logs v0.0.4/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.19.45/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.25.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw= github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.3.0-java/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/gofail v0.0.0-20190801230047-ad7f989257ca/go.mod h1:49H/RkXP8pKaZy4h0d+NW16rSLhyVBt4o6VLJbmOqDE= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fullstorydev/grpcurl v1.8.0/go.mod h1:Mn2jWbdMrQGJQ8UD62uNyMumT2acsZUCkZIqFxsQf1o= github.com/fullstorydev/grpcurl v1.8.1/go.mod h1:3BWhvHZwNO7iLXaQlojdg5NA6SxUDePli4ecpK1N7gw= github.com/fullstorydev/grpcurl v1.8.2/go.mod h1:YvWNT3xRp2KIRuvCphFodG0fKkMXwaxA9CJgKCcyzUQ= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/certificate-transparency-go v1.1.2-0.20210422104406-9f33727a7a18/go.mod h1:6CKh9dscIRoqc2kC6YUFICHZMT9NrClyPrRVFrdw1QQ= github.com/google/certificate-transparency-go v1.1.2-0.20210512142713-bed466244fa6/go.mod h1:aF2dp7Dh81mY8Y/zpzyXps4fQW5zQbDu2CxfpJB6NkI= github.com/google/certificate-transparency-go v1.1.2 h1:4hE0GEId6NAW28dFpC+LrRGwQX5dtmXQGDbg8+/MZOM= github.com/google/certificate-transparency-go v1.1.2/go.mod h1:3OL+HKDqHPUfdKrHVQxO6T8nDLO0HF7LRTlkIWXaWvQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM= github.com/google/go-licenses v0.0.0-20210329231322-ce1d9163b77d/go.mod h1:+TYOmkVoJOpwnS0wfdsJCV9CoD5nJYsHoFk/0CrTK4M= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no= github.com/google/go-sev-guest v0.9.3 h1:GOJ+EipURdeWFl/YYdgcCxyPeMgQUWlI056iFkBD8UU= github.com/google/go-tdx-guest v0.2.3-0.20231011100059-4cf02bed9d33 h1:lRlUusuieEuqljjihCXb+Mr73VNitOYPJYWXzJKtBWs= github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= github.com/google/go-tpm-tools v0.4.2 h1:iyaCPKt2N5Rd0yz0G8ANa022SgCNZkMpp+db6QELtvI= github.com/google/go-tpm-tools v0.4.2/go.mod h1:fGUDZu4tw3V4hUVuFHmiYgRd0c58/IXivn9v3Ea/ck4= github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus= github.com/google/go-tspi v0.3.0/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/licenseclassifier v0.0.0-20210325184830-bb04aff29e72/go.mod h1:qsqn2hxC+vURpyBRygGUuinTO42MFRLcsmQ/P8v94+M= github.com/google/logger v1.1.1 h1:+6Z2geNxc9G+4D4oDO9njjjn2d0wN5d7uOo0vOIW1NQ= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg= github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/trillian v1.3.14-0.20210409160123-c5ea3abd4a41/go.mod h1:1dPv0CUjNQVFEDuAUFhZql16pw/VlPgaX8qj+g5pVzQ= github.com/google/trillian v1.3.14-0.20210511103300-67b5f349eefa/go.mod h1:s4jO3Ai4NSvxucdvqUHON0bCqJyoya32eNw6XJwsmNc= github.com/google/trillian v1.4.0/go.mod h1:1Bja2nEgMDlEJWWRXBUemSPG9qYw84ZYX2gHRVHlR+g= github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s= github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= github.com/goreleaser/goreleaser v0.134.0/go.mod h1:ZT6Y2rSYa6NxQzIsdfWWNWAlYGXGbreo66NmE+3X3WQ= github.com/goreleaser/nfpm v1.2.1/go.mod h1:TtWrABZozuLOttX2uDlYyECfQX7x5XYkVxhjYcR6G9w= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4= github.com/jhump/protoreflect v1.8.2/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= github.com/jhump/protoreflect v1.9.0/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/pseudomuto/protoc-gen-doc v1.4.1/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg= github.com/pseudomuto/protoc-gen-doc v1.5.0/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg= github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.8.0/go.mod h1:EBwu+T5AvHOcXwvZIkQFjUN6s8Czyqw12GL/Y0tUyRM= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.5-0.20210205191134-5ec6847320e5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd/api/v3 v3.5.0-alpha.0/go.mod h1:mPcW6aZJukV6Aa81LSKpBjQXTWlXB5r74ymPoSWa3Sw= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0-alpha.0/go.mod h1:kdV+xzCJ3luEBSIeQyB/OEKkWKd8Zkux4sbDeANrosU= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.etcd.io/etcd/client/v3 v3.5.0-alpha.0/go.mod h1:wKt7jgDgf/OfKiYmCq5WFGxOFAkVMLxiiXgLDFhECr8= go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= go.etcd.io/etcd/etcdctl/v3 v3.5.0-alpha.0/go.mod h1:YPwSaBciV5G6Gpt435AasAG3ROetZsKNUzibRa/++oo= go.etcd.io/etcd/etcdctl/v3 v3.5.0/go.mod h1:vGTfKdsh87RI7kA2JHFBEGxjQEYx+pi299wqEOdi34M= go.etcd.io/etcd/etcdutl/v3 v3.5.0/go.mod h1:o98rKMCibbFAG8QS9KmvlYDGDShmmIbmRE8vSofzYNg= go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0/go.mod h1:tV31atvwzcybuqejDoY3oaNRTtlD2l/Ot78Pc9w7DMY= go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= go.etcd.io/etcd/raft/v3 v3.5.0-alpha.0/go.mod h1:FAwse6Zlm5v4tEWZaTjmNhe17Int4Oxbu7+2r0DiD3w= go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= go.etcd.io/etcd/server/v3 v3.5.0-alpha.0/go.mod h1:tsKetYpt980ZTpzl/gb+UOJj9RkIyCb1u4wjzMg90BQ= go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= go.etcd.io/etcd/tests/v3 v3.5.0-alpha.0/go.mod h1:HnrHxjyCuZ8YDt8PYVyQQ5d1ZQfzJVEtQWllr5Vp/30= go.etcd.io/etcd/tests/v3 v3.5.0/go.mod h1:f+mtZ1bE1YPvgKdOJV2BKy4JQW0nAFnQehgOE7+WyJE= go.etcd.io/etcd/v3 v3.5.0-alpha.0/go.mod h1:JZ79d3LV6NUfPjUxXrpiFAYcjhT+06qqw+i28snx8To= go.etcd.io/etcd/v3 v3.5.0/go.mod h1:FldM0/VzcxYWLvWx1sdA7ghKw7C3L2DvUTzGrcEtsC4= go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= gocloud.dev v0.19.0/go.mod h1:SmKwiR8YwIMMJvQBKLsC3fHNyMwXLw3PMDO+VVteJMI= golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210126194326-f9ce19ea3013/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191119060738-e882bf8e40c2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191118222007-07fc4c7f2b98/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201014170642-d1624618ad65/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.37.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.45.0/go.mod h1:ISLIJCedJolbZvDfAk+Ctuq5hf+aJ33WgtUsfyFoLXA= google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210331142528-b7513248f0ba/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210413151531-c14fb6ef47c3/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210427215850-f767ed18ee4d/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= go-attestation-0.5.1/oid/000077500000000000000000000000001452320553600152375ustar00rootroot00000000000000go-attestation-0.5.1/oid/oid.go000066400000000000000000000043661452320553600163520ustar00rootroot00000000000000// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package oid contains X.509 and TCG ASN.1 object identifiers. package oid // Trusted Computing Group (2.23.133) var ( TPMManufacturer = []int{2, 23, 133, 2, 1} TPMModel = []int{2, 23, 133, 2, 2} TPMVersion = []int{2, 23, 133, 2, 3} TCGPlatformSpecification = []int{2, 23, 133, 2, 17} TBBSecurityAssertions = []int{2, 23, 133, 2, 19} TPMSpecification = []int{2, 23, 133, 2, 16} TCGCredentialSpecification = []int{2, 23, 133, 2, 23} TCGCredentialType = []int{2, 23, 133, 2, 25} PlatformManufacturerStr = []int{2, 23, 133, 5, 1, 1} PlatformManufacturerID = []int{2, 23, 133, 5, 1, 2} PlatformConfigURI = []int{2, 23, 133, 5, 1, 3} PlatformModel = []int{2, 23, 133, 5, 1, 4} PlatformVersion = []int{2, 23, 133, 5, 1, 5} PlatformSerial = []int{2, 23, 133, 5, 1, 6} PlatformConfigurationV1 = []int{2, 23, 133, 5, 1, 7, 1} PlatformConfigurationV2 = []int{2, 23, 133, 5, 1, 7, 2} EKCertificate = []int{2, 23, 133, 8, 1} VerifiedTPMRestricted = []int{2, 23, 133, 11, 1, 3} EKPermIDSHA256 = []int{2, 23, 133, 12, 1} ) // X.509 (2.23.23) // // https://www.itu.int/ITU-T/recommendations/rec.aspx?rec=14033 // https://tools.ietf.org/html/rfc5280 var ( SubjectDirectoryAttributes = []int{2, 5, 29, 9} SubjectAltName = []int{2, 5, 29, 17} CertificatePolicies = []int{2, 5, 29, 32} ) // RFC 4043 // // https://tools.ietf.org/html/rfc4043 var ( PermanentIdentifier = []int{1, 3, 6, 1, 5, 5, 7, 8, 3} ) // Google (1.3.6.1.4.1.11129) var ( CloudComputeInstanceIdentifier = []int{1, 3, 6, 1, 4, 1, 11129, 2, 1, 21} ) go-attestation-0.5.1/x509/000077500000000000000000000000001452320553600151715ustar00rootroot00000000000000go-attestation-0.5.1/x509/x509ext.go000066400000000000000000000117221452320553600167510ustar00rootroot00000000000000// Package x509ext provides functions for (un)marshalling X.509 extensions not // supported by the crypto/x509 package. package x509ext import ( "crypto/x509/pkix" "encoding/asn1" "errors" "fmt" "github.com/google/go-attestation/oid" ) // RFC 4043 // // https://tools.ietf.org/html/rfc4043 var ( oidPermanentIdentifier = []int{1, 3, 6, 1, 5, 5, 7, 8, 3} ) // OtherName ::= SEQUENCE { // type-id OBJECT IDENTIFIER, // value [0] EXPLICIT ANY DEFINED BY type-id } type otherName struct { TypeID asn1.ObjectIdentifier Value asn1.RawValue } func marshalOtherName(typeID asn1.ObjectIdentifier, value interface{}) (asn1.RawValue, error) { valueBytes, err := asn1.MarshalWithParams(value, "explicit,tag:0") if err != nil { return asn1.RawValue{}, err } otherName := otherName{ TypeID: typeID, Value: asn1.RawValue{FullBytes: valueBytes}, } bytes, err := asn1.MarshalWithParams(otherName, "tag:0") if err != nil { return asn1.RawValue{}, err } return asn1.RawValue{FullBytes: bytes}, nil } // PermanentIdentifier represents an ASN.1 encoded "permanent identifier" as // defined by RFC4043. // // PermanentIdentifier ::= SEQUENCE { // identifierValue UTF8String OPTIONAL, // assigner OBJECT IDENTIFIER OPTIONAL // } // // https://datatracker.ietf.org/doc/html/rfc4043 type PermanentIdentifier struct { IdentifierValue string `asn1:"utf8,optional"` Assigner asn1.ObjectIdentifier `asn1:"optional"` } func parsePermanentIdentifier(der []byte) (PermanentIdentifier, error) { var permID PermanentIdentifier if _, err := asn1.UnmarshalWithParams(der, &permID, "explicit,tag:0"); err != nil { return PermanentIdentifier{}, err } return permID, nil } // SubjectAltName contains GeneralName variations not supported by the // crypto/x509 package. // // https://datatracker.ietf.org/doc/html/rfc5280 type SubjectAltName struct { DirectoryNames []pkix.Name PermanentIdentifiers []PermanentIdentifier } // ParseSubjectAltName parses a pkix.Extension into a SubjectAltName struct. func ParseSubjectAltName(ext pkix.Extension) (*SubjectAltName, error) { var out SubjectAltName dirNames, otherNames, err := parseSubjectAltName(ext) if err != nil { return nil, fmt.Errorf("parseSubjectAltName: %v", err) } out.DirectoryNames = dirNames for _, otherName := range otherNames { if otherName.TypeID.Equal(oidPermanentIdentifier) { permID, err := parsePermanentIdentifier(otherName.Value.FullBytes) if err != nil { return nil, fmt.Errorf("parsePermanentIdentifier: %v", err) } out.PermanentIdentifiers = append(out.PermanentIdentifiers, permID) } } return &out, nil } // https://datatracker.ietf.org/doc/html/rfc5280#page-35 func parseSubjectAltName(ext pkix.Extension) (dirNames []pkix.Name, otherNames []otherName, err error) { err = forEachSAN(ext.Value, func(generalName asn1.RawValue) error { switch generalName.Tag { case 0: // otherName var otherName otherName if _, err := asn1.UnmarshalWithParams(generalName.FullBytes, &otherName, "tag:0"); err != nil { return fmt.Errorf("OtherName: asn1.UnmarshalWithParams: %v", err) } otherNames = append(otherNames, otherName) case 4: // directoryName var rdns pkix.RDNSequence if _, err := asn1.Unmarshal(generalName.Bytes, &rdns); err != nil { return fmt.Errorf("DirectoryName: asn1.Unmarshal: %v", err) } var dirName pkix.Name dirName.FillFromRDNSequence(&rdns) dirNames = append(dirNames, dirName) default: return fmt.Errorf("expected tag %d", generalName.Tag) } return nil }) return } // Borrowed from the x509 package. func forEachSAN(extension []byte, callback func(ext asn1.RawValue) error) error { 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); err != nil { return err } } return nil } // MarshalSubjectAltName converts a SubjectAltName struct into a pkix.Extension. func MarshalSubjectAltName(san *SubjectAltName) (pkix.Extension, error) { var generalNames []asn1.RawValue for _, permID := range san.PermanentIdentifiers { val, err := marshalOtherName(oidPermanentIdentifier, permID) if err != nil { return pkix.Extension{}, err } generalNames = append(generalNames, val) } for _, dirName := range san.DirectoryNames { bytes, err := asn1.MarshalWithParams(dirName.ToRDNSequence(), "explicit,tag:4") if err != nil { return pkix.Extension{}, err } generalNames = append(generalNames, asn1.RawValue{FullBytes: bytes}) } val, err := asn1.Marshal(generalNames) if err != nil { return pkix.Extension{}, err } return pkix.Extension{ Id: oid.SubjectAltName, Value: val, }, nil }