# EGETKEY — Retrieves a Cryptographic Key

Opcode/Instruction | Op/En | 64/32 bit Mode Support | CPUID Feature Flag | Description
--- | --- | --- | --- | ---
EAX = 01H ENCLU[EGETKEY] | IR | V/V | SGX1 | This leaf function retrieves a cryptographic key.

## Instruction Operand Encoding ¶

Op/En | EAX | RBX | RCX
IR | EGETKEY (In) | Return error code (Out) | Address to a KEYREQUEST (In) | Address of the OUTPUTDATA (In)

### Description ¶

The ENCLU[EGETKEY] instruction returns a 128-bit secret key from the processor specific key hierarchy. The register RBX contains the effective address of a KEYREQUEST structure, which the instruction interprets to determine the key being requested. The Requesting Keys section below provides a description of the keys that can be requested. The RCX register contains the effective address where the key will be returned. Both the addresses in RBX & RCX should be locations inside the enclave.

EGETKEY derives keys using a processor unique value to create a specific key based on a number of possible inputs. This instruction leaf can only be executed inside an enclave.

## EEGETKEY Memory Parameter Semantics ¶

KEYREQUEST | OUTPUTDATA
Enclave read access | Enclave write access

After validating the operands, the instruction determines which key is to be produced and performs the following actions:

- The instruction assembles the derivation data for the key based on the Table 38-66.
- Computes derived key using the derivation data and package specific value.
- Outputs the calculated key to the address in RCX.

The instruction fails with #GP(0) if the operands are not properly aligned. Successful completion of the instruction will clear RFLAGS.{ZF, CF, AF, OF, SF, PF}. The instruction returns an error code if the user tries to request a key based on an invalid CPUSVN or ISVSVN (when the user request is accepted, see the table below), requests a key for which it has not been granted the attribute to request, or requests a key that is not supported by the hardware. These checks may be performed in any order. Thus, an indication by error number of one cause (for example, invalid attribute) does not imply that there are not also other errors. Different processors may thus give different error numbers for the same Enclave. The correctness of software should not rely on the order resulting from the checks documented in this section. In such cases the ZF flag is set and the corresponding error bit (SGX_INVALID_SVN, SGX_INVALID_ATTRIBUTE, SGX_INVALID_KEYNAME) is set in RAX and the data at the address specified by RCX is unmodified.

Requesting Keys

The KEYREQUEST structure (see Section 35.18.1) identifies the key to be provided. The Keyrequest.KeyName field identifies which type of key is requested.

Deriving Keys

Key derivation is based on a combination of the enclave specific values (see Table 38-66) and a processor key. Depending on the key being requested a field may either be included by definition or the value may be included from the KeyRequest. A “yes” in Table 38-66 indicates the value for the field is included from its default location, identified in the source row, and a “request” indicates the values for the field is included from its corresponding KeyRequest field.

| Key Name | Attributes | Owner Epoch | CPU SVN | ISV SVN | ISV PRODID | ISVEXT PRODID | ISVFAM ILYID | MRENCLAVE | MRSIGNER | CONFIG ID | CONFIGS VN | RAND
--- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ---
Source | Key Dependent Constant | Y := SECS.ATTRIBUTES and SECS.MISCSELECT and SECS.CET_ATTRIB UTES; | CR_SGX OWNER EPOCH | Y := CPUSVN Register; | R := Req.ISV SVN; | SECS. ISVID | SECS.IS VEXTPR ODID | SECS.IS VFAMIL YID | SECS. MRENCLAVE | SECS. MRSIGNER | SECS.CO NFIGID | SECS.CO NFIGSVN | Req. KEYID
R := AttribMask & SECS.ATTRIBUTES and SECS.MISCSELECT and SECS.CET_ATTRIB UTES; | R := Req.CPU SVN;
EINITTOKEN | Yes | Request | Yes | Request | Request | Yes | No | No | No | Yes | No | No | Request
Report | Yes | Yes | Yes | Yes | No | No | No | No | Yes | No | Yes | Yes | Request
Seal | Yes | Request | Yes | Request | Request | Request | Request | Request | Request | Request | Request | Request | Request
Provisioning | Yes | Request | No | Request | Request | Yes | No | No | No | Yes | No | No | Yes
Provisioning Seal | Yes | Request | No | Request | Request | Request | Request | Request | No | Yes | Request | Request | Yes

