SGX lingo
2022-04-12 ยท 21 min read
- Understanding Intel SGX is challenging due to the sheer number of new concepts and names that you need to internalize. In my experience, it's a bit like wading through "acronym soup", desperately searching for familiar ground to find your footing before you can truly begin learning.
- To make this process easier for newcomers, I've written an extended glossary of SGX terminology, with extensive links and explanations.
- Most of the code links and samples are written in Rust.
- The entries are not listed in any particular order.
Quote #
A datastructure provided as proof to an external party that an application enclave is running on genuine Intel hardware at a given TCB version.
An application's identity Report, signed by an Attestation Key (AK) (usually the one provisioned in the Quoting Enclave (QE)).
Report (EREPORT) #
A hardware report generated by an enclave containing (1) the enclave's identity, (2) measurement info, and (3) a small amount of application data (64-bytes), called the ReportData
.
Reports are efficiently verifiable inside other enclaves on the same machine. When generated via the EREPORT
instruction, the Report
struct will contain a MAC created from a special Seal Key used for tagging reports. This allows us to cheaply verify reports without an expensive signature verification, since other enclaves can just rederive the report key and check the MAC tag, which is fast.
Otherwise for remote attestation:
Attestation Key (AK) #
The key used by the QE to sign application enclave REPORTs, producing Quotes.
This Quote certifies that an application enclave is running on genuine Intel SGX HW at a given TCB version.
The AK is created and owned by the owner of the remote attestation infrastructure (e.g., Azure or Intel) but is also certified by the Intel SGX rooted key (this key is rooted to the platform HW fuses), which proves the enclave is valid.
Architectural Enclaves #
Intel provides several Intel-signed enclaves necessary for running user application enclaves, verifying launch policies, producing remote attestation Quotes, and more.
A non-exhaustive list of Architectural Enclaves:
- Launch Enclave (LE)
- Quoting Enclave (QE)
- Provisioning Certification Enclave (PCE)
- Provisioning Enclave (PE)
- Platform Services Enclave (PSE)
To see the complete list of signed enclaves:
# Valid for Intel SGX v2.21 and Intel DCAP v1.18
$ cd $(mktemp -d)
$ curl https://download.01.org/intel-sgx/sgx-linux/2.21/prebuilt_ae_2.21.tar.gz | tar -xzv
$ curl https://download.01.org/intel-sgx/sgx-dcap/1.18/linux/prebuilt_dcap_1.18.tar.gz | tar -xzv
$ cd psw/ae/data/prebuilt/
$ exa -1
le_prod_css.bin
libsgx_id_enclave.signed.so
libsgx_le.signed.so
libsgx_pce.signed.so
libsgx_pve.signed.so
libsgx_qe.signed.so
libsgx_qe3.signed.so
libsgx_qve.signed.so
libsgx_tdqe.signed.so
Launch Enclave (LE) #
The Launch Enclave generates a Launch Token, which is needed to run another enclave. The LE itself is special in that it doesn't need a launch token, but its signing key id, [[#Signer Measurement MRSIGNER|MRSIGNER
]], must match the CPU's configuration.
The API for generating a new Launch Token takes (1) a SIGSTRUCT and (2) an Enclave Attributes bitflag and returns a new launch token.
See: Fortanix EDP EinittokenProvider
trait
See: Fortanix EDP AesmService
impl
Enclave file: libsgx_le.signed.so
.
enclave {
include "arch.h"
include "sgx_report.h"
from "sgx_tstdc.edl" import *;
trusted {
public int le_get_launch_token_wrapper(
[in] const sgx_measurement_t *mrenclave,
[in] const sgx_measurement_t *mrsigner,
[in] const sgx_attributes_t *se_attributes,
[out] token_t * lictoken
);
public uint32_t le_init_white_list_wrapper(
[size = wl_cert_chain_size, in] const uint8_t *wl_cert_chain,
uint32_t wl_cert_chain_size
);
};
};
Quoting Enclave (QE) #
An Intel-provided, signed enclave trusted by the attestation infrastructure to sign and issue Quotes or attestations about other enclaves on the same platform.
The QE will include a hash of the AK in its QE.REPORT.ReportData
.
The QE will also include the PCE's certification of itself (the QE) in its REPORT.
Enclave file: libsgx_qe.signed.so
.
enclave {
include "sgx_report.h"
include "sgx_quote.h"
from "sgx_tstdc.edl" import *;
trusted {
public uint32_t verify_blob(
[size = blob_size, in, out] uint8_t *p_blob,
uint32_t blob_size,
[out] uint8_t *p_is_resealed,
[out] sgx_cpu_svn_t *p_cpusvn
);
public uint32_t get_quote(
[size = blob_size, in, out] uint8_t *p_blob,
uint32_t blob_size,
[in] const sgx_report_t *p_report,
sgx_quote_sign_type_t quote_type,
[in] const sgx_spid_t *p_spid,
[in] const sgx_quote_nonce_t *p_nonce,
// SigRL is relatively big, so we cannot copy it into EPC
[user_check] const uint8_t *p_sig_rl,
uint32_t sig_rl_size,
[out] sgx_report_t *qe_report,
// Quote is also big, we should output it in piece meal.
[user_check] uint8_t *p_quote,
uint32_t quote_size, sgx_isv_svn_t pce_isvnsvn
);
};
};
Provisioning Certification Enclave (PCE) #
An Intel-provided enclave that acts as a Certificate Authority (CA) for local Quoting Enclaves running on the same platform. It endorses the Attestation Keys provisioned to each Quoting Enclave with its Provisioning Certification Key (PCK).
The PCE's PCK is itself endorsed by the Intel Root CA.
The QEs can request the PCE to sign their REPORTs with the PCE's PCK. These signed REPORTs contain ReportData proving that attestation keys or provisioning protocol messages are generated on genuine HW.
Only the PCE can produce the PCK private keys.
The PCE provides an API for getting the PCK Cert-ID (EncPPID+TCB+PCE-ID) used by a verifier to lookup the matching PCK Cert via the remote IAS API.
The PCE also provides an API for signing another enclave (e.g., the QE) REPORT using the PCK.
Enclave file: libsgx_pce.signed.so
.
enclave{
include "pce_cert.h"
include "sgx_report.h"
from "sgx_tstdc.edl" import *;
trusted {
public uint32_t get_pc_info(
[in]const sgx_report_t *report,
[in, size=key_size]const uint8_t *public_key, uint32_t key_size,
uint8_t crypto_suite,
[out, size=encrypted_ppid_buf_size]uint8_t *encrypted_ppid, uint32_t encrypted_ppid_buf_size,
[out]uint32_t *encrypted_ppid_out_size,
[out]pce_info_t *pce_info,
[out] uint8_t *signature_scheme
);
public uint32_t certify_enclave(
[in]const psvn_t *cert_psvn,
[in]const sgx_report_t *report,
[out, size=signature_buf_size]uint8_t *signature, uint32_t signature_buf_size,
[out]uint32_t *signature_out_size
);
public uint32_t get_pc_info_without_ppid(
[out]pce_info_t *pce_info
);
};
};
Provisioning Enclave (PE or PvE) #
If using the anonymous EPID Attestation Key (AK) Algorithm, then a special Provisioning Enclave is used to interface with the Intel EPID provisioning servers to provision the enclave's AK.
Enclave file: libsgx_pve.signed.so
.
See: Enclave API
Platform Services Enclave (PSE) #
Intel also provides a set of additional platform enclaves which offer useful services like monotonic counters and trusted time to other enclaves on the machine.
The PSE talks to the local Intel Management Engine (IME) over a secure channel. Inside the IME is a small 32-bit Intel core running completely isolated from the general purpose CPU cores.
Trusted Time Service #
The PSE exposes a Protected Real-time Clock (PRTC), which measures relative elapsed seconds since the initial clock measurement. This value is not a calendar or wall-clock time. To establish a trusted clock base time, you'll need to query some remote semi-trusted servers over a secure channel.
See: Intel - Trusted Time and Monotonic Counters with SGX Platform Services Enclave
See: 2019 - Applications and Challenges in Securing Time
TDX Quoting Enclave (TDQE) #
Enclave File: libsqx_tdqe.signed.so
.
enclave {
include "sgx_report.h"
include "sgx_quote.h"
include "sgx_report2.h"
include "user_types.h"
include "ecdsa_quote.h"
trusted {
public uint32_t get_pce_encrypt_key(
[in]const sgx_target_info_t *pce_target_info,
[out] sgx_report_t *p_qe_report,
uint8_t crypto_suite,
uint16_t cert_key_type,
uint32_t key_size,
[out, size=key_size] uint8_t *p_public_key
);
public uint32_t gen_att_key(
[size = blob_size, in, out] uint8_t *p_blob,
uint32_t blob_size,
[in]const sgx_target_info_t *p_pce_target_info,
[out] sgx_report_t *qe_report,
[in, size = authentication_data_size] uint8_t* p_authentication_data,
uint32_t authentication_data_size
);
public uint32_t verify_blob(
[size = blob_size, in, out] uint8_t *p_blob,
uint32_t blob_size,
[out] uint8_t *p_is_resealed,
[out] sgx_report_body_t *p_report,
uint32_t pub_key_id_size,
[out, size=pub_key_id_size] uint8_t *p_pub_key_id
);
public uint32_t store_cert_data(
[in]ref_plaintext_ecdsa_data_sdk_t *p_plaintext_data,
sgx_ql_cert_key_type_t certification_key_type,
[in, size = encrypted_ppid_size] uint8_t* p_encrypted_ppid,
uint32_t encrypted_ppid_size,
[in, out, size = blob_size] uint8_t *p_blob,
uint32_t blob_size
);
public uint32_t gen_quote(
[size = blob_size, in, out] uint8_t *p_blob,
uint32_t blob_size,
[in] const sgx_report2_t *p_app_report,
[in] const sgx_quote_nonce_t *p_nonce,
[in] const sgx_target_info_t *p_app_enclave_target_info,
[out] sgx_report_t *p_qe_report,
[size = quote_size, in, out] uint8_t *p_quote,
uint32_t quote_size,
[in, size = cert_data_size] const uint8_t * p_cert_data,
uint32_t cert_data_size
);
};
};
Architectural Enclave Service Manager (AESM) #
Instead of interacting with the local Architectural Enclaves directly, local user applications and libraries typically interface with a local Intel-provided service called the Architectural Enclave Service Manager. The AESM service typically runs as a local daemon and provides a socket for applications to interface with.
An AESM client allows user applications to easily obtain Launch Tokens from the LE, needed for running enclaves, and turn Attestation Reports into Quotes via the QE.
Check out the Protobuf definitions and AesmClient API.
Provisioning Certification Key (PCK) #
A signing key available to the PCE for signing QE REPORTs.
This key is unique to the specific processor instance, HW TCB, and PCE version.
See: Fortanix EDP - dcap-retrieve-pckid via AESM
PCK Cert #
A long-lived x.509 CA cert signed and distributed by Intel for every SGX platform.
The Intel-provided Provisioning Certification Enclave (PCE) uses this cert to endorse Attestation Keys provisioned to any Quoting Enclaves.
This cert is used by Quote verifiers to check that the QE is valid and running and running on a specific PSVN.
The PCK Cert is endorsed by the Intel SGX Root CA via an intermediate Intel SGX PCK Platform CA.
The PCK Cert has some extra cert extension fields, described in more detail in the Intel PCK Cert Spec. These mostly appear to be metadata, like the PPID, TCB levels, CPUSVN, CPU SKU, and a list of supported extensions.
Platform Provisioning ID (PPID) #
The provisioning ID for a processor package or platform instance. PPID is not TCB dependent.
Security Version Number (SVN) #
A monotonically increasing version number that corresponds with major security releases of TCB software.
Note that new, non-security-critical software versions can be released without touching the SVN.
Part of the verification process is just checking that the remote enclave is running a recent TCB software version without any unpatched vulnerabilities.
Platform Security Version Number (PSVN, CPUSVN) #
A list of SVNs for each component in the SGX TCB, including the PCE SVN.
Think of a PSVN as pinning each component in the TCB to a specific (security-critical) version.
Independent Software Vendor (ISV) #
ISVs develop enclave applications.
Intel Attestation Services (IAS) #
See: Intel Attestation Services - API Specification v6.1
See: Intel Developer Zone Registration
See: Oasis IAS proxy backend to the Intel API
See: []
Service Provider ID (SPID) #
The id of the credentials needed for a Service Provider to talk with with the Intel Attestation Services (IAS).
Service Providers must register with Intel in order to acquire these credentials.
Enclave Page Cache (EPC) #
A region of memory on the platform allocated to enclave code and data.
Provisioning TCB #
The Intel SGX Trusted Computing Base (TCB). This TCB includes the platform HW TCB and PCE SVN.
PCE-ID #
The PCE SVN (?) used to generate the PPID and PCK signing key.
Data Center Attestation Primitives (DCAP) #
A library for generating and verifying attestation evidence.
The Intel-provided library is called Intel SGX DCAP. There's also a version by Microsoft called Azure DCAP, which (AFAICT) uses an Azure-run cache over the Intel API services.
Launch Token #
TODO
Flexible Launch Control (FLC) #
An SGX feature only available on more recent platforms that allows an arbitrary LE to generate launch tokens.
The default launch policy still uses an SGX client whitelist; however, FLC allows a platform owner to change the default LE MRSIGNER
to different value.
Enclave Load Policy #
The remote service providing enclave services, linked with the DCAP library, can choose whether system enclaves like the QE and PCE are loaded on-demand (as application enclaves request their services) or loaded persistently (load once and then keep them loaded until the application shuts down).
The two options trade off between greater EPC usage (Persistent) and greater remote attestation latency + overhead (Ephemeral).
Owner Epoch #
The Owner Epoch is a 128-bit value used in the Seal Key KDF.
Since the Owner Epoch is used in the Seal Key KDF, any change to this value would DoS our HW from unsealing any protected data from a previous Owner Epoch value. A malicious cloud operator (Azure) could DoS attack us by changing the Owner Epoch, forcing us to re-provision all enclave secrets.
More likely, a vulnerability, TCB violation, or operator error could lead to an unintended Owner Epoch rotation.
To help with recovery, applications should record the current Owner Epoch in case something goes wrong. If nobody remembers the Owner Epoch, we can never restore our Seal Keys.
Apparently it's also possible virtualize the Owner Epoch if running inside a hypervisor? (TODO: confirm).
Ref: 2018 - Some notes on SGX OwnerEpoch and Sealing
Quoting Enclave ID (QE-ID) #
A pseudo-platform ID that isn't associated with a particular SVN. Instead, the ID is dependent on (1) the QE's MRSIGNER
, (2) its Seal Key, which depends
Quoting Enclave QuoteInfo #
QuoteInfo
is the quoting enclave's information needed for clients to perform remote attestation. The target_info
is a serialized TargetInfo.
pub struct QuoteInfo {
target_info: Vec<u8>, // serialized Targetinfo
pub_key_id: Vec<u8>,
}
TargetInfo #
Targetinfo
is a measurement of the QE.
#[repr(C, align(512))]
pub struct Targetinfo {
pub measurement: [u8; 32],
pub attributes: Attributes,
pub _reserved1: [u8; 4],
pub miscselect: Miscselect,
pub _reserved2: [u8; 456],
}
Enclave Measurement (MRENCLAVE) #
In order to for a client to feel secure provisioning their secrets into an enclave, they need to verify that the enclave is running trusted software. An enclave measurement effectively summarizes the initial state of the trusted software running in the enclave.
Intel SGX constructs this measurement when the enclave is built and initialized. During enclave init, it records a log of all important build activities, including:
- Content: code, data, stack, heap
- Location of each page within the enclave
- Security flags used
The measurement is actually not the full log, but a 256-bit hash digest of the log. This measurement is stored as MRENCLAVE
inside the enclave's software TCB and is accessible inside the enclave via a syscall.
Clients can then compare the observed MRENCLAVE
with a trusted, expected MRENCLAVE
value to guarantee that the enclave is running the expected software.
For systems using the Fortanix SGX Stream format (SGXS) to describe an enclave, the SHA256 hash of the .sgxs
bytes is exactly the enclave's MRENCLAVE
*. Very convenient!
*Unless you use the Extended SGXS format, which allows unmeasured sections. In that case, you need to be a little more careful about how you hash the format and ignore the unmeasured sections.
Why do we need to verify the software inside the enclave? #
If the client forgets to verify the actual software running inside the enclave, there's a simple attack to exfiltrate the client's secrets! All we need to do is run some malicious code in the enclave, which just prints the client's secrets after provisioning. Boom, client secrets leaked.
Keep in mind the enclave could be 100% genuine Intel hardware, but unless the client verifies the actual software inside the enclave, they should absolutely not provision their secrets.
Fortanix SGX Stream format (SGXS) #
The SGX stream (SGXS) format is the most basic description of an enclave, and when combined with a signature and initialization token file contains all the information needed by an Operating System to load the enclave.
The format consists entirely of all data that would be hashed to produce the enclave measurement [[#Enclave Measurement MRENCLAVE|MRENCLAVE
]].
See: Fortanix EDP - SGX Stream format (SGXS)
.
See: Fortanix EDP - ftxsgx-elf2sgxs
for converting a standard ELF binary to SGXS.
See: Fortanix EDP - sgxs-sign
for signing SGXS with your RSA private key.
Signer Measurement (MRSIGNER) #
Each enclave is also signed by the client or the enclave author, depending on the exact trust model. The MRSIGNER
is just the enclave signer's pubkey hash.
The signer signs part of the SIGSTRUCT, which then includes the signature and signer pubkey inside.
Sealing keys can be derived from the signer measurement + ISV product id/svn, instead of the enclave measurement to allow easy upgrading across different versions of the same enclave.
Rust code for generating a signer and computing its measurement:
// Generating a 3072-bit RSA key + measurement for signing
// sigstructs. NOTE: the RSA exponent MUST be 3.
let e = openssl::bn::BigNum::from_u32(3)?;
let key = openssl::rsa::Rsa::generate_with_e(3072, &e)?;
// The signer measurement is the SHA-256 hash of the little-endian
// public key modulus.
// Openssl returns the modulus in big-endian, so we need to reverse
// the bytes to little-endian before hashing.
let mut modulus = key.n().to_vec();
modulus.reverse();
let mut modulus_buf = [0u8; 384];
modulus_buf[..modulus.len()].copy_from_slice(&modulus);
let signer_measurement = sha256::digest(&modulus_buf).as_slice();
Enclave Signature Struct (SIGSTRUCT) #
Each enclave has an associated SIGSTRUCT
, which contains (among other things):
- The MRENCLAVE, pinning the enclave initial state.
- The CPU SVN.
- The ISV
- The ISVPRODID
- The Enclave Attributes and Enclave Miscselect bit flags.
The enclave signer then signs a specific portion of the SIGSTRUCT
. This signature, along with the signer's full RSA-3072 pubkey, is then placed into the SIGSTRUCT
itself.
See the Fortanix EDP SIGSTRUCT definition.
struct Sigstruct {
header: [u8; 16],
vendor: u32,
date: u32,
header2: [u8; 16],
swdefined: u32,
_reserved1: [u8; 84],
modulus: [u8; 384],
exponent: u32,
signature: [u8; 384],
miscselect: Miscselect,
miscmask: u32,
_reserved2: [u8; 20],
attributes: Attributes,
attributemask: [u64; 2],
enclavehash: [u8; 32],
_reserved3: [u8; 32],
isvprodid: u16,
isvsvn: u16,
_reserved4: [u8; 12],
q1: [u8; 384],
q2: [u8; 384],
}
See: oasis-core/go/common/sgx/sigstruct.Verify
- (Binding) ensure that the
sigstruct.mrenclave
matches the actualmrenclave
that we're about to load.
Enclave Info #
struct EnclaveInfo {
// The enclave measurement
mrenclave: Vec<u8>,
// The signer measurement
mrsigner: Vec<u8>,
// The ISV Product ID
isvprodid: u32,
// The ISV SVN
isvsvn: u32,
}
Report TargetInfo (TARGETINFO) #
TargetInfo
is just the MRENCLAVE plus Attributes and Miscselect masks.
struct Targetinfo {
mrenclave: [u8; 32],
attributes: Attributes,
// padding
miscselect: Miscselect,
// padding
}
Enclave Init Token (EINITTOKEN) #
When launching an enclave, you need to pass a special token to the EINIT
instruction. This token is called the EINITTOKEN
and is generated by the Launch Enclave after it verifies the full Enclave Signature Struct SIGSTRUCT signature.
The SGX platform then verifies the contents of the token before it allows the enclave to initialize.
Why does Intel use this EINITTOKEN
thing rather than just passing the full SIGSTRUCT
each time we init? My guess is that it allows us to amortize the SIGSTRUCT
signature verification cost. The LE do the expensive signature verification once, produce a cheaply verifiable launch token, then use the launch token each time rather than the expensive SIGSTRUCT
.
Note that the token is only verifiable by other enclaves on the same machine; it just contains a MAC created with a privileged Intel-only Seal Key.
struct Einittoken {
valid: u32,
_reserved1: [u8; 44],
attributes: Attributes,
mrenclave: [u8; 32],
_reserved2: [u8; 32],
mrsigner: [u8; 32],
_reserved3: [u8; 32],
cpusvnle: [u8; 16],
isvprodidle: u16,
isvsvnle: u16,
_reserved4: [u8; 24],
maskedmiscselectle: Miscselect,
maskedattributesle: Attributes,
keyid: [u8; 32],
mac: [u8; 16],
}
Enclave Attributes #
struct Attributes {
flags: AttributesFlags,
xfrm: u64,
}
bitflags! {
struct AttributesFlags: u64 {
const INIT = 0b0000_0001;
const DEBUG = 0b0000_0010;
const MODE64BIT = 0b0000_0100;
const PROVISIONKEY = 0b0001_0000;
const EINITTOKENKEY = 0b0010_0000;
const CET = 0b0100_0000;
const KSS = 0b1000_0000;
}
}
// file: common/inc/sgx_attributes.h
/* Enclave Flags Bit Masks */
#define SGX_FLAGS_INITTED 0x0000000000000001ULL /* If set, then the enclave is initialized */
#define SGX_FLAGS_DEBUG 0x0000000000000002ULL /* If set, then the enclave is debug */
#define SGX_FLAGS_MODE64BIT 0x0000000000000004ULL /* If set, then the enclave is 64 bit */
#define SGX_FLAGS_PROVISION_KEY 0x0000000000000010ULL /* If set, then the enclave has access to provision key */
#define SGX_FLAGS_EINITTOKEN_KEY 0x0000000000000020ULL /* If set, then the enclave has access to EINITTOKEN key */
#define SGX_FLAGS_KSS 0x0000000000000080ULL /* If set, then the enclave uses KSS */
#define SGX_FLAGS_AEX_NOTIFY 0x0000000000000400ULL /* If set, then the enclave enables AEX Notify */
/* XSAVE Feature Request Mask */
#define SGX_XFRM_LEGACY 0x0000000000000003ULL /* Legacy XFRM which includes the basic feature bits required by SGX, x87 state(0x01) and SSE state(0x02) */
#define SGX_XFRM_AVX 0x0000000000000006ULL /* AVX XFRM which includes AVX state(0x04) and SSE state(0x02) required by AVX */
#define SGX_XFRM_AVX512 0x00000000000000E6ULL /* AVX-512 XFRM */
#define SGX_XFRM_MPX 0x0000000000000018ULL /* MPX XFRM - not supported */
#define SGX_XFRM_PKRU 0x0000000000000200ULL /* PKRU state */
#define SGX_XFRM_AMX 0x0000000000060000ULL /* AMX XFRM, including XTILEDATA(0x40000) and XTILECFG(0x20000) */
Most user enclaves only need to enable the MODE64BIT
attribute in production.
The KSS
attribute enables the Key sharing and separation (KSS) feature.
The Extended Features Request Mask (xfrm
) allows an enclave to ensure certain CPU features (e.g., SSE, AESNI) are available, or the enclave will fail to load.
Enclave Miscselect #
pub struct Miscselect: u32 {
const EXINFO = 0b0000_0001;
}
KEYREQUEST #
A struct which gets fed into the Seal Key KDF in order to generate keys for sealing or remote attestation.
The keyname
is a user-defined label
struct Keyrequest {
keyname: u16,
keypolicy: Keypolicy,
isvsvn: u16,
_reserved1: u16,
cpusvn: [u8; 16],
attributemask: [u64; 2],
keyid: [u8; 32],
miscmask: u32,
_reserved2: [u8; 436],
}
struct Keypolicy: u16 {
const MRENCLAVE = 0b0000_0001;
const MRSIGNER = 0b0000_0010;
}
#[repr(u16)]
enum Keyname {
Einittoken = 0,
Provision = 1,
ProvisionSeal = 2,
Report = 3,
Seal = 4,
}
Key sharing and separation (KSS) #
Premise: Communicating between two different enclaves is cumbersome. The KSS feature adds more flexibility.
The new KSS feature adds a configuration value+SVN and two extra 16-byte product IDs.
The 64-byte configuration value and 2-byte SVN is used as a post-init identity. The value affects the attestation identity and (optionally) seal key derivation, but isn't included in the Sigstruct. This allows a single enclave binary that is specialized into different services (with different identities!) at load time.
The extra product IDs are "family ID" and "extra product ID" (but can be used for other purposes). They can be used in seal key derivation. The IDs are included in the Sigstruct but not the EINITTOKEN. meaning a launch enclave can't use these for access controls.