kops/vendor/github.com/google/go-tdx-guest/client/client.go

159 lines
5.0 KiB
Go

// 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)
}