Table 38-66. Key Derivation

Keys that permit the specification of a CPU or ISV's code's, or enclave configuration's SVNs have additional requirements. The caller may not request a key for an SVN beyond the current CPU, ISV or enclave configuration's SVN, respectively.

Several keys are access controlled. Access to the Provisioning Key and Provisioning Seal key requires the enclave's ATTRIBUTES.PROVISIONKEY be set. The EINITTOKEN Key requires ATTRIBUTES.EINITTOKEN_KEY be set and SECS.MRSIGNER equal IA32_SGXLEPUBKEYHASH.

Some keys are derived based on a hardcode PKCS padding constant (352 byte string):

HARDCODED_PKCS1_5_PADDING[15:0] := 0100H;

HARDCODED_PKCS1_5_PADDING[2655:16] := SignExtend330Byte(-1); // 330 bytes of 0FFH

HARDCODED_PKCS1_5_PADDING[2815:2656] := 2004000501020403650148866009060D30313000H;

The error codes are:

Error Code (see Table 38-4) | Value | Description
--- | --- | ---
No Error | 0 | EGETKEY successful.
SGX_INVALID_ATTRIBUTE |  | The KEYREQUEST contains a KEYNAME for which the enclave is not authorized.
SGX_INVALID_CPUSVN |  | If KEYREQUEST.CPUSVN is an unsupported platforms CPUSVN value.
SGX_INVALID_ISVSVN |  | If KEYREQUEST software SVN (ISVSVN or CONFIGSVN) is greater than the enclave's corresponding SVN.
SGX_INVALID_KEYNAME |  | If KEYREQUEST.KEYNAME is an unsupported value.

Table 38-67. EGETKEY Return Value in RAX

### Concurrency Restrictions ¶

Leaf | Parameter | Base Concurrency Restrictions
--- | --- | ---
Access | On Conflict | SGX_CONFLICT VM Exit Qualification
EGETKEY | KEYREQUEST [DS:RBX] | Concurrent |  |
OUTPUTDATA [DS:RCX] | Concurrent |  |

Table 38-68. Base Concurrency Restrictions of EGETKEY

Leaf | Parameter | Additional Concurrency Restrictions
--- | --- | ---
vs. EACCEPT, EACCEPTCOPY, EMODPE, EMODPR, EMODT | vs. EADD, EEXTEND, EINIT | vs. ETRACK, ETRACKC
Access | On Conflict | Access | On Conflict | Access | On Conflict
EGETKEY | KEYREQUEST [DS:RBX] | Concurrent |  | Concurrent |  | Concurrent |
OUTPUTDATA [DS:RCX] | Concurrent |  | Concurrent |  | Concurrent |

Table 38-69. Additional Concurrency Restrictions of EGETKEY

### Operation ¶

## Temp Variables in EGETKEY Operational Flow ¶

Name | Type | Size (Bits) | Description
--- | --- | --- | ---
TMP_CURRENTSECS |  |  | Address of the SECS for the currently executing enclave.
TMP_KEYDEPENDENCIES |  |  | Temp space for key derivation.
TMP_ATTRIBUTES |  | 128 | Temp Space for the calculation of the sealable Attributes.
TMP_ISVEXTPRODID |  | 16 bytes | Temp Space for ISVEXTPRODID.
TMP_ISVPRODID |  | 2 bytes | Temp Space for ISVPRODID.
TMP_ISVFAMILYID |  | 16 bytes | Temp Space for ISVFAMILYID.
TMP_CONFIGID |  | 64 bytes | Temp Space for CONFIGID.
TMP_CONFIGSVN |  | 2 bytes | Temp Space for CONFIGSVN.
TMP_OUTPUTKEY |  | 128 | Temp Space for the calculation of the key.

(* Make sure KEYREQUEST is properly aligned and inside the current enclave *)

IF ( (DS:RBX is not 512Byte aligned) or (DS:RBX is not within CR_ELRANGE) )

THEN #GP(0); FI;

(* Make sure DS:RBX is an EPC address and the EPC page is valid *)

IF ( (DS:RBX does not resolve to an EPC address) or (EPCM(DS:RBX).VALID = 0) )

THEN #PF(DS:RBX); FI;

IF (EPCM(DS:RBX).BLOCKED = 1)

THEN #PF(DS:RBX); FI;

