gcetcbendorsement

package module
v0.0.0-...-ab56314 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 23, 2025 License: Apache-2.0 Imports: 33 Imported by: 0

README

gcbtcbendorsement CLI tool

Endorsements produced by the CLI tool in cmd/nonprod can be interpreted with this tool. The output is in the form of a binary-serialized VMLaunchEndorsement defined in proto/endorsement.proto, which for now is only used for providing measurements of the Open Virtual Machine Firmware (OVMF) UEFI implementation.

This tool provides commands for fetching and interpreting the UEFI endorsement.

What is endorsed

A VMLaunchEndorsement contains signed reference values to compare with trusted execution environment (TEE) attestation reports (AKA quotes) that include a measurement of the machine state at power-on. For GCE VMs this is includes the firmware ROM, vCPU state, and TEE-specific configuration options.

An endorsement file contains the binary serialization of the VMLaunchEndorsement message that the firmware vendor created offline prior to the firmware deployment. It is a pair of bytes that were signed, and the signature itself. The signing key's certificate is contained within the signed bytes, but the certificate's signature comes from the root key.

The signed bytes themselves are another serialized protocol buffer, VMGoldenMeasurement. This includes the timestamp the endorsement was created, very basic provenance information, and further information about the firmware and TEE-specifics.

message VMGoldenMeasurement {
  google.protobuf.Timestamp timestamp = 1;

  // The changelist number this UEFI was built from.
  uint64 cl_spec = 2;

  // The commit hash this UEFI was built from.
  bytes commit = 3;

  // DER format certificate of the key that signed this document.
  bytes cert = 4;

  // SHA-384 digest of the UEFI binary without TEE-specifics about launch.
  bytes digest = 5;

  // A sequence of PEM-encoded certificates of keys used in cert in Root ...
  // final intermediate order. The last certificate will have signed cert.
  bytes ca_bundle = 6;

  VMSevSnp sev_snp = 7;
}

The commit and ca_bundle fields are currently unused.

SEV-SNP specifics

Google Compute Engine does not use the IDBLOCK structure for SEV-SNP VM launch endorsement. Instead the fields that would be included there are in the VMSevSnp message.

message VMSevSnp {
  // The Google-reported security version number of this UEFI on SEV-SNP.
  uint32 svn = 1;
  // Expected MEASUREMENT report field values given [key]-many VMSAs at launch.
  map<uint32, bytes> measurements = 2;  // bytes size 48
  // A UUID that Google uses for its CVM UEFIs
  bytes family_id = 3;  // size 16
  // A UUID to name this specific release of the UEFI image.
  bytes image_id = 4;  // size 16
  // The launch policy that verifiers should expect with this UEFI.
  uint64 policy = 5;
  // Optional. PEM-encoded certs for Identity..Author..Root. If a singleton,
  // only an Id-key is used.
  bytes ca_bundle = 6;
}

The family_id and image_id fields are for attestation verifiers to interpret, but the corresponding fields of the SEV-SNP attestation report should be expected to be zeros.

The launch policy for SEV-SNP VMs (AKA guest policy) is not user-configurable on Google Compute Engine and should always match the reference value.

Common uses

Check the authenticity of the endorsement file
gcetcbendorsement verify "${ENDORSEMENT_PATH?}"
Extract the endorsement for the VM you're running on

Every firmware measurement possible on Google Compute Engine should be accounted for with an endorsed measurement, so a user in a TEE with permissions to get an attestation report can run the following to get a local or remote copy of the endorsement for the firmware the VM is running.

gcetcbendorsement extract --out="${ENDORSEMENT_PATH?}"

While rare, there may be cases that the endorsement delivered in-guest contains an error. In this case, an amended endorsement for the firmware may be posted in the storage bucket. Pass --force_fetch to fall back to the free storage bucket that provides a fallback source for firmware endorsements.

Extract the endorsement from a GCE VM attestation report

If not on the node itself, the measurement itself is enough to identify a copy of the firmware's endorsement in Google Cloud Storage.

gcetcbendorsement extract "${ATTESTATION_PATH?}" --out="${ENDORSEMENT_PATH?}"
Check an attestation report against an endorsement

You may want to augment your own attestation report appraisal logic to check the signed firmware measurement.

gcetcbendorsement sev validate "${ATTESTATION_PATH?}" \
  --endorsement="${ENDORSEMENT_PATH?}" \
  --allow_unspecified_vmsas

Commands

  • extract: Outputs the endorsement from an input attestation, or attempts to download it if unavailable.
  • inspect: offers options to output the contents of specific fields of the endorsement, such as the payload that is signed, the (encoded) signature, and fields of the payload when decoded as a VMGoldenMeasurement.
  • verify: checks cryptographic signatures. The first is the root key's signature of the signing key's certificate and the second is the signing key's signature of the serialized VMGoldenMeasurement.
  • sev: offers options for amending a base go-sev-guest checking policy with an endorsement's reference values and simply checking an endorsement against an attestation and optional base policy.
