Trusted Platform Module (TPM) and Virtualization based Security(VBS) enclave attestation protocol

Microsoft Azure Attestation to provide a strong security guarantee relies on verifying a chain of trust is maintained from a root of trust (TPM) to the launch of the hypervisor and secure kernel. To achieve this Azure Attestation must attest to the boot state of the machine before we can establish trust in the secure enclave. The operating system, hypervisor, and secure kernel binaries must be signed by the correct official Microsoft authorities and configured in a secure way. Once we have bound trust between the Trusted Platform Module (TPM) and the health of the hypervisor, we can trust the Virtualization Based Security(VBS) enclave IDKs provided in the Measured Boot Log, with this we can validate that a key pair was generated by the enclave and mint an attestation report that binds trust in that key and contains other claims such as the security level and boot attestation properties.

VBS enclaves require a TPM to provide the measurement to validate the security foundation. VBS enclaves are attested by the TPM endpoint with an addition to the request object in the protocol.

Protocol messages

Init message

Direction

Client -> Azure Attestation

Payload

{ 
  "type": "aikcert" 
} 

“type” (ASCII string): represents the type of attestation requested. Currently, only “aikcert” is supported.

Challenge message

Direction

Azure Attestation -> Client

Payload

{ 
  "challenge": "<BASE64URL(CHALLENGE)>", 
  "service_context": "<BASE64URL(SERVICECONTEXT)>" 
} 

challenge (BASE64URL(OCTETS)): Random value issued by the service.

service_context (BASE64URL(OCTETS)): Opaque context created by the service.

Request message

Direction

Client -> Azure Attestation

Payload

{
  "request": "<JWS>"
}

request (JWS): Request consists of a JSON Web Signature (JWS) structure. The JWS Protected Header and JWS Payload are shown below. As in any JWS structure, the final value consists of:

BASE64URL(UTF8(JWS Protected Header)) || '.' ||

BASE64URL(JWS Payload) || '.' ||

BASE64URL(JWS Signature)

JWS Protected Header
{
  "alg": "PS256",
  "typ": "attReq"
  // no "kid" parameter as the key specified by attest_key MUST sign this JWS to prove possession.
}
JWS Payload

JWS payload can be of type basic or VBS. Basic is used when attestation evidence does not include VBS data.

TPM only sample:

{ 
  "att_type": "basic", 
  "att_data": { 
    "rp_id": "<URL>", 
    "rp_data": "<BASE64URL(RPCUSTOMDATA)>", 
    "challenge": "<BASE64URL(CHALLENGE)>", 

    "tpm_att_data": { 
      "srtm_boot_log": "<BASE64URL(SRTMBOOTLOG)>", 
      "srtm_resume_log": "<BASE64URL(SRTMRESUMELOG)>", 
      "drtm_boot_log": "<BASE64URL(DRTMBOOTLOG)>", 
      "drtm_resume_log": "<BASE64URL(DRTMRESUMELOG)>", 
      "aik_cert": "<BASE64URL(AIKCERTIFICATE)>", 

      // aik_pub is represented as a JSON Web Key (JWK) object (RFC 7517). 

      "aik_pub": { 
        "kty": "RSA", 
        "n": "<Base64urlUInt(MODULUS)>", 
        "e": "<Base64urlUInt(EXPONENT)>" 
      }, 
      "current_claim": "<BASE64URL(CURRENTCLAIM)>", 
      "boot_claim": "<BASE64URL(BOOTCLAIM)>" 
    }, 

    // attest_key is represented as a JSON Web Key (JWK) object (RFC 7517). 

    "attest_key": { 
      "kty": "RSA", 
      "n": "<Base64urlUInt(MODULUS)>", 
      "e": "<Base64urlUInt(EXPONENT)>" 
    }, 
    "custom_claims": [ 
      { 
        "name": "<name>", 
        "value": "<value>", 
        "value_type": "<value_type>" 
      }, 
      { 
        "name": "<name>", 
        "value": "<value>", 
        "value_type": "<value_type>" 
      } 
    ], 
    "service_context": "<BASE64URL(SERVICECONTEXT)>" 
  } 
} 

TPM + VBS enclave sample:

