mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-08-07 07:14:50 +00:00
* inital tdx attestation support * fix fetching and verification errors * fix tests * fix lint problems * fix reading attestation policy * add tdx package * remove Makefile configuration for staticly built binaries
This commit is contained in:
committed by
GitHub
parent
79c66a89c3
commit
9c8ddfd2b1
+124
-25
@@ -9,6 +9,7 @@ import (
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -16,6 +17,7 @@ import (
|
||||
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/google/go-sev-guest/abi"
|
||||
"github.com/google/go-sev-guest/proto/check"
|
||||
"github.com/google/go-sev-guest/proto/sevsnp"
|
||||
"github.com/google/go-tpm-tools/client"
|
||||
"github.com/google/go-tpm-tools/proto/attest"
|
||||
@@ -26,11 +28,15 @@ import (
|
||||
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
||||
"golang.org/x/crypto/sha3"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/encoding/prototext"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var _ attestation.Provider = (*provider)(nil)
|
||||
var (
|
||||
_ attestation.Provider = (*provider)(nil)
|
||||
_ attestation.Verifier = (*verifier)(nil)
|
||||
)
|
||||
|
||||
const (
|
||||
eventLog = "/sys/kernel/security/tpm0/binary_bios_measurements"
|
||||
@@ -43,10 +49,15 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
ExternalTPM io.ReadWriteCloser
|
||||
ErrNoHashAlgo = errors.New("hash algo is not supported")
|
||||
ErrFetchQuote = errors.New("failed to fetch vTPM quote")
|
||||
ErrFetchAzureToken = errors.New("failed to fetch Azure token")
|
||||
ExternalTPM io.ReadWriteCloser
|
||||
ErrNoHashAlgo = errors.New("hash algo is not supported")
|
||||
ErrFetchQuote = errors.New("failed to fetch vTPM quote")
|
||||
ErrAttestationPolicyOpen = errors.New("failed to open Attestation Policy file")
|
||||
ErrAttestationPolicyDecode = errors.New("failed to decode Attestation Policy file")
|
||||
ErrAttestationPolicyMissing = errors.New("failed due to missing Attestation Policy file")
|
||||
ErrProtoMarshalFailed = errors.New("failed to marshal protojson")
|
||||
ErrJsonMarshalFailed = errors.New("failed to marshal json")
|
||||
ErrJsonUnarshalFailed = errors.New("failed to unmarshal json")
|
||||
)
|
||||
|
||||
type tpm struct {
|
||||
@@ -97,15 +108,13 @@ type provider struct {
|
||||
pubKey []byte
|
||||
teeAttestaion bool
|
||||
vmpl uint
|
||||
writer io.Writer
|
||||
}
|
||||
|
||||
func New(pubKey []byte, teeAttestation bool, vmpl uint, writer io.Writer) attestation.Provider {
|
||||
func NewProvider(pubKey []byte, teeAttestation bool, vmpl uint) attestation.Provider {
|
||||
return &provider{
|
||||
pubKey: pubKey,
|
||||
teeAttestaion: teeAttestation,
|
||||
vmpl: vmpl,
|
||||
writer: writer,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,26 +135,61 @@ func (v provider) VTpmAttestation(vTpmNonce []byte) ([]byte, error) {
|
||||
return proto.Marshal(quote)
|
||||
}
|
||||
|
||||
func (v provider) VerifTeeAttestation(report []byte, teeNonce []byte) error {
|
||||
func (v provider) AzureAttestationToken(tokenNonce []byte) ([]byte, error) {
|
||||
return nil, errors.New("Azure attestation token is not supported")
|
||||
}
|
||||
|
||||
type verifier struct {
|
||||
pubKey []byte
|
||||
writer io.Writer
|
||||
Policy *attestation.Config
|
||||
}
|
||||
|
||||
func NewVerifier(pubKey []byte, writer io.Writer) attestation.Verifier {
|
||||
policy := &attestation.Config{
|
||||
Config: &check.Config{Policy: &check.Policy{}, RootOfTrust: &check.RootOfTrust{}},
|
||||
PcrConfig: &attestation.PcrConfig{},
|
||||
}
|
||||
|
||||
return &verifier{
|
||||
pubKey: pubKey,
|
||||
writer: writer,
|
||||
Policy: policy,
|
||||
}
|
||||
}
|
||||
|
||||
func NewVerifierWithPolicy(pubKey []byte, writer io.Writer, policy *attestation.Config) attestation.Verifier {
|
||||
if policy == nil {
|
||||
return NewVerifier(pubKey, writer)
|
||||
}
|
||||
|
||||
return &verifier{
|
||||
pubKey: pubKey,
|
||||
writer: writer,
|
||||
Policy: policy,
|
||||
}
|
||||
}
|
||||
|
||||
func (v verifier) VerifTeeAttestation(report []byte, teeNonce []byte) error {
|
||||
attestReport, err := abi.ReportToProto(report)
|
||||
if err != nil {
|
||||
return errors.Wrap(fmt.Errorf("failed to convert TEE report to proto"), err)
|
||||
}
|
||||
|
||||
attestationReport := sevsnp.Attestation{Report: attestReport, CertificateChain: nil}
|
||||
return quoteprovider.VerifyAttestationReportTLS(&attestationReport, teeNonce)
|
||||
return quoteprovider.VerifyAttestationReportTLS(&attestationReport, teeNonce, v.Policy)
|
||||
}
|
||||
|
||||
func (v provider) VerifVTpmAttestation(report []byte, vTpmNonce []byte) error {
|
||||
return VerifyQuote(report, v.pubKey, vTpmNonce, v.writer)
|
||||
func (v verifier) VerifVTpmAttestation(report []byte, vTpmNonce []byte) error {
|
||||
return VerifyQuote(report, v.pubKey, vTpmNonce, v.writer, v.Policy)
|
||||
}
|
||||
|
||||
func (v provider) VerifyAttestation(report []byte, teeNonce []byte, vTpmNonce []byte) error {
|
||||
return VTPMVerify(report, v.pubKey, teeNonce, vTpmNonce, v.writer)
|
||||
func (v verifier) VerifyAttestation(report []byte, teeNonce []byte, vTpmNonce []byte) error {
|
||||
return VTPMVerify(report, v.pubKey, teeNonce, vTpmNonce, v.writer, v.Policy)
|
||||
}
|
||||
|
||||
func (v provider) AzureAttestationToken(tokenNonce []byte) ([]byte, error) {
|
||||
return nil, errors.New("Azure attestation token is not supported")
|
||||
func (v verifier) JSONToPolicy(path string) error {
|
||||
return ReadPolicy(path, v.Policy)
|
||||
}
|
||||
|
||||
func Attest(teeNonce []byte, vTPMNonce []byte, teeAttestaion bool, vmpl uint) ([]byte, error) {
|
||||
@@ -164,8 +208,8 @@ func Attest(teeNonce []byte, vTPMNonce []byte, teeAttestaion bool, vmpl uint) ([
|
||||
return marshalQuote(attestation)
|
||||
}
|
||||
|
||||
func VTPMVerify(quote []byte, pubKeyTLS []byte, teeNonce []byte, vtpmNonce []byte, writer io.Writer) error {
|
||||
if err := VerifyQuote(quote, pubKeyTLS, vtpmNonce, writer); err != nil {
|
||||
func VTPMVerify(quote []byte, pubKeyTLS []byte, teeNonce []byte, vtpmNonce []byte, writer io.Writer, policy *attestation.Config) error {
|
||||
if err := VerifyQuote(quote, pubKeyTLS, vtpmNonce, writer, policy); err != nil {
|
||||
return fmt.Errorf("failed to verify vTPM quote: %v", err)
|
||||
}
|
||||
|
||||
@@ -176,14 +220,14 @@ func VTPMVerify(quote []byte, pubKeyTLS []byte, teeNonce []byte, vtpmNonce []byt
|
||||
return errors.Wrap(fmt.Errorf("failed to unmarshal quote"), err)
|
||||
}
|
||||
|
||||
if err := quoteprovider.VerifyAttestationReportTLS(attestation.GetSevSnpAttestation(), teeNonce); err != nil {
|
||||
if err := quoteprovider.VerifyAttestationReportTLS(attestation.GetSevSnpAttestation(), teeNonce, policy); err != nil {
|
||||
return fmt.Errorf("failed to verify TEE attestation report: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func VerifyQuote(quote []byte, pubKeyTLS []byte, vtpmNonce []byte, writer io.Writer) error {
|
||||
func VerifyQuote(quote []byte, pubKeyTLS []byte, vtpmNonce []byte, writer io.Writer, policy *attestation.Config) error {
|
||||
attestation := &attest.Attestation{}
|
||||
|
||||
err := proto.Unmarshal(quote, attestation)
|
||||
@@ -209,7 +253,7 @@ func VerifyQuote(quote []byte, pubKeyTLS []byte, vtpmNonce []byte, writer io.Wri
|
||||
|
||||
s256, s384 := calculatePCRTLSKey(pubKeyTLS)
|
||||
|
||||
if err := checkExpectedPCRValues(attestation, s256, s384); err != nil {
|
||||
if err := checkExpectedPCRValues(attestation, s256, s384, policy); err != nil {
|
||||
return fmt.Errorf("PCR values do not match expected PCR values: %w", err)
|
||||
}
|
||||
|
||||
@@ -286,7 +330,7 @@ func addTEEAttestation(attestation *attest.Attestation, nonce []byte, vmpl uint)
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkExpectedPCRValues(attQuote *attest.Attestation, ePcr256, ePcr384 []byte) error {
|
||||
func checkExpectedPCRValues(attQuote *attest.Attestation, ePcr256, ePcr384 []byte, policy *attestation.Config) error {
|
||||
quotes := attQuote.GetQuotes()
|
||||
for i := range quotes {
|
||||
quote := quotes[i]
|
||||
@@ -294,21 +338,21 @@ func checkExpectedPCRValues(attQuote *attest.Attestation, ePcr256, ePcr384 []byt
|
||||
var pcr15 []byte
|
||||
switch quote.Pcrs.Hash {
|
||||
case ptpm.HashAlgo_SHA256:
|
||||
pcrMap = attestation.AttestationPolicy.PcrConfig.PCRValues.Sha256
|
||||
pcrMap = policy.PcrConfig.PCRValues.Sha256
|
||||
if ePcr256 == nil {
|
||||
pcr15 = make([]byte, 32)
|
||||
} else {
|
||||
pcr15 = ePcr256
|
||||
}
|
||||
case ptpm.HashAlgo_SHA384:
|
||||
pcrMap = attestation.AttestationPolicy.PcrConfig.PCRValues.Sha384
|
||||
pcrMap = policy.PcrConfig.PCRValues.Sha384
|
||||
if ePcr384 == nil {
|
||||
pcr15 = make([]byte, 48)
|
||||
} else {
|
||||
pcr15 = ePcr384
|
||||
}
|
||||
case ptpm.HashAlgo_SHA1:
|
||||
pcrMap = attestation.AttestationPolicy.PcrConfig.PCRValues.Sha1
|
||||
pcrMap = policy.PcrConfig.PCRValues.Sha1
|
||||
pcr15 = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
default:
|
||||
return errors.Wrap(ErrNoHashAlgo, fmt.Errorf("algo: %s", ptpm.HashAlgo_name[int32(quote.Pcrs.Hash)]))
|
||||
@@ -383,3 +427,58 @@ func GetPCRSHA256Value(index int) ([]byte, error) {
|
||||
func GetPCRSHA384Value(index int) ([]byte, error) {
|
||||
return getPCRValue(index, tpm2.AlgSHA384)
|
||||
}
|
||||
|
||||
func ReadPolicy(policyPath string, attestationConfiguration *attestation.Config) error {
|
||||
if policyPath != "" {
|
||||
policyData, err := os.ReadFile(policyPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(ErrAttestationPolicyOpen, err)
|
||||
}
|
||||
|
||||
return ReadPolicyFromByte(policyData, attestationConfiguration)
|
||||
}
|
||||
|
||||
return ErrAttestationPolicyMissing
|
||||
}
|
||||
|
||||
func ReadPolicyFromByte(policyData []byte, attestationConfiguration *attestation.Config) error {
|
||||
unmarshalOptions := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
|
||||
|
||||
if err := unmarshalOptions.Unmarshal(policyData, attestationConfiguration.Config); err != nil {
|
||||
return errors.Wrap(ErrAttestationPolicyDecode, err)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(policyData, attestationConfiguration.PcrConfig); err != nil {
|
||||
return errors.Wrap(ErrAttestationPolicyDecode, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ConvertPolicyToJSON(attestationConfiguration *attestation.Config) ([]byte, error) {
|
||||
pbJson, err := protojson.Marshal(attestationConfiguration.Config)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrProtoMarshalFailed, err)
|
||||
}
|
||||
|
||||
var pbMap map[string]interface{}
|
||||
if err := json.Unmarshal(pbJson, &pbMap); err != nil {
|
||||
return nil, errors.Wrap(ErrJsonUnarshalFailed, err)
|
||||
}
|
||||
|
||||
pcrJson, err := json.Marshal(attestationConfiguration.PcrConfig)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ErrJsonMarshalFailed, err)
|
||||
}
|
||||
|
||||
var pcrMap map[string]interface{}
|
||||
if err := json.Unmarshal(pcrJson, &pcrMap); err != nil {
|
||||
return nil, errors.Wrap(ErrJsonUnarshalFailed, err)
|
||||
}
|
||||
|
||||
for k, v := range pcrMap {
|
||||
pbMap[k] = v
|
||||
}
|
||||
|
||||
return json.MarshalIndent(pbMap, "", " ")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user