Skip to content
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

extract optional and required SGX claims provided by Open Enclave #233

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions attestation/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,127 @@ type Report struct {
SignerID []byte // The signer ID for the enclave. For SGX enclaves, this is the MRSIGNER value.
ProductID []byte // The Product ID for the enclave. For SGX enclaves, this is the ISVPRODID value.
TCBStatus tcbstatus.Status // The status of the enclave's TCB level.
UEID []byte // The universal entity ID. For SGX enclaves, this is QE identity value with an additional first bit that indicates the OE UEID type.
SGXClaims *SGXClaims
}

// SGX specific claims provided by Open Enclave
type SGXClaims struct {
SGXRequired SGXRequired
SGXOptional *SGXOptional
}

// Claims that are in every Open Enclave generated report for SGX
type SGXRequired struct {
PfGpExinfoEnabled bool
ISVExtendedProductID []byte
IsMode64Bit bool
HasProvisionKey bool
HasEINITTokenKey bool
UsesKSS bool
ConfigID []byte
ConfigSVN []byte
ISVFamilyID []byte
CPUSVN []byte
}

// SQX quote verification collaterals and PCESVN claims from OE.
// Those are optional and might be empty
type SGXOptional struct {
TCBInfo []byte
TCBIssuerChain []byte
PCKCRL []byte
RootCACRL []byte
CRLIssuerChain []byte
QEIDInfo []byte
QEIDIssuerChain []byte
PCESVN []byte
}

func FromInternal(internal attestation.Report) Report {
var reportSGXClaims *SGXClaims
if internal.SGXClaims != nil {
reportSGXClaims = &SGXClaims{}
reportSGXClaims.SGXRequired = SGXRequired{
PfGpExinfoEnabled: internal.SGXClaims.SGXRequired.PfGpExinfoEnabled,
ISVExtendedProductID: internal.SGXClaims.SGXRequired.ISVExtendedProductID,
IsMode64Bit: internal.SGXClaims.SGXRequired.IsMode64Bit,
HasProvisionKey: internal.SGXClaims.SGXRequired.HasProvisionKey,
HasEINITTokenKey: internal.SGXClaims.SGXRequired.HasEINITTokenKey,
UsesKSS: internal.SGXClaims.SGXRequired.UsesKSS,
ConfigID: internal.SGXClaims.SGXRequired.ConfigID,
ConfigSVN: internal.SGXClaims.SGXRequired.ConfigSVN,
ISVFamilyID: internal.SGXClaims.SGXRequired.ISVFamilyID,
CPUSVN: internal.SGXClaims.SGXRequired.CPUSVN,
}
if internal.SGXClaims.SGXOptional != nil {
reportSGXClaims.SGXOptional = &SGXOptional{
TCBInfo: internal.SGXClaims.SGXOptional.TCBInfo,
TCBIssuerChain: internal.SGXClaims.SGXOptional.TCBIssuerChain,
PCKCRL: internal.SGXClaims.SGXOptional.PCKCRL,
RootCACRL: internal.SGXClaims.SGXOptional.RootCACRL,
CRLIssuerChain: internal.SGXClaims.SGXOptional.CRLIssuerChain,
QEIDInfo: internal.SGXClaims.SGXOptional.QEIDInfo,
QEIDIssuerChain: internal.SGXClaims.SGXOptional.QEIDIssuerChain,
PCESVN: internal.SGXClaims.SGXOptional.PCESVN,
}
}
}

return Report{
Data: internal.Data,
SecurityVersion: internal.SecurityVersion,
Debug: internal.Debug,
UniqueID: internal.UniqueID,
SignerID: internal.SignerID,
ProductID: internal.ProductID,
TCBStatus: internal.TCBStatus,
UEID: internal.UEID,
SGXClaims: reportSGXClaims,
}
}

