diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4cd4941..863d6de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,15 +19,15 @@ on: push: tags: - v* - branches: - - main + branches: [main] pull_request: + branches: [main] jobs: build: strategy: matrix: - go-version: [1.19.x, 1.20.x] + go-version: [1.21.x, 1.22.x] os: [macos-latest, ubuntu-latest] name: Build/Test (${{ matrix.os}}, Go ${{ matrix.go-version }}) @@ -61,7 +61,7 @@ jobs: lint: strategy: matrix: - go-version: [1.19.x] + go-version: [1.21.x] os: [ubuntu-latest] name: Lint ${{ matrix.dir }} (${{ matrix.os }}, Go ${{ matrix.go-version }}) @@ -93,7 +93,7 @@ jobs: lintc: strategy: matrix: - go-version: [1.19.x] + go-version: [1.21.x] os: [ubuntu-latest] name: Lint CGO (${{ matrix.os}}, Go ${{ matrix.go-version }}) diff --git a/abi/abi.go b/abi/abi.go index f8c1cba..30f6c2c 100644 --- a/abi/abi.go +++ b/abi/abi.go @@ -73,7 +73,7 @@ const ( policyDebugBit = 19 policySingleSocketBit = 20 - maxPlatformInfoBit = 1 + maxPlatformInfoBit = 5 signatureOffset = 0x2A0 ecdsaRSsize = 72 // From the ECDSA-P384-SHA384 format in SEV SNP API specification. @@ -132,10 +132,14 @@ const ( // ReportVersion2 is set by the SNP API specification // https://web.archive.org/web/20231222054111if_/http://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/56860.pdf ReportVersion2 = 2 + // MinSupportedReportVersion is the lowest attestation report version that this library supports. + MinSupportedReportVersion = 2 // ReportVersion3 is set by the SNP API specification // https://www.amd.com/system/files/TechDocs/56860.pdf ReportVersion3 = 3 + // MaxSupportedReportVersion is the highest attestation report version that this library supports. + MaxSupportedReportVersion = 4 ) // CertTableHeaderEntry defines an entry of the beginning of an extended attestation report which @@ -186,6 +190,16 @@ type SnpPlatformInfo struct { // TSMEEnabled represents if the platform that produced the attestation report has transparent // secure memory encryption (TSME) enabled. TSMEEnabled bool + // ECCEnabled indicates that the platform is using error correcting codes for memory. + // Present when EccMemReporting feature bit is set. + ECCEnabled bool + // RAPLDisabled indicates that the RAPL is disabled. + RAPLDisabled bool + // CiphertextHidingDRAMEnabled indicates cypher text hiding is enabled for DRAM. + CiphertextHidingDRAMEnabled bool + // AliasCheckComplete indicates that alias detection has completed since the last system reset and there are no aliasing addresses. + // Mitigation for https://badram.eu/, see https://www.amd.com/en/resources/product-security/bulletin/amd-sb-3015.html#mitigation. + AliasCheckComplete bool } // SnpPolicy represents the bitmask guest policy that governs the VM's behavior from launch. @@ -244,8 +258,12 @@ func SnpPolicyToBytes(policy SnpPolicy) uint64 { // unrecognized bits. func ParseSnpPlatformInfo(platformInfo uint64) (SnpPlatformInfo, error) { result := SnpPlatformInfo{ - SMTEnabled: (platformInfo & (1 << 0)) != 0, - TSMEEnabled: (platformInfo & (1 << 1)) != 0, + SMTEnabled: (platformInfo & (1 << 0)) != 0, + TSMEEnabled: (platformInfo & (1 << 1)) != 0, + ECCEnabled: (platformInfo & (1 << 2)) != 0, + RAPLDisabled: (platformInfo & (1 << 3)) != 0, + CiphertextHidingDRAMEnabled: (platformInfo & (1 << 4)) != 0, + AliasCheckComplete: (platformInfo & (1 << 5)) != 0, } reserved := platformInfo & ^uint64((1<<(maxPlatformInfoBit+1))-1) if reserved != 0 { @@ -488,7 +506,7 @@ func ReportToProto(data []uint8) (*pb.Report, error) { r.ReportedTcb = binary.LittleEndian.Uint64(data[0x180:0x188]) mbzLo := 0x188 - if r.Version == ReportVersion3 { + if r.Version >= ReportVersion3 { mbzLo = 0x18B r.Cpuid1EaxFms = FmsToCpuid1Eax(data[0x188], data[0x189], data[0x18A]) } @@ -589,8 +607,8 @@ func ValidateReportFormat(r []byte) error { } version := binary.LittleEndian.Uint32(r[0x00:0x04]) - if version != ReportVersion2 && version != ReportVersion3 { - return fmt.Errorf("report version is: %d. Expected %d or %d", version, ReportVersion2, ReportVersion3) + if version < MinSupportedReportVersion || version > MaxSupportedReportVersion { + return fmt.Errorf("report version is: %d. Expected between %d and %d", version, MinSupportedReportVersion, MaxSupportedReportVersion) } policy := binary.LittleEndian.Uint64(r[0x08:0x10]) @@ -635,7 +653,7 @@ func ReportToAbiBytes(r *pb.Report) ([]byte, error) { binary.LittleEndian.PutUint64(data[0x180:0x188], r.ReportedTcb) // Add CPUID information if this is a version 3 report. - if r.Version == ReportVersion3 { + if r.Version >= ReportVersion3 { family, model, stepping := FmsFromCpuid1Eax(r.Cpuid1EaxFms) data[0x188] = family data[0x189] = model diff --git a/abi/abi_test.go b/abi/abi_test.go index e64239a..bc8d932 100644 --- a/abi/abi_test.go +++ b/abi/abi_test.go @@ -236,8 +236,35 @@ func TestSnpPlatformInfo(t *testing.T) { want: SnpPlatformInfo{TSMEEnabled: true, SMTEnabled: true}, }, { - input: 4, - wantErr: "unrecognized platform info bit(s): 0x4", + input: 21, + want: SnpPlatformInfo{ + SMTEnabled: true, + ECCEnabled: true, + CiphertextHidingDRAMEnabled: true, + }, + }, + { + input: 42, + want: SnpPlatformInfo{ + TSMEEnabled: true, + RAPLDisabled: true, + AliasCheckComplete: true, + }, + }, + { + input: 63, + want: SnpPlatformInfo{ + TSMEEnabled: true, + SMTEnabled: true, + ECCEnabled: true, + RAPLDisabled: true, + CiphertextHidingDRAMEnabled: true, + AliasCheckComplete: true, + }, + }, + { + input: 64, + wantErr: "unrecognized platform info bit(s): 0x40", }, } for _, tc := range tests { diff --git a/verify/verify.go b/verify/verify.go index df7b4a5..72a04f5 100644 --- a/verify/verify.go +++ b/verify/verify.go @@ -118,7 +118,7 @@ func validateAmdLocation(name pkix.Name, role string) error { if err := checkSingletonList(name.Organization, "organization", "organizations", "Advanced Micro Devices"); err != nil { return err } - return checkSingletonList(name.OrganizationalUnit, "organizational unit", "organizational uints", "Engineering") + return checkSingletonList(name.OrganizationalUnit, "organizational unit", "organizational units", "Engineering") } func validateRootX509(productLine string, x *x509.Certificate, version int, role, cn string) error { @@ -301,6 +301,9 @@ func GetCrlAndCheckRoot(r *trust.AMDRootCerts, opts *Options) (*x509.RevocationL getter = trust.DefaultHTTPSGetter() } if r.CRL != nil && opts.Now.Before(r.CRL.NextUpdate) { + if err := verifyCRL(r); err != nil { + return nil, err + } return r.CRL, nil } var errs error