(* Check page parameters for correctness *)

IF ( (EPCM(DS:RBX).PT ≠ PT_REG) or (EPCM(DS:RBX).ENCLAVESECS ≠ CR_ACTIVE_SECS) or (EPCM(DS:RBX).PENDING = 1) or

(EPCM(DS:RBX).MODIFIED = 1) or (EPCM(DS:RBX).ENCLAVEADDRESS ≠ (DS:RBX & ~0FFFH) ) or (EPCM(DS:RBX).R = 0) )

THEN #PF(DS:RBX);

FI;

(* Make sure OUTPUTDATA is properly aligned and inside the current enclave *)

IF ( (DS:RCX is not 16Byte aligned) or (DS:RCX is not within CR_ELRANGE) )

THEN #GP(0); FI;

(* Make sure DS:RCX is an EPC address and the EPC page is valid *)

IF ( (DS:RCX does not resolve to an EPC address) or (EPCM(DS:RCX).VALID = 0) )

THEN #PF(DS:RCX); FI;

IF (EPCM(DS:RCX).BLOCKED = 1)

THEN #PF(DS:RCX); FI;

(* Check page parameters for correctness *)

IF ( (EPCM(DS:RCX).PT ≠ PT_REG) or (EPCM(DS:RCX).ENCLAVESECS ≠ CR_ACTIVE_SECS) or (EPCM(DS:RCX).PENDING = 1) or

(EPCM(DS:RCX).MODIFIED = 1) or (EPCM(DS:RCX).ENCLAVEADDRESS ≠ (DS:RCX & ~0FFFH) ) or (EPCM(DS:RCX).W = 0) )

THEN #PF(DS:RCX);

FI;

(* Verify RESERVED spaces in KEYREQUEST are valid *)

IF ( (DS:RBX).RESERVED ≠ 0) or (DS:RBX.KEYPOLICY.RESERVED ≠ 0) )

THEN #GP(0); FI;

TMP_CURRENTSECS := CR_ACTIVE_SECS;

(* Verify that CONFIGSVN & New Policy bits are not used if KSS is not enabled *)

IF ((TMP_CURRENTSECS.ATTRIBUTES.KSS == 0) AND ((DS:RBX.KEYPOLICY & 0x003C ≠ 0) OR (DS:RBX.CONFIGSVN > 0)))

THEN #GP(0); FI;

(* Determine which enclave attributes that must be included in the key. Attributes that must always be include INIT & DEBUG *)

REQUIRED_SEALING_MASK[127:0] := 00000000 00000000 00000000 00000003H;

TMP_ATTRIBUTES := (DS:RBX.ATTRIBUTEMASK | REQUIRED_SEALING_MASK) & TMP_CURRENTSECS.ATTRIBUTES;

(* Compute MISCSELECT fields to be included *)

TMP_MISCSELECT := DS:RBX.MISCMASK & TMP_CURRENTSECS.MISCSELECT

(* Compute CET_ATTRIBUTES fields to be included *)

IF (CPUID.(EAX=12H, ECX=1):EAX[6] = 1)

THEN TMP_CET_ATTRIBUTES := DS:RBX.CET_ATTRIBUTES_ MASK & TMP_CURRENTSECS.CET_ATTRIBUTES; FI;

TMP_KEYDEPENDENCIES := 0;

CASE (DS:RBX.KEYNAME)

SEAL_KEY:

IF (DS:RBX.CPUSVN is beyond current CPU configuration)

THEN

RFLAGS.ZF := 1;

RAX := SGX_INVALID_CPUSVN;

GOTO EXIT;

FI;

IF (DS:RBX.ISVSVN > TMP_CURRENTSECS.ISVSVN)

THEN

RFLAGS.ZF := 1;

RAX := SGX_INVALID_ISVSVN;

GOTO EXIT;

FI;

IF (DS:RBX.CONFIGSVN > TMP_CURRENTSECS.CONFIGSVN)

THEN

RFLAGS.ZF := 1;

RAX := SGX_INVALID_ISVSVN;

GOTO EXIT;

FI;

(*Include enclave identity?*)

TMP_MRENCLAVE := 0;

IF (DS:RBX.KEYPOLICY.MRENCLAVE = 1)

THEN TMP_MRENCLAVE := TMP_CURRENTSECS.MRENCLAVE;

FI;

(*Include enclave author?*)

