mirror of https://github.com/kubernetes/kops.git
159 lines
5.0 KiB
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)
|
|
}
|