func (report Report) ToInternal() attestation.Report {
var reportSGXClaims *attestation.SGXClaims
if report.SGXClaims != nil {
reportSGXClaims = &attestation.SGXClaims{}
reportSGXClaims.SGXRequired = attestation.SGXRequired{
PfGpExinfoEnabled: report.SGXClaims.SGXRequired.PfGpExinfoEnabled,
ISVExtendedProductID: report.SGXClaims.SGXRequired.ISVExtendedProductID,
IsMode64Bit: report.SGXClaims.SGXRequired.IsMode64Bit,
HasProvisionKey: report.SGXClaims.SGXRequired.HasProvisionKey,
HasEINITTokenKey: report.SGXClaims.SGXRequired.HasEINITTokenKey,
UsesKSS: report.SGXClaims.SGXRequired.UsesKSS,
ConfigID: report.SGXClaims.SGXRequired.ConfigID,
ConfigSVN: report.SGXClaims.SGXRequired.ConfigSVN,
ISVFamilyID: report.SGXClaims.SGXRequired.ISVFamilyID,
CPUSVN: report.SGXClaims.SGXRequired.CPUSVN,
}
if report.SGXClaims.SGXOptional != nil {
reportSGXClaims.SGXOptional = &attestation.SGXOptional{
TCBInfo: report.SGXClaims.SGXOptional.TCBInfo,
TCBIssuerChain: report.SGXClaims.SGXOptional.TCBIssuerChain,
PCKCRL: report.SGXClaims.SGXOptional.PCKCRL,
RootCACRL: report.SGXClaims.SGXOptional.RootCACRL,
CRLIssuerChain: report.SGXClaims.SGXOptional.CRLIssuerChain,
QEIDInfo: report.SGXClaims.SGXOptional.QEIDInfo,
QEIDIssuerChain: report.SGXClaims.SGXOptional.QEIDIssuerChain,
PCESVN: report.SGXClaims.SGXOptional.PCESVN,
}
}
}

return attestation.Report{
Data: report.Data,
SecurityVersion: report.SecurityVersion,
Debug: report.Debug,
UniqueID: report.UniqueID,
SignerID: report.SignerID,
ProductID: report.ProductID,
TCBStatus: report.TCBStatus,
UEID: report.UEID,
SGXClaims: reportSGXClaims,
}
}

