Skip to content

Conversation

@jraman567
Copy link
Collaborator

@jraman567 jraman567 commented Mar 7, 2025

This PR implements the SEVSNP scheme for Veraison.

@jraman567
Copy link
Collaborator Author

I think the linters and integration tests are failing because I bumped go version to 1.24.1. ratsd needs it. Let me try to fix that

@jraman567 jraman567 force-pushed the sevsnp-plugin branch 5 times, most recently from 1106e48 to 94456b3 Compare March 7, 2025 21:48
@jraman567
Copy link
Collaborator Author

golangci-lint version 1.64.2 introduces support for golang 1.24. Bumping up its version fixes the linters CI error.

"github.com/google/go-sev-guest/proto/sevsnp"
"github.com/google/go-sev-guest/verify"
"github.com/google/go-sev-guest/verify/trust"
sevsnpParser "github.com/jraman567/go-gen-ref/cmd/sevsnp"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to merge github.com/jraman567/go-gen-ref with github.com/veraison/gen-corim. It's in my pipeline but has the overhead of refactoring gen-corim.

@yogeshbdeshpande
Copy link
Collaborator

yogeshbdeshpande commented Mar 11, 2025

Thank you for the great work:

I request you add the README.md similar to, here and also add a link to any profile documentation you may have for the reader of this profile!

@jraman567
Copy link
Collaborator Author

jraman567 commented Mar 26, 2025

I have addressed the comments in this PR so far. I'm working on addressing Dionna's latest changes to SEV-SNP profile: deeglaze/draft-deeglaze-amd-sev-snp-corim-profile@150696c

I'll send a new rev out shortly.

define SEV-SNP scheme for Veraison. Switch to CoRIM version
v1.1.3-0.20250307044607-0bbdd6c78526

Signed-off-by: Jagannathan Raman <[email protected]>
store the trust anchors and reference values in the CoMID's
"Attest Key Triple" and "Reference Value Triple" formats.

Signed-off-by: Jagannathan Raman <[email protected]>
accept CoRIM endorsements, reference values & trust anchors,
and save them in the database.

Signed-off-by: Jagannathan Raman <[email protected]>
implement parts of the store handler that synthesize
keys from trust anchors and reference values.

Signed-off-by: Jagannathan Raman <[email protected]>
Implement an evidence handler to extract claims from the evidence token
and store them in an internal representation format ( CoRIM for SEV-SNP).

Additionally, implement the GetLevel interface for HCLogger, which was
introduced with v1.5.0.

Signed-off-by: Jagannathan Raman <[email protected]>
Update the store handler to get Trust Anchor and Reference Value
keys from evidence.

Add helper routines to parse the TSM report's auxblob to extract
AMD keys.

Signed-off-by: Jagannathan Raman <[email protected]>
Implement the ValidateEvidenceIntegrity routine of the EvidenceHandler interface.

Ensure the root key in auxblob matches the ARK in provisioned trust anchors.
Confirm the integrity of the certificate chain in the auxblob and the
validity of the signature in the evidence.

Signed-off-by: Jagannathan Raman <[email protected]>
Implement the AppraiseEvidence routine in the EvidenceHandler interface
to confirm the claims match with the evidence.

Signed-off-by: Jagannathan Raman <[email protected]>
@jraman567
Copy link
Collaborator Author

I'm working on addressing Dionna's latest changes to SEV-SNP profile: deeglaze/draft-deeglaze-amd-sev-snp-corim-profile@150696c

This is taking longer I thought, so I'm pushing my current version while I work on Dionna's latest update to the SEV-SNP profile.

Add unit tests for endorsement, evidence and storage handlers

Signed-off-by: Jagannathan Raman <[email protected]>
Add README document for SEVSNP scheme

Signed-off-by: Jagannathan Raman <[email protected]>
Comment on lines +84 to +104
func getKey(auxblob []byte, guid []byte) ([]byte, error) {
for i := 0; i < len(auxblob); i += 24 {
var entry certTableEntry
b := auxblob[i : i+24]
buf := bytes.NewReader(b)
err := binary.Read(buf, binary.LittleEndian, &entry)
if err != nil {
return nil, err
}

if entry.Guid[0] == 0x0 {
break
}

if bytes.Equal(guid, entry.Guid[:]) {
return auxblob[entry.Offset : entry.Offset+entry.Length], nil
}
}

return nil, fmt.Errorf("key not found: %v", guid)
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is implemented in go-sev-guest/abi, no?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GitHub says you posted this comment 3 weeks ago. For some reason, I didn't see this until now. Sorry about that.

Yes, go-sev-guest/abi has this. I'll use that instead of implementing my own.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GitHub says you posted this comment 3 weeks ago. For some reason, I didn't see this until now. Sorry about that.

GitHub says you posted this comment 3 weeks ago, but an email notification says you just added this comment. Weird.
ss1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I started the review 3 weeks ago and sent it today.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, thanks

Comment on lines +60 to +62
if len(extractedCorim.Tags) > 1 {
return nil, errors.New("too many tags")
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't a CoRIM have multiple CoMIDs? Seems like a strange restriction.

token *proto.AttestationToken,
_ []string,
) (map[string]interface{}, error) {
var claimsSet map[string]interface{}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var claimsSet map[string]interface{}
var claimsSet map[string]any

}

refValCorim := corim.UnsignedCorim{}
refValCorim.SetProfile("http://amd.com/2024/snp-corim-profile")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
refValCorim.SetProfile("http://amd.com/2024/snp-corim-profile")
refValCorim.SetProfile("tag:amd.com,2025:snp-corim-profile")

return err
}

