-
Notifications
You must be signed in to change notification settings - Fork 32
Add SEVSNP plugin for Veraison server #307
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
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 |
1106e48 to
94456b3
Compare
|
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" |
There was a problem hiding this comment.
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.
|
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! |
|
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. |
Signed-off-by: Jagannathan Raman <[email protected]>
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]>
94456b3 to
55d86bd
Compare
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]>
55d86bd to
54d5bd8
Compare
| 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) | ||
| } |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, thanks
| if len(extractedCorim.Tags) > 1 { | ||
| return nil, errors.New("too many tags") | ||
| } |
There was a problem hiding this comment.
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{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| var claimsSet map[string]interface{} | |
| var claimsSet map[string]any |
| } | ||
|
|
||
| refValCorim := corim.UnsignedCorim{} | ||
| refValCorim.SetProfile("http://amd.com/2024/snp-corim-profile") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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) |
There was a problem hiding this comment.
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") |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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") |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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 _.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
thomas-fossati
left a comment
There was a problem hiding this 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) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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.
| // 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. |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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. :)
| const ( | ||
| SchemeName = "SEVSNP" | ||
| EndorsementMediaTypeRV = `application/corim-unsigned+cbor; profile="tag:amd.com,2024:snp-corim-profile"` | ||
| // ToDo: check media type for AMD ARK |
There was a problem hiding this comment.
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,...
There was a problem hiding this comment.
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"` |
There was a problem hiding this comment.
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..?
There was a problem hiding this comment.
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.
yogeshbdeshpande
left a comment
There was a problem hiding this 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!
Co-authored-by: Yogesh Deshpande <[email protected]>
Co-authored-by: Yogesh Deshpande <[email protected]>
Co-authored-by: Yogesh Deshpande <[email protected]>
Co-authored-by: Yogesh Deshpande <[email protected]>
Thank you for reviewing the PR, @yogeshbdeshpande ! :) I have a newer version of this; I'll refresh this PR shortly with it. |
|
Closing this, please refer to PR #333. |

This PR implements the SEVSNP scheme for Veraison.