extract
gcetcbendorsement extract [FILE] [--out=FILE]

Reads the given file as any of the output formats of go-sev-guest’s attest tool, a go-tpm-tools attestation, or the contents of the auxblob attribute from configfs-tsm and outputs the embedded UEFI endorsement to the given path. Default is --out=endorsement.binarypb since the contents aren't easily human-readable in any form.

If no input file is given, it expects to be running as a guest and attempts to get the certificate locally from an extended report, and then attempts via network.

inspect
gcetcbendorsement inspect CMD FILE [options]

Options for all inspect commands:

  • --out=FILE: where to write the output. Default is stdout, i.e., --out=-.
  • --bytesform=bin|hex|base64|auto: selects whether bytes fields should be output as raw binary, or encoded as hex or base64. Default is auto, which chooses base64 for terminal outputs and binary otherwise.

CMD specifies what part of the endorsement to inspect:

  • signature: outputs the signature bytes.
  • payload: outputs the serialized VMGoldenMeasurement bytes.
  • mask: outputs the fields of the VMGoldenMeasurement selected by the paths in the repeatable flag --path, e.g., --path=timestamp, --path=sev_snp.svn, or --path=sev_snp.measurements[8].
verify
gcetcbendorsement verify FILE [--show|--root_cert=FILE]

Checks cryptographic signatures. The first is the root key's signature of the signing key's certificate and the second is the signing key's signature of the serialized VMGoldenMeasurement.

If run with --show, outputs a shell command that uses Openssl which is equivalent to running the command without --show:

$ gcetcbendorsement verify FILE --show
openssl dgst -verify <(gcetcbendorsement inspect mask FILE --path=cert) \
 -signature <(gcetcbendorsement inspect signature FILE) \
 <(gcetcbendorsement inspect payload FILE)