TMP_MRSIGNER := 0;

IF (DS:RBX.KEYPOLICY.MRSIGNER = 1)

THEN TMP_MRSIGNER := TMP_CURRENTSECS.MRSIGNER;

FI;

(* Include enclave product family ID? *)

TMP_ISVFAMILYID := 0;

IF (DS:RBX.KEYPOLICY.ISVFAMILYID = 1)

THEN TMP_ISVFAMILYID := TMP_CURRENTSECS.ISVFAMILYID;

FI;

(* Include enclave product ID? *)

TMP_ISVPRODID := 0;

IF (DS:RBX.KEYPOLICY.NOISVPRODID = 0)

TMP_ISVPRODID := TMP_CURRENTSECS.ISVPRODID;

FI;

(* Include enclave Config ID? *)

TMP_CONFIGID := 0;

TMP_CONFIGSVN := 0;

IF (DS:RBX.KEYPOLICY.CONFIGID = 1)

TMP_CONFIGID := TMP_CURRENTSECS.CONFIGID;

TMP_CONFIGSVN := DS:RBX.CONFIGSVN;

FI;

(* Include enclave extended product ID? *)

TMP_ISVEXTPRODID := 0;

IF (DS:RBX.KEYPOLICY.ISVEXTPRODID = 1 )

TMP_ISVEXTPRODID := TMP_CURRENTSECS.ISVEXTPRODID;

FI;

//Determine values key is based on

TMP_KEYDEPENDENCIES.KEYNAME := SEAL_KEY;

TMP_KEYDEPENDENCIES.ISVFAMILYID := TMP_ISVFAMILYID;

TMP_KEYDEPENDENCIES.ISVEXTPRODID := TMP_ISVEXTPRODID;

TMP_KEYDEPENDENCIES.ISVPRODID := TMP_ISVPRODID;

TMP_KEYDEPENDENCIES.ISVSVN := DS:RBX.ISVSVN;

TMP_KEYDEPENDENCIES.SGXOWNEREPOCH := CR_SGXOWNEREPOCH;

TMP_KEYDEPENDENCIES.ATTRIBUTES := TMP_ATTRIBUTES;

TMP_KEYDEPENDENCIES.ATTRIBUTESMASK := DS:RBX.ATTRIBUTEMASK;

TMP_KEYDEPENDENCIES.MRENCLAVE := TMP_MRENCLAVE;

TMP_KEYDEPENDENCIES.MRSIGNER := TMP_MRSIGNER;

TMP_KEYDEPENDENCIES.KEYID := DS:RBX.KEYID;

TMP_KEYDEPENDENCIES.SEAL_KEY_FUSES := CR_SEAL_FUSES;

TMP_KEYDEPENDENCIES.CPUSVN := DS:RBX.CPUSVN;

TMP_KEYDEPENDENCIES.PADDING := TMP_CURRENTSECS.PADDING;

TMP_KEYDEPENDENCIES.MISCSELECT := TMP_MISCSELECT;

TMP_KEYDEPENDENCIES.MISCMASK := ~DS:RBX.MISCMASK;

TMP_KEYDEPENDENCIES.KEYPOLICY := DS:RBX.KEYPOLICY;

TMP_KEYDEPENDENCIES.CONFIGID := TMP_CONFIGID;

TMP_KEYDEPENDENCIES.CONFIGSVN := TMP_CONFIGSVN;

IF CPUID.(EAX=12H, ECX=1):EAX[6] = 1

THEN

TMP_KEYDEPENDENCIES.CET_ATTRIBUTES := TMP_CET_ATTRIBUTES;

TMP_KEYDEPENDENCIES.CET_ATTRIBUTES _MASK := DS:RBX.CET_ATTRIBUTES _MASK;

FI;

BREAK;

REPORT_KEY:

//Determine values key is based on

TMP_KEYDEPENDENCIES.KEYNAME := REPORT_KEY;

TMP_KEYDEPENDENCIES.ISVFAMILYID := 0;

TMP_KEYDEPENDENCIES.ISVEXTPRODID := 0;

TMP_KEYDEPENDENCIES.ISVPRODID := 0;

TMP_KEYDEPENDENCIES.ISVSVN := 0;

TMP_KEYDEPENDENCIES.SGXOWNEREPOCH := CR_SGXOWNEREPOCH;