var (
Expand Down
4 changes: 2 additions & 2 deletions eclient/eclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
// The caller must verify the returned report's content.
func VerifyRemoteReport(reportBytes []byte) (attestation.Report, error) {
report, err := verifyRemoteReport(reportBytes)
return attestation.Report(report), err
return attestation.FromInternal(report), err
}

// CreateAttestationClientTLSConfig creates a tls.Config object that verifies a certificate with embedded report.
Expand All @@ -37,7 +37,7 @@ func CreateAttestationClientTLSConfig(verifyReport func(attestation.Report) erro
return internal.CreateAttestationClientTLSConfig(
verifyRemoteReport,
appliedOpts,
func(rep internal.Report) error { return verifyReport(attestation.Report(rep)) },
func(rep internal.Report) error { return verifyReport(attestation.FromInternal(rep)) },
)
}

Expand Down
4 changes: 2 additions & 2 deletions enclave/enclave.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ func CreateAttestationClientTLSConfig(verifyReport func(attestation.Report) erro
return internal.CreateAttestationClientTLSConfig(
func(reportBytes []byte) (internal.Report, error) {
report, err := VerifyRemoteReport(reportBytes)
return internal.Report(report), err
return report.ToInternal(), err
},
appliedOpts,
func(rep internal.Report) error { return verifyReport(attestation.Report(rep)) },
func(rep internal.Report) error { return verifyReport(attestation.FromInternal(rep)) },
)
}

Expand Down
11 changes: 2 additions & 9 deletions enclave/ert.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,8 @@ func VerifyRemoteReport(reportBytes []byte) (attestation.Report, error) {
if err != nil {
return attestation.Report{}, err
}
return attestation.Report{
Data: report.Data,
SecurityVersion: report.SecurityVersion,
Debug: report.Debug,
UniqueID: report.UniqueID,
SignerID: report.SignerID,
ProductID: report.ProductID,
TCBStatus: report.TCBStatus,
}, verifyErr

return attestation.FromInternal(report), verifyErr
}

// GetLocalReport gets a report signed by the enclave platform for use in local attestation.
Expand Down
36 changes: 36 additions & 0 deletions internal/attestation/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,42 @@ type Report struct {
SignerID []byte // The signer ID for the enclave. For SGX enclaves, this is the MRSIGNER value.
ProductID []byte // The Product ID for the enclave. For SGX enclaves, this is the ISVPRODID value.
TCBStatus tcbstatus.Status // The status of the enclave's TCB level.
UEID []byte // The universal entity ID. For SGX enclaves, this is QE identity value with an additional first bit that indicates the OE UEID type.
HardwareModel []byte
SGXClaims *SGXClaims
}

// SGX specific claims provided by Open Enclave
type SGXClaims struct {
SGXRequired SGXRequired
SGXOptional *SGXOptional
}

// Claims that are in every Open Enclave generated report for SGX
type SGXRequired struct {
PfGpExinfoEnabled bool
ISVExtendedProductID []byte
IsMode64Bit bool
HasProvisionKey bool
HasEINITTokenKey bool
UsesKSS bool
ConfigID []byte
ConfigSVN []byte
ISVFamilyID []byte
CPUSVN []byte
}

// SQX quote verification collaterals and PCESVN claims from OE.
// Those are optional and might be empty
type SGXOptional struct {
TCBInfo []byte
TCBIssuerChain []byte
PCKCRL []byte
RootCACRL []byte
CRLIssuerChain []byte
QEIDInfo []byte
QEIDIssuerChain []byte
PCESVN []byte
}

// https://github.com/openenclave/openenclave/blob/master/include/openenclave/internal/report.h
Expand Down
90 changes: 90 additions & 0 deletions internal/attestation/claim.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
package attestation

// #include "claim.h"
// #include "sgx_evidence.h"
import "C"
import (
"errors"
"fmt"
"unsafe"

"github.com/edgelesssys/ego/attestation/tcbstatus"
Expand All @@ -23,6 +25,10 @@ func ParseClaims(claims uintptr, claimsLength uintptr) (Report, error) {
func parseClaims(claims []C.oe_claim_t) (Report, error) {
report := Report{TCBStatus: tcbstatus.Unknown}
hasAttributes := false
var reportSGX SGXClaims
var reportSGXOptional SGXOptional
var claimCountSGXrequired = 0
var claimCountSGXoptional = 0

for _, claim := range claims {
switch C.GoString(claim.name) {
Expand All @@ -45,12 +51,92 @@ func parseClaims(claims []C.oe_claim_t) (Report, error) {
report.TCBStatus = tcbstatus.Status(claimUint(claim))
case C.OE_CLAIM_SGX_REPORT_DATA:
report.Data = claimBytes(claim)
case C.OE_CLAIM_UEID:
// The UEID is prefixed with a type which is currently always OE_UEID_TYPE_RAND for SGX
claimUEID := claimBytes(claim)
if len(claimUEID) > 0 && claimUEID[0] != C.OE_UEID_TYPE_RAND {
return Report{}, errors.New("Expected UEID of type OE_UEID_TYPE_RAND")
}
report.UEID = claimUEID
// SGX Required claims
case C.OE_CLAIM_SGX_PF_GP_EXINFO_ENABLED:
reportSGX.SGXRequired.PfGpExinfoEnabled = claimBool(claim)
claimCountSGXrequired++
case C.OE_CLAIM_SGX_ISV_EXTENDED_PRODUCT_ID:
reportSGX.SGXRequired.ISVExtendedProductID = claimBytes(claim)
claimCountSGXrequired++
case C.OE_CLAIM_SGX_IS_MODE64BIT:
reportSGX.SGXRequired.IsMode64Bit = claimBool(claim)
claimCountSGXrequired++
case C.OE_CLAIM_SGX_HAS_PROVISION_KEY:
reportSGX.SGXRequired.HasProvisionKey = claimBool(claim)
claimCountSGXrequired++
case C.OE_CLAIM_SGX_HAS_EINITTOKEN_KEY:
reportSGX.SGXRequired.HasEINITTokenKey = claimBool(claim)
claimCountSGXrequired++
case C.OE_CLAIM_SGX_USES_KSS:
reportSGX.SGXRequired.UsesKSS = claimBool(claim)
claimCountSGXrequired++
case C.OE_CLAIM_SGX_CONFIG_ID:
reportSGX.SGXRequired.ConfigID = claimBytes(claim)
claimCountSGXrequired++
case C.OE_CLAIM_SGX_CONFIG_SVN:
reportSGX.SGXRequired.ConfigSVN = claimBytes(claim)
claimCountSGXrequired++
case C.OE_CLAIM_SGX_ISV_FAMILY_ID:
reportSGX.SGXRequired.ISVFamilyID = claimBytes(claim)
claimCountSGXrequired++
case C.OE_CLAIM_SGX_CPU_SVN:
reportSGX.SGXRequired.CPUSVN = claimBytes(claim)
claimCountSGXrequired++
//SGX optional claims
case C.OE_CLAIM_SGX_TCB_INFO:
reportSGXOptional.TCBInfo = claimBytes(claim)
claimCountSGXoptional++
case C.OE_CLAIM_SGX_TCB_ISSUER_CHAIN:
reportSGXOptional.TCBIssuerChain = claimBytes(claim)
claimCountSGXoptional++
case C.OE_CLAIM_SGX_PCK_CRL:
reportSGXOptional.PCKCRL = claimBytes(claim)
claimCountSGXoptional++
case C.OE_CLAIM_SGX_ROOT_CA_CRL:
reportSGXOptional.RootCACRL = claimBytes(claim)
claimCountSGXoptional++
case C.OE_CLAIM_SGX_CRL_ISSUER_CHAIN:
reportSGXOptional.CRLIssuerChain = claimBytes(claim)
claimCountSGXoptional++
case C.OE_CLAIM_SGX_QE_ID_INFO:
reportSGXOptional.QEIDInfo = claimBytes(claim)
claimCountSGXoptional++
case C.OE_CLAIM_SGX_QE_ID_ISSUER_CHAIN:
reportSGXOptional.QEIDIssuerChain = claimBytes(claim)
claimCountSGXoptional++
case C.OE_CLAIM_SGX_PCE_SVN:
reportSGXOptional.PCESVN = claimBytes(claim)
claimCountSGXoptional++
}

}
if claimCountSGXrequired > 0 && claimCountSGXrequired != C.OE_SGX_REQUIRED_CLAIMS_COUNT {
return Report{}, fmt.Errorf("some required SGX claims are missing. Only got: %d, expected: %d", claimCountSGXrequired, C.OE_SGX_REQUIRED_CLAIMS_COUNT)
}

if claimCountSGXoptional > C.OE_SGX_OPTIONAL_CLAIMS_COUNT {
return Report{}, fmt.Errorf("optional SGX claims are too many. Got: %d, expected maximum: %d", claimCountSGXoptional, C.OE_SGX_OPTIONAL_CLAIMS_COUNT)
}

if !hasAttributes {
return Report{}, errors.New("missing attributes in report claims")
}

if claimCountSGXoptional > 0 {
reportSGX.SGXOptional = &reportSGXOptional
}

if claimCountSGXrequired > 0 {
report.SGXClaims = &reportSGX
}

return report, nil
}

Expand All @@ -61,6 +147,10 @@ func claimUint(claim C.oe_claim_t) uint {
return uint(*(*C.uint32_t)(unsafe.Pointer(claim.value)))
}

func claimBool(claim C.oe_claim_t) bool {
return bool(*(*C._Bool)(unsafe.Pointer(claim.value)))
}

func claimBytes(claim C.oe_claim_t) []byte {
return C.GoBytes(unsafe.Pointer(claim.value), C.int(claim.value_size))
}
3 changes: 3 additions & 0 deletions internal/attestation/claim.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ typedef struct _oe_claim
#define OE_CLAIM_PRODUCT_ID "product_id"
#define OE_CLAIM_TCB_STATUS "tcb_status"
#define OE_CLAIM_SGX_REPORT_DATA "sgx_report_data"
#define OE_CLAIM_UEID "ueid"

#define OE_UEID_TYPE_RAND 0x01
41 changes: 41 additions & 0 deletions internal/attestation/sgx_evidence.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) Open Enclave SDK contributors.
// Licensed under the MIT License.

// Based on attestation/sgx/evidence.h

// SGX specific claims
// Required: SGX report body fields that every SQX Quote verification should
// output.
// 1 boolean flag indicated by "sgx_misc_select_t"
#define OE_CLAIM_SGX_PF_GP_EXINFO_ENABLED "sgx_pf_gp_exit_info_enabled"
#define OE_CLAIM_SGX_ISV_EXTENDED_PRODUCT_ID "sgx_isv_extended_product_id"
// 4 boolean flags indicated by "sgx_attributes_t"
#define OE_CLAIM_SGX_IS_MODE64BIT "sgx_is_mode64bit"
#define OE_CLAIM_SGX_HAS_PROVISION_KEY "sgx_has_provision_key"
#define OE_CLAIM_SGX_HAS_EINITTOKEN_KEY "sgx_has_einittoken_key"
#define OE_CLAIM_SGX_USES_KSS "sgx_uses_kss"
#define OE_CLAIM_SGX_CONFIG_ID "sgx_config_id"
#define OE_CLAIM_SGX_CONFIG_SVN "sgx_config_svn"
#define OE_CLAIM_SGX_ISV_FAMILY_ID "sgx_isv_family_id"
#define OE_CLAIM_SGX_CPU_SVN "sgx_cpu_svn"
#define OE_SGX_REQUIRED_CLAIMS_COUNT 10

/*
* Optional: SQX Quote data
*/
// SQX quote verification collaterals.
#define OE_CLAIM_SGX_TCB_INFO "sgx_tcb_info"
#define OE_CLAIM_SGX_TCB_ISSUER_CHAIN "sgx_tcb_issuer_chain"
#define OE_CLAIM_SGX_PCK_CRL "sgx_pck_crl"
#define OE_CLAIM_SGX_ROOT_CA_CRL "sgx_root_ca_crl"
#define OE_CLAIM_SGX_CRL_ISSUER_CHAIN "sgx_crl_issuer_chain"
#define OE_CLAIM_SGX_QE_ID_INFO "sgx_qe_id_info"
#define OE_CLAIM_SGX_QE_ID_ISSUER_CHAIN "sgx_qe_id_issuer_chain"
#define OE_SGX_OPTIONAL_CLAIMS_SGX_COLLATERALS_COUNT 7
// SGX PCESVN.
#define OE_CLAIM_SGX_PCE_SVN "sgx_pce_svn"
#define OE_SGX_OPTIONAL_CLAIMS_COUNT 8

// Additional SGX specific claim: for the report data embedded in the SGX quote.

#define OE_CLAIM_SGX_REPORT_DATA "sgx_report_data"