pax_global_header 0000666 0000000 0000000 00000000064 14563713763 0014531 g ustar 00root root 0000000 0000000 52 comment=43efd1ff6ae89a081dbb3cccb6f1fbe6541a0ad6
go-tdx-guest-0.3.1/ 0000775 0000000 0000000 00000000000 14563713763 0014061 5 ustar 00root root 0000000 0000000 go-tdx-guest-0.3.1/.github/ 0000775 0000000 0000000 00000000000 14563713763 0015421 5 ustar 00root root 0000000 0000000 go-tdx-guest-0.3.1/.github/workflows/ 0000775 0000000 0000000 00000000000 14563713763 0017456 5 ustar 00root root 0000000 0000000 go-tdx-guest-0.3.1/.github/workflows/CI.yml 0000664 0000000 0000000 00000005644 14563713763 0020505 0 ustar 00root root 0000000 0000000 #
# Copyright 2023 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
#
# 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.
#
name: CI
'on':
push:
tags:
- v*
branches:
- main
pull_request: null
jobs:
build:
strategy:
matrix:
go-version:
- 1.19.x
os:
- macos-latest
- ubuntu-latest
name: 'Build/Test (${{ matrix.os}}, Go ${{ matrix.go-version }})'
runs-on: '${{ matrix.os }}'
steps:
- uses: actions/checkout@v3
- name: Setup Go
uses: actions/setup-go@v3
with:
go-version: '${{ matrix.go-version }}'
- name: Install Protoc
uses: arduino/setup-protoc@v1
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
version: 3.12.4
- name: Install protoc-gen-go
run: go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28.1
- name: Check Protobuf Generation
run: |
go generate ./...
git diff -G'^[^/]' --exit-code
- name: Generate all protobufs
run: go generate ./...
- name: Build all packages
run: go build -v ./...
- name: Test all packages
run: go test -v ./...
lint:
strategy:
matrix:
go-version:
- 1.19.x
os:
- ubuntu-latest
name: 'Lint ${{ matrix.dir }} (${{ matrix.os }}, Go ${{ matrix.go-version }})'
runs-on: '${{ matrix.os }}'
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v2
with:
go-version: '${{ matrix.go-version }}'
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v3.3.0
with:
version: latest
working-directory: ./
args: >
-D errcheck -E stylecheck -E goimports -E misspell -E revive -E
gofmt -E goimports --exclude-use-default=false --max-same-issues=0
--max-issues-per-linter=0 --timeout 2m
lintc:
strategy:
matrix:
go-version:
- 1.19.x
os:
- ubuntu-latest
name: 'Lint CGO (${{ matrix.os}}, Go ${{ matrix.go-version }})'
runs-on: '${{ matrix.os }}'
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v2
with:
go-version: '${{ matrix.go-version }}'
- name: Check for CGO Warnings (gcc)
run: CGO_CFLAGS=-Werror CC=gcc go build ./...
- name: Check for CGO Warnings (clang)
run: CGO_CFLAGS=-Werror CC=clang go build ./...
go-tdx-guest-0.3.1/.github/workflows/release.yml 0000664 0000000 0000000 00000002240 14563713763 0021617 0 ustar 00root root 0000000 0000000 name: release
'on':
push:
branches:
- main
tags:
- v*
pull_request: null
jobs:
release:
strategy:
matrix:
go-version:
- 1.19.x
os:
- ubuntu-latest
name: 'Release for (${{ matrix.os}}, Go ${{ matrix.go-version }})'
runs-on: '${{ matrix.os }}'
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v3
with:
go-version: '${{ matrix.go-version }}'
cache: true
- shell: bash
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- id: cache
uses: actions/cache@v3
with:
path: 'dist/${{ matrix.os }}'
key: '${{ matrix.go }}-${{ env.sha_short }}'
- name: Build all packages
run: go build -v ./...
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v3
if: >-
success() && startsWith(github.ref, 'refs/tags/') &&
steps.cache.outputs.cache-hit != 'true'
with:
version: latest
args: release --clean
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
go-tdx-guest-0.3.1/.goreleaser.yml 0000664 0000000 0000000 00000002121 14563713763 0017006 0 ustar 00root root 0000000 0000000 builds:
- env:
- CGO_ENABLED=0
goos:
- linux
# - windows
# - darwin
goarch:
- amd64
id: "attest"
main: ./tools/attest/attest.go
binary: attest
- env:
- CGO_ENABLED=0
goos:
- linux
# - windows
# - darwin
goarch:
- amd64
id: "check"
main: ./tools/check/check.go
binary: check
archives:
- format: tar.gz
# this name template makes the OS and Arch compatible with the results of uname.
name_template: >-
{{ .ProjectName }}_
{{- title .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
# use zip for windows archives
format_overrides:
- goos: windows
format: zip
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ incpatch .Version }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj go-tdx-guest-0.3.1/CONTRIBUTING.md 0000664 0000000 0000000 00000002115 14563713763 0016311 0 ustar 00root root 0000000 0000000 # 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-tdx-guest-0.3.1/LICENSE 0000664 0000000 0000000 00000026135 14563713763 0015075 0 ustar 00root root 0000000 0000000 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-tdx-guest-0.3.1/README.md 0000664 0000000 0000000 00000012341 14563713763 0015341 0 ustar 00root root 0000000 0000000 # TDX Guest
This project offers libraries for a simple wrapper around quote providing tools
such as the `go-configfs-tsm` library, or the `/dev/tdx_guest` device in Linux,
as well as a library for attestation verification of fundamental components of
an attestation quote.
This project is split into two complementary roles. The first role is producing
an attestation quote, and the second is checking an attestation quote. The
`client` library produces quote, the `verify` library verifies quote's
signatures and certificates.
## `client`
This library should be used within the confidential workload to collect an
attestation quote along with requisite certificates.
Your main interactions with it will be to first get the quote provider, or
open the device, then get an attestation quote with your provided 64 bytes of
user data (typically a nonce), and then close the device. For convenience, the
attestation with its associated certificates can be collected in a
wire-transmittable protocol buffer format.
### `func GetQuoteProvider() (*LinuxConfigFsQuoteProvider, error)`
This function creates an instance of a quote provider which uses the go-configfs-tsm
library to fetch attestation quotes via ConfigFS.
### `func OpenDevice() (*LinuxDevice, error)`
This function creates a file descriptor to the `/dev/tdx_guest` device and
returns an object that has methods encapsulating commands to the device. When
done, remember to `Close()` the device.
Note:- The Device interface is deprecated, and use of quote provider interface
is recommended for fetching attestation quote.
### `func GetQuote(quoteProvider any, reportData [64]byte) (any, error)`
This function takes an object implementing either the `QuoteProvider` interface
(e.g. `LinuxConfigFsQuoteProvider`), or the `Device` interface (e.g., a `LinuxDevice`)
along with report data which typically consists of a nonce value.
It returns the protocol buffer representation of the attestation quote.
You can use `GetRawQuote` to get the TDX Quote in byte array format.
### `func (d Device) Close() error`
Closes the device.
## `verify`
This library will check the signature, certificate chain and basic
well-formedness properties of an attestation quote. The requirements for quote
well-formedness come from the [Intel TDX specification](https://cdrdv2.intel.com/v1/dl/getContent/733568),
and the requirements for certificate well-formedness come from the
[Intel PCK Certificate specification](https://api.trustedservices.intel.com/documents/Intel_SGX_PCK_Certificate_CRL_Spec-1.5.pdf).
The presence of the PCK Certificate Chain within the input attestation quote is
expected.
### `func TdxQuote(quote *pb.QuoteV4, options *Options) error`
This function verifies that the attestation has a valid signature and
certificate chain. It provides an optional verification against the collateral
obtained from the Intel PCS API and also offers an optional check against
the certificate revocation list (CRL). By default, the option to verify against
collaterals and the certificate revocation list(CRL) is disabled. The
verification using collaterals is based on [Intel PCS API specification](https://api.portal.trustedservices.intel.com/provisioning-certification)
documentation.
Example expected invocation:
```
verify.TdxQuote(myAttestation, verify.Options())
```
#### `Options` type
This type contains five fields:
* `GetCollateral bool`: if true, then `TdxQuote` will download the collateral
from Intel PCS API service and check against collateral obtained.
Must be `true` if `CheckRevocations` is true.
* `CheckRevocations bool`: if true, then `TdxQuote` will download the
certificate revocation list (CRL) from Intel PCS API service and check for
revocations.
* `Getter HTTPSGetter`: if `nil`, uses `DefaultHTTPSGetter()`.
The `HTTPSGetter` interface consists of a single method `Get(url string)
(map[string][]string, []byte, error)` that should return the headers and body
of the HTTPS response.
* `Now time.Time`: if `nil`, uses `time.Now()`. It is the time at which to verify
the validity of certificates and collaterals.
* `TrustedRoots *x509.CertPool`: if `nil`, uses the library's embedded
certificate.
Certificate chain verification is performed using trusted roots.
## License
go-tdx-guest is released under the Apache 2.0 license.
```
Copyright 2023 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
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.
```
## Links
* [Intel TDX specification](https://cdrdv2.intel.com/v1/dl/getContent/733568)
* [Intel PCK Certificate specification](https://api.trustedservices.intel.com/documents/Intel_SGX_PCK_Certificate_CRL_Spec-1.5.pdf)
* [Intel PCS API specification](https://api.portal.trustedservices.intel.com/provisioning-certification)
## Disclaimers
This is not an officially supported Google product. go-tdx-guest-0.3.1/abi/ 0000775 0000000 0000000 00000000000 14563713763 0014614 5 ustar 00root root 0000000 0000000 go-tdx-guest-0.3.1/abi/abi.go 0000664 0000000 0000000 00000114010 14563713763 0015673 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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 abi provides Go representations and conversions for TDX attestation
// data structures
package abi
import (
"encoding/binary"
"errors"
"fmt"
"math/big"
pb "github.com/google/go-tdx-guest/proto/tdx"
"golang.org/x/crypto/cryptobyte"
"golang.org/x/crypto/cryptobyte/asn1"
)
const (
// QuoteMinSize is the minimum specified size of TDX generated quote
QuoteMinSize = 0x3FC
// QuoteVersion currently in support
QuoteVersion = 4
// AttestationKeyType supported value
AttestationKeyType = 2 // (ECDSA-256-with-P-256 curve)
// TeeTDX for Attestation
TeeTDX = 0x00000081
// TeeTcbSvnSize is the size of TEE_TCB_SVN field in TdQuoteBody
TeeTcbSvnSize = 0x10
// MrSeamSize is the size of MR_SEAM field in TdQuoteBody
MrSeamSize = 0x30
// TdAttributesSize is the size of TD_ATTRIBUTES field in TdQuoteBody
TdAttributesSize = 0x08
// XfamSize is the size of XFAM field in TdQuoteBody
XfamSize = 0x08
// MrTdSize is the size of MR_TD field in TdQuoteBody
MrTdSize = 0x30
// MrConfigIDSize is the size of MR_CONFIG_ID field in TdQuoteBody
MrConfigIDSize = 0x30
// MrOwnerSize is the size of MR_OWNER field in TdQuoteBody
MrOwnerSize = 0x30
// MrOwnerConfigSize is the size of MR_OWNER_CONFIG field in TdQuoteBody
MrOwnerConfigSize = 0x30
// RtmrSize is the size of Runtime extendable measurement register
RtmrSize = 0x30
// ReportDataSize is the size of ReportData field in TdQuoteBody
ReportDataSize = 0x40
// QeVendorIDSize is the size of QeVendorID field in Header
QeVendorIDSize = 0x10
userDataSize = 0x14
qeReportCertificationDataType = 0x6
pckReportCertificationDataType = 0x5
qeReportSize = 0x180
headerSize = 0x30
tdQuoteBodySize = 0x248
qeSvnSize = 0x2
pceSvnSize = 0x2
mrSignerSeamSize = 0x30
seamAttributesSize = 0x08
cpuSvnSize = 0x10
reserved1Size = 0x1C
attributesSize = 0x10
mrEnclaveSize = 0x20
reserved2Size = 0x20
mrSignerSize = 0x20
reserved3Size = 0x60
reserved4Size = 0x3C
signatureSize = 0x40
attestationKeySize = 0x40
pckCertificateChainKnownSize = 0x06
qeAuthDataKnownSize = 0x02
certificationDataKnownSize = 0x06
quoteV4AuthDataKnownSize = 0x80
quoteHeaderStart = 0x00
quoteHeaderEnd = 0x30
quoteBodyStart = 0x30
quoteBodyEnd = 0x278
quoteSignedDataSizeStart = 0x278
quoteSignedDataSizeEnd = 0x27C
quoteSignedDataStart = quoteSignedDataSizeEnd
headerVersionStart = 0x00
headerVersionEnd = 0x02
headerAttestationKeyTypeStart = headerVersionEnd
headerAttestationKeyTypeEnd = 0x04
headerTeeTypeStart = headerAttestationKeyTypeEnd
headerTeeTypeEnd = 0x08
headerPceSvnStart = headerTeeTypeEnd
headerPceSvnEnd = 0xA
headerQeSvnStart = headerPceSvnEnd
headerQeSvnEnd = 0xC
headerQeVendorIDStart = headerQeSvnEnd
headerQeVendorIDEnd = 0x1C
headerUserDataStart = headerQeVendorIDEnd
headerUserDataEnd = 0x30
intelQuoteV4Version = 4
tdTeeTcbSvnStart = 0x00
tdTeeTcbSvnEnd = 0x10
tdMrSeamStart = tdTeeTcbSvnEnd
tdMrSeamEnd = 0x40
tdMrSignerSeamStart = tdMrSeamEnd
tdMrSignerSeamEnd = 0x70
tdSeamAttributesStart = tdMrSignerSeamEnd
tdSeamAttributesEnd = 0x78
tdAttributesStart = tdSeamAttributesEnd
tdAttributesEnd = 0x80
tdXfamStart = tdAttributesEnd
tdXfamEnd = 0x88
tdMrTdStart = tdXfamEnd
tdMrTdEnd = 0xB8
tdMrConfigIDStart = tdMrTdEnd
tdMrConfigIDEnd = 0xE8
tdMrOwnerStart = tdMrConfigIDEnd
tdMrOwnerEnd = 0x118
tdMrOwnerConfigStart = tdMrOwnerEnd
tdMrOwnerConfigEnd = 0x148
tdRtmrsStart = tdMrOwnerConfigEnd
tdRtmrsEnd = 0x208
tdReportDataStart = tdRtmrsEnd
tdReportDataEnd = 0x248
signedDataSignatureStart = 0x00
signedDataSignatureEnd = 0x40
signedDataAttestationKeyStart = signedDataSignatureEnd
signedDataAttestationKeyEnd = 0x80
signedDataCertificationDataStart = signedDataAttestationKeyEnd
certificateDataTypeStart = 0x00
certificateDataTypeEnd = 0x02
certificateSizeStart = certificateDataTypeEnd
certificateSizeEnd = 0x06
certificateDataStart = certificateSizeEnd
enclaveReportStart = 0x00
enclaveReportEnd = 0x180
qeReportCertificationDataSignatureStart = enclaveReportEnd
qeReportCertificationDataSignatureEnd = 0x1C0
qeReportCertificationDataAuthDataStart = qeReportCertificationDataSignatureEnd
qeCPUSvnStart = 0x00
qeCPUSvnEnd = 0x10
qeMiscSelectStart = qeCPUSvnEnd
qeMiscSelectEnd = 0x14
qeReserved1Start = qeMiscSelectEnd
qeReserved1End = 0x30
qeAttributesStart = qeReserved1End
qeAttributesEnd = 0x40
qeMrEnclaveStart = qeAttributesEnd
qeMrEnclaveEnd = 0x60
qeReserved2Start = qeMrEnclaveEnd
qeReserved2End = 0x80
qeMrSignerStart = qeReserved2End
qeMrSignerEnd = 0xA0
qeReserved3Start = qeMrSignerEnd
qeReserved3End = 0x100
qeIsvProdIDStart = qeReserved3End
qeIsvProdIDEnd = 0x102
qeIsvSvnStart = qeIsvProdIDEnd
qeIsvSvnEnd = 0x104
qeReserved4Start = qeIsvSvnEnd
qeReserved4End = 0x140
qeReportDataStart = qeReserved4End
qeReportDataEnd = 0x180
authDataParsedDataSizeStart = 0x00
authDataParsedDataSizeEnd = 0x02
authDataStart = authDataParsedDataSizeEnd
pckCertChainCertificationDataTypeStart = 0x00
pckCertChainCertificationDataTypeEnd = 0x02
pckCertChainSizeStart = pckCertChainCertificationDataTypeEnd
pckCertChainSizeEnd = 0x06
pckCertChainDataStart = pckCertChainSizeEnd
rtmrsCount = 4
)
var (
// ErrQuoteNil error returned when Quote is nil
ErrQuoteNil = errors.New("quote is nil")
// ErrQuoteV4Nil error returned when QuoteV4 is nil
ErrQuoteV4Nil = errors.New("QuoteV4 is nil")
// ErrQuoteV4AuthDataNil error returned when QuoteV4 Auth Data is nil
ErrQuoteV4AuthDataNil = errors.New("QuoteV4 authData is nil")
// ErrCertificationDataNil error returned when Certification Data is nil
ErrCertificationDataNil = errors.New("certification data is nil")
// ErrQeReportCertificationDataNil error returned when QE report certification data is nil
ErrQeReportCertificationDataNil = errors.New("QE Report certification data is nil")
// ErrQeAuthDataNil error returned when QE Auth Data is nil
ErrQeAuthDataNil = errors.New("QE AuthData is nil")
// ErrQeReportNil error returned when QE Report is nil
ErrQeReportNil = errors.New("QE Report is nil")
// ErrPckCertChainNil error returned when PCK Certificate Chain is nil
ErrPckCertChainNil = errors.New("PCK certificate chain is nil")
// ErrTDQuoteBodyNil error returned when TD quote body is nil
ErrTDQuoteBodyNil = errors.New("TD quote body is nil")
// ErrTeeType error returned when TEE type is not TDX
ErrTeeType = errors.New("TEE type is not TDX")
// ErrAttestationKeyType error returned when attestation key is not of expected type
ErrAttestationKeyType = errors.New("attestation key type not supported")
// ErrHeaderNil error returned when header is nil
ErrHeaderNil = errors.New("header is nil")
)
func clone(b []byte) []byte {
result := make([]byte, len(b))
copy(result, b)
return result
}
// determineQuoteFormat returns the quote format version from the header.
func determineQuoteFormat(b []uint8) (uint32, error) {
if len(b) < headerVersionEnd {
return 0, fmt.Errorf("unable to determine quote format since bytes length is less than %d bytes", headerVersionEnd)
}
data := clone(b)
header := &pb.Header{}
header.Version = uint32(binary.LittleEndian.Uint16(data[headerVersionStart:headerVersionEnd]))
return header.Version, nil
}
// QuoteToProto creates a Quote from the Intel's attestation quote byte array in Intel's ABI format.
// Supported quote formats - QuoteV4.
func QuoteToProto(b []uint8) (any, error) {
quoteFormat, err := determineQuoteFormat(b)
if err != nil {
return nil, err
}
switch quoteFormat {
case intelQuoteV4Version:
return quoteToProtoV4(b)
default:
return nil, fmt.Errorf("quote format not supported")
}
}
// quoteToProtoV4 creates a pb.QuoteV4 from the Intel's attestation quote byte array in Intel's ABI format.
func quoteToProtoV4(b []uint8) (*pb.QuoteV4, error) {
data := clone(b) // Created an independent copy to make the interface less error-prone
if len(data) < QuoteMinSize {
return nil, fmt.Errorf("raw quote size is 0x%x, a TDX quote should have size a minimum size of 0x%x", len(data), QuoteMinSize)
}
quote := &pb.QuoteV4{}
header, err := headerToProto(data[quoteHeaderStart:quoteHeaderEnd])
if err != nil {
return nil, err
}
tdQuoteBody, err := tdQuoteBodyToProto(data[quoteBodyStart:quoteBodyEnd])
if err != nil {
return nil, err
}
quote.SignedDataSize = binary.LittleEndian.Uint32(data[quoteSignedDataSizeStart:quoteSignedDataSizeEnd])
additionalData := data[quoteSignedDataStart:]
if uint32(len(additionalData)) < quote.GetSignedDataSize() {
return nil, fmt.Errorf("size of signed data is 0x%x. Expected minimum size of 0x%x", len(additionalData), quote.GetSignedDataSize())
}
quoteSignedDataEnd := quoteSignedDataStart + quote.GetSignedDataSize()
rawSignedData := data[quoteSignedDataStart:quoteSignedDataEnd]
extraBytes := data[quoteSignedDataEnd:]
signedData, err := signedDataToProto(rawSignedData)
if err != nil {
return nil, err
}
quote.Header = header
quote.TdQuoteBody = tdQuoteBody
quote.SignedData = signedData
if len(extraBytes) > 0 {
quote.ExtraBytes = extraBytes
}
if err := CheckQuoteV4(quote); err != nil {
return nil, fmt.Errorf("parsing QuoteV4 failed: %v", err)
}
return quote, nil
}
func headerToProto(b []uint8) (*pb.Header, error) {
data := clone(b) // Created an independent copy to make the interface less error-prone
header := &pb.Header{}
header.Version = uint32(binary.LittleEndian.Uint16(data[headerVersionStart:headerVersionEnd]))
header.AttestationKeyType = uint32(binary.LittleEndian.Uint16(data[headerAttestationKeyTypeStart:headerAttestationKeyTypeEnd]))
header.TeeType = binary.LittleEndian.Uint32(data[headerTeeTypeStart:headerTeeTypeEnd])
header.PceSvn = data[headerPceSvnStart:headerPceSvnEnd]
header.QeSvn = data[headerQeSvnStart:headerQeSvnEnd]
header.QeVendorId = data[headerQeVendorIDStart:headerQeVendorIDEnd]
header.UserData = data[headerUserDataStart:headerUserDataEnd]
if err := checkHeader(header); err != nil {
return nil, fmt.Errorf("parsing header failed: %v", err)
}
return header, nil
}
func tdQuoteBodyToProto(b []uint8) (*pb.TDQuoteBody, error) {
data := clone(b) // Created an independent copy to make the interface less error-prone
report := &pb.TDQuoteBody{}
report.TeeTcbSvn = data[tdTeeTcbSvnStart:tdTeeTcbSvnEnd]
report.MrSeam = data[tdMrSeamStart:tdMrSeamEnd]
report.MrSignerSeam = data[tdMrSignerSeamStart:tdMrSignerSeamEnd]
report.SeamAttributes = data[tdSeamAttributesStart:tdSeamAttributesEnd]
report.TdAttributes = data[tdAttributesStart:tdAttributesEnd]
report.Xfam = data[tdXfamStart:tdXfamEnd]
report.MrTd = data[tdMrTdStart:tdMrTdEnd]
report.MrConfigId = data[tdMrConfigIDStart:tdMrConfigIDEnd]
report.MrOwner = data[tdMrOwnerStart:tdMrOwnerEnd]
report.MrOwnerConfig = data[tdMrOwnerConfigStart:tdMrOwnerConfigEnd]
report.ReportData = data[tdReportDataStart:tdReportDataEnd]
rtmrsStart := tdRtmrsStart
for i := 0; i < rtmrsCount; i++ {
rtmrsEnd := rtmrsStart + RtmrSize
arr := data[rtmrsStart:rtmrsEnd]
report.Rtmrs = append(report.Rtmrs, arr)
rtmrsStart += RtmrSize
}
if err := checkTDQuoteBody(report); err != nil {
return nil, fmt.Errorf("parsing TD Quote Body failed: %v", err)
}
return report, nil
}
func signedDataToProto(b []uint8) (*pb.Ecdsa256BitQuoteV4AuthData, error) {
data := clone(b) // Created an independent copy to make the interface less error-prone
signedData := &pb.Ecdsa256BitQuoteV4AuthData{}
signedData.Signature = data[signedDataSignatureStart:signedDataSignatureEnd]
signedData.EcdsaAttestationKey = data[signedDataAttestationKeyStart:signedDataAttestationKeyEnd]
certificationData, err := certificationDataToProto(data[signedDataCertificationDataStart:])
if err != nil {
return nil, err
}
signedData.CertificationData = certificationData
if err := checkEcdsa256BitQuoteV4AuthData(signedData); err != nil {
return nil, fmt.Errorf("parsing QuoteV4 AuthData failed: %v", err)
}
return signedData, nil
}
func certificationDataToProto(b []uint8) (*pb.CertificationData, error) {
data := clone(b) // Created an independent copy to make the interface less error-prone
certification := &pb.CertificationData{}
certification.CertificateDataType = uint32(binary.LittleEndian.Uint16(data[certificateDataTypeStart:certificateDataTypeEnd]))
certification.Size = binary.LittleEndian.Uint32(data[certificateSizeStart:certificateSizeEnd])
rawCertificateData := data[certificateDataStart:]
if uint32(len(rawCertificateData)) != certification.GetSize() {
return nil, fmt.Errorf("size of certificate data is 0x%x. Expected size 0x%x", len(rawCertificateData), certification.GetSize())
}
qeReportCertificationData, err := qeReportCertificationDataToProto(rawCertificateData)
if err != nil {
return nil, err
}
certification.QeReportCertificationData = qeReportCertificationData
if err := checkCertificationData(certification); err != nil {
return nil, fmt.Errorf("parsing certification data failed: %v", err)
}
return certification, nil
}
func qeReportCertificationDataToProto(b []uint8) (*pb.QEReportCertificationData, error) {
data := clone(b) // Created an independent copy to make the interface less error-prone
qeReportCertificationData := &pb.QEReportCertificationData{}
enclaveReport, err := enclaveReportToProto(data[enclaveReportStart:enclaveReportEnd])
if err != nil {
return nil, err
}
qeReportCertificationData.QeReport = enclaveReport
qeReportCertificationData.QeReportSignature = data[qeReportCertificationDataSignatureStart:qeReportCertificationDataSignatureEnd]
authData, authDataSize, err := qeAuthDataToProto(data[qeReportCertificationDataAuthDataStart:])
if err != nil {
return nil, err
}
qeReportCertificationData.QeAuthData = authData
pckCertificateStart := qeReportCertificationDataAuthDataStart + authDataSize
pckCertificateChain, err := pckCertificateChainToProto(data[pckCertificateStart:])
if err != nil {
return nil, err
}
qeReportCertificationData.PckCertificateChainData = pckCertificateChain
if err := checkQeReportCertificationData(qeReportCertificationData); err != nil {
return nil, fmt.Errorf("parsing QE Report Certification Data failed: %v", err)
}
return qeReportCertificationData, nil
}
func enclaveReportToProto(b []uint8) (*pb.EnclaveReport, error) {
data := clone(b) // Created an independent copy to make the interface less error-prone
enclaveReport := &pb.EnclaveReport{}
enclaveReport.CpuSvn = data[qeCPUSvnStart:qeCPUSvnEnd]
enclaveReport.MiscSelect = binary.LittleEndian.Uint32(data[qeMiscSelectStart:qeMiscSelectEnd])
enclaveReport.Reserved1 = data[qeReserved1Start:qeReserved1End]
enclaveReport.Attributes = data[qeAttributesStart:qeAttributesEnd]
enclaveReport.MrEnclave = data[qeMrEnclaveStart:qeMrEnclaveEnd]
enclaveReport.Reserved2 = data[qeReserved2Start:qeReserved2End]
enclaveReport.MrSigner = data[qeMrSignerStart:qeMrSignerEnd]
enclaveReport.Reserved3 = data[qeReserved3Start:qeReserved3End]
enclaveReport.IsvProdId = uint32(binary.LittleEndian.Uint16(data[qeIsvProdIDStart:qeIsvProdIDEnd]))
enclaveReport.IsvSvn = uint32(binary.LittleEndian.Uint16(data[qeIsvSvnStart:qeIsvSvnEnd]))
enclaveReport.Reserved4 = data[qeReserved4Start:qeReserved4End]
enclaveReport.ReportData = data[qeReportDataStart:qeReportDataEnd]
if err := checkQeReport(enclaveReport); err != nil {
return nil, fmt.Errorf("parsing QE Report failed: %v", err)
}
return enclaveReport, nil
}
func qeAuthDataToProto(b []uint8) (*pb.QeAuthData, uint32, error) {
data := clone(b) // Created an independent copy to make the interface less error-prone
authData := &pb.QeAuthData{}
authData.ParsedDataSize = uint32(binary.LittleEndian.Uint16(data[authDataParsedDataSizeStart:authDataParsedDataSizeEnd]))
authDataEnd := authDataParsedDataSizeEnd + authData.GetParsedDataSize()
authData.Data = data[authDataStart:authDataEnd]
if err := checkQeAuthData(authData); err != nil {
return nil, 0, fmt.Errorf("parsing QE AuthData failed: %v", err)
}
return authData, authDataEnd, nil
}
func pckCertificateChainToProto(b []uint8) (*pb.PCKCertificateChainData, error) {
data := clone(b) // Created an independent copy to make the interface less error-prone
pckCertificateChain := &pb.PCKCertificateChainData{}
pckCertificateChain.CertificateDataType = uint32(binary.LittleEndian.Uint16(data[pckCertChainCertificationDataTypeStart:pckCertChainCertificationDataTypeEnd]))
pckCertificateChain.Size = binary.LittleEndian.Uint32(data[pckCertChainSizeStart:pckCertChainSizeEnd])
pckCertificateChain.PckCertChain = data[pckCertChainDataStart:]
if err := checkPCKCertificateChain(pckCertificateChain); err != nil {
return nil, fmt.Errorf("parsing PCK certification chain failed: %v", err)
}
return pckCertificateChain, nil
}
func checkHeader(header *pb.Header) error {
if header == nil {
return ErrHeaderNil
}
if header.GetVersion() >= (1 << 16) {
return fmt.Errorf("version field size must fit in 2 bytes , got %d", header.GetVersion())
}
if header.GetVersion() != QuoteVersion {
return fmt.Errorf("version %d not supported", header.GetVersion())
}
if header.GetAttestationKeyType() >= (1 << 16) {
return fmt.Errorf("attestation key type field size must fit in 2 bytes , got %d", header.GetAttestationKeyType())
}
if header.GetAttestationKeyType() != AttestationKeyType {
return ErrAttestationKeyType
}
if header.GetTeeType() != TeeTDX {
return ErrTeeType
}
if len(header.GetQeSvn()) != qeSvnSize {
return fmt.Errorf("qeSvn size is %d bytes. Expected %d bytes", len(header.GetQeSvn()), qeSvnSize)
}
if len(header.GetPceSvn()) != pceSvnSize {
return fmt.Errorf("pceSvn size is %d bytes. Expected %d bytes", len(header.GetPceSvn()), pceSvnSize)
}
if len(header.GetQeVendorId()) != QeVendorIDSize {
return fmt.Errorf("qeVendorId size is %d bytes. Expected %d bytes", len(header.GetQeVendorId()), QeVendorIDSize)
}
if len(header.GetUserData()) != userDataSize {
return fmt.Errorf("user data size is %d bytes. Expected %d bytes", len(header.GetUserData()), userDataSize)
}
return nil
}
func checkTDQuoteBody(tdQuoteBody *pb.TDQuoteBody) error {
if tdQuoteBody == nil {
return ErrTDQuoteBodyNil
}
if len(tdQuoteBody.GetTeeTcbSvn()) != TeeTcbSvnSize {
return fmt.Errorf("teeTcbSvn size is %d bytes. Expected %d bytes", len(tdQuoteBody.GetTeeTcbSvn()), TeeTcbSvnSize)
}
if len(tdQuoteBody.GetMrSeam()) != MrSeamSize {
return fmt.Errorf("mrSeam size is %d bytes. Expected %d bytes", len(tdQuoteBody.GetMrSeam()), MrSeamSize)
}
if len(tdQuoteBody.GetMrSignerSeam()) != mrSignerSeamSize {
return fmt.Errorf("mrSignerSeam size is %d bytes. Expected %d bytes", len(tdQuoteBody.GetMrSignerSeam()), mrSignerSeamSize)
}
if len(tdQuoteBody.GetSeamAttributes()) != seamAttributesSize {
return fmt.Errorf("seamAttributes size is %d bytes. Expected %d bytes", len(tdQuoteBody.GetSeamAttributes()), seamAttributesSize)
}
if len(tdQuoteBody.GetTdAttributes()) != TdAttributesSize {
return fmt.Errorf("tdAttributes size is %d bytes. Expected %d bytes", len(tdQuoteBody.GetTdAttributes()), TdAttributesSize)
}
if len(tdQuoteBody.GetXfam()) != XfamSize {
return fmt.Errorf("xfam size is %d bytes. Expected %d bytes", len(tdQuoteBody.GetXfam()), XfamSize)
}
if len(tdQuoteBody.GetMrTd()) != MrTdSize {
return fmt.Errorf("mrTd size is %d bytes. Expected %d bytes", len(tdQuoteBody.GetMrTd()), MrTdSize)
}
if len(tdQuoteBody.GetMrConfigId()) != MrConfigIDSize {
return fmt.Errorf("mrConfigId size is %d bytes. Expected %d bytes", len(tdQuoteBody.GetMrConfigId()), MrConfigIDSize)
}
if len(tdQuoteBody.GetMrOwner()) != MrOwnerSize {
return fmt.Errorf("mrOwner size is %d bytes. Expected %d bytes", len(tdQuoteBody.GetMrOwner()), MrOwnerSize)
}
if len(tdQuoteBody.GetMrOwnerConfig()) != MrOwnerConfigSize {
return fmt.Errorf("mrOwnerConfig size is %d bytes. Expected %d bytes", len(tdQuoteBody.GetMrOwnerConfig()), MrOwnerConfigSize)
}
if len(tdQuoteBody.GetRtmrs()) != rtmrsCount {
return fmt.Errorf("rtmrs count is %d. Expected %d", len(tdQuoteBody.GetRtmrs()), rtmrsCount)
}
for i := 0; i < rtmrsCount; i++ {
if len(tdQuoteBody.GetRtmrs()[i]) != RtmrSize {
return fmt.Errorf("rtmr%d size is %d bytes. Expected %d bytes", i, len(tdQuoteBody.GetRtmrs()[i]), RtmrSize)
}
}
return nil
}
func checkPCKCertificateChain(chain *pb.PCKCertificateChainData) error {
if chain == nil {
return ErrPckCertChainNil
}
if chain.GetCertificateDataType() >= (1 << 16) {
return fmt.Errorf("certification data type expected to be of 2 bytes, got %d", chain.GetCertificateDataType())
}
if chain.GetCertificateDataType() != pckReportCertificationDataType {
return fmt.Errorf("PCK certificate chain data type invalid, got %d, expected %d", chain.GetCertificateDataType(), pckReportCertificationDataType)
}
if chain.GetSize() != uint32(len(chain.GetPckCertChain())) {
return fmt.Errorf("PCK certificate chain size is %d. Expected size %d", len(chain.GetPckCertChain()), chain.GetSize())
}
return nil
}
func checkQeReport(report *pb.EnclaveReport) error {
if report == nil {
return ErrQeReportNil
}
if len(report.GetCpuSvn()) != cpuSvnSize {
return fmt.Errorf("cpuSvn size is %d bytes. Expected %d bytes", len(report.GetCpuSvn()), cpuSvnSize)
}
if len(report.GetReserved1()) != reserved1Size {
return fmt.Errorf("reserved1 size is %d bytes. Expected %d bytes", len(report.GetReserved1()), reserved1Size)
}
if len(report.GetAttributes()) != attributesSize {
return fmt.Errorf("attributes size is %d bytes. Expected %d bytes", len(report.GetAttributes()), attributesSize)
}
if len(report.GetMrEnclave()) != mrEnclaveSize {
return fmt.Errorf("mrEnclave size is %d bytes. Expected %d bytes", len(report.GetMrEnclave()), mrEnclaveSize)
}
if len(report.GetReserved2()) != reserved2Size {
return fmt.Errorf("reserved2 size is %d bytes. Expected %d bytes", len(report.GetReserved2()), reserved2Size)
}
if len(report.GetMrSigner()) != mrSignerSize {
return fmt.Errorf("mrSigner size is %d bytes. Expected %d bytes", len(report.GetMrSigner()), mrSignerSize)
}
if len(report.GetReserved3()) != reserved3Size {
return fmt.Errorf("reserved3 size is %d bytes. Expected %d bytes", len(report.GetReserved3()), reserved3Size)
}
if report.GetIsvProdId() >= (1 << 16) {
return fmt.Errorf("isVProdId field size must fit in 2 bytes , got %d", report.GetIsvProdId())
}
if report.GetIsvSvn() >= (1 << 16) {
return fmt.Errorf("isVSvn field size must fit in 2 bytes , got %d", report.GetIsvSvn())
}
if len(report.GetReserved4()) != reserved4Size {
return fmt.Errorf("reserved4 size is %d bytes. Expected %d bytes", len(report.GetReserved4()), reserved4Size)
}
if len(report.GetReportData()) != ReportDataSize {
return fmt.Errorf("report data size is %d bytes. Expected %d bytes", len(report.GetReportData()), ReportDataSize)
}
return nil
}
func checkQeAuthData(authData *pb.QeAuthData) error {
if authData == nil {
return ErrQeAuthDataNil
}
if authData.GetParsedDataSize() >= (1 << 16) {
return fmt.Errorf("parsed data size field size must fit in 2 bytes , got %d", authData.GetParsedDataSize())
}
if authData.GetParsedDataSize() != uint32(len(authData.GetData())) {
return fmt.Errorf("parsed data size is %d bytes. Expected %d bytes", len(authData.GetData()), authData.GetParsedDataSize())
}
return nil
}
func checkQeReportCertificationData(qeReport *pb.QEReportCertificationData) error {
if qeReport == nil {
return ErrQeReportCertificationDataNil
}
if err := checkQeReport(qeReport.GetQeReport()); err != nil {
return fmt.Errorf("QE Report error: %v", err)
}
if len(qeReport.GetQeReportSignature()) != signatureSize {
return fmt.Errorf("signature size is %d bytes. Expected %d bytes", len(qeReport.GetQeReportSignature()), signatureSize)
}
if err := checkQeAuthData(qeReport.GetQeAuthData()); err != nil {
return fmt.Errorf("QE AuthData error: %v", err)
}
if err := checkPCKCertificateChain(qeReport.GetPckCertificateChainData()); err != nil {
return fmt.Errorf("PCK certificate chain error: %v", err)
}
return nil
}
func checkCertificationData(certification *pb.CertificationData) error {
if certification == nil {
return ErrCertificationDataNil
}
if certification.GetCertificateDataType() >= (1 << 16) {
return fmt.Errorf("certification data type field size must fit in 2 bytes , got %d", certification.GetCertificateDataType())
}
if certification.GetCertificateDataType() != qeReportCertificationDataType {
return fmt.Errorf("certification data type invalid, got %d, expected %d", certification.GetCertificateDataType(), qeReportCertificationDataType)
}
if err := checkQeReportCertificationData(certification.GetQeReportCertificationData()); err != nil {
return fmt.Errorf("QE Report certification data error: %v", err)
}
return nil
}
func checkEcdsa256BitQuoteV4AuthData(signedData *pb.Ecdsa256BitQuoteV4AuthData) error {
if signedData == nil {
return ErrQuoteV4AuthDataNil
}
if len(signedData.GetSignature()) != signatureSize {
return fmt.Errorf("signature size is %d bytes. Expected %d bytes", len(signedData.GetSignature()), signatureSize)
}
if len(signedData.GetEcdsaAttestationKey()) != attestationKeySize {
return fmt.Errorf("ecdsa attestation key size is %d bytes. Expected %d bytes", len(signedData.GetEcdsaAttestationKey()), attestationKeySize)
}
if err := checkCertificationData(signedData.GetCertificationData()); err != nil {
return fmt.Errorf("certification data error: %v", err)
}
return nil
}
// CheckQuoteV4 validates a quote protobuf by ensuring all parameters meet their required size
func CheckQuoteV4(quote *pb.QuoteV4) error {
if quote == nil {
return ErrQuoteV4Nil
}
if err := checkHeader(quote.GetHeader()); err != nil {
return fmt.Errorf("QuoteV4 Header error: %v", err)
}
if err := checkTDQuoteBody(quote.GetTdQuoteBody()); err != nil {
return fmt.Errorf("QuoteV4 TD Quote Body error: %v", err)
}
if err := checkEcdsa256BitQuoteV4AuthData(quote.GetSignedData()); err != nil {
return fmt.Errorf("QuoteV4 AuthData error: %v", err)
}
return nil
}
// EnclaveReportToAbiBytes translates the EnclaveReport back into its little-endian ABI format
func EnclaveReportToAbiBytes(report *pb.EnclaveReport) ([]byte, error) {
if report == nil {
return nil, ErrQeReportNil
}
if err := checkQeReport(report); err != nil {
return nil, fmt.Errorf("QE Report invalid: %v", err)
}
data := make([]byte, qeReportSize)
copy(data[qeCPUSvnStart:qeCPUSvnEnd], report.GetCpuSvn())
binary.LittleEndian.PutUint32(data[qeMiscSelectStart:qeMiscSelectEnd], report.GetMiscSelect())
copy(data[qeReserved1Start:qeReserved1End], report.GetReserved1())
copy(data[qeAttributesStart:qeAttributesEnd], report.GetAttributes())
copy(data[qeMrEnclaveStart:qeMrEnclaveEnd], report.GetMrEnclave())
copy(data[qeReserved2Start:qeReserved2End], report.GetReserved2())
copy(data[qeMrSignerStart:qeMrSignerEnd], report.GetMrSigner())
copy(data[qeReserved3Start:qeReserved3End], report.GetReserved3())
binary.LittleEndian.PutUint16(data[qeIsvProdIDStart:qeIsvProdIDEnd], uint16(report.GetIsvProdId()))
binary.LittleEndian.PutUint16(data[qeIsvSvnStart:qeIsvSvnEnd], uint16(report.GetIsvSvn()))
copy(data[qeReserved4Start:qeReserved4End], report.GetReserved4())
copy(data[qeReportDataStart:qeReportDataEnd], report.GetReportData())
return data, nil
}
// HeaderToAbiBytes translates the Header back into its little-endian ABI format
func HeaderToAbiBytes(header *pb.Header) ([]byte, error) {
if header == nil {
return nil, ErrHeaderNil
}
if err := checkHeader(header); err != nil {
return nil, fmt.Errorf("header invalid: %v", err)
}
data := make([]byte, headerSize)
binary.LittleEndian.PutUint16(data[headerVersionStart:headerVersionEnd], uint16(header.GetVersion()))
binary.LittleEndian.PutUint16(data[headerAttestationKeyTypeStart:headerAttestationKeyTypeEnd], uint16(header.GetAttestationKeyType()))
binary.LittleEndian.PutUint32(data[headerTeeTypeStart:headerTeeTypeEnd], (header.GetTeeType()))
copy(data[headerPceSvnStart:headerPceSvnEnd], header.GetPceSvn())
copy(data[headerQeSvnStart:headerQeSvnEnd], header.GetQeSvn())
copy(data[headerQeVendorIDStart:headerQeVendorIDEnd], header.GetQeVendorId())
copy(data[headerUserDataStart:headerUserDataEnd], header.GetUserData())
return data, nil
}
// TdQuoteBodyToAbiBytes translates the TDQuoteBody back into its little-endian ABI format
func TdQuoteBodyToAbiBytes(tdQuoteBody *pb.TDQuoteBody) ([]byte, error) {
if tdQuoteBody == nil {
return nil, ErrTDQuoteBodyNil
}
if err := checkTDQuoteBody(tdQuoteBody); err != nil {
return nil, fmt.Errorf("TD quote body invalid: %v", err)
}
data := make([]byte, tdQuoteBodySize)
copy(data[tdTeeTcbSvnStart:tdTeeTcbSvnEnd], tdQuoteBody.GetTeeTcbSvn())
copy(data[tdMrSeamStart:tdMrSeamEnd], tdQuoteBody.GetMrSeam())
copy(data[tdMrSignerSeamStart:tdMrSignerSeamEnd], tdQuoteBody.GetMrSignerSeam())
copy(data[tdSeamAttributesStart:tdSeamAttributesEnd], tdQuoteBody.GetSeamAttributes())
copy(data[tdAttributesStart:tdAttributesEnd], tdQuoteBody.GetTdAttributes())
copy(data[tdXfamStart:tdXfamEnd], tdQuoteBody.GetXfam())
copy(data[tdMrTdStart:tdMrTdEnd], tdQuoteBody.GetMrTd())
copy(data[tdMrConfigIDStart:tdMrConfigIDEnd], tdQuoteBody.GetMrConfigId())
copy(data[tdMrOwnerStart:tdMrOwnerEnd], tdQuoteBody.GetMrOwner())
copy(data[tdMrOwnerConfigStart:tdMrOwnerConfigEnd], tdQuoteBody.GetMrOwnerConfig())
rtmrsStart := tdRtmrsStart
for i := 0; i < rtmrsCount; i++ {
rtmrsEnd := rtmrsStart + RtmrSize
copy(data[rtmrsStart:rtmrsEnd], tdQuoteBody.GetRtmrs()[i])
rtmrsStart += RtmrSize
}
copy(data[tdReportDataStart:tdReportDataEnd], tdQuoteBody.GetReportData())
return data, nil
}
func pckCertificateChainToAbiBytes(pckCertificateChain *pb.PCKCertificateChainData) ([]byte, error) {
if pckCertificateChain == nil {
return nil, ErrPckCertChainNil
}
if err := checkPCKCertificateChain(pckCertificateChain); err != nil {
return nil, fmt.Errorf("PCK certificate chain data invalid: %v", err)
}
data := make([]byte, pckCertificateChainKnownSize+pckCertificateChain.GetSize())
binary.LittleEndian.PutUint16(data[pckCertChainCertificationDataTypeStart:pckCertChainCertificationDataTypeEnd], uint16(pckCertificateChain.GetCertificateDataType()))
binary.LittleEndian.PutUint32(data[pckCertChainSizeStart:pckCertChainSizeEnd], pckCertificateChain.GetSize())
copy(data[pckCertChainDataStart:], pckCertificateChain.GetPckCertChain())
return data, nil
}
func qeAuthDataToAbiBytes(authData *pb.QeAuthData) ([]byte, error) {
if authData == nil {
return nil, ErrQeAuthDataNil
}
if err := checkQeAuthData(authData); err != nil {
return nil, fmt.Errorf("QE AuthData invalid: %v", err)
}
data := make([]byte, qeAuthDataKnownSize+authData.GetParsedDataSize())
binary.LittleEndian.PutUint16(data[authDataParsedDataSizeStart:authDataParsedDataSizeEnd], uint16(authData.GetParsedDataSize()))
copy(data[authDataStart:], authData.GetData())
return data, nil
}
func qeReportCertificationDataToAbiBytes(qeReport *pb.QEReportCertificationData) ([]byte, error) {
if qeReport == nil {
return nil, ErrQeReportCertificationDataNil
}
if err := checkQeReportCertificationData(qeReport); err != nil {
return nil, fmt.Errorf("QE Report certification data invalid: %v", err)
}
data, err := EnclaveReportToAbiBytes(qeReport.GetQeReport())
if err != nil {
return nil, fmt.Errorf("enclave report to abi bytes conversion failed: %v", err)
}
qeReportSignatureData := clone(qeReport.GetQeReportSignature())
data = append(data, qeReportSignatureData...)
qeAuthData, err := qeAuthDataToAbiBytes(qeReport.GetQeAuthData())
if err != nil {
return nil, fmt.Errorf("QE AuthData to abi bytes conversion failed: %v", err)
}
data = append(data, qeAuthData...)
pckCertificateChainData, err := pckCertificateChainToAbiBytes(qeReport.GetPckCertificateChainData())
if err != nil {
return nil, fmt.Errorf("PCK certificate chain to abi bytes conversion failed: %v", err)
}
data = append(data, pckCertificateChainData...)
return data, nil
}
func certificationDataToAbiBytes(certification *pb.CertificationData) ([]byte, error) {
if certification == nil {
return nil, ErrCertificationDataNil
}
if err := checkCertificationData(certification); err != nil {
return nil, fmt.Errorf("certification data invalid: %v", err)
}
data := make([]byte, certificationDataKnownSize)
binary.LittleEndian.PutUint16(data[certificateDataTypeStart:certificateDataTypeEnd], uint16(certification.GetCertificateDataType()))
binary.LittleEndian.PutUint32(data[certificateSizeStart:certificateSizeEnd], certification.GetSize())
certificationData, err := qeReportCertificationDataToAbiBytes(certification.GetQeReportCertificationData())
if err != nil {
return nil, fmt.Errorf("QE Report certification data to abi bytes conversion failed: %v", err)
}
data = append(data, certificationData...)
return data, nil
}
func signedDataToAbiBytes(signedData *pb.Ecdsa256BitQuoteV4AuthData) ([]byte, error) {
if signedData == nil {
return nil, ErrQuoteV4AuthDataNil
}
if err := checkEcdsa256BitQuoteV4AuthData(signedData); err != nil {
return nil, fmt.Errorf("QuoteV4 AuthData invalid: %v", err)
}
data := make([]byte, quoteV4AuthDataKnownSize)
copy(data[signedDataSignatureStart:signedDataSignatureEnd], signedData.GetSignature())
copy(data[signedDataAttestationKeyStart:signedDataAttestationKeyEnd], signedData.GetEcdsaAttestationKey())
certificationData, err := certificationDataToAbiBytes(signedData.GetCertificationData())
if err != nil {
return nil, fmt.Errorf("signed data certification data to abi bytes conversion failed: %v", err)
}
data = append(data, certificationData...)
return data, nil
}
// QuoteToAbiBytes translates the Quote back into its little-endian ABI format.
// Supported quote formats - QuoteV4.
func QuoteToAbiBytes(quote any) ([]byte, error) {
if quote == nil {
return nil, ErrQuoteNil
}
switch q := quote.(type) {
case *pb.QuoteV4:
return quoteToAbiBytesV4(q)
default:
return nil, fmt.Errorf("unsupported quote type: %T", quote)
}
}
// quoteToAbiBytesV4 translates the QuoteV4 back into its little-endian ABI format
func quoteToAbiBytesV4(quote *pb.QuoteV4) ([]byte, error) {
if err := CheckQuoteV4(quote); err != nil {
return nil, fmt.Errorf("QuoteV4 invalid: %v", err)
}
var data []byte
headerData, err := HeaderToAbiBytes(quote.GetHeader())
if err != nil {
return nil, fmt.Errorf("header to abi bytes conversion failed: %v", err)
}
data = append(data, headerData...)
tdReportData, err := TdQuoteBodyToAbiBytes(quote.GetTdQuoteBody())
if err != nil {
return nil, fmt.Errorf("TD quote body to abi bytes conversion failed: %v", err)
}
data = append(data, tdReportData...)
signedDataSizeBytes := make([]byte, 0x04)
binary.LittleEndian.PutUint32(signedDataSizeBytes[0x00:0x04], quote.GetSignedDataSize())
data = append(data, signedDataSizeBytes...)
signedData, err := signedDataToAbiBytes(quote.GetSignedData())
if err != nil {
return nil, fmt.Errorf("signed data to abi bytes conversion failed: %v", err)
}
data = append(data, signedData...)
if quote.GetExtraBytes() != nil {
data = append(data, quote.GetExtraBytes()...)
}
return data, nil
}
// SignatureToDER converts the signature to DER format
func SignatureToDER(x []byte) ([]byte, error) {
if len(x) != signatureSize {
return nil, fmt.Errorf("signature size is %d bytes. Expected %d bytes", len(x), signatureSize)
}
var b cryptobyte.Builder
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
b.AddASN1BigInt(new(big.Int).SetBytes(ecdsaGetR(x)))
b.AddASN1BigInt(new(big.Int).SetBytes(ecdsaGetS(x)))
})
return b.Bytes()
}
func ecdsaGetR(signature []byte) []byte {
return signature[0x0:0x20]
}
func ecdsaGetS(signature []byte) []byte {
return signature[0x20:0x40]
}
go-tdx-guest-0.3.1/abi/abi_test.go 0000664 0000000 0000000 00000015263 14563713763 0016744 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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 abi
import (
"bytes"
"testing"
pb "github.com/google/go-tdx-guest/proto/tdx"
test "github.com/google/go-tdx-guest/testing/testdata"
)
func TestQuoteToProto(t *testing.T) {
expectedError := "unable to determine quote format since bytes length is less than 2 bytes"
var emptyRawQuote []uint8
_, err := QuoteToProto(emptyRawQuote)
if err == nil || err.Error() != expectedError {
t.Errorf("error found: %v, want error: %s", err, expectedError)
}
_, err = QuoteToProto(test.RawQuote)
if err != nil {
t.Fatal(err)
}
}
func TestQuoteToAbiBytes(t *testing.T) {
quote, err := QuoteToProto(test.RawQuote)
if err != nil {
t.Fatal(err)
}
rawQuote, err := QuoteToAbiBytes(quote)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(test.RawQuote, rawQuote) {
t.Errorf("raw quote bytes got %v. Expected %v", rawQuote, test.RawQuote)
}
}
func TestNilToAbiBytesConversions(t *testing.T) {
if _, err := QuoteToAbiBytes(nil); err != ErrQuoteNil {
t.Error(err)
}
if _, err := signedDataToAbiBytes(nil); err != ErrQuoteV4AuthDataNil {
t.Error(err)
}
if _, err := certificationDataToAbiBytes(nil); err != ErrCertificationDataNil {
t.Error(err)
}
if _, err := qeReportCertificationDataToAbiBytes(nil); err != ErrQeReportCertificationDataNil {
t.Error(err)
}
if _, err := qeAuthDataToAbiBytes(nil); err != ErrQeAuthDataNil {
t.Error(err)
}
if _, err := pckCertificateChainToAbiBytes(nil); err != ErrPckCertChainNil {
t.Error(err)
}
if _, err := TdQuoteBodyToAbiBytes(nil); err != ErrTDQuoteBodyNil {
t.Error(err)
}
if _, err := HeaderToAbiBytes(nil); err != ErrHeaderNil {
t.Error(err)
}
if _, err := EnclaveReportToAbiBytes(nil); err != ErrQeReportNil {
t.Error(err)
}
}
func TestInvalidConversionsToAbiBytes(t *testing.T) {
expectedErrors := []string{
"QuoteV4 invalid: QuoteV4 Header error: header is nil",
"QuoteV4 AuthData invalid: signature size is 0 bytes. Expected 64 bytes",
"certification data invalid: certification data type invalid, got 0, expected 6",
"certification data invalid: certification data type invalid, got 7, expected 6",
"certification data invalid: QE Report certification data error: QE Report certification data is nil",
"QE Report certification data invalid: QE Report error: QE Report is nil",
"QE AuthData invalid: parsed data size is 0 bytes. Expected 1 bytes",
"PCK certificate chain data invalid: PCK certificate chain data type invalid, got 0, expected 5",
"PCK certificate chain data invalid: PCK certificate chain data type invalid, got 7, expected 5",
"PCK certificate chain data invalid: PCK certificate chain size is 0. Expected size 2",
"TD quote body invalid: teeTcbSvn size is 0 bytes. Expected 16 bytes",
"header invalid: version 0 not supported",
"header invalid: version 1 not supported",
"header invalid: attestation key type not supported",
"header invalid: TEE type is not TDX",
"QE Report invalid: cpuSvn size is 0 bytes. Expected 16 bytes",
}
if _, err := QuoteToAbiBytes(&pb.QuoteV4{}); err == nil || err.Error() != expectedErrors[0] {
t.Errorf("error found: %v, want error: %s", err, expectedErrors[0])
}
if _, err := signedDataToAbiBytes(&pb.Ecdsa256BitQuoteV4AuthData{}); err == nil || err.Error() != expectedErrors[1] {
t.Errorf("error found: %v, want error: %s", err, expectedErrors[1])
}
if _, err := certificationDataToAbiBytes(&pb.CertificationData{}); err == nil || err.Error() != expectedErrors[2] {
t.Errorf("error found: %v, want error: %s", err, expectedErrors[2])
}
if _, err := certificationDataToAbiBytes(&pb.CertificationData{CertificateDataType: 7}); err == nil || err.Error() != expectedErrors[3] {
t.Errorf("error found: %v, want error: %s", err, expectedErrors[3])
}
if _, err := certificationDataToAbiBytes(&pb.CertificationData{CertificateDataType: qeReportCertificationDataType, Size: 2}); err == nil || err.Error() != expectedErrors[4] {
t.Errorf("error found: %v, want error: %s", err, expectedErrors[4])
}
if _, err := qeReportCertificationDataToAbiBytes(&pb.QEReportCertificationData{}); err == nil || err.Error() != expectedErrors[5] {
t.Errorf("error found: %v, want error: %s", err, expectedErrors[5])
}
if _, err := qeAuthDataToAbiBytes(&pb.QeAuthData{ParsedDataSize: 1}); err == nil || err.Error() != expectedErrors[6] {
t.Errorf("error found: %v, want error: %s", err, expectedErrors[6])
}
if _, err := pckCertificateChainToAbiBytes(&pb.PCKCertificateChainData{}); err == nil || err.Error() != expectedErrors[7] {
t.Errorf("error found: %v, want error: %s", err, expectedErrors[7])
}
if _, err := pckCertificateChainToAbiBytes(&pb.PCKCertificateChainData{CertificateDataType: 7}); err == nil || err.Error() != expectedErrors[8] {
t.Errorf("error found: %v, want error: %s", err, expectedErrors[8])
}
if _, err := pckCertificateChainToAbiBytes(&pb.PCKCertificateChainData{CertificateDataType: pckReportCertificationDataType, Size: 2}); err == nil || err.Error() != expectedErrors[9] {
t.Errorf("error found: %v, want error: %s", err, expectedErrors[9])
}
if _, err := TdQuoteBodyToAbiBytes(&pb.TDQuoteBody{}); err == nil || err.Error() != expectedErrors[10] {
t.Errorf("error found: %v, want error: %s", err, expectedErrors[10])
}
if _, err := HeaderToAbiBytes(&pb.Header{}); err == nil || err.Error() != expectedErrors[11] {
t.Errorf("error found: %v, want error: %s", err, expectedErrors[11])
}
if _, err := HeaderToAbiBytes(&pb.Header{Version: 1}); err == nil || err.Error() != expectedErrors[12] {
t.Errorf("error found: %v, want error: %s", err, expectedErrors[12])
}
if _, err := HeaderToAbiBytes(&pb.Header{Version: QuoteVersion, AttestationKeyType: 1}); err == nil || err.Error() != expectedErrors[13] {
t.Errorf("error found: %v, want error: %s", err, expectedErrors[13])
}
if _, err := HeaderToAbiBytes(&pb.Header{Version: QuoteVersion, AttestationKeyType: AttestationKeyType, TeeType: 0x01}); err == nil || err.Error() != expectedErrors[14] {
t.Errorf("error found: %v, want error: %s", err, expectedErrors[14])
}
if _, err := EnclaveReportToAbiBytes(&pb.EnclaveReport{}); err == nil || err.Error() != expectedErrors[15] {
t.Errorf("error found: %v, want error: %s", err, expectedErrors[15])
}
}
go-tdx-guest-0.3.1/client/ 0000775 0000000 0000000 00000000000 14563713763 0015337 5 ustar 00root root 0000000 0000000 go-tdx-guest-0.3.1/client/client.go 0000664 0000000 0000000 00000012027 14563713763 0017146 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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 client provides the library functions to get a TDX quote
// from the TDX guest device
package client
import (
"flag"
"fmt"
"os"
"github.com/google/go-tdx-guest/abi"
labi "github.com/google/go-tdx-guest/client/linuxabi"
"github.com/google/logger"
)
var tdxGuestPath = flag.String("tdx_guest_device_path", "default",
"Path to TDX guest device. If \"default\", uses platform default or a fake if testing.")
// Device encapsulates the possible commands to the TDX guest device.
// Deprecated: The Device interface is deprecated, and use of quote provider interface is
// recommended for fetching attestation quote.
type Device interface {
Open(path string) error
Close() error
Ioctl(command uintptr, argument any) (uintptr, error)
}
// QuoteProvider encapsulates calls to attestation quote.
type QuoteProvider interface {
IsSupported() error
GetRawQuote(reportData [64]byte) ([]uint8, error)
}
// UseDefaultTdxGuestDevice returns true if tdxGuestPath=default.
func UseDefaultTdxGuestDevice() bool {
return *tdxGuestPath == "default"
}
// getReport requests for tdx report by making an ioctl call.
func getReport(d Device, reportData [64]byte) ([]uint8, error) {
tdxReportReq := labi.TdxReportReq{}
copy(tdxReportReq.ReportData[:], reportData[:])
result, err := d.Ioctl(labi.IocTdxGetReport, &tdxReportReq)
if err != nil {
return nil, err
}
if result != uintptr(labi.TdxAttestSuccess) {
return nil, fmt.Errorf("unable to get the report: %d", result)
}
return tdxReportReq.TdReport[:], nil
}
// GetRawQuote uses Quote provider or Device(deprecated) to get the quote in byte array.
func GetRawQuote(quoteProvider any, reportData [64]byte) ([]uint8, error) {
switch qp := quoteProvider.(type) {
case Device:
return getRawQuoteViaDevice(qp, reportData)
case QuoteProvider:
return getRawQuoteViaProvider(qp, reportData)
default:
return nil, fmt.Errorf("unsupported quote provider type: %T", quoteProvider)
}
}
// getRawQuoteViaDevice uses TDX device driver to call getReport for report and convert it to
// quote using an ioctl call.
func getRawQuoteViaDevice(d Device, reportData [64]byte) ([]uint8, error) {
logger.V(1).Info("Get raw TDX quote via Device")
tdReport, err := getReport(d, reportData)
if err != nil {
return nil, err
}
tdxHdr := &labi.TdxQuoteHdr{
Status: 0,
Version: 1,
InLen: labi.TdReportSize,
OutLen: 0,
}
copy(tdxHdr.Data[:], tdReport[:labi.TdReportSize])
tdxReq := labi.TdxQuoteReq{
Buffer: tdxHdr,
Length: labi.ReqBufSize,
}
result, err := d.Ioctl(labi.IocTdxGetQuote, &tdxReq)
if err != nil {
return nil, err
}
if result != uintptr(labi.TdxAttestSuccess) {
return nil, fmt.Errorf("unable to get the quote")
}
if tdxHdr.Status != 0 {
if labi.GetQuoteInFlight == tdxHdr.Status {
return nil, fmt.Errorf("the device driver return busy")
} else if labi.GetQuoteServiceUnavailable == tdxHdr.Status {
return nil, fmt.Errorf("request feature is not supported")
} else if tdxHdr.OutLen == 0 || tdxHdr.OutLen > labi.ReqBufSize {
return nil, fmt.Errorf("invalid Quote size: %v. It must be > 0 and <= : %v", tdxHdr.OutLen, labi.ReqBufSize)
}
return nil, fmt.Errorf("unexpected error: %v", tdxHdr.Status)
}
return tdxHdr.Data[:tdxHdr.OutLen], nil
}
// getRawQuoteViaProvider use QuoteProvider to fetch quote in byte array format.
func getRawQuoteViaProvider(qp QuoteProvider, reportData [64]byte) ([]uint8, error) {
if err := qp.IsSupported(); err == nil {
logger.V(1).Info("Get raw TDX quote via QuoteProvider")
quote, err := qp.GetRawQuote(reportData)
return quote, err
}
return fallbackToDeviceForRawQuote(reportData)
}
// GetQuote uses Quote provider or Device(deprecated) to get the quote in byte array and convert it
// into proto.
// Supported quote formats - QuoteV4.
func GetQuote(quoteProvider any, reportData [64]byte) (any, error) {
quotebytes, err := GetRawQuote(quoteProvider, reportData)
if err != nil {
return nil, err
}
quote, err := abi.QuoteToProto(quotebytes)
if err != nil {
return nil, err
}
return quote, nil
}
// fallbackToDeviceForRawQuote opens tdx_guest device to fetch raw quote.
func fallbackToDeviceForRawQuote(reportData [64]byte) ([]uint8, error) {
// Fall back to TDX device driver.
device, err := OpenDevice()
if err != nil {
return nil, fmt.Errorf("neither TDX device, nor ConfigFs is available to fetch attestation quote")
}
bytes, err := getRawQuoteViaDevice(device, reportData)
device.Close()
return bytes, err
}
func init() {
logger.Init("", false, false, os.Stdout)
}
go-tdx-guest-0.3.1/client/client_linux.go 0000664 0000000 0000000 00000007323 14563713763 0020370 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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
// Package client provides an interface to the Intel TDX guest device commands.
package client
import (
"fmt"
"unsafe"
"github.com/google/go-configfs-tsm/configfs/linuxtsm"
"github.com/google/go-configfs-tsm/report"
labi "github.com/google/go-tdx-guest/client/linuxabi"
"golang.org/x/sys/unix"
)
// defaultTdxGuestDevicePath is the platform's usual device path to the TDX guest.
const defaultTdxGuestDevicePath = "/dev/tdx_guest"
// LinuxDevice implements the Device interface with Linux ioctls.
type LinuxDevice struct {
fd int
}
// Open opens the TDX guest device from a given path
func (d *LinuxDevice) Open(path string) error {
fd, err := unix.Open(path, unix.O_RDWR|unix.O_SYNC, 0)
if err != nil {
d.fd = -1
return fmt.Errorf("could not open Intel TDX guest device at %q: %v", path, err)
}
d.fd = fd
return nil
}
// OpenDevice opens the TDX guest device.
func OpenDevice() (*LinuxDevice, error) {
result := &LinuxDevice{}
path := *tdxGuestPath
if UseDefaultTdxGuestDevice() {
path = defaultTdxGuestDevicePath
}
if err := result.Open(path); err != nil {
return nil, err
}
return result, nil
}
// Close closes the TDX guest device.
func (d *LinuxDevice) Close() error {
if d.fd == -1 { // Not open
return nil
}
if err := unix.Close(d.fd); err != nil {
return err
}
// Prevent double-close.
d.fd = -1
return nil
}
// Ioctl sends a command with its wrapped request and response values to the Linux device.
func (d *LinuxDevice) Ioctl(command uintptr, req any) (uintptr, error) {
if d.fd == -1 {
return 0, fmt.Errorf("intel TDX Guest Device is not open")
}
switch sreq := req.(type) {
case *labi.TdxQuoteReq:
abi := sreq.ABI()
result, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(d.fd), command, uintptr(abi.Pointer()))
abi.Finish(sreq)
if errno == unix.EBUSY {
return 0, errno
} else if errno == unix.ENOTTY {
return 0, fmt.Errorf("invalid ioctl! use QuoteProvider to fetch attestation quote")
} else if errno != 0 {
return 0, errno
}
return result, nil
case *labi.TdxReportReq:
result, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(d.fd), command, uintptr(unsafe.Pointer(req.(*labi.TdxReportReq))))
if errno != 0 {
return 0, errno
}
return result, nil
}
return 0, fmt.Errorf("unexpected request value: %v", req)
}
// LinuxConfigFsQuoteProvider implements the QuoteProvider interface to fetch
// attestation quote via ConfigFS.
type LinuxConfigFsQuoteProvider struct{}
// IsSupported checks if TSM client can be created to use ConfigFS system.
func (p *LinuxConfigFsQuoteProvider) IsSupported() error {
_, err := linuxtsm.MakeClient()
return err
}
// GetRawQuote returns byte format attestation quote via ConfigFS.
func (p *LinuxConfigFsQuoteProvider) GetRawQuote(reportData [64]byte) ([]uint8, error) {
req := &report.Request{
InBlob: reportData[:],
GetAuxBlob: false,
}
resp, err := linuxtsm.GetReport(req)
if err != nil {
return nil, err
}
tdReport := resp.OutBlob
return tdReport, nil
}
// GetQuoteProvider returns an instance of LinuxConfigFsQuoteProvider.
func GetQuoteProvider() (*LinuxConfigFsQuoteProvider, error) {
return &LinuxConfigFsQuoteProvider{}, nil
}
go-tdx-guest-0.3.1/client/client_macos.go 0000664 0000000 0000000 00000004055 14563713763 0020332 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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 darwin
// Package client provides an interface to the Intel TDX guest device commands.
package client
import (
"fmt"
)
// defaultTdxGuestDevicePath is the platform's usual device path to the TDX guest.
const defaultTdxGuestDevicePath = "unknown"
// MacOSDevice implements the Device interface with Linux ioctls.
type MacOSDevice struct{}
// Open is not supported on MacOS.
func (*MacOSDevice) Open(_ string) error {
return fmt.Errorf("MacOS is unsupported")
}
// OpenDevice fails on MacOS.
func OpenDevice() (*MacOSDevice, error) {
return nil, fmt.Errorf("MacOS is unsupported")
}
// Close is not supported on MacOS.
func (*MacOSDevice) Close() error {
return fmt.Errorf("MacOS is unsupported")
}
// Ioctl is not supported on MacOS.
func (*MacOSDevice) Ioctl(_ uintptr, _ any) (uintptr, error) {
return 0, fmt.Errorf("MacOS is unsupported")
}
// MacOsConfigFsQuoteProvider implements the QuoteProvider interface to fetch attestation quote via ConfigFS.
type MacOsConfigFsQuoteProvider struct{}
// IsSupported is not supported on MacOS.
func (p *MacOsConfigFsQuoteProvider) IsSupported() error {
return fmt.Errorf("MacOS is unsupported")
}
// GetRawQuote is not supported on MacOS.
func (p *MacOsConfigFsQuoteProvider) GetRawQuote(reportData [64]byte) ([]uint8, error) {
return nil, fmt.Errorf("MacOS is unsupported")
}
// GetQuoteProvider is not supported on MacOS.
func GetQuoteProvider() (*MacOsConfigFsQuoteProvider, error) {
return nil, fmt.Errorf("MacOS is unsupported")
}
go-tdx-guest-0.3.1/client/client_test.go 0000664 0000000 0000000 00000010357 14563713763 0020211 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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 client
import (
"bytes"
"fmt"
"sync"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-tdx-guest/abi"
test "github.com/google/go-tdx-guest/testing"
"google.golang.org/protobuf/testing/protocmp"
)
var devMu sync.Once
var device Device
var quoteProvider QuoteProvider
var tests []test.TestCase
const defaultTDXDevicePath = "/dev/tdx-guest"
func initialize() {
for _, tc := range test.TestCases() {
// Don't test faked errors when running real hardware tests.
if !UseDefaultTdxGuestDevice() && tc.WantErr != "" {
continue
}
tests = append(tests, tc)
}
tdxTestQuoteProvider, err := test.TcQuoteProvider(tests)
if err != nil {
panic(fmt.Sprintf("failed to create test quote provider: %v", err))
}
quoteProvider = tdxTestQuoteProvider
// Choose a mock device or a real device depending on the --tdx_guest_device_path flag.
if UseDefaultTdxGuestDevice() {
tdxTestDevice, err := test.TcDevice(tests)
if err != nil {
panic(fmt.Sprintf("failed to create test device: %v", err))
}
if err := tdxTestDevice.Open(defaultTDXDevicePath); err != nil {
panic(err)
}
device = tdxTestDevice
return
}
client, err := OpenDevice()
if err != nil {
panic(err)
}
device = client
}
func TestGetReport(t *testing.T) {
devMu.Do(initialize)
for _, tc := range test.TestCases() {
t.Run(tc.Name, func(t *testing.T) {
got, err := getReport(device, tc.Input)
if err != nil {
t.Errorf("failed to get the report: %v", err)
}
if tc.WantErr == "" {
want := tc.Report
if !bytes.Equal(got[:], want[:]) {
t.Errorf("Got %v want %v", got, want)
}
}
})
}
}
func TestGetRawQuote(t *testing.T) {
devMu.Do(initialize)
for _, tc := range test.TestCases() {
t.Run(tc.Name, func(t *testing.T) {
got, err := GetRawQuote(device, tc.Input)
if !test.Match(err, tc.WantErr) {
t.Fatalf("GetRawQuote(device, %v) = %v, %v. Want err: %q", tc.Input, got, err, tc.WantErr)
}
if tc.WantErr == "" {
want := tc.Quote
if !bytes.Equal(got, want) {
t.Errorf("GetRawQuote(device, %v) = %v want %v", tc.Input, got, want)
}
}
})
}
}
func TestGetQuote(t *testing.T) {
devMu.Do(initialize)
for _, tc := range test.TestCases() {
t.Run(tc.Name, func(t *testing.T) {
got, err := GetQuote(device, tc.Input)
if !test.Match(err, tc.WantErr) {
t.Fatalf("Expected %v got err: %v", err, tc.WantErr)
}
if tc.WantErr == "" {
quote, err := abi.QuoteToProto(tc.Quote)
if err != nil {
t.Error(err)
}
if diff := cmp.Diff(got, quote, protocmp.Transform()); diff != "" {
t.Errorf("Difference in quote: %s", diff)
}
}
})
}
}
func TestGetRawQuoteViaProvider(t *testing.T) {
devMu.Do(initialize)
for _, tc := range test.TestCases() {
t.Run(tc.Name, func(t *testing.T) {
got, err := GetRawQuote(quoteProvider, tc.Input)
if !test.Match(err, tc.WantErr) {
t.Fatalf("GetRawQuoteViaProvider(quoteProvider, %v) = %v, %v. Want err: %q", tc.Input, got, err, tc.WantErr)
}
if tc.WantErr == "" {
want := tc.Quote
if !bytes.Equal(got, want) {
t.Errorf("GetRawQuoteViaProvider(quoteProvider, %v) = %v want %v", tc.Input, got, want)
}
}
})
}
}
func TestGetQuoteViaProvider(t *testing.T) {
devMu.Do(initialize)
for _, tc := range test.TestCases() {
t.Run(tc.Name, func(t *testing.T) {
got, err := GetQuote(quoteProvider, tc.Input)
if !test.Match(err, tc.WantErr) {
t.Fatalf("Expected %v got err: %v", err, tc.WantErr)
}
if tc.WantErr == "" {
quote, err := abi.QuoteToProto(tc.Quote)
if err != nil {
t.Error(err)
}
if diff := cmp.Diff(got, quote, protocmp.Transform()); diff != "" {
t.Errorf("Difference in quote: %s", diff)
}
}
})
}
}
go-tdx-guest-0.3.1/client/client_windows.go 0000664 0000000 0000000 00000003716 14563713763 0020725 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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
package client
import (
"fmt"
)
// WindowsDevice implements the Device interface with Linux ioctls.
type WindowsDevice struct{}
// Open is not supported on Windows.
func (*WindowsDevice) Open(_ string) error {
return fmt.Errorf("Windows is unsupported")
}
// OpenDevice fails on Windows.
func OpenDevice() (*WindowsDevice, error) {
return nil, fmt.Errorf("Windows is unsupported")
}
// Close is not supported on Windows.
func (*WindowsDevice) Close() error {
return fmt.Errorf("Windows is unsupported")
}
// Ioctl is not supported on Windows.
func (*WindowsDevice) Ioctl(_ uintptr, _ any) (uintptr, error) {
// The GuestAttestation library on Windows is closed source.
return 0, fmt.Errorf("Windows is unsupported")
}
// WindowsConfigFsQuoteProvider implements the QuoteProvider interface to fetch attestation quote via ConfigFS.
type WindowsConfigFsQuoteProvider struct{}
// IsSupported is not supported on Windows.
func (p *WindowsConfigFsQuoteProvider) IsSupported() error {
return fmt.Errorf("Windows is unsupported")
}
// GetRawQuote is not supported on Windows.
func (p *WindowsConfigFsQuoteProvider) GetRawQuote(reportData [64]byte) ([]uint8, error) {
return nil, fmt.Errorf("Windows is unsupported")
}
// GetQuoteProvider is not supported on Windows.
func GetQuoteProvider() (*WindowsConfigFsQuoteProvider, error) {
return nil, fmt.Errorf("Windows is unsupported")
}
go-tdx-guest-0.3.1/client/linuxabi/ 0000775 0000000 0000000 00000000000 14563713763 0017152 5 ustar 00root root 0000000 0000000 go-tdx-guest-0.3.1/client/linuxabi/linux_abi.go 0000664 0000000 0000000 00000013437 14563713763 0021463 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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 linuxabi describes the ABI required for the TDX ioctl commands
package linuxabi
import (
"fmt"
"reflect"
"unsafe"
)
const (
iocNrbits = 8
iocTypebits = 8
iocSizebits = 14
iocDirbits = 2
iocNrshift = 0
iocTypeshift = (iocNrshift + iocNrbits)
iocSizeshift = (iocTypeshift + iocTypebits)
iocDirshift = (iocSizeshift + iocSizebits)
iocWrite = 1
iocRead = 2
// Linux /dev/tdx-guest ioctl interface
iocTypeTdxGuestReq = 'T'
iocTdxWithoutNrWithoutSize = ((iocWrite | iocRead) << iocDirshift) |
(iocTypeTdxGuestReq << iocTypeshift)
// IocTdxGetReport is the ioctl command for getting an attestation report.
IocTdxGetReport = iocTdxWithoutNrWithoutSize | (unsafe.Sizeof(TdxReportReq{}) << iocSizeshift) | (0x1 << iocNrshift)
// IocTdxGetQuote is the ioctl command for getting an attestation quote.
IocTdxGetQuote = iocTdxWithoutNrWithoutSize | (unsafe.Sizeof(TdxQuoteReqABI{}) << iocSizeshift) | (0x2 << iocNrshift)
// TdReportDataSize is a constant for TDX ReportData size
TdReportDataSize = 64
// TdReportSize is a constant for TDX Report size
TdReportSize = 1024
// HeaderSize is the size of header to serialized quote request
HeaderSize = 4
// ReqBufSize is a constant for serialized Tdx quote response
ReqBufSize = 4 * 4 * 1024
// TdxUUIDSize is a constant for intel TDQE ID
TdxUUIDSize = 16
// GetQuoteReq is a constant for report request
GetQuoteReq = 0
// GetQuoteResp is a constant for report response
GetQuoteResp = 1
)
// EsResult is the status code type for Linux's GHCB communication results.
type EsResult int
// constant for TD quote status code.
const (
GetQuoteSuccess = 0
GetQuoteInFlight = 0xffffffffffffffff
GetQuoteError = 0x8000000000000000
GetQuoteServiceUnavailable = 0x8000000000000001
)
const (
// TdxAttestSuccess denotes success
TdxAttestSuccess = iota
// TdxAttestErrorBusy returns when device driver is busy
TdxAttestErrorBusy = 0x0009
// TdxAttestErrorQuoteFailure denotes failure to get the TD Quote
TdxAttestErrorQuoteFailure = 0x0008
// TdxAttestErrorNotSupported denotes request feature is not supported
TdxAttestErrorNotSupported = 0x0007
// TdxAttestErrorUnexpected denotes Unexpected error
TdxAttestErrorUnexpected = 0x0001
)
// TdxReportReq is Linux's tdx-guest ABI for TDX Report. The
// types here enhance runtime safety when using Ioctl as an interface.
type TdxReportReq struct {
/* Report data of 64 bytes */
ReportData [TdReportDataSize]byte
/* Actual TD Report Data */
TdReport [TdReportSize]byte
}
// MsgHeader is used to add header field to serialized request and response message.
type MsgHeader struct {
MajorVersion uint16
MinorVersion uint16
MsgType uint32
Size uint32 // size of the whole message, include this header, in byte
ErrorCode uint32 // used in response only
}
// SerializedGetQuoteReq is used to serialized the request message to get quote.
type SerializedGetQuoteReq struct {
Header MsgHeader // header.type = GET_QUOTE_REQ
ReportSize uint32 // cannot be 0
IDListSize uint32 // length of id_list, in byte, can be 0
ReportIDList [TdReportSize]uint8 // report followed by id list - [TODO revisit if attestation key ID is included]
}
// TdxQuoteHdr is Linux's tdx-guest ABI for quote header
type TdxQuoteHdr struct {
/* Quote version, filled by TD */
Version uint64
/* Status code of Quote request, filled by VMM */
Status uint64
/* Length of TDREPORT, filled by TD */
InLen uint32
/* Length of Quote, filled by VMM */
OutLen uint32
/* Actual Quote data or TDREPORT on input */
Data [ReqBufSize]byte
}
// ABI returns the object itself.
func (r *TdxQuoteHdr) ABI() BinaryConversion { return r }
// Pointer returns a pointer to the object itself.
func (r *TdxQuoteHdr) Pointer() unsafe.Pointer { return unsafe.Pointer(r) }
// Finish is a no-op.
func (r *TdxQuoteHdr) Finish(BinaryConvertible) error {
return nil
}
// TdxQuoteReqABI is Linux's tdx-guest ABI for quote response
type TdxQuoteReqABI struct {
Buffer unsafe.Pointer
Length uint64
}
// TdxQuoteReq is Linux's tdx-guest ABI for TDX Report. The
// types here enhance runtime safety when using Ioctl as an interface.
type TdxQuoteReq struct {
Buffer BinaryConvertible
Length uint64
}
// ABI returns the object itself.
func (r *TdxQuoteReq) ABI() BinaryConversion {
return &TdxQuoteReqABI{
Buffer: unsafe.Pointer(r.Buffer.ABI().Pointer()),
Length: r.Length,
}
}
// Pointer returns a pointer to the object itself.
func (r *TdxQuoteReqABI) Pointer() unsafe.Pointer { return unsafe.Pointer(r) }
// Finish is a no-op.
func (r *TdxQuoteReqABI) Finish(b BinaryConvertible) error {
_, ok := b.(*TdxQuoteReq)
if !ok {
return fmt.Errorf("Finish argument is %v. Expects a *TdxReportReq", reflect.TypeOf(b))
}
return nil
}
// BinaryConversion is an interface that abstracts a "stand-in" object that passes through an ABI
// boundary and can finalize changes to the original object.
type BinaryConversion interface {
Pointer() unsafe.Pointer
Finish(BinaryConvertible) error
}
// BinaryConvertible is an interface for an object that can produce a partner BinaryConversion
// object to allow its representation to pass the ABI boundary.
type BinaryConvertible interface {
ABI() BinaryConversion
}
go-tdx-guest-0.3.1/go.mod 0000664 0000000 0000000 00000000625 14563713763 0015172 0 ustar 00root root 0000000 0000000 module github.com/google/go-tdx-guest
go 1.19
require (
github.com/google/go-cmp v0.5.7
github.com/google/go-configfs-tsm v0.2.2
github.com/google/go-sev-guest v0.8.0
github.com/google/logger v1.1.1
go.uber.org/multierr v1.11.0
golang.org/x/crypto v0.17.0
golang.org/x/sys v0.15.0
google.golang.org/protobuf v1.31.0
)
require golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
go-tdx-guest-0.3.1/go.sum 0000664 0000000 0000000 00000004323 14563713763 0015216 0 ustar 00root root 0000000 0000000 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-configfs-tsm v0.2.2 h1:YnJ9rXIOj5BYD7/0DNnzs8AOp7UcvjfTvt215EWcs98=
github.com/google/go-configfs-tsm v0.2.2/go.mod h1:EL1GTDFMb5PZQWDviGfZV9n87WeGTR/JUg13RfwkgRo=
github.com/google/go-sev-guest v0.8.0 h1:IIZIqdcMJXgTm1nMvId442OUpYebbWDWa9bi9/lUUwc=
github.com/google/go-sev-guest v0.8.0/go.mod h1:hc1R4R6f8+NcJwITs0L90fYWTsBpd1Ix+Gur15sqHDs=
github.com/google/logger v1.1.1 h1:+6Z2geNxc9G+4D4oDO9njjjn2d0wN5d7uOo0vOIW1NQ=
github.com/google/logger v1.1.1/go.mod h1:BkeJZ+1FhQ+/d087r4dzojEg1u2ZX+ZqG1jTUrLM+zQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
go-tdx-guest-0.3.1/pcs/ 0000775 0000000 0000000 00000000000 14563713763 0014646 5 ustar 00root root 0000000 0000000 go-tdx-guest-0.3.1/pcs/pcs.go 0000664 0000000 0000000 00000041230 14563713763 0015762 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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 pcs defines values specified for the Intel's Provisioning Certification Service
package pcs
import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/hex"
"errors"
"fmt"
"strconv"
"time"
)
const (
pckCertExtensionSize = 6
sgxExtensionMinSize = 4
tcbExtensionSize = 18
ppidSize = 16
cpuSvnSize = 16
fmspcSize = 6
pceIDSize = 2
tcbComponentSize = 16
)
var (
pcsSgxBaseURL = "https://api.trustedservices.intel.com/sgx/certification/v4"
pcsTdxBaseURL = "https://api.trustedservices.intel.com/tdx/certification/v4"
sgxTcbComponentOidPrefix = []int{1, 2, 840, 113741, 1, 13, 1, 2}
// OidSgxExtension is the x509v3 extension for PCK certificate's SGX Extension.
OidSgxExtension = asn1.ObjectIdentifier([]int{1, 2, 840, 113741, 1, 13, 1})
// OidPPID is the x509v3 extension for PCK certificate's SGX Extensions PPID value.
OidPPID = asn1.ObjectIdentifier([]int{1, 2, 840, 113741, 1, 13, 1, 1})
// OidTCB is the x509v3 extension for PCK certificate's SGX Extensions TCB struct.
OidTCB = asn1.ObjectIdentifier([]int{1, 2, 840, 113741, 1, 13, 1, 2})
// OidPCESvn is the x509v3 extension for PCK certificate's SGX Extensions PCESVN component in TCB struct.
OidPCESvn = asn1.ObjectIdentifier([]int{1, 2, 840, 113741, 1, 13, 1, 2, 17})
// OidCPUSvn is the x509v3 extension for PCK certificate's SGX Extensions CPUSVN component in TCB struct.
OidCPUSvn = asn1.ObjectIdentifier([]int{1, 2, 840, 113741, 1, 13, 1, 2, 18})
// OidPCEID is the x509v3 extension for PCK certificate's SGX Extensions PCEID value.
OidPCEID = asn1.ObjectIdentifier([]int{1, 2, 840, 113741, 1, 13, 1, 3})
// OidFMSPC is the x509v3 extension for PCK certificate's SGX Extensions FMSPC value.
OidFMSPC = asn1.ObjectIdentifier([]int{1, 2, 840, 113741, 1, 13, 1, 4})
// ErrPckExtInvalid error returned when parsing PCK certificate's extension returns leftover bytes
ErrPckExtInvalid = errors.New("unexpected leftover bytes for PCK certificate's extension")
// ErrTcbExtInvalid error returned when parsing of TCB in SGX Extension returns leftover bytes
ErrTcbExtInvalid = errors.New("unexpected leftover bytes for TCB extension inside SGX extension field")
// ErrTcbCompInvalid error returned when parsing of TCB components in SGX Extension returns leftover bytes
ErrTcbCompInvalid = errors.New("unexpected leftover bytes for TCB components in TCB Extension inside SGX extension field")
// ErrSgxExtInvalid error returned when parsing SGX extensions returns leftover bytes
ErrSgxExtInvalid = errors.New("unexpected leftover bytes when parsing SGX extensions")
)
// TdxTcbInfo struct is used to map response from tcbInfo PCS API Service
type TdxTcbInfo struct {
TcbInfo TcbInfo `json:"tcbInfo"`
Signature string `json:"signature"`
}
// TcbInfo struct is used to map response from tcbInfo field
type TcbInfo struct {
ID string `json:"id"`
Version byte `json:"version"`
IssueDate time.Time `json:"issueDate"`
NextUpdate time.Time `json:"nextUpdate"`
Fmspc string `json:"fmspc"`
PceID string `json:"pceId"`
TcbType byte `json:"tcbType"`
TcbEvaluationDataNumber int `json:"tcbEvaluationDataNumber"`
TdxModule TdxModule `json:"tdxModule"`
TdxModuleIdentities []TdxModuleIdentity `json:"tdxModuleIdentities"`
TcbLevels []TcbLevel `json:"tcbLevels"`
}
// TdxModule struct is used to map response from tcbInfo for tdxModule field
type TdxModule struct {
Mrsigner HexBytes `json:"mrsigner"`
Attributes HexBytes `json:"attributes"`
AttributesMask HexBytes `json:"attributesMask"`
}
// TdxModuleIdentity struct is used to map response from tcbInfo for TdxModuleIdentity field
type TdxModuleIdentity struct {
ID string `json:"id"`
Mrsigner HexBytes `json:"mrsigner"`
Attributes HexBytes `json:"attributes"`
AttributesMask HexBytes `json:"attributesMask"`
TcbLevels []TcbLevel `json:"tcbLevels"`
}
// TcbLevel struct is used to map TCB Level field
type TcbLevel struct {
Tcb Tcb `json:"tcb"`
TcbDate string `json:"tcbDate"`
TcbStatus TcbComponentStatus `json:"tcbStatus"`
AdvisoryIDs []string `json:"advisoryIDs"`
}
// Tcb struct is used to map TCB field
type Tcb struct {
SgxTcbcomponents []TcbComponent `json:"sgxtcbcomponents"`
Pcesvn uint16 `json:"pcesvn"`
TdxTcbcomponents []TcbComponent `json:"tdxtcbcomponents"`
Isvsvn uint32 `json:"isvsvn"`
}
// TcbComponent struct is used to map sgx/tdx tcb components
type TcbComponent struct {
Svn byte `json:"svn"`
Category string `json:"category"`
Type string `json:"type"`
}
// QeIdentity struct is used to map response from enclaveIdentity PCS API Call
type QeIdentity struct {
EnclaveIdentity EnclaveIdentity `json:"enclaveIdentity"`
Signature string `json:"signature"`
}
// EnclaveIdentity struct is used to map enclave identity field
type EnclaveIdentity struct {
ID string `json:"id"`
Version byte `json:"version"`
IssueDate time.Time `json:"issueDate"`
NextUpdate time.Time `json:"nextUpdate"`
TcbEvaluationDataNumber int `json:"tcbEvaluationDataNumber"`
Miscselect HexBytes `json:"miscselect"`
MiscselectMask HexBytes `json:"miscselectMask"`
Attributes HexBytes `json:"attributes"`
AttributesMask HexBytes `json:"attributesMask"`
Mrsigner HexBytes `json:"mrsigner"`
IsvProdID uint16 `json:"isvprodid"`
TcbLevels []TcbLevel `json:"tcbLevels"`
}
// PckCertTCB represents struct that store information related to TCB components
type PckCertTCB struct {
PCESvn uint16
CPUSvn []byte
CPUSvnComponents []byte
}
// PckExtensions represents the information stored in the x509 extensions of a PCK certificate which
// will be required for verification
type PckExtensions struct {
PPID string
TCB PckCertTCB
PCEID string
FMSPC string
}
// HexBytes struct contains hex decoded string to bytes value
type HexBytes struct {
Bytes []byte
}
// UnmarshalJSON for hex bytes converts hex encoded string to bytes
func (hb *HexBytes) UnmarshalJSON(s []byte) error {
unquoted, err := strconv.Unquote(string(s))
if err != nil {
return err
}
val, err := hex.DecodeString(unquoted)
if err != nil {
return err
}
hb.Bytes = val
return nil
}
// TcbComponentStatus represents the status of corresponding TCB field
type TcbComponentStatus string
const (
// TcbComponentStatusUpToDate denotes tcb status as UpToDate
TcbComponentStatusUpToDate TcbComponentStatus = "UpToDate"
// TcbComponentStatusSwHardeningNeeded denotes tcb status as SWHardeningNeeded
TcbComponentStatusSwHardeningNeeded TcbComponentStatus = "SWHardeningNeeded"
// TcbComponentStatusConfigurationNeeded denotes tcb status as ConfigurationNeeded
TcbComponentStatusConfigurationNeeded TcbComponentStatus = "ConfigurationNeeded"
// TcbComponentStatusConfigurationAndSWHardeningNeeded denotes tcb status as ConfigurationAndSWHardeningNeeded
TcbComponentStatusConfigurationAndSWHardeningNeeded TcbComponentStatus = "ConfigurationAndSWHardeningNeeded"
// TcbComponentStatusOutOfDate denotes tcb status as OutOfDate
TcbComponentStatusOutOfDate TcbComponentStatus = "OutOfDate"
// TcbComponentStatusOutOfDateConfigurationNeeded denotes tcb status as OutOfDateConfigurationNeeded
TcbComponentStatusOutOfDateConfigurationNeeded TcbComponentStatus = "OutOfDateConfigurationNeeded"
// TcbComponentStatusRevoked denotes tcb status as Revoked
TcbComponentStatusRevoked TcbComponentStatus = "Revoked"
)
// UnmarshalJSON for TcbComponentStatus maps tcb status to corresponding valid strings
func (st *TcbComponentStatus) UnmarshalJSON(s []byte) error {
unquotedStatus, err := strconv.Unquote(string(s))
if err != nil {
return err
}
val := TcbComponentStatus(unquotedStatus)
switch val {
case TcbComponentStatusUpToDate, TcbComponentStatusSwHardeningNeeded, TcbComponentStatusConfigurationNeeded,
TcbComponentStatusConfigurationAndSWHardeningNeeded, TcbComponentStatusOutOfDate, TcbComponentStatusOutOfDateConfigurationNeeded, TcbComponentStatusRevoked:
*st = val
default:
return fmt.Errorf("unexpected tcb status found: %q", val)
}
return nil
}
func sgxTcbComponentOid(component int) asn1.ObjectIdentifier {
return asn1.ObjectIdentifier(append(sgxTcbComponentOidPrefix, component))
}
func asn1U8(ext *pkix.AttributeTypeAndValue, field string, out *byte) error {
if ext == nil {
return fmt.Errorf("no extension for field %s", field)
}
val, ok := ext.Value.(int64)
if !ok {
return fmt.Errorf("%s extension is of type %T, expected int64", field, ext.Value)
}
if val < 0 || val > 255 {
return fmt.Errorf("int value for field %s isn't a byte: %d", field, val)
}
*out = byte(val)
return nil
}
func asn1U16(ext *pkix.AttributeTypeAndValue, field string, out *uint16) error {
if ext == nil {
return fmt.Errorf("no extension for field %s", field)
}
val, ok := ext.Value.(int64)
if !ok {
return fmt.Errorf("%s extension is of type %T, expected int64", field, ext.Value)
}
if val < 0 || val > 65535 {
return fmt.Errorf("int value for field %s isn't a uint16: %d", field, val)
}
*out = uint16(val)
return nil
}
func asn1OctetString(ext *pkix.Extension, field string, size int) ([]byte, error) {
if ext == nil {
return nil, fmt.Errorf("no extension for field %s", field)
}
if len(ext.Value) == size {
return ext.Value, nil
}
var octet []byte
rest, err := asn1.Unmarshal(ext.Value, &octet)
if err != nil {
return nil, fmt.Errorf("could not parse %v extension as an octet string %v (value %v): %v", field, *ext, ext.Value, err)
}
if len(rest) != 0 {
return nil, fmt.Errorf("expected leftover bytes in extension value for field %v", field)
}
// Check the expected length.
if size >= 0 && len(octet) != size {
return nil, fmt.Errorf("%v extension's value size is %d, expected %d", field, len(octet), size)
}
return octet, nil
}
func extractTcbExtension(tcbExtension []asn1.RawValue, tcb *PckCertTCB) error {
tcbComponents := make([]byte, tcbComponentSize)
for _, ext := range tcbExtension {
var tcbValue pkix.AttributeTypeAndValue
rest, err := asn1.Unmarshal(ext.FullBytes, &tcbValue)
if err != nil {
return fmt.Errorf("could not parse TCB component inside the TCB extension in the PCK certificate: %v", err)
}
if len(rest) != 0 {
return ErrTcbCompInvalid
}
for i := 0; i < tcbComponentSize; i++ {
tcbComponentOid := sgxTcbComponentOid(i + 1)
if tcbValue.Type.Equal(tcbComponentOid) {
phrase := fmt.Sprintf("sgxTcbComponent%d", i+1)
var val byte
if err := asn1U8(&tcbValue, phrase, &val); err != nil {
return err
}
tcbComponents[i] = val
break
}
}
if tcbValue.Type.Equal(OidPCESvn) {
if err := asn1U16(&tcbValue, "PCESvn", &tcb.PCESvn); err != nil {
return err
}
}
if tcbValue.Type.Equal(OidCPUSvn) {
val, ok := tcbValue.Value.([]byte)
if !ok {
return fmt.Errorf("CPUSVN component in TCB extension is of type %T, expected []byte", tcbValue.Value)
}
if len(tcbValue.Value.([]byte)) != cpuSvnSize {
return fmt.Errorf("CPUSVN component in TCB extension is of size %d, expected %d", len(tcbValue.Value.([]byte)), cpuSvnSize)
}
tcb.CPUSvn = val
}
}
tcb.CPUSvnComponents = tcbComponents
return nil
}
func extractAsn1SequenceTcbExtension(ext asn1.RawValue) (*PckCertTCB, error) {
tcb := &PckCertTCB{}
var sExtension []asn1.RawValue
rest, err := asn1.Unmarshal(ext.FullBytes, &sExtension)
if err != nil {
return nil, fmt.Errorf("could not parse TCB extension present inside the SGX extension in PCK certificate: %v", err)
}
if len(rest) != 0 {
return nil, ErrTcbExtInvalid
}
if len(sExtension) != 2 {
return nil, fmt.Errorf("TCB extension when unmarshalled is of size %d, expected 2", len(sExtension))
}
var tcbExtension []asn1.RawValue
rest, err = asn1.Unmarshal(sExtension[1].FullBytes, &tcbExtension)
if err != nil {
return nil, fmt.Errorf("could not parse TCB components present inside the SGX extension in PCK certificate: %v", err)
}
if len(rest) != 0 {
return nil, ErrTcbCompInvalid
}
if len(tcbExtension) != tcbExtensionSize {
return nil, fmt.Errorf("TCB extension is of size %d, expected %d", len(tcbExtension), tcbExtensionSize)
}
if err := extractTcbExtension(tcbExtension, tcb); err != nil {
return nil, err
}
return tcb, nil
}
func extractAsn1OctetStringExtension(name string, extension asn1.RawValue, size int) (string, error) {
var sExtension pkix.Extension
rest, err := asn1.Unmarshal(extension.FullBytes, &sExtension)
if err != nil {
return "", fmt.Errorf("could not parse %s present inside the SGX extension in PCK certificate: %v", name, err)
}
if len(rest) != 0 {
return "", fmt.Errorf("unexpected leftover bytes for %s extension inside SGX extension field", name)
}
val, err := asn1OctetString(&sExtension, name, size)
if err != nil {
return "", err
}
return hex.EncodeToString(val), nil
}
func extractSgxExtensions(extensions []asn1.RawValue) (*PckExtensions, error) {
pckExtension := &PckExtensions{}
if len(extensions) < sgxExtensionMinSize {
return nil, fmt.Errorf("SGX Extension has length %d. It should have a minimum length of %d", len(extensions), sgxExtensionMinSize)
}
for i, ext := range extensions {
var sExtension pkix.AttributeTypeAndValue
rest, err := asn1.Unmarshal(ext.FullBytes, &sExtension)
if err != nil {
return nil, fmt.Errorf("could not parse SGX extension's in PCK certificate: %v", err)
}
if len(rest) != 0 {
return nil, ErrSgxExtInvalid
}
if sExtension.Type.Equal(OidPPID) {
pckExtension.PPID, err = extractAsn1OctetStringExtension("PPID", extensions[i], ppidSize)
if err != nil {
return nil, err
}
}
if sExtension.Type.Equal(OidTCB) {
tcb, err := extractAsn1SequenceTcbExtension(extensions[i])
if err != nil {
return nil, err
}
pckExtension.TCB = *tcb
}
if sExtension.Type.Equal(OidPCEID) {
pckExtension.PCEID, err = extractAsn1OctetStringExtension("PCEID", extensions[i], pceIDSize)
if err != nil {
return nil, err
}
}
if sExtension.Type.Equal(OidFMSPC) {
pckExtension.FMSPC, err = extractAsn1OctetStringExtension("FMSPC", extensions[i], fmspcSize)
if err != nil {
return nil, err
}
}
}
return pckExtension, nil
}
func findMatchingExtension(extns []pkix.Extension, oid asn1.ObjectIdentifier) (*pkix.Extension, error) {
for _, ext := range extns {
if ext.Id.Equal(oid) {
return &ext, nil
}
}
return nil, fmt.Errorf("unable to find extension with OID %v in PCK Certificate", oid)
}
// PckCertificateExtensions returns only those x509v3 extensions from the PCK certificate into a
// struct type which will be required in verification purpose.
func PckCertificateExtensions(cert *x509.Certificate) (*PckExtensions, error) {
if len(cert.Extensions) != pckCertExtensionSize {
return nil, fmt.Errorf("PCK certificate extensions length found %d. Expected %d", len(cert.Extensions), pckCertExtensionSize)
}
sgxExt, err := findMatchingExtension(cert.Extensions, OidSgxExtension)
if err != nil {
return nil, fmt.Errorf("could not find SGX extension present in the PCK certificate: %v", err)
}
var sgxExtensions []asn1.RawValue
rest, err := asn1.Unmarshal(sgxExt.Value, &sgxExtensions)
if err != nil {
return nil, fmt.Errorf("could not parse SGX extension present in the PCK certificate: %v", err)
}
if len(rest) != 0 {
return nil, ErrPckExtInvalid
}
return extractSgxExtensions(sgxExtensions)
}
// PckCrlURL returns the Intel PCS URL for retrieving PCK CRL
func PckCrlURL(ca string) string {
return fmt.Sprintf("%s/pckcrl?ca=%s&encoding=der", pcsSgxBaseURL, ca)
}
// TcbInfoURL returns the Intel PCS URL for retrieving TCB Info
func TcbInfoURL(fmspc string) string {
return fmt.Sprintf("%s/tcb?fmspc=%s", pcsTdxBaseURL, fmspc)
}
// QeIdentityURL returns the Intel PCS URL for retrieving QE identity
func QeIdentityURL() string {
return fmt.Sprintf("%s/qe/identity", pcsTdxBaseURL)
}
go-tdx-guest-0.3.1/pcs/pcs_test.go 0000664 0000000 0000000 00000002461 14563713763 0017024 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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 pcs
import (
"encoding/hex"
"testing"
)
func TestPckCrlURL(t *testing.T) {
want := pcsSgxBaseURL + "/pckcrl?ca=platform&encoding=der"
if got := PckCrlURL("platform"); got != want {
t.Errorf(`PckCrlURL("platform") = %q. Expected %q`, got, want)
}
}
func TestTcbInfoURL(t *testing.T) {
want := pcsTdxBaseURL + "/tcb?fmspc=50806f000000"
fmspcBytes := []byte{80, 128, 111, 0, 0, 0}
fmspc := hex.EncodeToString(fmspcBytes)
if got := TcbInfoURL(fmspc); got != want {
t.Errorf("TcbInfoURL(%q) = %q. Expected %q", fmspc, got, want)
}
}
func TestQeIdentityURL(t *testing.T) {
want := pcsTdxBaseURL + "/qe/identity"
if got := QeIdentityURL(); got != want {
t.Errorf("QEIdentityURL() = %q. Expected %q", got, want)
}
}
go-tdx-guest-0.3.1/proto/ 0000775 0000000 0000000 00000000000 14563713763 0015224 5 ustar 00root root 0000000 0000000 go-tdx-guest-0.3.1/proto/checkconfig.proto 0000664 0000000 0000000 00000006174 14563713763 0020564 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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.
syntax = "proto3";
// Package checkconfig represents an attestation validation policy.
package checkconfig;
option go_package = "github.com/google/go-tdx-guest/proto/checkconfig";
// Policy is a representation of an attestation quote validation policy.
// Each field corresponds to a field on validate.Options. This format
// is useful for providing programmatic inputs to the `check` CLI tool.
message Policy {
// HeaderPolicy is representation of Header of an attestation quote validation
// policy.
HeaderPolicy header_policy = 1; // should be 20 bytes
// TDQuoteBodyPolicy is representation of TdQuoteBody of an attestation quote
// validation policy.
TDQuoteBodyPolicy td_quote_body_policy = 2; // should be 528 bytes
}
message HeaderPolicy {
uint32 minimum_qe_svn = 1; // should not exceed uint16 max
uint32 minimum_pce_svn = 2; // should not exceed uint16 max
// Unique vendor id of QE vendor
bytes qe_vendor_id = 3; // should be 16 bytes
}
message TDQuoteBodyPolicy {
bytes minimum_tee_tcb_svn = 1; // should be 16 bytes
bytes mr_seam = 2; // should be 48 bytes
bytes td_attributes = 3; // should be 8 bytes
bytes xfam = 4; // should be 8 bytes
bytes mr_td = 5; // should be 48 bytes
bytes mr_config_id = 6; // should be 48 bytes
bytes mr_owner = 7; // should be 48 bytes
bytes mr_owner_config = 8; // should be 48 bytes
repeated bytes rtmrs = 9; // should be 48 * rtmrsCount
bytes report_data = 10; // should be 64 bytes
}
// RootOfTrust represents configuration for which hardware root of trust
// certificates to use for verifying attestation quote.
message RootOfTrust {
// Paths to CA bundles for the Intel TDX.
// Must be in PEM format.
// If empty, uses the verification library's embedded certificates from Intel.
repeated string cabundle_paths = 1;
// PEM format CA bundles for Intel TDX. Combined with contents of
// cabundle_paths.
repeated string cabundles = 2;
// If true, download and check the CRL for revoked certificates.
bool check_crl = 3;
// If true, then check is not permitted to download necessary files for
// verification.
bool get_collateral = 4;
}
// Config is the overall message input for the check tool. This provides all
// the flags that configure the tool, including the validation policy.
message Config {
// The report validation policy.
Policy policy = 1;
// Configures which hardware keys to trust. Default uses library-embedded
// certificate.
RootOfTrust root_of_trust = 2;
}
go-tdx-guest-0.3.1/proto/checkconfig/ 0000775 0000000 0000000 00000000000 14563713763 0017467 5 ustar 00root root 0000000 0000000 go-tdx-guest-0.3.1/proto/checkconfig/checkconfig.pb.go 0000664 0000000 0000000 00000053105 14563713763 0022665 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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.
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.21.12
// source: checkconfig.proto
// Package checkconfig represents an attestation validation policy.
package checkconfig
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// Policy is a representation of an attestation quote validation policy.
// Each field corresponds to a field on validate.Options. This format
// is useful for providing programmatic inputs to the `check` CLI tool.
type Policy struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// HeaderPolicy is representation of Header of an attestation quote validation
// policy.
HeaderPolicy *HeaderPolicy `protobuf:"bytes,1,opt,name=header_policy,json=headerPolicy,proto3" json:"header_policy,omitempty"` // should be 20 bytes
// TDQuoteBodyPolicy is representation of TdQuoteBody of an attestation quote
// validation policy.
TdQuoteBodyPolicy *TDQuoteBodyPolicy `protobuf:"bytes,2,opt,name=td_quote_body_policy,json=tdQuoteBodyPolicy,proto3" json:"td_quote_body_policy,omitempty"` // should be 528 bytes
}
func (x *Policy) Reset() {
*x = Policy{}
if protoimpl.UnsafeEnabled {
mi := &file_checkconfig_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Policy) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Policy) ProtoMessage() {}
func (x *Policy) ProtoReflect() protoreflect.Message {
mi := &file_checkconfig_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Policy.ProtoReflect.Descriptor instead.
func (*Policy) Descriptor() ([]byte, []int) {
return file_checkconfig_proto_rawDescGZIP(), []int{0}
}
func (x *Policy) GetHeaderPolicy() *HeaderPolicy {
if x != nil {
return x.HeaderPolicy
}
return nil
}
func (x *Policy) GetTdQuoteBodyPolicy() *TDQuoteBodyPolicy {
if x != nil {
return x.TdQuoteBodyPolicy
}
return nil
}
type HeaderPolicy struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
MinimumQeSvn uint32 `protobuf:"varint,1,opt,name=minimum_qe_svn,json=minimumQeSvn,proto3" json:"minimum_qe_svn,omitempty"` // should not exceed uint16 max
MinimumPceSvn uint32 `protobuf:"varint,2,opt,name=minimum_pce_svn,json=minimumPceSvn,proto3" json:"minimum_pce_svn,omitempty"` // should not exceed uint16 max
// Unique vendor id of QE vendor
QeVendorId []byte `protobuf:"bytes,3,opt,name=qe_vendor_id,json=qeVendorId,proto3" json:"qe_vendor_id,omitempty"` // should be 16 bytes
}
func (x *HeaderPolicy) Reset() {
*x = HeaderPolicy{}
if protoimpl.UnsafeEnabled {
mi := &file_checkconfig_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *HeaderPolicy) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HeaderPolicy) ProtoMessage() {}
func (x *HeaderPolicy) ProtoReflect() protoreflect.Message {
mi := &file_checkconfig_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HeaderPolicy.ProtoReflect.Descriptor instead.
func (*HeaderPolicy) Descriptor() ([]byte, []int) {
return file_checkconfig_proto_rawDescGZIP(), []int{1}
}
func (x *HeaderPolicy) GetMinimumQeSvn() uint32 {
if x != nil {
return x.MinimumQeSvn
}
return 0
}
func (x *HeaderPolicy) GetMinimumPceSvn() uint32 {
if x != nil {
return x.MinimumPceSvn
}
return 0
}
func (x *HeaderPolicy) GetQeVendorId() []byte {
if x != nil {
return x.QeVendorId
}
return nil
}
type TDQuoteBodyPolicy struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
MinimumTeeTcbSvn []byte `protobuf:"bytes,1,opt,name=minimum_tee_tcb_svn,json=minimumTeeTcbSvn,proto3" json:"minimum_tee_tcb_svn,omitempty"` // should be 16 bytes
MrSeam []byte `protobuf:"bytes,2,opt,name=mr_seam,json=mrSeam,proto3" json:"mr_seam,omitempty"` // should be 48 bytes
TdAttributes []byte `protobuf:"bytes,3,opt,name=td_attributes,json=tdAttributes,proto3" json:"td_attributes,omitempty"` // should be 8 bytes
Xfam []byte `protobuf:"bytes,4,opt,name=xfam,proto3" json:"xfam,omitempty"` // should be 8 bytes
MrTd []byte `protobuf:"bytes,5,opt,name=mr_td,json=mrTd,proto3" json:"mr_td,omitempty"` // should be 48 bytes
MrConfigId []byte `protobuf:"bytes,6,opt,name=mr_config_id,json=mrConfigId,proto3" json:"mr_config_id,omitempty"` // should be 48 bytes
MrOwner []byte `protobuf:"bytes,7,opt,name=mr_owner,json=mrOwner,proto3" json:"mr_owner,omitempty"` // should be 48 bytes
MrOwnerConfig []byte `protobuf:"bytes,8,opt,name=mr_owner_config,json=mrOwnerConfig,proto3" json:"mr_owner_config,omitempty"` // should be 48 bytes
Rtmrs [][]byte `protobuf:"bytes,9,rep,name=rtmrs,proto3" json:"rtmrs,omitempty"` // should be 48 * rtmrsCount
ReportData []byte `protobuf:"bytes,10,opt,name=report_data,json=reportData,proto3" json:"report_data,omitempty"` // should be 64 bytes
}
func (x *TDQuoteBodyPolicy) Reset() {
*x = TDQuoteBodyPolicy{}
if protoimpl.UnsafeEnabled {
mi := &file_checkconfig_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TDQuoteBodyPolicy) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TDQuoteBodyPolicy) ProtoMessage() {}
func (x *TDQuoteBodyPolicy) ProtoReflect() protoreflect.Message {
mi := &file_checkconfig_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TDQuoteBodyPolicy.ProtoReflect.Descriptor instead.
func (*TDQuoteBodyPolicy) Descriptor() ([]byte, []int) {
return file_checkconfig_proto_rawDescGZIP(), []int{2}
}
func (x *TDQuoteBodyPolicy) GetMinimumTeeTcbSvn() []byte {
if x != nil {
return x.MinimumTeeTcbSvn
}
return nil
}
func (x *TDQuoteBodyPolicy) GetMrSeam() []byte {
if x != nil {
return x.MrSeam
}
return nil
}
func (x *TDQuoteBodyPolicy) GetTdAttributes() []byte {
if x != nil {
return x.TdAttributes
}
return nil
}
func (x *TDQuoteBodyPolicy) GetXfam() []byte {
if x != nil {
return x.Xfam
}
return nil
}
func (x *TDQuoteBodyPolicy) GetMrTd() []byte {
if x != nil {
return x.MrTd
}
return nil
}
func (x *TDQuoteBodyPolicy) GetMrConfigId() []byte {
if x != nil {
return x.MrConfigId
}
return nil
}
func (x *TDQuoteBodyPolicy) GetMrOwner() []byte {
if x != nil {
return x.MrOwner
}
return nil
}
func (x *TDQuoteBodyPolicy) GetMrOwnerConfig() []byte {
if x != nil {
return x.MrOwnerConfig
}
return nil
}
func (x *TDQuoteBodyPolicy) GetRtmrs() [][]byte {
if x != nil {
return x.Rtmrs
}
return nil
}
func (x *TDQuoteBodyPolicy) GetReportData() []byte {
if x != nil {
return x.ReportData
}
return nil
}
// RootOfTrust represents configuration for which hardware root of trust
// certificates to use for verifying attestation quote.
type RootOfTrust struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Paths to CA bundles for the Intel TDX.
// Must be in PEM format.
// If empty, uses the verification library's embedded certificates from Intel.
CabundlePaths []string `protobuf:"bytes,1,rep,name=cabundle_paths,json=cabundlePaths,proto3" json:"cabundle_paths,omitempty"`
// PEM format CA bundles for Intel TDX. Combined with contents of
// cabundle_paths.
Cabundles []string `protobuf:"bytes,2,rep,name=cabundles,proto3" json:"cabundles,omitempty"`
// If true, download and check the CRL for revoked certificates.
CheckCrl bool `protobuf:"varint,3,opt,name=check_crl,json=checkCrl,proto3" json:"check_crl,omitempty"`
// If true, then check is not permitted to download necessary files for
// verification.
GetCollateral bool `protobuf:"varint,4,opt,name=get_collateral,json=getCollateral,proto3" json:"get_collateral,omitempty"`
}
func (x *RootOfTrust) Reset() {
*x = RootOfTrust{}
if protoimpl.UnsafeEnabled {
mi := &file_checkconfig_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RootOfTrust) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RootOfTrust) ProtoMessage() {}
func (x *RootOfTrust) ProtoReflect() protoreflect.Message {
mi := &file_checkconfig_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RootOfTrust.ProtoReflect.Descriptor instead.
func (*RootOfTrust) Descriptor() ([]byte, []int) {
return file_checkconfig_proto_rawDescGZIP(), []int{3}
}
func (x *RootOfTrust) GetCabundlePaths() []string {
if x != nil {
return x.CabundlePaths
}
return nil
}
func (x *RootOfTrust) GetCabundles() []string {
if x != nil {
return x.Cabundles
}
return nil
}
func (x *RootOfTrust) GetCheckCrl() bool {
if x != nil {
return x.CheckCrl
}
return false
}
func (x *RootOfTrust) GetGetCollateral() bool {
if x != nil {
return x.GetCollateral
}
return false
}
// Config is the overall message input for the check tool. This provides all
// the flags that configure the tool, including the validation policy.
type Config struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The report validation policy.
Policy *Policy `protobuf:"bytes,1,opt,name=policy,proto3" json:"policy,omitempty"`
// Configures which hardware keys to trust. Default uses library-embedded
// certificate.
RootOfTrust *RootOfTrust `protobuf:"bytes,2,opt,name=root_of_trust,json=rootOfTrust,proto3" json:"root_of_trust,omitempty"`
}
func (x *Config) Reset() {
*x = Config{}
if protoimpl.UnsafeEnabled {
mi := &file_checkconfig_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_checkconfig_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_checkconfig_proto_rawDescGZIP(), []int{4}
}
func (x *Config) GetPolicy() *Policy {
if x != nil {
return x.Policy
}
return nil
}
func (x *Config) GetRootOfTrust() *RootOfTrust {
if x != nil {
return x.RootOfTrust
}
return nil
}
var File_checkconfig_proto protoreflect.FileDescriptor
var file_checkconfig_proto_rawDesc = []byte{
0x0a, 0x11, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x22, 0x99, 0x01, 0x0a, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x3e, 0x0a, 0x0d, 0x68,
0x65, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0c, 0x68,
0x65, 0x61, 0x64, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x4f, 0x0a, 0x14, 0x74,
0x64, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x70, 0x6f, 0x6c,
0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x68, 0x65, 0x63,
0x6b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x54, 0x44, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x42,
0x6f, 0x64, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x11, 0x74, 0x64, 0x51, 0x75, 0x6f,
0x74, 0x65, 0x42, 0x6f, 0x64, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x7e, 0x0a, 0x0c,
0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x24, 0x0a, 0x0e,
0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x71, 0x65, 0x5f, 0x73, 0x76, 0x6e, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x51, 0x65, 0x53,
0x76, 0x6e, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x70, 0x63,
0x65, 0x5f, 0x73, 0x76, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x6d, 0x69, 0x6e,
0x69, 0x6d, 0x75, 0x6d, 0x50, 0x63, 0x65, 0x53, 0x76, 0x6e, 0x12, 0x20, 0x0a, 0x0c, 0x71, 0x65,
0x5f, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x0a, 0x71, 0x65, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x49, 0x64, 0x22, 0xc5, 0x02, 0x0a,
0x11, 0x54, 0x44, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x42, 0x6f, 0x64, 0x79, 0x50, 0x6f, 0x6c, 0x69,
0x63, 0x79, 0x12, 0x2d, 0x0a, 0x13, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x74, 0x65,
0x65, 0x5f, 0x74, 0x63, 0x62, 0x5f, 0x73, 0x76, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x10, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x54, 0x65, 0x65, 0x54, 0x63, 0x62, 0x53, 0x76,
0x6e, 0x12, 0x17, 0x0a, 0x07, 0x6d, 0x72, 0x5f, 0x73, 0x65, 0x61, 0x6d, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x06, 0x6d, 0x72, 0x53, 0x65, 0x61, 0x6d, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x64,
0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x0c, 0x74, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12,
0x12, 0x0a, 0x04, 0x78, 0x66, 0x61, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x78,
0x66, 0x61, 0x6d, 0x12, 0x13, 0x0a, 0x05, 0x6d, 0x72, 0x5f, 0x74, 0x64, 0x18, 0x05, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x04, 0x6d, 0x72, 0x54, 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x6d, 0x72, 0x5f, 0x63,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a,
0x6d, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x72,
0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x72,
0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x72, 0x5f, 0x6f, 0x77, 0x6e, 0x65,
0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d,
0x6d, 0x72, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x14, 0x0a,
0x05, 0x72, 0x74, 0x6d, 0x72, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x05, 0x72, 0x74,
0x6d, 0x72, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x64, 0x61,
0x74, 0x61, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x44, 0x61, 0x74, 0x61, 0x22, 0x96, 0x01, 0x0a, 0x0b, 0x52, 0x6f, 0x6f, 0x74, 0x4f, 0x66, 0x54,
0x72, 0x75, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x61, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65,
0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x61,
0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x63,
0x61, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09,
0x63, 0x61, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x68, 0x65,
0x63, 0x6b, 0x5f, 0x63, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x63, 0x68,
0x65, 0x63, 0x6b, 0x43, 0x72, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x67, 0x65, 0x74, 0x5f, 0x63, 0x6f,
0x6c, 0x6c, 0x61, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d,
0x67, 0x65, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x61, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x22, 0x73, 0x0a,
0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2b, 0x0a, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x63,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x06, 0x70, 0x6f,
0x6c, 0x69, 0x63, 0x79, 0x12, 0x3c, 0x0a, 0x0d, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x6f, 0x66, 0x5f,
0x74, 0x72, 0x75, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x68,
0x65, 0x63, 0x6b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x6f, 0x6f, 0x74, 0x4f, 0x66,
0x54, 0x72, 0x75, 0x73, 0x74, 0x52, 0x0b, 0x72, 0x6f, 0x6f, 0x74, 0x4f, 0x66, 0x54, 0x72, 0x75,
0x73, 0x74, 0x42, 0x32, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x67, 0x6f, 0x2d, 0x74, 0x64, 0x78, 0x2d, 0x67,
0x75, 0x65, 0x73, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x68, 0x65, 0x63, 0x6b,
0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_checkconfig_proto_rawDescOnce sync.Once
file_checkconfig_proto_rawDescData = file_checkconfig_proto_rawDesc
)
func file_checkconfig_proto_rawDescGZIP() []byte {
file_checkconfig_proto_rawDescOnce.Do(func() {
file_checkconfig_proto_rawDescData = protoimpl.X.CompressGZIP(file_checkconfig_proto_rawDescData)
})
return file_checkconfig_proto_rawDescData
}
var file_checkconfig_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_checkconfig_proto_goTypes = []interface{}{
(*Policy)(nil), // 0: checkconfig.Policy
(*HeaderPolicy)(nil), // 1: checkconfig.HeaderPolicy
(*TDQuoteBodyPolicy)(nil), // 2: checkconfig.TDQuoteBodyPolicy
(*RootOfTrust)(nil), // 3: checkconfig.RootOfTrust
(*Config)(nil), // 4: checkconfig.Config
}
var file_checkconfig_proto_depIdxs = []int32{
1, // 0: checkconfig.Policy.header_policy:type_name -> checkconfig.HeaderPolicy
2, // 1: checkconfig.Policy.td_quote_body_policy:type_name -> checkconfig.TDQuoteBodyPolicy
0, // 2: checkconfig.Config.policy:type_name -> checkconfig.Policy
3, // 3: checkconfig.Config.root_of_trust:type_name -> checkconfig.RootOfTrust
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_checkconfig_proto_init() }
func file_checkconfig_proto_init() {
if File_checkconfig_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_checkconfig_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Policy); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_checkconfig_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*HeaderPolicy); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_checkconfig_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TDQuoteBodyPolicy); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_checkconfig_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RootOfTrust); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_checkconfig_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Config); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_checkconfig_proto_rawDesc,
NumEnums: 0,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_checkconfig_proto_goTypes,
DependencyIndexes: file_checkconfig_proto_depIdxs,
MessageInfos: file_checkconfig_proto_msgTypes,
}.Build()
File_checkconfig_proto = out.File
file_checkconfig_proto_rawDesc = nil
file_checkconfig_proto_goTypes = nil
file_checkconfig_proto_depIdxs = nil
}
go-tdx-guest-0.3.1/proto/checkconfig/doc.go 0000664 0000000 0000000 00000001256 14563713763 0020567 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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 checkconfig defines the message type for the check CLI tool's options.
package checkconfig
go-tdx-guest-0.3.1/proto/doc.go 0000664 0000000 0000000 00000004137 14563713763 0016325 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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 proto contains protocol buffers that are exchanged between the client
// and server, as well as convenience configuration definitions for tools.
//
// # Generating Protocol Buffer Code
//
// Anytime the Protocol Buffer definitions change, the generated Go code must be
// regenerated. This can be done with "go generate". Just run:
//
// go generate ./...
//
// Upstream documentation:
// https://developers.google.com/protocol-buffers/docs/reference/go-generated
//
// # Code Generation Dependencies
//
// To generate the Go code, your system must have "protoc" installed. See:
// https://github.com/protocolbuffers/protobuf#protocol-compiler-installation
//
// The "protoc-gen-go" tool must also be installed. To install it, run:
//
// go install google.golang.org/protobuf/cmd/protoc-gen-go
//
// If you see a 'protoc-gen-go: program not found or is not executable' error
// for the 'go generate' command, run the following:
//
// echo 'export PATH=$PATH:$GOPATH/bin' >> $HOME/.bashrc
// source $HOME/.bashrc
//
// If you see 'google/protobuf/wrappers.proto not found', then you need to
// similarly set your PROTOC_INSTALL_DIR environment variable to the protoc
// installation directory which should have the "well-known types" in the
// include subdirectory.
package proto
//go:generate protoc -I$PROTOC_INSTALL_DIR/include -I=. --go_out=. --go_opt=module=github.com/google/go-tdx-guest/proto tdx.proto
//go:generate protoc -I$PROTOC_INSTALL_DIR/include -I=. --go_out=. --go_opt=module=github.com/google/go-tdx-guest/proto checkconfig.proto
go-tdx-guest-0.3.1/proto/tdx.proto 0000664 0000000 0000000 00000013061 14563713763 0017111 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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.
syntax = "proto3";
// Package tdx represents a TDX attestation quote.
package tdx;
option go_package = "github.com/google/go-tdx-guest/proto/tdx";
message QuoteV4 {
// Header of quote structure
Header header = 1; // should be 48 bytes
// TD report by which quote is generated
TDQuoteBody td_quote_body = 2; // should be 584 bytes
// Size of the Quote Signature Data structure
uint32 signed_data_size = 3;
// Quote Signature Data structure.
Ecdsa256BitQuoteV4AuthData signed_data =
4; // The size should be same as signed_data_size
// Extra bytes included to fill the quote buffer
bytes extra_bytes = 5; // These trailing bytes can be ignored
}
message Header {
// Version 4 supported
uint32 version = 1;
// Type of attestation key used by quoting enclave
// Values :
// 2 (ECDSA-256-with-P-256 curve)
// 3 (ECDSA-384-with-P-384 curve) (Currently not supported)
uint32 attestation_key_type = 2;
// TEE for this attestation
// TDX : 0x00000081
uint32 tee_type = 3;
bytes qe_svn = 4; // should be 2 bytes
bytes pce_svn = 5; // should be 2 bytes
// Unique vendor id of QE vendor
bytes qe_vendor_id = 6; // should be 16 bytes
// Custom user defined data
bytes user_data = 7; // should be 20 bytes
}
message TDQuoteBody {
bytes tee_tcb_svn = 1; // should be 16 bytes
bytes mr_seam = 2; // should be 48 bytes
bytes mr_signer_seam = 3; // should be 48 bytes
bytes seam_attributes = 4; // should be 8 bytes
bytes td_attributes = 5; // should be 8 bytes
bytes xfam = 6; // should be 8 bytes
bytes mr_td = 7; // should be 48 bytes
bytes mr_config_id = 8; // should be 48 bytes
bytes mr_owner = 9; // should be 48 bytes
bytes mr_owner_config = 10; // should be 48 bytes
repeated bytes rtmrs = 11; // should be 48 * rtmrsCount
bytes report_data = 12; // should be 64 bytes
}
message Ecdsa256BitQuoteV4AuthData {
// The ECDSA 256-bit signature.
bytes signature = 1; // should be 64 bytes
// The ECDSA 256-bit public key of the attestation key.
bytes ecdsa_attestation_key = 2; // should be 64 bytes
// The certification data.
CertificationData certification_data = 3;
}
message CertificationData {
// Supported values:
// - 1 (PCK identifier: PPID in plain text, CPUSVN and PCESVN)
// - 2 (PCK identifier: PPID encrypted using RSA-2048-OAEP, CPUSVN and PCESVN)
// - 3 (PCK identifier: PPID encrypted using RSA-3072-OAEP, CPUSVN and PCESVN)
// - 4 (PCK Leaf Certificate in plain text, currently not supported)
// - 5 (Concatenated PCK Cert Chain)
// - 6 (QE Report Certification Data)
// - 7 (PLATFORM_MANIFEST, currently not supported)
uint32 certificate_data_type = 1;
// Size of Certification Data field
uint32 size = 2;
// Certification Data Type:
// - 1: Byte array that contains concatenation of PPID, CPUSVN,PCESVN (LE),
// PCEID (LE).
// - 2: Byte array that contains concatenation of PPID encrypted using
// RSA-2048-OAEP, CPUSVN, PCESVN (LE), PCEID (LE).
// - 3: Byte array that contains concatenation of PPID encrypted using
// RSA-3072-OAEP, CPUSVN, PCESVN (LE), PCEID (LE).
// - 4: PCK Leaf Certificate
// - 5: Concatenated PCK Cert Chain (PEM formatted). PCK LeafCert||
// Intermediate CA Cert|| Root CA Cert
//- 6: QE Report Certification Data
//- 7: PLATFORM_MANIFEST (currently not supported)
QEReportCertificationData qe_report_certification_data = 3;
}
message QEReportCertificationData {
EnclaveReport qe_report = 1;
bytes qe_report_signature = 2; // should be 64 bytes
QeAuthData qe_auth_data = 3;
PCKCertificateChainData pck_certificate_chain_data = 4;
}
message PCKCertificateChainData {
// Supported values:
// - 1 (PCK identifier: PPID in plain text, CPUSVN and PCESVN)
// - 2 (PCK identifier: PPID encrypted using RSA-2048-OAEP, CPUSVN and PCESVN)
// - 3 (PCK identifier: PPID encrypted using RSA-3072-OAEP, CPUSVN and PCESVN)
// - 4 (PCK Leaf Certificate in plain text, currently not supported)
// - 5 (Concatenated PCK Cert Chain)
// - 6 (QE Report Certification Data)
// - 7 (PLATFORM_MANIFEST, currently not supported)
uint32 certificate_data_type = 1;
// Size of Certification Data field
uint32 size = 2;
bytes pck_cert_chain = 3;
}
message QeAuthData {
// The parsed data size.
uint32 parsed_data_size = 1; // should be 2 bytes
// The data.
bytes data = 2;
}
message EnclaveReport {
bytes cpu_svn = 1; // should be 16 bytes
uint32 misc_select = 2; // should be 4 bytes
bytes reserved1 = 3; // should be 28 bytes
bytes attributes = 4; // should be 16 bytes
bytes mr_enclave = 5; // should be 32 bytes
bytes reserved2 = 6; // should be 32 bytes
bytes mr_signer = 7; // should be 32 bytes
bytes reserved3 = 8; // should be 96 bytes
uint32 isv_prod_id = 9; // should be 2 bytes
uint32 isv_svn = 10; // should be 2 bytes
bytes reserved4 = 11; // should be 60 bytes
bytes report_data = 12; // should be 64 bytes
}
go-tdx-guest-0.3.1/proto/tdx/ 0000775 0000000 0000000 00000000000 14563713763 0016023 5 ustar 00root root 0000000 0000000 go-tdx-guest-0.3.1/proto/tdx/doc.go 0000664 0000000 0000000 00000001243 14563713763 0017117 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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 tdx implements a protocol buffer for representing TDX attestations.
package tdx
go-tdx-guest-0.3.1/proto/tdx/tdx.pb.go 0000664 0000000 0000000 00000122601 14563713763 0017553 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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.
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.21.12
// source: tdx.proto
// Package tdx represents a TDX attestation quote.
package tdx
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type QuoteV4 struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Header of quote structure
Header *Header `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` // should be 48 bytes
// TD report by which quote is generated
TdQuoteBody *TDQuoteBody `protobuf:"bytes,2,opt,name=td_quote_body,json=tdQuoteBody,proto3" json:"td_quote_body,omitempty"` // should be 584 bytes
// Size of the Quote Signature Data structure
SignedDataSize uint32 `protobuf:"varint,3,opt,name=signed_data_size,json=signedDataSize,proto3" json:"signed_data_size,omitempty"`
// Quote Signature Data structure.
SignedData *Ecdsa256BitQuoteV4AuthData `protobuf:"bytes,4,opt,name=signed_data,json=signedData,proto3" json:"signed_data,omitempty"` // The size should be same as signed_data_size
// Extra bytes included to fill the quote buffer
ExtraBytes []byte `protobuf:"bytes,5,opt,name=extra_bytes,json=extraBytes,proto3" json:"extra_bytes,omitempty"` // These trailing bytes can be ignored
}
func (x *QuoteV4) Reset() {
*x = QuoteV4{}
if protoimpl.UnsafeEnabled {
mi := &file_tdx_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *QuoteV4) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*QuoteV4) ProtoMessage() {}
func (x *QuoteV4) ProtoReflect() protoreflect.Message {
mi := &file_tdx_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use QuoteV4.ProtoReflect.Descriptor instead.
func (*QuoteV4) Descriptor() ([]byte, []int) {
return file_tdx_proto_rawDescGZIP(), []int{0}
}
func (x *QuoteV4) GetHeader() *Header {
if x != nil {
return x.Header
}
return nil
}
func (x *QuoteV4) GetTdQuoteBody() *TDQuoteBody {
if x != nil {
return x.TdQuoteBody
}
return nil
}
func (x *QuoteV4) GetSignedDataSize() uint32 {
if x != nil {
return x.SignedDataSize
}
return 0
}
func (x *QuoteV4) GetSignedData() *Ecdsa256BitQuoteV4AuthData {
if x != nil {
return x.SignedData
}
return nil
}
func (x *QuoteV4) GetExtraBytes() []byte {
if x != nil {
return x.ExtraBytes
}
return nil
}
type Header struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Version 4 supported
Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
// Type of attestation key used by quoting enclave
// Values :
// 2 (ECDSA-256-with-P-256 curve)
// 3 (ECDSA-384-with-P-384 curve) (Currently not supported)
AttestationKeyType uint32 `protobuf:"varint,2,opt,name=attestation_key_type,json=attestationKeyType,proto3" json:"attestation_key_type,omitempty"`
// TEE for this attestation
// TDX : 0x00000081
TeeType uint32 `protobuf:"varint,3,opt,name=tee_type,json=teeType,proto3" json:"tee_type,omitempty"`
QeSvn []byte `protobuf:"bytes,4,opt,name=qe_svn,json=qeSvn,proto3" json:"qe_svn,omitempty"` // should be 2 bytes
PceSvn []byte `protobuf:"bytes,5,opt,name=pce_svn,json=pceSvn,proto3" json:"pce_svn,omitempty"` // should be 2 bytes
// Unique vendor id of QE vendor
QeVendorId []byte `protobuf:"bytes,6,opt,name=qe_vendor_id,json=qeVendorId,proto3" json:"qe_vendor_id,omitempty"` // should be 16 bytes
// Custom user defined data
UserData []byte `protobuf:"bytes,7,opt,name=user_data,json=userData,proto3" json:"user_data,omitempty"` // should be 20 bytes
}
func (x *Header) Reset() {
*x = Header{}
if protoimpl.UnsafeEnabled {
mi := &file_tdx_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Header) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Header) ProtoMessage() {}
func (x *Header) ProtoReflect() protoreflect.Message {
mi := &file_tdx_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Header.ProtoReflect.Descriptor instead.
func (*Header) Descriptor() ([]byte, []int) {
return file_tdx_proto_rawDescGZIP(), []int{1}
}
func (x *Header) GetVersion() uint32 {
if x != nil {
return x.Version
}
return 0
}
func (x *Header) GetAttestationKeyType() uint32 {
if x != nil {
return x.AttestationKeyType
}
return 0
}
func (x *Header) GetTeeType() uint32 {
if x != nil {
return x.TeeType
}
return 0
}
func (x *Header) GetQeSvn() []byte {
if x != nil {
return x.QeSvn
}
return nil
}
func (x *Header) GetPceSvn() []byte {
if x != nil {
return x.PceSvn
}
return nil
}
func (x *Header) GetQeVendorId() []byte {
if x != nil {
return x.QeVendorId
}
return nil
}
func (x *Header) GetUserData() []byte {
if x != nil {
return x.UserData
}
return nil
}
type TDQuoteBody struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
TeeTcbSvn []byte `protobuf:"bytes,1,opt,name=tee_tcb_svn,json=teeTcbSvn,proto3" json:"tee_tcb_svn,omitempty"` // should be 16 bytes
MrSeam []byte `protobuf:"bytes,2,opt,name=mr_seam,json=mrSeam,proto3" json:"mr_seam,omitempty"` // should be 48 bytes
MrSignerSeam []byte `protobuf:"bytes,3,opt,name=mr_signer_seam,json=mrSignerSeam,proto3" json:"mr_signer_seam,omitempty"` // should be 48 bytes
SeamAttributes []byte `protobuf:"bytes,4,opt,name=seam_attributes,json=seamAttributes,proto3" json:"seam_attributes,omitempty"` // should be 8 bytes
TdAttributes []byte `protobuf:"bytes,5,opt,name=td_attributes,json=tdAttributes,proto3" json:"td_attributes,omitempty"` // should be 8 bytes
Xfam []byte `protobuf:"bytes,6,opt,name=xfam,proto3" json:"xfam,omitempty"` // should be 8 bytes
MrTd []byte `protobuf:"bytes,7,opt,name=mr_td,json=mrTd,proto3" json:"mr_td,omitempty"` // should be 48 bytes
MrConfigId []byte `protobuf:"bytes,8,opt,name=mr_config_id,json=mrConfigId,proto3" json:"mr_config_id,omitempty"` // should be 48 bytes
MrOwner []byte `protobuf:"bytes,9,opt,name=mr_owner,json=mrOwner,proto3" json:"mr_owner,omitempty"` // should be 48 bytes
MrOwnerConfig []byte `protobuf:"bytes,10,opt,name=mr_owner_config,json=mrOwnerConfig,proto3" json:"mr_owner_config,omitempty"` // should be 48 bytes
Rtmrs [][]byte `protobuf:"bytes,11,rep,name=rtmrs,proto3" json:"rtmrs,omitempty"` // should be 48 * rtmrsCount
ReportData []byte `protobuf:"bytes,12,opt,name=report_data,json=reportData,proto3" json:"report_data,omitempty"` // should be 64 bytes
}
func (x *TDQuoteBody) Reset() {
*x = TDQuoteBody{}
if protoimpl.UnsafeEnabled {
mi := &file_tdx_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TDQuoteBody) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TDQuoteBody) ProtoMessage() {}
func (x *TDQuoteBody) ProtoReflect() protoreflect.Message {
mi := &file_tdx_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TDQuoteBody.ProtoReflect.Descriptor instead.
func (*TDQuoteBody) Descriptor() ([]byte, []int) {
return file_tdx_proto_rawDescGZIP(), []int{2}
}
func (x *TDQuoteBody) GetTeeTcbSvn() []byte {
if x != nil {
return x.TeeTcbSvn
}
return nil
}
func (x *TDQuoteBody) GetMrSeam() []byte {
if x != nil {
return x.MrSeam
}
return nil
}
func (x *TDQuoteBody) GetMrSignerSeam() []byte {
if x != nil {
return x.MrSignerSeam
}
return nil
}
func (x *TDQuoteBody) GetSeamAttributes() []byte {
if x != nil {
return x.SeamAttributes
}
return nil
}
func (x *TDQuoteBody) GetTdAttributes() []byte {
if x != nil {
return x.TdAttributes
}
return nil
}
func (x *TDQuoteBody) GetXfam() []byte {
if x != nil {
return x.Xfam
}
return nil
}
func (x *TDQuoteBody) GetMrTd() []byte {
if x != nil {
return x.MrTd
}
return nil
}
func (x *TDQuoteBody) GetMrConfigId() []byte {
if x != nil {
return x.MrConfigId
}
return nil
}
func (x *TDQuoteBody) GetMrOwner() []byte {
if x != nil {
return x.MrOwner
}
return nil
}
func (x *TDQuoteBody) GetMrOwnerConfig() []byte {
if x != nil {
return x.MrOwnerConfig
}
return nil
}
func (x *TDQuoteBody) GetRtmrs() [][]byte {
if x != nil {
return x.Rtmrs
}
return nil
}
func (x *TDQuoteBody) GetReportData() []byte {
if x != nil {
return x.ReportData
}
return nil
}
type Ecdsa256BitQuoteV4AuthData struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The ECDSA 256-bit signature.
Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"` // should be 64 bytes
// The ECDSA 256-bit public key of the attestation key.
EcdsaAttestationKey []byte `protobuf:"bytes,2,opt,name=ecdsa_attestation_key,json=ecdsaAttestationKey,proto3" json:"ecdsa_attestation_key,omitempty"` // should be 64 bytes
// The certification data.
CertificationData *CertificationData `protobuf:"bytes,3,opt,name=certification_data,json=certificationData,proto3" json:"certification_data,omitempty"`
}
func (x *Ecdsa256BitQuoteV4AuthData) Reset() {
*x = Ecdsa256BitQuoteV4AuthData{}
if protoimpl.UnsafeEnabled {
mi := &file_tdx_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Ecdsa256BitQuoteV4AuthData) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Ecdsa256BitQuoteV4AuthData) ProtoMessage() {}
func (x *Ecdsa256BitQuoteV4AuthData) ProtoReflect() protoreflect.Message {
mi := &file_tdx_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Ecdsa256BitQuoteV4AuthData.ProtoReflect.Descriptor instead.
func (*Ecdsa256BitQuoteV4AuthData) Descriptor() ([]byte, []int) {
return file_tdx_proto_rawDescGZIP(), []int{3}
}
func (x *Ecdsa256BitQuoteV4AuthData) GetSignature() []byte {
if x != nil {
return x.Signature
}
return nil
}
func (x *Ecdsa256BitQuoteV4AuthData) GetEcdsaAttestationKey() []byte {
if x != nil {
return x.EcdsaAttestationKey
}
return nil
}
func (x *Ecdsa256BitQuoteV4AuthData) GetCertificationData() *CertificationData {
if x != nil {
return x.CertificationData
}
return nil
}
type CertificationData struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Supported values:
//
// - 1 (PCK identifier: PPID in plain text, CPUSVN and PCESVN)
// - 2 (PCK identifier: PPID encrypted using RSA-2048-OAEP, CPUSVN and PCESVN)
// - 3 (PCK identifier: PPID encrypted using RSA-3072-OAEP, CPUSVN and PCESVN)
// - 4 (PCK Leaf Certificate in plain text, currently not supported)
// - 5 (Concatenated PCK Cert Chain)
// - 6 (QE Report Certification Data)
// - 7 (PLATFORM_MANIFEST, currently not supported)
CertificateDataType uint32 `protobuf:"varint,1,opt,name=certificate_data_type,json=certificateDataType,proto3" json:"certificate_data_type,omitempty"`
// Size of Certification Data field
Size uint32 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"`
QeReportCertificationData *QEReportCertificationData `protobuf:"bytes,3,opt,name=qe_report_certification_data,json=qeReportCertificationData,proto3" json:"qe_report_certification_data,omitempty"`
}
func (x *CertificationData) Reset() {
*x = CertificationData{}
if protoimpl.UnsafeEnabled {
mi := &file_tdx_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CertificationData) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CertificationData) ProtoMessage() {}
func (x *CertificationData) ProtoReflect() protoreflect.Message {
mi := &file_tdx_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CertificationData.ProtoReflect.Descriptor instead.
func (*CertificationData) Descriptor() ([]byte, []int) {
return file_tdx_proto_rawDescGZIP(), []int{4}
}
func (x *CertificationData) GetCertificateDataType() uint32 {
if x != nil {
return x.CertificateDataType
}
return 0
}
func (x *CertificationData) GetSize() uint32 {
if x != nil {
return x.Size
}
return 0
}
func (x *CertificationData) GetQeReportCertificationData() *QEReportCertificationData {
if x != nil {
return x.QeReportCertificationData
}
return nil
}
type QEReportCertificationData struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
QeReport *EnclaveReport `protobuf:"bytes,1,opt,name=qe_report,json=qeReport,proto3" json:"qe_report,omitempty"`
QeReportSignature []byte `protobuf:"bytes,2,opt,name=qe_report_signature,json=qeReportSignature,proto3" json:"qe_report_signature,omitempty"` // should be 64 bytes
QeAuthData *QeAuthData `protobuf:"bytes,3,opt,name=qe_auth_data,json=qeAuthData,proto3" json:"qe_auth_data,omitempty"`
PckCertificateChainData *PCKCertificateChainData `protobuf:"bytes,4,opt,name=pck_certificate_chain_data,json=pckCertificateChainData,proto3" json:"pck_certificate_chain_data,omitempty"`
}
func (x *QEReportCertificationData) Reset() {
*x = QEReportCertificationData{}
if protoimpl.UnsafeEnabled {
mi := &file_tdx_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *QEReportCertificationData) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*QEReportCertificationData) ProtoMessage() {}
func (x *QEReportCertificationData) ProtoReflect() protoreflect.Message {
mi := &file_tdx_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use QEReportCertificationData.ProtoReflect.Descriptor instead.
func (*QEReportCertificationData) Descriptor() ([]byte, []int) {
return file_tdx_proto_rawDescGZIP(), []int{5}
}
func (x *QEReportCertificationData) GetQeReport() *EnclaveReport {
if x != nil {
return x.QeReport
}
return nil
}
func (x *QEReportCertificationData) GetQeReportSignature() []byte {
if x != nil {
return x.QeReportSignature
}
return nil
}
func (x *QEReportCertificationData) GetQeAuthData() *QeAuthData {
if x != nil {
return x.QeAuthData
}
return nil
}
func (x *QEReportCertificationData) GetPckCertificateChainData() *PCKCertificateChainData {
if x != nil {
return x.PckCertificateChainData
}
return nil
}
type PCKCertificateChainData struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Supported values:
//
// - 1 (PCK identifier: PPID in plain text, CPUSVN and PCESVN)
// - 2 (PCK identifier: PPID encrypted using RSA-2048-OAEP, CPUSVN and PCESVN)
// - 3 (PCK identifier: PPID encrypted using RSA-3072-OAEP, CPUSVN and PCESVN)
// - 4 (PCK Leaf Certificate in plain text, currently not supported)
// - 5 (Concatenated PCK Cert Chain)
// - 6 (QE Report Certification Data)
// - 7 (PLATFORM_MANIFEST, currently not supported)
CertificateDataType uint32 `protobuf:"varint,1,opt,name=certificate_data_type,json=certificateDataType,proto3" json:"certificate_data_type,omitempty"`
// Size of Certification Data field
Size uint32 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"`
PckCertChain []byte `protobuf:"bytes,3,opt,name=pck_cert_chain,json=pckCertChain,proto3" json:"pck_cert_chain,omitempty"`
}
func (x *PCKCertificateChainData) Reset() {
*x = PCKCertificateChainData{}
if protoimpl.UnsafeEnabled {
mi := &file_tdx_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *PCKCertificateChainData) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PCKCertificateChainData) ProtoMessage() {}
func (x *PCKCertificateChainData) ProtoReflect() protoreflect.Message {
mi := &file_tdx_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PCKCertificateChainData.ProtoReflect.Descriptor instead.
func (*PCKCertificateChainData) Descriptor() ([]byte, []int) {
return file_tdx_proto_rawDescGZIP(), []int{6}
}
func (x *PCKCertificateChainData) GetCertificateDataType() uint32 {
if x != nil {
return x.CertificateDataType
}
return 0
}
func (x *PCKCertificateChainData) GetSize() uint32 {
if x != nil {
return x.Size
}
return 0
}
func (x *PCKCertificateChainData) GetPckCertChain() []byte {
if x != nil {
return x.PckCertChain
}
return nil
}
type QeAuthData struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The parsed data size.
ParsedDataSize uint32 `protobuf:"varint,1,opt,name=parsed_data_size,json=parsedDataSize,proto3" json:"parsed_data_size,omitempty"` // should be 2 bytes
// The data.
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
}
func (x *QeAuthData) Reset() {
*x = QeAuthData{}
if protoimpl.UnsafeEnabled {
mi := &file_tdx_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *QeAuthData) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*QeAuthData) ProtoMessage() {}
func (x *QeAuthData) ProtoReflect() protoreflect.Message {
mi := &file_tdx_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use QeAuthData.ProtoReflect.Descriptor instead.
func (*QeAuthData) Descriptor() ([]byte, []int) {
return file_tdx_proto_rawDescGZIP(), []int{7}
}
func (x *QeAuthData) GetParsedDataSize() uint32 {
if x != nil {
return x.ParsedDataSize
}
return 0
}
func (x *QeAuthData) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type EnclaveReport struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
CpuSvn []byte `protobuf:"bytes,1,opt,name=cpu_svn,json=cpuSvn,proto3" json:"cpu_svn,omitempty"` // should be 16 bytes
MiscSelect uint32 `protobuf:"varint,2,opt,name=misc_select,json=miscSelect,proto3" json:"misc_select,omitempty"` // should be 4 bytes
Reserved1 []byte `protobuf:"bytes,3,opt,name=reserved1,proto3" json:"reserved1,omitempty"` // should be 28 bytes
Attributes []byte `protobuf:"bytes,4,opt,name=attributes,proto3" json:"attributes,omitempty"` // should be 16 bytes
MrEnclave []byte `protobuf:"bytes,5,opt,name=mr_enclave,json=mrEnclave,proto3" json:"mr_enclave,omitempty"` // should be 32 bytes
Reserved2 []byte `protobuf:"bytes,6,opt,name=reserved2,proto3" json:"reserved2,omitempty"` // should be 32 bytes
MrSigner []byte `protobuf:"bytes,7,opt,name=mr_signer,json=mrSigner,proto3" json:"mr_signer,omitempty"` // should be 32 bytes
Reserved3 []byte `protobuf:"bytes,8,opt,name=reserved3,proto3" json:"reserved3,omitempty"` // should be 96 bytes
IsvProdId uint32 `protobuf:"varint,9,opt,name=isv_prod_id,json=isvProdId,proto3" json:"isv_prod_id,omitempty"` // should be 2 bytes
IsvSvn uint32 `protobuf:"varint,10,opt,name=isv_svn,json=isvSvn,proto3" json:"isv_svn,omitempty"` // should be 2 bytes
Reserved4 []byte `protobuf:"bytes,11,opt,name=reserved4,proto3" json:"reserved4,omitempty"` // should be 60 bytes
ReportData []byte `protobuf:"bytes,12,opt,name=report_data,json=reportData,proto3" json:"report_data,omitempty"` // should be 64 bytes
}
func (x *EnclaveReport) Reset() {
*x = EnclaveReport{}
if protoimpl.UnsafeEnabled {
mi := &file_tdx_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *EnclaveReport) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*EnclaveReport) ProtoMessage() {}
func (x *EnclaveReport) ProtoReflect() protoreflect.Message {
mi := &file_tdx_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use EnclaveReport.ProtoReflect.Descriptor instead.
func (*EnclaveReport) Descriptor() ([]byte, []int) {
return file_tdx_proto_rawDescGZIP(), []int{8}
}
func (x *EnclaveReport) GetCpuSvn() []byte {
if x != nil {
return x.CpuSvn
}
return nil
}
func (x *EnclaveReport) GetMiscSelect() uint32 {
if x != nil {
return x.MiscSelect
}
return 0
}
func (x *EnclaveReport) GetReserved1() []byte {
if x != nil {
return x.Reserved1
}
return nil
}
func (x *EnclaveReport) GetAttributes() []byte {
if x != nil {
return x.Attributes
}
return nil
}
func (x *EnclaveReport) GetMrEnclave() []byte {
if x != nil {
return x.MrEnclave
}
return nil
}
func (x *EnclaveReport) GetReserved2() []byte {
if x != nil {
return x.Reserved2
}
return nil
}
func (x *EnclaveReport) GetMrSigner() []byte {
if x != nil {
return x.MrSigner
}
return nil
}
func (x *EnclaveReport) GetReserved3() []byte {
if x != nil {
return x.Reserved3
}
return nil
}
func (x *EnclaveReport) GetIsvProdId() uint32 {
if x != nil {
return x.IsvProdId
}
return 0
}
func (x *EnclaveReport) GetIsvSvn() uint32 {
if x != nil {
return x.IsvSvn
}
return 0
}
func (x *EnclaveReport) GetReserved4() []byte {
if x != nil {
return x.Reserved4
}
return nil
}
func (x *EnclaveReport) GetReportData() []byte {
if x != nil {
return x.ReportData
}
return nil
}
var File_tdx_proto protoreflect.FileDescriptor
var file_tdx_proto_rawDesc = []byte{
0x0a, 0x09, 0x74, 0x64, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x74, 0x64, 0x78,
0x22, 0xf1, 0x01, 0x0a, 0x07, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x56, 0x34, 0x12, 0x23, 0x0a, 0x06,
0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x74,
0x64, 0x78, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65,
0x72, 0x12, 0x34, 0x0a, 0x0d, 0x74, 0x64, 0x5f, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x5f, 0x62, 0x6f,
0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x64, 0x78, 0x2e, 0x54,
0x44, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x0b, 0x74, 0x64, 0x51, 0x75,
0x6f, 0x74, 0x65, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x69, 0x67, 0x6e, 0x65,
0x64, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0d, 0x52, 0x0e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x53, 0x69, 0x7a,
0x65, 0x12, 0x40, 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x61,
0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x64, 0x78, 0x2e, 0x45, 0x63, 0x64,
0x73, 0x61, 0x32, 0x35, 0x36, 0x42, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x56, 0x34, 0x41,
0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x44,
0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x62, 0x79, 0x74,
0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x72, 0x61, 0x42,
0x79, 0x74, 0x65, 0x73, 0x22, 0xde, 0x01, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12,
0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x14, 0x61, 0x74, 0x74,
0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x74, 0x79, 0x70,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x74,
0x65, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x74,
0x65, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x71, 0x65, 0x5f, 0x73, 0x76, 0x6e,
0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x71, 0x65, 0x53, 0x76, 0x6e, 0x12, 0x17, 0x0a,
0x07, 0x70, 0x63, 0x65, 0x5f, 0x73, 0x76, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06,
0x70, 0x63, 0x65, 0x53, 0x76, 0x6e, 0x12, 0x20, 0x0a, 0x0c, 0x71, 0x65, 0x5f, 0x76, 0x65, 0x6e,
0x64, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x71, 0x65,
0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72,
0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x75, 0x73, 0x65,
0x72, 0x44, 0x61, 0x74, 0x61, 0x22, 0xff, 0x02, 0x0a, 0x0b, 0x54, 0x44, 0x51, 0x75, 0x6f, 0x74,
0x65, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x1e, 0x0a, 0x0b, 0x74, 0x65, 0x65, 0x5f, 0x74, 0x63, 0x62,
0x5f, 0x73, 0x76, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x74, 0x65, 0x65, 0x54,
0x63, 0x62, 0x53, 0x76, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x6d, 0x72, 0x5f, 0x73, 0x65, 0x61, 0x6d,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x6d, 0x72, 0x53, 0x65, 0x61, 0x6d, 0x12, 0x24,
0x0a, 0x0e, 0x6d, 0x72, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x61, 0x6d,
0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x6d, 0x72, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72,
0x53, 0x65, 0x61, 0x6d, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x61, 0x6d, 0x5f, 0x61, 0x74, 0x74,
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x73,
0x65, 0x61, 0x6d, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x23, 0x0a,
0x0d, 0x74, 0x64, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x05,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x74, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x66, 0x61, 0x6d, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x04, 0x78, 0x66, 0x61, 0x6d, 0x12, 0x13, 0x0a, 0x05, 0x6d, 0x72, 0x5f, 0x74, 0x64, 0x18,
0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x6d, 0x72, 0x54, 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x6d,
0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x0a, 0x6d, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x64, 0x12, 0x19, 0x0a,
0x08, 0x6d, 0x72, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x07, 0x6d, 0x72, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x72, 0x5f, 0x6f,
0x77, 0x6e, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x0d, 0x6d, 0x72, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x12, 0x14, 0x0a, 0x05, 0x72, 0x74, 0x6d, 0x72, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0c, 0x52,
0x05, 0x72, 0x74, 0x6d, 0x72, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x65, 0x70,
0x6f, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x22, 0xb5, 0x01, 0x0a, 0x1a, 0x45, 0x63, 0x64, 0x73,
0x61, 0x32, 0x35, 0x36, 0x42, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x65, 0x56, 0x34, 0x41, 0x75,
0x74, 0x68, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74,
0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61,
0x74, 0x75, 0x72, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x65, 0x63, 0x64, 0x73, 0x61, 0x5f, 0x61, 0x74,
0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x13, 0x65, 0x63, 0x64, 0x73, 0x61, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x45, 0x0a, 0x12, 0x63, 0x65, 0x72, 0x74,
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x64, 0x78, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69,
0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x11, 0x63, 0x65,
0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x22,
0xbc, 0x01, 0x0a, 0x11, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
0x63, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
0x65, 0x44, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x5f, 0x0a,
0x1c, 0x71, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69,
0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x64, 0x78, 0x2e, 0x51, 0x45, 0x52, 0x65, 0x70, 0x6f,
0x72, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44,
0x61, 0x74, 0x61, 0x52, 0x19, 0x71, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x65, 0x72,
0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x22, 0x8a,
0x02, 0x0a, 0x19, 0x51, 0x45, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69,
0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2f, 0x0a, 0x09,
0x71, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x12, 0x2e, 0x74, 0x64, 0x78, 0x2e, 0x45, 0x6e, 0x63, 0x6c, 0x61, 0x76, 0x65, 0x52, 0x65, 0x70,
0x6f, 0x72, 0x74, 0x52, 0x08, 0x71, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x2e, 0x0a,
0x13, 0x71, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61,
0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x71, 0x65, 0x52, 0x65,
0x70, 0x6f, 0x72, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x31, 0x0a,
0x0c, 0x71, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x64, 0x78, 0x2e, 0x51, 0x65, 0x41, 0x75, 0x74, 0x68,
0x44, 0x61, 0x74, 0x61, 0x52, 0x0a, 0x71, 0x65, 0x41, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61,
0x12, 0x59, 0x0a, 0x1a, 0x70, 0x63, 0x6b, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x64, 0x78, 0x2e, 0x50, 0x43, 0x4b, 0x43, 0x65,
0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x44, 0x61,
0x74, 0x61, 0x52, 0x17, 0x70, 0x63, 0x6b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x22, 0x87, 0x01, 0x0a, 0x17,
0x50, 0x43, 0x4b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68,
0x61, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x65, 0x72, 0x74, 0x69,
0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x74, 0x79, 0x70, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x65, 0x44, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73,
0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12,
0x24, 0x0a, 0x0e, 0x70, 0x63, 0x6b, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x69,
0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x70, 0x63, 0x6b, 0x43, 0x65, 0x72, 0x74,
0x43, 0x68, 0x61, 0x69, 0x6e, 0x22, 0x4a, 0x0a, 0x0a, 0x51, 0x65, 0x41, 0x75, 0x74, 0x68, 0x44,
0x61, 0x74, 0x61, 0x12, 0x28, 0x0a, 0x10, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x5f, 0x64, 0x61,
0x74, 0x61, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x70,
0x61, 0x72, 0x73, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a,
0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74,
0x61, 0x22, 0xf7, 0x02, 0x0a, 0x0d, 0x45, 0x6e, 0x63, 0x6c, 0x61, 0x76, 0x65, 0x52, 0x65, 0x70,
0x6f, 0x72, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x63, 0x70, 0x75, 0x5f, 0x73, 0x76, 0x6e, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x70, 0x75, 0x53, 0x76, 0x6e, 0x12, 0x1f, 0x0a, 0x0b,
0x6d, 0x69, 0x73, 0x63, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0d, 0x52, 0x0a, 0x6d, 0x69, 0x73, 0x63, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x12, 0x1c, 0x0a,
0x09, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x31, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x09, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x31, 0x12, 0x1e, 0x0a, 0x0a, 0x61,
0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6d,
0x72, 0x5f, 0x65, 0x6e, 0x63, 0x6c, 0x61, 0x76, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x09, 0x6d, 0x72, 0x45, 0x6e, 0x63, 0x6c, 0x61, 0x76, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65,
0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x32, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x72,
0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x32, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x72, 0x5f, 0x73,
0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x72, 0x53,
0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65,
0x64, 0x33, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76,
0x65, 0x64, 0x33, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x73, 0x76, 0x5f, 0x70, 0x72, 0x6f, 0x64, 0x5f,
0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x69, 0x73, 0x76, 0x50, 0x72, 0x6f,
0x64, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x73, 0x76, 0x5f, 0x73, 0x76, 0x6e, 0x18, 0x0a,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x69, 0x73, 0x76, 0x53, 0x76, 0x6e, 0x12, 0x1c, 0x0a, 0x09,
0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x34, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x09, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x34, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65,
0x70, 0x6f, 0x72, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x0a, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x44, 0x61, 0x74, 0x61, 0x42, 0x2a, 0x5a, 0x28, 0x67,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2f, 0x67, 0x6f, 0x2d, 0x74, 0x64, 0x78, 0x2d, 0x67, 0x75, 0x65, 0x73, 0x74, 0x2f, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2f, 0x74, 0x64, 0x78, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_tdx_proto_rawDescOnce sync.Once
file_tdx_proto_rawDescData = file_tdx_proto_rawDesc
)
func file_tdx_proto_rawDescGZIP() []byte {
file_tdx_proto_rawDescOnce.Do(func() {
file_tdx_proto_rawDescData = protoimpl.X.CompressGZIP(file_tdx_proto_rawDescData)
})
return file_tdx_proto_rawDescData
}
var file_tdx_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_tdx_proto_goTypes = []interface{}{
(*QuoteV4)(nil), // 0: tdx.QuoteV4
(*Header)(nil), // 1: tdx.Header
(*TDQuoteBody)(nil), // 2: tdx.TDQuoteBody
(*Ecdsa256BitQuoteV4AuthData)(nil), // 3: tdx.Ecdsa256BitQuoteV4AuthData
(*CertificationData)(nil), // 4: tdx.CertificationData
(*QEReportCertificationData)(nil), // 5: tdx.QEReportCertificationData
(*PCKCertificateChainData)(nil), // 6: tdx.PCKCertificateChainData
(*QeAuthData)(nil), // 7: tdx.QeAuthData
(*EnclaveReport)(nil), // 8: tdx.EnclaveReport
}
var file_tdx_proto_depIdxs = []int32{
1, // 0: tdx.QuoteV4.header:type_name -> tdx.Header
2, // 1: tdx.QuoteV4.td_quote_body:type_name -> tdx.TDQuoteBody
3, // 2: tdx.QuoteV4.signed_data:type_name -> tdx.Ecdsa256BitQuoteV4AuthData
4, // 3: tdx.Ecdsa256BitQuoteV4AuthData.certification_data:type_name -> tdx.CertificationData
5, // 4: tdx.CertificationData.qe_report_certification_data:type_name -> tdx.QEReportCertificationData
8, // 5: tdx.QEReportCertificationData.qe_report:type_name -> tdx.EnclaveReport
7, // 6: tdx.QEReportCertificationData.qe_auth_data:type_name -> tdx.QeAuthData
6, // 7: tdx.QEReportCertificationData.pck_certificate_chain_data:type_name -> tdx.PCKCertificateChainData
8, // [8:8] is the sub-list for method output_type
8, // [8:8] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension type_name
8, // [8:8] is the sub-list for extension extendee
0, // [0:8] is the sub-list for field type_name
}
func init() { file_tdx_proto_init() }
func file_tdx_proto_init() {
if File_tdx_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_tdx_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*QuoteV4); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_tdx_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Header); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_tdx_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TDQuoteBody); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_tdx_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Ecdsa256BitQuoteV4AuthData); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_tdx_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CertificationData); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_tdx_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*QEReportCertificationData); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_tdx_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PCKCertificateChainData); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_tdx_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*QeAuthData); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_tdx_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*EnclaveReport); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_tdx_proto_rawDesc,
NumEnums: 0,
NumMessages: 9,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_tdx_proto_goTypes,
DependencyIndexes: file_tdx_proto_depIdxs,
MessageInfos: file_tdx_proto_msgTypes,
}.Build()
File_tdx_proto = out.File
file_tdx_proto_rawDesc = nil
file_tdx_proto_goTypes = nil
file_tdx_proto_depIdxs = nil
}
go-tdx-guest-0.3.1/testing/ 0000775 0000000 0000000 00000000000 14563713763 0015536 5 ustar 00root root 0000000 0000000 go-tdx-guest-0.3.1/testing/client/ 0000775 0000000 0000000 00000000000 14563713763 0017014 5 ustar 00root root 0000000 0000000 go-tdx-guest-0.3.1/testing/client/client.go 0000664 0000000 0000000 00000003346 14563713763 0020627 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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 client (in testing) allows tests to get a fake or real tdx-guest device.
package client
import (
"testing"
"github.com/google/go-tdx-guest/client"
test "github.com/google/go-tdx-guest/testing"
)
// GetTdxGuest is a testing helper function that retrieves the
// appropriate TDX-guest device from the flags passed into "go test".
//
// If using a test guest device, this will also produce a fake Device.
func GetTdxGuest(tcs []test.TestCase, tb testing.TB) client.Device {
tb.Helper()
if client.UseDefaultTdxGuestDevice() {
tdxTestDevice, err := test.TcDevice(tcs)
if err != nil {
tb.Fatalf("failed to create test device: %v", err)
}
return tdxTestDevice
}
client, err := client.OpenDevice()
if err != nil {
tb.Fatalf("Failed to open TDX guest device: %v", err)
}
return client
}
// GetMockTdxQuoteProvider is a testing helper function that produces a fake TDX quote provider.
func GetMockTdxQuoteProvider(tcs []test.TestCase, tb testing.TB) client.QuoteProvider {
tb.Helper()
tdxTestQuoteProvider, err := test.TcQuoteProvider(tcs)
if err != nil {
tb.Fatalf("Failed to create test quote provider: %v", err)
}
return tdxTestQuoteProvider
}
go-tdx-guest-0.3.1/testing/mocks.go 0000664 0000000 0000000 00000010776 14563713763 0017214 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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 testing defines the mock tdx-guest device
package testing
import (
"fmt"
"strings"
labi "github.com/google/go-tdx-guest/client/linuxabi"
)
// GetReportResponse represents a mocked response to a command request.
type GetReportResponse struct {
Resp labi.TdxReportReq
EsResult labi.EsResult
}
// GetQuoteResponse represents a mocked response to a command request.
type GetQuoteResponse struct {
Resp labi.TdxQuoteHdr
EsResult labi.EsResult
}
// Device represents a fake tdx-guest device with pre-programmed responses.
type Device struct {
isOpen bool
reportResponse map[[labi.TdReportDataSize]byte]any
quoteResponse map[[labi.TdReportSize]byte]any
}
// Match returns true if both errors match expectations closely enough
func Match(got error, want string) bool {
if got == nil {
return want == ""
}
return strings.Contains(got.Error(), want)
}
// Open changes the mock device's state to open.
func (d *Device) Open(_ string) error {
if d.isOpen {
return fmt.Errorf("device is already open")
}
d.isOpen = true
return nil
}
// Close changes the mock device's state to close.
func (d *Device) Close() error {
if !d.isOpen {
return fmt.Errorf("device is already closed")
}
d.isOpen = false
return nil
}
func (d *Device) getReport(req *labi.TdxReportReq) (uintptr, error) {
tdReportRespI, ok := d.reportResponse[req.ReportData]
if !ok {
return 0, fmt.Errorf("test error: no response for %v", req.ReportData)
}
tdReportResp, ok := tdReportRespI.(*GetReportResponse)
if !ok {
return 0, fmt.Errorf("test error: incorrect response for %v", tdReportRespI)
}
esResult := uintptr(tdReportResp.EsResult)
req.TdReport = tdReportResp.Resp.TdReport
return esResult, nil
}
func (d *Device) getQuote(req *labi.TdxQuoteHdr) (uintptr, error) {
var report [labi.TdReportSize]byte
copy(report[:], req.Data[:labi.TdReportSize])
quoteRespI, ok := d.quoteResponse[report]
if !ok {
return 0, fmt.Errorf("test error: no response for %v", report)
}
quoteResp, ok := quoteRespI.(*GetQuoteResponse)
if !ok {
return 0, fmt.Errorf("test error: incorrect response for %v", quoteRespI)
}
esResult := uintptr(quoteResp.EsResult)
copy(req.Data[:], quoteResp.Resp.Data[:])
req.OutLen = quoteResp.Resp.OutLen
return esResult, nil
}
// Ioctl mocks commands with pre-specified responses for a finite number of requests.
func (d *Device) Ioctl(command uintptr, req any) (uintptr, error) {
switch sreq := req.(type) {
case *labi.TdxQuoteReq:
switch command {
case labi.IocTdxGetQuote:
return d.getQuote(sreq.Buffer.(*labi.TdxQuoteHdr))
default:
return 0, fmt.Errorf("unexpected request value: %v", req)
}
case *labi.TdxReportReq:
switch command {
case labi.IocTdxGetReport:
return d.getReport(sreq)
default:
return 0, fmt.Errorf("unexpected request value: %v", req)
}
}
return 0, fmt.Errorf("unexpected request value: %v", req)
}
// HTTPResponse represents structure for containing header and body
type HTTPResponse struct {
Header map[string][]string
Body []byte
}
// Getter represents a static server for request/respond url -> body contents.
type Getter struct {
Responses map[string]HTTPResponse
}
// Get returns a registered response for a given URL.
func (g *Getter) Get(url string) (map[string][]string, []byte, error) {
v, ok := g.Responses[url]
if !ok {
return nil, nil, fmt.Errorf("404: %s", url)
}
return v.Header, v.Body, nil
}
// TdxQuoteProvider represents a fake quote provider with pre-programmed responses.
type TdxQuoteProvider struct {
isSupported bool
rawQuoteResponse map[[labi.TdReportDataSize]byte][]uint8
}
// IsSupported checks if mock quote provider is supported.
func (p *TdxQuoteProvider) IsSupported() error {
if p.isSupported {
return nil
}
return fmt.Errorf("configfs not supported")
}
// GetRawQuote returns pre-programmed response as raw quote.
func (p *TdxQuoteProvider) GetRawQuote(reportData [64]byte) ([]uint8, error) {
return p.rawQuoteResponse[reportData], nil
}
go-tdx-guest-0.3.1/testing/test_cases.go 0000664 0000000 0000000 00000023560 14563713763 0020230 0 ustar 00root root 0000000 0000000 // Copyright 2023 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
//
// 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 testing defines the mock tdx-guest device
package testing
import (
labi "github.com/google/go-tdx-guest/client/linuxabi"
"github.com/google/go-tdx-guest/testing/testdata"
)
var pckCrlIssuerChain = []string{
"-----BEGIN%20CERTIFICATE-----%0AMIICljCCAj2gAwIBAgIVAJVvXc29G%2BHpQEnJ1PQzzgFXC95UMAoGCCqGSM49BAMC%0AMGgxGjAYBgNVBAMMEUludGVsIFNHWCBSb290IENBMRowGAYDVQQKDBFJbnRlbCBD%0Ab3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQsw%0ACQYDVQQGEwJVUzAeFw0xODA1MjExMDUwMTBaFw0zMzA1MjExMDUwMTBaMHAxIjAg%0ABgNVBAMMGUludGVsIFNHWCBQQ0sgUGxhdGZvcm0gQ0ExGjAYBgNVBAoMEUludGVs%0AIENvcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0Ex%0ACzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENSB%2F7t21lXSO%0A2Cuzpxw74eJB72EyDGgW5rXCtx2tVTLq6hKk6z%2BUiRZCnqR7psOvgqFeSxlmTlJl%0AeTmi2WYz3qOBuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBS%0ABgNVHR8ESzBJMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2Vy%0AdmljZXMuaW50ZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUlW9d%0Azb0b4elAScnU9DPOAVcL3lQwDgYDVR0PAQH%2FBAQDAgEGMBIGA1UdEwEB%2FwQIMAYB%0AAf8CAQAwCgYIKoZIzj0EAwIDRwAwRAIgXsVki0w%2Bi6VYGW3UF%2F22uaXe0YJDj1Ue%0AnA%2BTjD1ai5cCICYb1SAmD5xkfTVpvo4UoyiSYxrDWLmUR4CI9NKyfPN%2B%0A-----END%20CERTIFICATE-----%0A-----BEGIN%20CERTIFICATE-----%0AMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw%0AaDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv%0AcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ%0ABgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG%0AA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0%0AaW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT%0AAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj%2FiPWsCzaEKi7%0A1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB%0AuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ%0AMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50%0AZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV%0AUr9QGzknBqwwDgYDVR0PAQH%2FBAQDAgEGMBIGA1UdEwEB%2FwQIMAYBAf8CAQEwCgYI%0AKoZIzj0EAwIDSQAwRgIhAOW%2F5QkR%2BS9CiSDcNoowLuPRLsWGf%2FYi7GSX94BgwTwg%0AAiEA4J0lrHoMs%2BXo5o%2FsX6O9QWxHRAvZUGOdRQ7cvqRXaqI%3D%0A-----END%20CERTIFICATE-----%0A"}
var tcbInfoIssuerChain = []string{
"-----BEGIN%20CERTIFICATE-----%0AMIICizCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw%0AaDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv%0AcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ%0ABgNVBAYTAlVTMB4XDTE4MDUyMTEwNTAxMFoXDTI1MDUyMTEwNTAxMFowbDEeMBwG%0AA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw%0Ab3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD%0AVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv%0AP%2BmAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh%2FzN3C4xvpoouGlirMba%2BW2lju%0AypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f%0ABEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz%0ALmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK%0AQEmORYQD6RSRvfRVMA4GA1UdDwEB%2FwQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG%0ASM49BAMCA0cAMEQCIB9C8wOAN%2FImxDtGACV246KcqjagZOR0kyctyBrsGGJVAiAj%0AftbrNGsGU8YH211dRiYNoPPu19Zp%2Fze8JmhujB0oBw%3D%3D%0A-----END%20CERTIFICATE-----%0A-----BEGIN%20CERTIFICATE-----%0AMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw%0AaDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv%0AcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ%0ABgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG%0AA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0%0AaW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT%0AAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj%2FiPWsCzaEKi7%0A1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB%0AuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ%0AMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50%0AZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV%0AUr9QGzknBqwwDgYDVR0PAQH%2FBAQDAgEGMBIGA1UdEwEB%2FwQIMAYBAf8CAQEwCgYI%0AKoZIzj0EAwIDSQAwRgIhAOW%2F5QkR%2BS9CiSDcNoowLuPRLsWGf%2FYi7GSX94BgwTwg%0AAiEA4J0lrHoMs%2BXo5o%2FsX6O9QWxHRAvZUGOdRQ7cvqRXaqI%3D%0A-----END%20CERTIFICATE-----%0A",
}
var qeIdentityIssuerChain = []string{
"-----BEGIN%20CERTIFICATE-----%0AMIICizCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw%0AaDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv%0AcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ%0ABgNVBAYTAlVTMB4XDTE4MDUyMTEwNTAxMFoXDTI1MDUyMTEwNTAxMFowbDEeMBwG%0AA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw%0Ab3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD%0AVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv%0AP%2BmAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh%2FzN3C4xvpoouGlirMba%2BW2lju%0AypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f%0ABEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz%0ALmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK%0AQEmORYQD6RSRvfRVMA4GA1UdDwEB%2FwQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG%0ASM49BAMCA0cAMEQCIB9C8wOAN%2FImxDtGACV246KcqjagZOR0kyctyBrsGGJVAiAj%0AftbrNGsGU8YH211dRiYNoPPu19Zp%2Fze8JmhujB0oBw%3D%3D%0A-----END%20CERTIFICATE-----%0A-----BEGIN%20CERTIFICATE-----%0AMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw%0AaDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv%0AcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ%0ABgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG%0AA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0%0AaW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT%0AAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj%2FiPWsCzaEKi7%0A1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB%0AuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ%0AMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50%0AZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV%0AUr9QGzknBqwwDgYDVR0PAQH%2FBAQDAgEGMBIGA1UdEwEB%2FwQIMAYBAf8CAQEwCgYI%0AKoZIzj0EAwIDSQAwRgIhAOW%2F5QkR%2BS9CiSDcNoowLuPRLsWGf%2FYi7GSX94BgwTwg%0AAiEA4J0lrHoMs%2BXo5o%2FsX6O9QWxHRAvZUGOdRQ7cvqRXaqI%3D%0A-----END%20CERTIFICATE-----%0A",
}
// PckCrlHeader is the response header for pck crl
var PckCrlHeader = map[string][]string{
"Sgx-Pck-Crl-Issuer-Chain": pckCrlIssuerChain,
}
// TcbInfoHeader is the response header for pck crl
var TcbInfoHeader = map[string][]string{
"Tcb-Info-Issuer-Chain": tcbInfoIssuerChain,
}
// QeIdentityHeader is the response header for pck crl
var QeIdentityHeader = map[string][]string{
"Sgx-Enclave-Identity-Issuer-Chain": qeIdentityIssuerChain,
}
// TestGetter is a local getter tied to the included sample quote
var TestGetter = &Getter{
Responses: map[string]HTTPResponse{
"https://api.trustedservices.intel.com/tdx/certification/v4/qe/identity": {
Header: QeIdentityHeader,
Body: testdata.QeIdentityBody,
},
"https://api.trustedservices.intel.com/tdx/certification/v4/tcb?fmspc=50806f000000": {
Header: TcbInfoHeader,
Body: testdata.TcbInfoBody,
},
"https://api.trustedservices.intel.com/sgx/certification/v4/pckcrl?ca=platform&encoding=der": {
Header: PckCrlHeader,
Body: testdata.PckCrlBody,
},
"https://certificates.trustedservices.intel.com/IntelSGXRootCA.der": {
Header: nil,
Body: testdata.RootCrlBody,
},
},
}
// reportdata defines a ReportData example that is all zeros except the last byte is 1.
var reportdata = [64]byte{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1}
// TestCase represents a get_quote input/output test case.
type TestCase struct {
Name string
Input [labi.TdReportDataSize]uint8
Report [labi.TdReportSize]uint8
Quote []uint8
EsResult labi.EsResult
WantErr string
}
// TestCases returns common test cases for get_report.
func TestCases() []TestCase {
var report [1024]byte
copy(report[:], testdata.RawReport)
return []TestCase{
{
Name: "zeros",
Input: reportdata,
Report: report,
Quote: testdata.RawQuote,
},
}
}
// TcQuoteProvider returns a mock quote provider populated from test cases inputs and expected outputs.
func TcQuoteProvider(tcs []TestCase) (*TdxQuoteProvider, error) {
rawQuoteResponses := map[[labi.TdReportDataSize]byte][]uint8{}
for _, tc := range tcs {
rawQuoteResponses[tc.Input] = tc.Quote
}
return &TdxQuoteProvider{
isSupported: true,
rawQuoteResponse: rawQuoteResponses,
}, nil
}
// TcDevice returns a mock device populated from test cases inputs and expected outputs.
func TcDevice(tcs []TestCase) (*Device, error) {
reportResponses := map[[labi.TdReportDataSize]byte]any{}
quoteResponses := map[[labi.TdReportSize]byte]any{}
for _, tc := range tcs {
reportResponses[tc.Input] = &GetReportResponse{
Resp: labi.TdxReportReq{
TdReport: tc.Report,
},
EsResult: tc.EsResult,
}
var idQuote [labi.ReqBufSize]byte
copy(idQuote[:], tc.Quote)
quoteResponses[tc.Report] = &GetQuoteResponse{
Resp: labi.TdxQuoteHdr{
Status: labi.GetQuoteSuccess,
OutLen: uint32(len(tc.Quote)),
Data: idQuote,
},
EsResult: tc.EsResult,
}
}
return &Device{
reportResponse: reportResponses,
quoteResponse: quoteResponses,
}, nil
}
go-tdx-guest-0.3.1/testing/testdata/ 0000775 0000000 0000000 00000000000 14563713763 0017347 5 ustar 00root root 0000000 0000000 go-tdx-guest-0.3.1/testing/testdata/README.md 0000664 0000000 0000000 00000011775 14563713763 0020641 0 ustar 00root root 0000000 0000000 # `testdata`
This folder contains embedded files that serve as sample API responses,
intended for testing purposes. These responses can be used to stimulate the
behavior of Intel PCS APIs without actually making network access. This folder
also contains a sample TDX quote version 4 which is only used for testing purpose.
## Files
### `pckcrl`
This file serves as sample for Intel PCS API response for PCK certificate
Revocation List. This response is specifically designed to check whether a PCK
certificate is revoked or not.
This sample API follows a structure similar to
`https://api.trustedservices.intel.com/sgx/certification/v4/pckcrl?ca=platform&encoding=der`
### `sample_tcbInfo_response`
This file serves as sample for Intel PCS API response to retrieve TDX TCB
information for given FMSPC. This response helps in determining the status of a
TDX TCB level for a given platform needs to be done using TDX TCB information
according to the following algorithm:
1. Retrieve FMSPC value from SGX PCK Certificate assigned to a given platform.
2. Retrieve TDX TCB Info matching the FMSPC value.
3. Go over the sorted collection of TCB Levels retrieved from TCB Info starting
from the first item on the list:
a. Compare all of the SGX TCB Comp SVNs retrieved from the SGX PCK Certificate
(from 01 to 16) with the corresponding values of SVNs in sgxtcbcomponents
array of TCB Level. If all SGX TCB Comp SVNs in the certificate are greater
or equal to the corresponding values in TCB Level, go to 3.b, otherwise move
to the next item on TCB Levels list.
b. Compare PCESVN value retrieved from the SGX PCK certificate with the
corresponding value in the TCB Level. If it is greater or equal to the
value in TCB Level, go to 3.c, otherwise move to the next item on TCB
Levels list.
c. Compare all of the SVNs in TEE TCB SVN array retrieved from TD Report in
Quote (from index 0 to 15) with the corresponding values of SVNs in
tdxtcbcomponents array of TCB Level. If all TEE TCB SVNs in the TD Report
are greater or equal to the corresponding values in TCB Level, read status
assigned to this TCB level. Otherwise, move to the next item on TCB Levels
list.
4. For the selected TCB level verify that SVN at index 1 in tdxtcbcomponents
array matches the value of SVN at index 1 in TEE TCB SVNs array (from TD Report
in Quote). In case of a mismatch the selected TCB level should be rejected as
TCB Info that was used for the comparison is not supported for this platform
configuration.
5. If no TCB level matches the SGX PCK Certificate and TD Report, then the TCB
level is not supported.
This sample API follows a structure similar to
`https://api.trustedservices.intel.com/tdx/certification/v4/tcb?fmspc=50806f000000`
### `sample_qeIdentity_response`
This file serves as sample for Intel PCS API response to retrieve QE identity
response. This response helps in determining if the identity of a SGX Enclave
(represented by SGX Enclave Report) matches a valid, up-to-date Enclave Identity
issued by Intel requires following steps:
1. Retrieve Enclave Identity(TDX QE) from PCS and verify that it is a valid
structure issued by Intel.
2. Perform the following comparison of SGX Enclave Report against the retrieved
Enclave Identity:
a. Verify if MRSIGNER field retrieved from SGX Enclave Report is equal to the
value of mrsigner field in Enclave Identity.
b. Verify if ISVPRODID field retrieved from SGX Enclave Report is equal to the
value of isvprodid field in Enclave Identity.
c. Apply miscselectMask (binary mask) from Enclave Identity to MISCSELECT
field retrieved from SGX Enclave Report. Verify if the outcome
(miscselectMask & MISCSELECT) is equal to the value of miscselect field in
Enclave Identity.
d. Apply attributesMask (binary mask) from Enclave Identity to ATTRIBUTES
field retrieved from SGX Enclave Report. Verify if the outcome (attributesMask
& ATTRIBUTES) is equal to the value of attributes field in Enclave Identity.
3. If any of the checks above fail, the identity of the enclave does not match
Enclave Identity published by Intel.
4. Determine a TCB status of the Enclave:
a. Retrieve a collection of TCB Levels (sorted by ISVSVNs) from tcbLevels field
in Enclave Identity structure.
b. Go over the list of TCB Levels (descending order) and find the one that has
ISVSVN that is lower or equal to the ISVSVN value from SGX Enclave Report.
c. If a TCB level is found, read its status from tcbStatus field, otherwise
the TCB Level is not supported.
This sample API follows a structure similar to
`https://api.trustedservices.intel.com/tdx/certification/v4/qe/identity`
### `rootcrl.der`
This file serves as sample for Intel PCS API response for Root certificate
Revocation List. This response is specifically designed to check whether a Root
certificate is revoked or not.
This sample API follows a structure similar to
`https://certificates.trustedservices.intel.com/IntelSGXRootCA.der`
go-tdx-guest-0.3.1/testing/testdata/pckcrl 0000664 0000000 0000000 00000005147 14563713763 0020557 0 ustar 00root root 0000000 0000000 0‚
c0‚
0
*†HÎ=0p1"0 UIntel SGX PCK Platform CA10U
Intel Corporation10USanta Clara10 UCA10 UUS
230608072752Z
230708072752Z0‚ 403oÃNP#ç(’45Ö¤¸