TMP_KEYDEPENDENCIES.ATTRIBUTES := TMP_CURRENTSECS.ATTRIBUTES;

TMP_KEYDEPENDENCIES.ATTRIBUTESMASK := 0;

TMP_KEYDEPENDENCIES.MRENCLAVE := TMP_CURRENTSECS.MRENCLAVE;

TMP_KEYDEPENDENCIES.MRSIGNER := 0;

TMP_KEYDEPENDENCIES.KEYID := DS:RBX.KEYID;

TMP_KEYDEPENDENCIES.SEAL_KEY_FUSES := CR_SEAL_FUSES;

TMP_KEYDEPENDENCIES.CPUSVN := CR_CPUSVN;

TMP_KEYDEPENDENCIES.PADDING := HARDCODED_PKCS1_5_PADDING;

TMP_KEYDEPENDENCIES.MISCSELECT := TMP_CURRENTSECS.MISCSELECT;

TMP_KEYDEPENDENCIES.MISCMASK := 0;

TMP_KEYDEPENDENCIES.KEYPOLICY := 0;

TMP_KEYDEPENDENCIES.CONFIGID := TMP_CURRENTSECS.CONFIGID;

TMP_KEYDEPENDENCIES.CONFIGSVN := TMP_CURRENTSECS.CONFIGSVN;

IF (CPUID.(EAX=12H, ECX=1):EAX[6] = 1)

THEN

TMP_KEYDEPENDENCIES.CET_ATTRIBUTES := TMP_CURRENTSECS.CET_ATTRIBUTES;

TMP_KEYDEPENDENCIES.CET_ATTRIBUTES_MASK := 0;

FI;

BREAK;

EINITTOKEN_KEY:

(* Check ENCLAVE has EINITTOKEN Key capability *)

IF (TMP_CURRENTSECS.ATTRIBUTES.EINITTOKEN_KEY = 0)

THEN

RFLAGS.ZF := 1;

RAX := SGX_INVALID_ATTRIBUTE;

GOTO EXIT;

FI;

IF (DS:RBX.CPUSVN is beyond current CPU configuration)

THEN

RFLAGS.ZF := 1;

RAX := SGX_INVALID_CPUSVN;

GOTO EXIT;

FI;

IF (DS:RBX.ISVSVN > TMP_CURRENTSECS.ISVSVN)

THEN

RFLAGS.ZF := 1;

RAX := SGX_INVALID_ISVSVN;

GOTO EXIT;

FI;

(* Determine values key is based on *)

TMP_KEYDEPENDENCIES.KEYNAME := EINITTOKEN_KEY;

TMP_KEYDEPENDENCIES.ISVFAMILYID := 0;

TMP_KEYDEPENDENCIES.ISVEXTPRODID := 0;

TMP_KEYDEPENDENCIES.ISVPRODID := TMP_CURRENTSECS.ISVPRODID

TMP_KEYDEPENDENCIES.ISVSVN := DS:RBX.ISVSVN;

TMP_KEYDEPENDENCIES.SGXOWNEREPOCH := CR_SGXOWNEREPOCH;

TMP_KEYDEPENDENCIES.ATTRIBUTES := TMP_ATTRIBUTES;

TMP_KEYDEPENDENCIES.ATTRIBUTESMASK := 0;

TMP_KEYDEPENDENCIES.MRENCLAVE := 0;

TMP_KEYDEPENDENCIES.MRSIGNER := TMP_CURRENTSECS.MRSIGNER;

TMP_KEYDEPENDENCIES.KEYID := DS:RBX.KEYID;

TMP_KEYDEPENDENCIES.SEAL_KEY_FUSES := CR_SEAL_FUSES;

TMP_KEYDEPENDENCIES.CPUSVN := DS:RBX.CPUSVN;

TMP_KEYDEPENDENCIES.PADDING := TMP_CURRENTSECS.PADDING;

TMP_KEYDEPENDENCIES.MISCSELECT := TMP_MISCSELECT;

TMP_KEYDEPENDENCIES.MISCMASK := 0;

TMP_KEYDEPENDENCIES.KEYPOLICY := 0;

TMP_KEYDEPENDENCIES.CONFIGID := 0;

TMP_KEYDEPENDENCIES.CONFIGSVN := 0;

IF (CPUID.(EAX=12H, ECX=1):EAX[6] = 1)

THEN