&&
openssl verify -CAfile <(curl https://pki.goog/cloud_integrity/GCE-cc-tcb-root_1.crt) \
  -untrusted <(gcetcbendorsement inspect mask FILE --path=cert)

and

$ gcetcbendorsement verify FILE --show --root_cert=root.crt
openssl dgst -verify <(gcetcbendorsement inspect mask FILE --path=cert) \
 -signature <(gcetcbendorsement inspect signature FILE) \
 <(gcetcbendorsement inspect payload FILE)
&&
openssl verify -CAfile root.crt \
  -untrusted <(gcetcbendorsement inspect mask FILE --path=cert)

The shell command can therefore be run directly with

$ $(gcetcbendorsement verify FILE --show)

Without --show, gcetcbendorsement verify FILE returns the functional equivalent of running the openssl commands, but with the Golang crypto library. On success, the command will return a 0 exit code. On failure, it will log an error message and exit with a non-zero exit code.

sev
gcetcbendorsement sev CMD FILE [options]

Options for both sev subcommands:

  • --overwrite: If --overwrite=false or --nooverwrite, it is an error for populated base policy fields to be overwritten. Default is false.
  • --base=FILE: Path to base go-sev-guest check.Policy. Default is "", equivalent to &Policy{Policy: 0x70000, MinimumVersion: "0.0"}
  • --launch_vmsas=#: Number of VMSAs measured at launch. This should be the number of vCPUs the VM was created with. If running with an SVSM, it should be 1. Default 0 for unspecified, which is an error without --allow_unspecified_vmsas.
  • --allow_unspecified_vmsas: If true, then commands will not error when --launch_vmsas=0. See individual commands for the impact on behavior. Default false.
policy subcommand:

Produces a check.Policy with reference values from an endorsement. It may amend an optional --base policy. If fields conflict, the command will fail unless overwrite is true. If --launch_vmsas=0 and --allow_unspecified_vmsas, then the base policy's measurement field will not be changed.

The FILE mandatory argument is expected to be a binary-serialized VMLaunchEndorsement.

Options:

  • --out=FILE: A path to the output location for the updated policy. Default is stdout, i.e., -out=-.
  • --outform=textproto|bin|hex|base64|auto: selects the output format of the policy. Use textproto for human-readable format or one of bin, hex, base64, or auto (default). If auto and the output is a terminal, the output format is textproto, otherwise bin. The bin, hex, and base64 output forms are raw or encoded forms of the serialized binary protocol buffer.
validate subcommand:

Returns the results of comparing endorsed values (and optional base policy) against an attestation report. If --launch_vmsas=0 and --allow_unspecified_vmsas, then an attestation is valid only if its measurement is in the endorsement for any number of VMSAs.

The FILE mandatory argument is expected to be an attestation report (and optional collateral) in one of the supported formats.

Options:

  • --endorsement=FILE: A path to a binary serialized VMLaunchEndorsement to supplement or replace the endorsement collateral of the attestation report. Default "" and will not attempt to extract an endorsement from the local environment as with extract.
  • --root_cert=FILE: A path to the endorsement root signing certificate. If empty, defaults to attempting to download the GCE-cc-tcb-root_1.crt root certificate from pki.goog.

Returns exit code 0 if all fields of the given attestation pass go-sev-guest validation against the given endorsement.

Documentation

Overview

Package gcetcbendorsement provides functions for interpreting VMLaunchEndorsements.

Index

Constants

View Source
const (
	// DefaultRootURL is the trusted location of the GCE Confidential Computing TCB signing key root
	// certificate.
	DefaultRootURL = "https://pki.goog/cloud_integrity/GCE-cc-tcb-root_1.crt"
	// DefaultRootCmd is a shell command for use as a path to the root certificate.
	DefaultRootCmd = "<(curl " + DefaultRootURL + ")"
)

Variables

View Source
var (
	// ErrNoInspect is returned when no Inspect is found in the context.
	ErrNoInspect = errors.New("no Inspect found in context")
)

Functions

func InspectMask

func InspectMask(ctx context.Context, endorsement *epb.VMLaunchEndorsement, mask *fmpb.FieldMask) error

InspectMask outputs the masked fields of the endorsement's golden measurement.

func InspectPayload

func InspectPayload(ctx context.Context, endorsement *epb.VMLaunchEndorsement) error

InspectPayload outputs the signature of the endorsement.

func InspectSignature

func InspectSignature(ctx context.Context, endorsement *epb.VMLaunchEndorsement) error

InspectSignature outputs the signature of the endorsement.

func OpensslVerifyCertShellCmd

func OpensslVerifyCertShellCmd(self, endorsement, root string) string

OpensslVerifyCertShellCmd returns the shell command for using openssl to verify the code- signing certificate inside the endorsement in path `endorsement` as extracted by the gcetcbendorsement CLI tool at the `self` path. The `endorsement` path must be to a file containing a binary-serialized VMLaunchEndorsement.

func OpensslVerifyShellCmd

func OpensslVerifyShellCmd(self, endorsement string) string

OpensslVerifyShellCmd returns the shell command for using openssl and the gcetcbendorsement CLI tool at path `self` to verify the endorsement at path `endorsement` signature. The `endorsement` path must be to a file containing a binary-serialized VMLaunchEndorsement.

func SevPolicy

func SevPolicy(ctx context.Context, endorsement *epb.VMLaunchEndorsement, opts *SevPolicyOptions) (*cpb.Policy, error)

SevPolicy extends a base go-sev-guest validation policy with reference values contained in the endorsement.

func SevValidate

func SevValidate(ctx context.Context, attestation *spb.Attestation, opts *SevValidateOptions) error

SevValidate validates an attestation against the given or extracted endorsement and an optional base policy.

func TdxPolicy

func TdxPolicy(ctx context.Context, endorsement *epb.VMLaunchEndorsement, opts *TdxPolicyOptions) (*tcpb.Policy, error)

TdxPolicy extends a base go-tdx-guest validation policy with reference values contained in the endorsement.

func TdxValidate

func TdxValidate(ctx context.Context, attestation []byte, opts *TdxValidateOptions) error

TdxValidate validates an attestation against the given or extracted endorsement and an optional base policy.

func WithInspect

func WithInspect(ctx context.Context, i *Inspect) context.Context

WithInspect returns a context with the inspect options added.

func WriteBytesForm

func WriteBytesForm(bytes []byte, form BytesForm, w TerminalWriter) error

WriteBytesForm writes bytes according to a BytesForm to the given TerminalWriter.

Types

type BytesForm

type BytesForm int

BytesForm is the type of form to use for rendering `bytes` fields.

const (
	// BytesRaw instructs Mask to write `bytes` fields as a raw string.
	BytesRaw BytesForm = iota
	// BytesHex  instructs Mask to write `bytes` fields with a hex-encoded string.
	BytesHex
	// BytesHexGuidify instructs Mask to write `bytes` fields with a hex-encoded string unless 16
	// bytes long. If 16 bytes long, render as a GUID.
	BytesHexGuidify
	// BytesBase64  instructs Mask to write `bytes` fields with a base64-encoded string.
	BytesBase64
	// BytesAuto is instructs Mask to write `bytes` fields in a form dependent on the writer. If the
	// writer is terminal, then it uses a base64-encoded string. If it's not a terminal, it uses raw
	// binary.
	BytesAuto
)

func ParseBytesForm

func ParseBytesForm(form string) (BytesForm, error)

ParseBytesForm parses a BytesForm option name to the corresponding constant.

type FieldRenderer

type FieldRenderer func(*MaskOptions, protopathIndex) error

FieldRenderer is called on fields that are present at the path this function is mapped to.

func RenderTimestamp

func RenderTimestamp(timeFormat string) FieldRenderer

RenderTimestamp return a FieldRenderer for a Timestamp message using a given Golang time format string.

type Inspect

type Inspect struct {
	Writer TerminalWriter
	Form   BytesForm
}

Inspect represents arguments to the VMLaunchEndorsement inspect command.

type MaskOptions

type MaskOptions struct {
	BytesForm    BytesForm
	Writer       TerminalWriter
	PathRenderer map[string]FieldRenderer
}

MaskOptions contains options for rendering named fields in a VMGoldenMeasurement.

func (*MaskOptions) Mask

func (opts *MaskOptions) Mask(src proto.Message, mask *fpb.FieldMask) error

Mask writes `src` restricted to `mask` with `bytes` fields rendered with the given `form` in the opts.Writer.

type NonterminalWriter

type NonterminalWriter struct{ Writer io.Writer }

NonterminalWriter wraps the io.Writer interface while also making IsTerminal() always return false.

func (NonterminalWriter) IsTerminal

func (w NonterminalWriter) IsTerminal() bool

IsTerminal returns false.

func (NonterminalWriter) Write

func (w NonterminalWriter) Write(p []byte) (int, error)

type OSFileWriter

type OSFileWriter struct{ File *os.File }

OSFileWriter wraps the os.File interface while also making IsTerminal() return whether the file's encapsulated file descriptor is a TTY.

func (OSFileWriter) IsTerminal

func (w OSFileWriter) IsTerminal() bool

IsTerminal returns whether the file's encapsulated file descriptor is a TTY.

func (OSFileWriter) Write

func (w OSFileWriter) Write(p []byte) (int, error)

type SevPolicyOptions

type SevPolicyOptions struct {
	Base *cpb.Policy
	// LaunchVmsas is the number of expected Vmsas the VM was launched with. A policy is limited to
	// check a single measurement.
	LaunchVmsas uint32
	// Overwrite if false, it is an error for reference values from Endorsement to overwrite the
	// associated fields in the Base policy.
	Overwrite bool
	// AllowUnspecifiedVmsas indicates that LaunchVmsas == 0 should not be an error, and the
	// measurement should be disregarded.
	AllowUnspecifiedVmsas bool
}

SevPolicyOptions contains options for modifying a go-sev-guest validation policy from an endorsement.

type SevValidateOptions

type SevValidateOptions struct {
	Endorsement         *epb.VMLaunchEndorsement
	BasePolicy          *cpb.Policy
	Overwrite           bool
	RootsOfTrust        *x509.CertPool
	Now                 time.Time
	Getter              verify.HTTPSGetter
	ExpectedLaunchVmsas uint32
	TestonlyForceGCS    bool
}

SevValidateOptions holds options for the sev-validate command.

type TdxPolicyOptions

type TdxPolicyOptions struct {
	Base *tcpb.Policy
	// RAMGiB is the amount of RAM that the VM launched with as accounted by its TDHOB.
	RAMGiB int
	// Overwrite indicates that the policy should be modified even if it already has values.
	Overwrite bool
}

TdxPolicyOptions contains options for modifying a go-tdx-guest validation policy from an endorsement.

type TdxValidateOptions

type TdxValidateOptions struct {
	Endorsement    *epb.VMLaunchEndorsement
	BasePolicy     *tcpb.Policy
	Overwrite      bool
	RootsOfTrust   *x509.CertPool
	Now            time.Time
	Getter         verify.HTTPSGetter
	ExpectedRAMGiB int
}

TdxValidateOptions holds options for the tdx-validate command.

type TerminalWriter

type TerminalWriter interface {
	// Write writes len(p) bytes from p to the underlying data stream.
	// It returns the number of bytes written from p (0 <= n <= len(p))
	// and any error encountered that caused the write to stop early.
	// Write must return a non-nil error if it returns n < len(p).
	// Write must not modify the slice data, even temporarily.
	Write([]byte) (int, error)
	// IsTerminal returns true if the writer is a terminal.
	IsTerminal() bool
}

TerminalWriter is an io.Writer that can determine if it's a terminal or not.

Directories

Path Synopsis
The gcetcbendorsement command provides a CLI tool for interpreting the UEFI binary endorsement.
The gcetcbendorsement command provides a CLI tool for interpreting the UEFI binary endorsement.
Package cmd provides the gcetcbendorsement CLI command abstractions.
Package cmd provides the gcetcbendorsement CLI command abstractions.
Package parsepath provides a parser for the protopath syntax of referencing fields within a protobuf.
Package parsepath provides a parser for the protopath syntax of referencing fields within a protobuf.
Package testing provides helpers for testing gcetcbendorsement.
Package testing provides helpers for testing gcetcbendorsement.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL