Skip to content

Commit

Permalink
sev: perform attestation
Browse files Browse the repository at this point in the history
- Add "SevToken" data structure for the evidence token
- Use "sevtool" to validate the certificate chain and signature in the
  Attestation Report
- Generate EAR containing the Trust Worthiness Vector and the evidence
  received
- Add sample endorsement & evidence tokens for SEV

Signed-off-by: Jagannathan Raman <[email protected]>
  • Loading branch information
jraman567 committed Jan 23, 2024
1 parent 89fc9fc commit 6110565
Show file tree
Hide file tree
Showing 6 changed files with 391 additions and 4 deletions.
13 changes: 10 additions & 3 deletions end-to-end/end-to-end
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash
# Copyright 2022-2023 Contributors to the Veraison project.
# Copyright 2022-2024 Contributors to the Veraison project.
# SPDX-License-Identifier: Apache-2.0

SCHEME=${SCHEME:-psa}
Expand All @@ -20,6 +20,10 @@ function provision() {
local corim_file=$THIS_DIR/input/cca-endorsements.cbor
local media_type="application/corim-unsigned+cbor; profile=http://arm.com/cca/ssd/1"
;;
sev)
local corim_file=$THIS_DIR/input/sev-endorsements.cbor
local media_type="application/corim-unsigned+cbor; profile=https://amd.com/sev"
;;
*)
echo "ERROR: bad SCHEME: $SCHEME"
exit 1
Expand Down Expand Up @@ -67,6 +71,9 @@ function verify_as_relying_party() {
cca)
local token=$THIS_DIR/input/cca-evidence.cbor
;;
sev)
local token=$THIS_DIR/input/sev-evidence.cbor
;;
*)
echo "ERROR: bad SCHEME: $SCHEME"
exit 1
Expand Down Expand Up @@ -108,10 +115,10 @@ EOF

function _check_scheme() {
case $SCHEME in
psa | cca)
psa | cca | sev)
;;
*)
echo "ERROR: unknown SCHEME: '$SCHEME'; must be 'cca' or 'psa'"; exit 1
echo "ERROR: unknown SCHEME: '$SCHEME'; must be 'cca', 'psa' or 'sev'"; exit 1
;;
esac
}
Expand Down
Binary file added end-to-end/input/sev-endorsements.cbor
Binary file not shown.
Binary file added end-to-end/input/sev-evidence.cbor
Binary file not shown.
23 changes: 23 additions & 0 deletions scheme/sev/cbor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2024 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

package sev

import cbor "github.com/fxamacker/cbor/v2"

var (
dm, dmError = initCBORDecMode()
)

func initCBORDecMode() (dm cbor.DecMode, err error) {
decOpt := cbor.DecOptions{
IndefLength: cbor.IndefLengthForbidden,
}
return decOpt.DecMode()
}

func init() {
if dmError != nil {
panic(dmError)
}
}
260 changes: 259 additions & 1 deletion scheme/sev/evidence_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ import (
"encoding/json"
"net/url"
"strings"
"os"
"os/exec"
"fmt"
"path/filepath"
"bytes"

"github.com/google/uuid"

"github.com/veraison/services/handler"
"github.com/veraison/services/proto"
Expand Down Expand Up @@ -50,7 +57,20 @@ func (o EvidenceHandler) SynthKeysFromRefValue(
}

func (o EvidenceHandler) GetTrustAnchorID(token *proto.AttestationToken) (string, error) {
return "ID-Milan", nil
var sevToken SevToken

err := dm.Unmarshal(token.Data, &sevToken)
if err != nil {
return "", err
}

u := url.URL{
Scheme: SchemeName,
Host: "AMD",
Path: strings.Join([]string{"TA", sevToken.Evidence.Core.HwModel}, "/"),
}

return u.String(), nil
}

func (o EvidenceHandler) SynthKeysFromTrustAnchor(tenantID string, ta *handler.Endorsement) ([]string, error) {
Expand All @@ -75,23 +95,261 @@ func (o EvidenceHandler) ExtractClaims(
trustAnchor string,
) (*handler.ExtractedClaims, error) {
var extracted handler.ExtractedClaims
var claimsSet map[string]interface{}
var sevToken SevToken

err := dm.Unmarshal(token.Data, &sevToken)
if err != nil {
return nil, err
}

sevClaims, err := json.Marshal(sevToken)
if err != nil {
return nil, err
}

err = json.Unmarshal(sevClaims, &claimsSet)
if err != nil {
return nil, err
}

extracted.ClaimsSet = claimsSet
extracted.ReferenceID = sevToken.ReferenceId

return &extracted, nil
}

func createCertDirectory() (string, error) {
var err error
var dirName string
var retry int

for retry = 5; retry > 0; retry-- {
dirName = uuid.New().String()

_, err = os.Stat("certs" + dirName)
if err != nil {
break
}
}

if retry == 0 {
return "", fmt.Errorf("failed to get unique name for certificate directory")
}

dirName = "certs" + dirName

err = os.Mkdir(dirName, 0755)
if err != nil {
return "", err
}

return dirName, nil
}

func populateCertDirectory(dirName string, sevTa SevTrustAnchors, sevToken SevToken) error {
err := os.WriteFile(filepath.Join(".", dirName, "ark.cert"),
sevTa.ARK, 0644)
if err != nil {
return err
}

err = os.WriteFile(filepath.Join(".", dirName, "ask.cert"),
sevTa.ASK, 0644)
if err != nil {
return err
}

err = os.WriteFile(filepath.Join(".", dirName, "cek.cert"),
sevToken.Evidence.Keys.Cek, 0644)
if err != nil {
return err
}

err = os.WriteFile(filepath.Join(".", dirName, "oca.cert"),
sevToken.Evidence.Keys.Oca, 0644)
if err != nil {
return err
}

err = os.WriteFile(filepath.Join(".", dirName, "pek.cert"),
sevToken.Evidence.Keys.Pek, 0644)
if err != nil {
return err
}

err = os.WriteFile(filepath.Join(".", dirName, "pdh.cert"),
sevToken.Evidence.Keys.Pdh, 0644)
if err != nil {
return err
}

err = os.WriteFile(filepath.Join(".", dirName, "attestation_report.bin"),
sevToken.Evidence.Core.AttestationReport, 0644)
if err != nil {
return err
}

return nil
}

func validateCertChain(dirName string) error {
cmd := exec.Command("sevtool", "--ofolder", dirName, "--validate_cert_chain")

out, err := cmd.CombinedOutput()
if err != nil {
return err
}

output := string(out)

if strings.Contains(output, "Command Unsuccessful:") {
return fmt.Errorf("Certificate chain validation failed")
}

return nil
}

func validateAttestationReport(dirName string) error {
cmd := exec.Command("sevtool", "--ofolder", dirName, "--validate_attestation")

out, err := cmd.CombinedOutput()
if err != nil {
return err
}

output := string(out)

if strings.Contains(output, "Command Unsuccessful:") {
return fmt.Errorf("Attestation Report validation failed")
}
return nil
}

func (o EvidenceHandler) ValidateEvidenceIntegrity(
token *proto.AttestationToken,
trustAnchor string,
endorsementsStrings []string,
) error {
var taEndorsement handler.Endorsement
var sevTa SevTrustAnchors
var sevToken SevToken
var err error
var dirName string = ""

err = dm.Unmarshal(token.Data, &sevToken)
if err != nil {
return err
}

err = json.Unmarshal([]byte(trustAnchor), &taEndorsement)
if err != nil {
goto exit
}

err = json.Unmarshal([]byte(taEndorsement.Attributes), &sevTa)
if err != nil {
goto exit
}

dirName, err = createCertDirectory()
if err != nil {
goto exit
}

err = populateCertDirectory(dirName, sevTa, sevToken)
if err != nil {
goto exit
}

err = validateCertChain(dirName)
if err != nil {
goto exit
}

err = validateAttestationReport(dirName)
if err != nil {
goto exit
}

exit:
if dirName != "" {
os.RemoveAll(dirName)
}

if err != nil {
return handler.BadEvidence(err)
}

return nil
}

func (o EvidenceHandler) AppraiseEvidence(
ec *proto.EvidenceContext,
endorsementsStrings []string,
) (*ear.AttestationResult, error) {
var refValEndorsement handler.Endorsement
var refVal SevReferenceValues
var sevToken SevToken

result := handler.CreateAttestationResult(SchemeName)

for i, e := range endorsementsStrings {
var endorsement handler.Endorsement

if err := json.Unmarshal([]byte(e), &endorsement); err != nil {
return nil, fmt.Errorf("could not decode endorsement at index %d: %w", i, err)
}

if endorsement.Type == handler.EndorsementType_REFERENCE_VALUE {
refValEndorsement = endorsement
break
}
}

if refValEndorsement.Type != handler.EndorsementType_REFERENCE_VALUE {
return nil, fmt.Errorf("reference values unavailable")
}

err := json.Unmarshal([]byte(refValEndorsement.Attributes), &refVal)
if err != nil {
return nil, err
}

tokenJson, err := json.Marshal(ec.Evidence.AsMap())
if err != nil {
return nil, err
}

err = json.Unmarshal([]byte(tokenJson), &sevToken)
if err != nil {
return nil, err
}

expectedLD := refVal.LaunchDigest
claimedLD := sevToken.Evidence.Core.AttestationReport[0x10:0x30]

evidence := ec.Evidence.AsMap()

appraisal := result.Submods[SchemeName]

if bytes.Equal(expectedLD, claimedLD) {
appraisal.TrustVector.Hardware = ear.GenuineHardwareClaim
appraisal.TrustVector.InstanceIdentity = ear.TrustworthyInstanceClaim
appraisal.TrustVector.RuntimeOpaque = ear.ApprovedRuntimeClaim
appraisal.TrustVector.StorageOpaque = ear.HwKeysEncryptedSecretsClaim
appraisal.TrustVector.Executables = ear.ApprovedRuntimeClaim
} else {
appraisal.TrustVector.Hardware = ear.UnsafeHardwareClaim
appraisal.TrustVector.InstanceIdentity = ear.UntrustworthyInstanceClaim
appraisal.TrustVector.RuntimeOpaque = ear.VisibleMemoryRuntimeClaim
appraisal.TrustVector.StorageOpaque = ear.UnencryptedSecretsClaim
appraisal.TrustVector.Executables = ear.UnrecognizedRuntimeClaim
}

appraisal.UpdateStatusFromTrustVector()

appraisal.VeraisonAnnotatedEvidence = &evidence

return result, nil
}
Loading

0 comments on commit 6110565

Please sign in to comment.