TMP_KEYDEPENDENCIES.CET_ATTRIBUTES := TMP_CET_ATTRIBUTES;

TMP_KEYDEPENDENCIES.CET_ATTRIBUTES _MASK := 0;

FI;

BREAK;

PROVISION_KEY:

(* Check ENCLAVE has PROVISIONING capability *)

IF (TMP_CURRENTSECS.ATTRIBUTES.PROVISIONKEY = 0)

THEN

RFLAGS.ZF := 1;

RAX := SGX_INVALID_ATTRIBUTE;

GOTO EXIT;

FI;

IF (DS:RBX.CPUSVN is beyond current CPU configuration)

THEN

RFLAGS.ZF := 1;

RAX := SGX_INVALID_CPUSVN;

GOTO EXIT;

FI;

IF (DS:RBX.ISVSVN > TMP_CURRENTSECS.ISVSVN)

THEN

RFLAGS.ZF := 1;

RAX := SGX_INVALID_ISVSVN;

GOTO EXIT;

FI;

(* Determine values key is based on *)

TMP_KEYDEPENDENCIES.KEYNAME := PROVISION_KEY;

TMP_KEYDEPENDENCIES.ISVFAMILYID := 0;

TMP_KEYDEPENDENCIES.ISVEXTPRODID := 0;

TMP_KEYDEPENDENCIES.ISVPRODID := TMP_CURRENTSECS.ISVPRODID;

TMP_KEYDEPENDENCIES.ISVSVN := DS:RBX.ISVSVN;

TMP_KEYDEPENDENCIES.SGXOWNEREPOCH := 0;

TMP_KEYDEPENDENCIES.ATTRIBUTES := TMP_ATTRIBUTES;

TMP_KEYDEPENDENCIES.ATTRIBUTESMASK := DS:RBX.ATTRIBUTEMASK;

TMP_KEYDEPENDENCIES.MRENCLAVE := 0;

TMP_KEYDEPENDENCIES.MRSIGNER := TMP_CURRENTSECS.MRSIGNER;

TMP_KEYDEPENDENCIES.KEYID := 0;

TMP_KEYDEPENDENCIES.SEAL_KEY_FUSES := 0;

TMP_KEYDEPENDENCIES.CPUSVN := DS:RBX.CPUSVN;

TMP_KEYDEPENDENCIES.PADDING := TMP_CURRENTSECS.PADDING;

TMP_KEYDEPENDENCIES.MISCSELECT := TMP_MISCSELECT;

TMP_KEYDEPENDENCIES.MISCMASK := ~DS:RBX.MISCMASK;

TMP_KEYDEPENDENCIES.KEYPOLICY := 0;

TMP_KEYDEPENDENCIES.CONFIGID := 0;

IF (CPUID.(EAX=12H, ECX=1):EAX[6] = 1)

THEN

TMP_KEYDEPENDENCIES.CET_ATTRIBUTES := TMP_CET_ATTRIBUTES;

TMP_KEYDEPENDENCIES.CET_ATTRIBUTES _MASK := 0;

FI;

BREAK;

PROVISION_SEAL_KEY:

(* Check ENCLAVE has PROVISIONING capability *)

IF (TMP_CURRENTSECS.ATTRIBUTES.PROVISIONKEY = 0)

THEN

RFLAGS.ZF := 1;

RAX := SGX_INVALID_ATTRIBUTE;

GOTO EXIT;

FI;

IF (DS:RBX.CPUSVN is beyond current CPU configuration)

THEN

RFLAGS.ZF := 1;

RAX := SGX_INVALID_CPUSVN;

GOTO EXIT;

FI;

IF (DS:RBX.ISVSVN > TMP_CURRENTSECS.ISVSVN)

THEN

RFLAGS.ZF := 1;

RAX := SGX_INVALID_ISVSVN;

GOTO EXIT;

FI;

(* Include enclave product family ID? *)

TMP_ISVFAMILYID := 0;

IF (DS:RBX.KEYPOLICY.ISVFAMILYID = 1)

THEN TMP_ISVFAMILYID := TMP_CURRENTSECS.ISVFAMILYID;

FI;

(* Include enclave product ID? *)

TMP_ISVPRODID := 0;

IF (DS:RBX.KEYPOLICY.NOISVPRODID = 0)

TMP_ISVPRODID := TMP_CURRENTSECS.ISVPRODID;

FI;

(* Include enclave Config ID? *)

TMP_CONFIGID := 0;

TMP_CONFIGSVN := 0;

IF (DS:RBX.KEYPOLICY.CONFIGID = 1)

TMP_CONFIGID := TMP_CURRENTSECS.CONFIGID;

TMP_CONFIGSVN := DS:RBX.CONFIGSVN;

FI;

(* Include enclave extended product ID? *)

TMP_ISVEXTPRODID := 0;

IF (DS:RBX.KEYPOLICY.ISVEXTPRODID = 1)

TMP_ISVEXTPRODID := TMP_CURRENTSECS.ISVEXTPRODID;

FI;

(* Determine values key is based on *)

TMP_KEYDEPENDENCIES.KEYNAME := PROVISION_SEAL_KEY;

TMP_KEYDEPENDENCIES.ISVFAMILYID := TMP_ISVFAMILYID;

TMP_KEYDEPENDENCIES.ISVEXTPRODID := TMP_ISVEXTPRODID;

TMP_KEYDEPENDENCIES.ISVPRODID := TMP_ISVPRODID;

TMP_KEYDEPENDENCIES.ISVSVN := DS:RBX.ISVSVN;

TMP_KEYDEPENDENCIES.SGXOWNEREPOCH := 0;

TMP_KEYDEPENDENCIES.ATTRIBUTES := TMP_ATTRIBUTES;

TMP_KEYDEPENDENCIES.ATTRIBUTESMASK := DS:RBX.ATTRIBUTEMASK;

TMP_KEYDEPENDENCIES.MRENCLAVE := 0;

TMP_KEYDEPENDENCIES.MRSIGNER := TMP_CURRENTSECS.MRSIGNER;

TMP_KEYDEPENDENCIES.KEYID := 0;

TMP_KEYDEPENDENCIES.SEAL_KEY_FUSES := CR_SEAL_FUSES;

TMP_KEYDEPENDENCIES.CPUSVN := DS:RBX.CPUSVN;

TMP_KEYDEPENDENCIES.PADDING := TMP_CURRENTSECS.PADDING;

TMP_KEYDEPENDENCIES.MISCSELECT := TMP_MISCSELECT;

TMP_KEYDEPENDENCIES.MISCMASK := ~DS:RBX.MISCMASK;

TMP_KEYDEPENDENCIES.KEYPOLICY := DS:RBX.KEYPOLICY;

TMP_KEYDEPENDENCIES.CONFIGID := TMP_CONFIGID;

TMP_KEYDEPENDENCIES.CONFIGSVN := TMP_CONFIGSVN;

IF (CPUID.(EAX=12H, ECX=1):EAX[6] = 1)

THEN

TMP_KEYDEPENDENCIES.CET_ATTRIBUTES := TMP_CET_ATTRIBUTES;

TMP_KEYDEPENDENCIES.CET_ATTRIBUTES _MASK := 0;

FI;

BREAK;

DEFAULT:

(* The value of KEYNAME is invalid *)

RFLAGS.ZF := 1;

RAX := SGX_INVALID_KEYNAME;

GOTO EXIT:

ESAC;

(* Calculate the final derived key and output to the address in RCX *)

TMP_OUTPUTKEY := derivekey(TMP_KEYDEPENDENCIES);

DS:RCX[15:0] := TMP_OUTPUTKEY;

RAX := 0;

RFLAGS.ZF := 0;

EXIT:

RFLAGS.CF := 0;

RFLAGS.PF := 0;

RFLAGS.AF := 0;

RFLAGS.OF := 0;

RFLAGS.SF := 0;

### Flags Affected ¶

ZF is cleared if successful, otherwise ZF is set. CF, PF, AF, OF, SF are cleared.

### Protected Mode Exceptions ¶

#GP(0) | If executed outside an enclave.
If a memory operand effective address is outside the current enclave.
If an effective address is not properly aligned.
If an effective address is outside the DS segment limit.
If KEYREQUEST format is invalid.
#PF(error | code) If a page fault occurs in accessing memory.

### 64-Bit Mode Exceptions ¶

#GP(0) | If executed outside an enclave.
If a memory operand effective address is outside the current enclave.
If an effective address is not properly aligned.
If an effective address is not canonical.
If KEYREQUEST format is invalid.
#PF(error | code) If a page fault occurs in accessing memory operands.