{ 
  "att_type": "vbs", 
  "att_data": { 
    "report_signed": { 
      "rp_id": "<URL>", 
      "rp_data": "<BASE64URL(RPCUSTOMDATA)>", 
      "challenge": "<BASE64URL(CHALLENGE)>", 
      "tpm_att_data": { 
        "srtm_boot_log": "<BASE64URL(SRTMBOOTLOG)>", 
        "srtm_resume_log": "<BASE64URL(SRTMRESUMELOG)>", 
        "drtm_boot_log": "<BASE64URL(DRTMBOOTLOG)>", 
        "drtm_resume_log": "<BASE64URL(DRTMRESUMELOG)>", 
        "aik_cert": "<BASE64URL(AIKCERTIFICATE)>", 

        // aik_pub is represented as a JSON Web Key (JWK) object (RFC 7517). 

        "aik_pub": { 
          "kty": "RSA", 
          "n": "<Base64urlUInt(MODULUS)>", 
          "e": "<Base64urlUInt(EXPONENT)>" 
        }, 
        "current_claim": "<BASE64URL(CURRENTCLAIM)>", 
        "boot_claim": "<BASE64URL(BOOTCLAIM)>" 
      }, 

      // attest_key is represented as a JSON Web Key (JWK) object (RFC 7517). 

      "attest_key": { 
        "kty": "RSA", 
        "n": "<Base64urlUInt(MODULUS)>", 
        "e": "<Base64urlUInt(EXPONENT)>" 
      }, 
      "custom_claims": [ 
        { 
          "name": "<name>", 
          "value": "<value>", 
          "value_type": "<value_type>" 
        }, 
        { 
          "name": "<name>", 
          "value": "<value>", 
          "value_type": "<value_type>" 
        } 
      ], 
      "service_context": "<BASE64URL(SERVICECONTEXT)>" 
    }, 
    "vsm_report": "<BASE64URL(REPORT)>" 
  } 
} 

rp_id (StringOrURI): Relying party identifier. Used by the service in the computation of the machine ID claim

rp_data (BASE64URL(OCTETS)): Opaque data passed by the relying party. This is normally used by the relying party as a nonce to guarantee freshness of the report

challenge (BASE64URL(OCTETS)): Random value issued by the service

tpm_att_data: TPM-related attestation data

  • srtm_boot_log (BASE64URL(OCTETS)): SRTM boot logs as retrieved by function Tbsi_Get_TCG_Log_Ex with log type = TBS_TCGLOG_SRTM_BOOT

  • srtm_resume_log (BASE64URL(OCTETS)): SRTM resumes log as retrieved by function Tbsi_Get_TCG_Log_Ex with log type = TBS_TCGLOG_SRTM_RESUME

  • drtm_boot_log (BASE64URL(OCTETS)): DRTM boot logs as retrieved by function Tbsi_Get_TCG_Log_Ex with log type = TBS_TCGLOG_DRTM_BOOT

  • drtm_resume_log (BASE64URL(OCTETS)): DRTM resumes log as retrieved by function Tbsi_Get_TCG_Log_Ex with log type = TBS_TCGLOG_DRTM_RESUME

  • aik_cert (BASE64URL(OCTETS)): The X.509 certificate for the AIK as returned by function NCryptGetProperty with property = NCRYPT_CERTIFICATE_PROPERTY

  • aik_pub: The public part of the AIK represented as a JSON Web Key (JWK) object (RFC 7517)

  • current_claim (BASE64URL(OCTETS)): The attestation claim for the current PCR state as returned by function NCryptCreateClaim with dwClaimType = NCRYPT_CLAIM_PLATFORM and parameter NCRYPTBUFFER_TPM_PLATFORM_CLAIM_PCR_MASK set to include all PCRs. The challenge sent by the service should also be used in the computation of this claim

  • boot_claim (BASE64URL(OCTETS)): The attestation claim for the PCR state at boot as returned by function NCryptCreateClaim with dwClaimType = NCRYPT_CLAIM_PLATFORM and parameter NCRYPTBUFFER_TPM_PLATFORM_CLAIM_PCR_MASK set to include all PCRs

vsm_report (BASE64URL(OCTETS)): The VBS enclave attestation report as returned by function EnclaveGetAttestationReport. The EnclaveData parameter must be the SHA-512 hash of the value of report_signed (including the opening and closing braces). The hash function input is UTF8(report_signed)

attest_key: The public part of the enclave key represented as a JSON Web Key (JWK) object (RFC 7517)

custom_claims: Array of custom enclave claims sent to the service that can be evaluated by the policy. The claim

  • name (String): Name of the claim. This name will be appended to a url determined by the Attestation Service (to avoid conflicts) and the concatenated string becomes the type of the claim that can be used in the policy

  • value (String): Value of the claim

  • value_type (String): Data type of the claim’s value

service_context (BASE64URL(OCTETS)): Opaque context created by the service.

Report message

Direction

Azure Attestation -> Client

Payload

{
  "report": "<JWT>"
}

report (JWT): The attestation report in JSON Web Token (JWT) format (RFC 7519).

Next steps