ark, err := getARK(tsm.AuxBlob)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ARK and ASK certs may not be in the AuxBlob and should always be provided by the user as their trust anchor in order to not be tricked with a fake SEV platform. I do see you have compareTAs, so the current logic is safe. I know I do the same thing is go-sev-guest, but I just filed a bug against myself to remove this.

}

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Errorf without formatting is wasteful. Better to have a global var like ErrRefValUnavailable = errors.New("reference values unavailable") so a caller can compare for equality if needed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I'll add a global variable so a caller can compare for equality.

}

// compareMeasurements checks if two given comid.Measurement variables are the same.
func compareMeasurements(refM comid.Measurement, evM comid.Measurement) bool {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a generic function for the base spec's measurement-map. Shouldn't this be something we can import from a generic library for appraisal against a base CoRIM?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. It's not specific to SEV-SNP per se, it will benefit from being in a library. Let me do that change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As also discussed in one of the Veraison weeklies, while eventually this kind of comparison logic should be encapsulated in the CoRIM library, this version of the function is not generic enough to be ported.

// SVN comparison
if refM.Val.SVN != nil {
if evM.Val.SVN == nil {
log.Debugf("evidence doesn't have SVN")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an expected case when the host doesn't use an IDBLOCK_AUTH.

func (o EvidenceHandler) ValidateEvidenceIntegrity(
token *proto.AttestationToken,
trustAnchors []string,
endorsementsStrings []string,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are endorsements strings instead of CoMIDs for example? This is also not used, so should be _.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The IEvidenceHandler interface defines it that way.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.cbor files should be created with go generate from .diag files for understandability. Binary test files are write-once-read-never. See // go:generate documentation

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, got it. That makes sense. I'll give //go:generate directive a shot for creating .cbor files.

@jraman567 jraman567 self-assigned this Apr 1, 2025
Copy link
Contributor

@thomas-fossati thomas-fossati left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, LGTM.

(I’ve left a few non-blocking comments inline)

err = verify.SnpAttestation(&attestation, snpAttestationOptions())

if err != nil {
log.Errorf("failed to validate certificate chain: %+v\n", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a curiosity: why is the NL needed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove it.

}

// compareMeasurements checks if two given comid.Measurement variables are the same.
func compareMeasurements(refM comid.Measurement, evM comid.Measurement) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As also discussed in one of the Veraison weeklies, while eventually this kind of comparison logic should be encapsulated in the CoRIM library, this version of the function is not generic enough to be ported.


appraisal := result.Submods[SchemeName]

appraisal.TrustVector.InstanceIdentity = ear.NoClaim
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick (ignorant) question: Does a verified certificate contain information about the SEV-SNP instance?
If so, this should be populated accordingly (i.e., ear.TrustworthyInstanceClaim).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With SEV-SNP alone, we don't have evidence to verify the instance identity. We need evidence from attesters like TPM to establish instance identity.

Comment on lines +391 to +393
// REPORT_ID is ephemeral, so we can't use it for verification.
// REPORT_DATA is client-supplied , which we aren't using for
// verification in this scheme.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be linked to the verification session nonce?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're correct, it should be linked to a nonce.

When verifying as a relying party, this should be the session nonce. Whereas, when verifying as an attester, it should could be any nonce.

The RATSd token specifies a nonce in the outer envelope, which acts a binding between multiple evidence in a composite evidence scenario. I'll ensure that this matches the nonce specified in the envelope.

Thank you, I appreciate the review. :)

@jraman567 jraman567 closed this Jun 25, 2025
@jraman567 jraman567 deleted the sevsnp-plugin branch June 25, 2025 19:44
@jraman567 jraman567 restored the sevsnp-plugin branch July 8, 2025 13:48
@jraman567 jraman567 reopened this Jul 8, 2025
const (
SchemeName = "SEVSNP"
EndorsementMediaTypeRV = `application/corim-unsigned+cbor; profile="tag:amd.com,2024:snp-corim-profile"`
// ToDo: check media type for AMD ARK
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is Line 8 still a TO DO, if so please track it using github issue, else please Delete this,...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK

SchemeName = "SEVSNP"
EndorsementMediaTypeRV = `application/corim-unsigned+cbor; profile="tag:amd.com,2024:snp-corim-profile"`
// ToDo: check media type for AMD ARK
EndorsementMediaTypeTA = `application/corim-unsigned+cbor; profile="https://amd.com/ark"`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for Line 9: MediaType Usage different for the profile, as compared to one on Line 7..?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it better to use the same media type for both Trust Anchors and Reference Values?

The SEV-SNP profile defined the media type for Reference Values, but I couldn't find a media type for Trust Anchors. The TA is an AMD Root Key, so I'm using the base CoRIM format for it.

In summary, the TA is using the base CoRIM format, and RV is using the format specified in the SEV-SNP profile.

Copy link
Collaborator

@yogeshbdeshpande yogeshbdeshpande left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some minor .nits to look at!

jraman567 and others added 4 commits July 9, 2025 07:35
Co-authored-by: Yogesh Deshpande <[email protected]>
Co-authored-by: Yogesh Deshpande <[email protected]>
Co-authored-by: Yogesh Deshpande <[email protected]>
@jraman567
Copy link
Collaborator Author

some minor .nits to look at!

Thank you for reviewing the PR, @yogeshbdeshpande ! :) I have a newer version of this; I'll refresh this PR shortly with it.

@jraman567
Copy link
Collaborator Author

Closing this, please refer to PR #333.

@jraman567 jraman567 closed this Sep 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants