# KBS Attestation Protocol

The Key Broker Service attestation protocol defines communication between a
Key Broker Client (KBC) in a confidential guest and a trusted Key Broker
Service (KBS). The protocol uses the simple, universal, and extensible
"Request-Challenge-Attestation-Response" (RCAR) method to facilitate guest
attestation and secret injection.

# Introduction

The purpose of the attestation between KBS and KBC is to confirm whether **the
platform where the KBC is located is in the expected security state**, i.e. if
it runs in a trustworthy HW-TEE, and the software stack is measured and
verifiable.

In this document, the HW-TEE attestation process is the semantics of the
application layer, which is defined as a simple, universal and extensible
`RCAR` protocol. The temporary asymmetric key generated by HW-TEE is used to
encrypt the response output payload, and the standard
[HTTP Cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies)
mechanism is used to avoid the performance problems caused by multiple
attestations: it's fairly typical for the KBC to require several resources,
resulting in multiple Requests to the KBS. Having to do the whole attestation
dance would be time consuming and have a latency impact on the guest.

In order to ensure the ease of use and security completeness of KBS, we will use
[HTTPS](#http-integration) as the transport protocol to carry the application
layer semantics designed in this document. This is because HTTPS provides KBC
with a means to authenticate KBS identity, which effectively avoids malicious
attackers from hijacking KBS address to impersonate KBS and deceive KBC.
In order to achieve this, the public key of KBS needs to be transmitted to KBC
through an effective way, and the specific way of public key distribution is out
of this document scope.

It should be noted that the confidentiality protection provided by HTTPS alone
is not enough to meet the security requirements of the KBS protocol.
Therefore, as mentioned above, the key generated by HW-TEE needs to be used to
encrypt and protect the confidential data.

# Request-Challenge-Attestation-Response Semantics

The semantics of attestation defined by KBS is a simple and extensible four-step
model, which uses JSON structure to organize information. As follows:

1. **Request**: The KBC sends the initial `Request` payload to the KBS, in order
   to authenticate itself against the KBS, and eventually request resources.
2. **Challenge**: After receiving the initial `Request` payload, the KBS
   responds with the `Challenge` payload. This is how the KBS sends the
   attestation challenge to the KBC. Together with the attestation challenge,
   the KBS also sends a session identifier to the KBC, as an HTTP Cookie. This
   session identifier can be used to skip steps 2 and 3 after a successful
   attestation.
3. **Attestation**: The KBC replies to the attestation challenge from step 2
   with an attestation evidence, in order to prove that its environment (HW-TEE)
   is safe and reliable. The KBC sends an `Attestation` payload to the KBS, that
   contains the attestation evidence and the HW-TEE generated, ephemeral public
   key.
4. **Response**: The KBS returns a `Response` payload to a KBC requesting a
   resource if and only if the `Attestation` payload was successfully validated.
   The KBC requests resources by sending HTTP `GET` requests to resource
   specific endpoints. Within the valid time of the HTTP Cookie generated by the
   KBS during step 2, the KBC can directly request resources or services from
   KBS, without going through steps 2 and 3.

# Payloads

## `Request`

The payload format of the request is as follows:

```json
{
    /* KBS protocol version number used by KBC */
    "version": "0.1.1",
    /*
     * Type of HW-TEE platforms where KBC is located,
     * e.g. "intel-tdx", "amd-sev-snp", etc.
     */
    "tee": "$tee",
    /* Reserved fields to support some special requests sent by HW-TEE. */
    "extra-params": {}
}
```
> **Note:** the `/*...*/` comments are not valid in JSON, and must not be used.

- `version`

The protocol version number supported by KBC. KBS needs to judge whether this
KBC can communicate normally according to this field.

- `tee`

Used to declare the type of HW-TEE platform where KBC is located, the valid
values are `intel-tdx`, `intel-sgx` and `amd-sev-snp`.

- `extra-params`

In the run-time attestation scenario (Intel TDX and SGX, AMD SEV-SNP), the
`extra-params` field is not used, so is set to the empty string. However, for
the attestation of some special HW-TEE platforms, this field may be used to
transfer some specific information. For example, some attestations follow the
Diffie–Hellman key exchange protocol to first build a secure channel and
transfer secret messages (Such as AMD SEV(-ES) pre-attestation).

## `Challenge`

If the KBC does not own any KBS generated HTTP Cookie, or if the Cookie validity
has expired, the KBC can not directly request resources and the KBS respond with
an error to the KBC requests. The KBC must first go through the attestation
process and send an initial [`Request`](#request) payload to the KBS. The KBS
will then respond to it with an attestation challenge described in the following
format:

```json
{
    /* Evidence freshness. */
    "nonce": "$nonce",
    /* Extra parameters to support some special HW-TEE attestation. */
    "extra-params": {}
}
```
> **Note:** the `/*...*/` comments are not valid in JSON, and must not be used.

- `nonce`

The freshness number passed to KBC. KBC needs to place it in the evidence sent
to the KBS in the next step to prevent replay attacks.

- `extra-params`

The reserved extra parameter field which is used to pass the additional
information provided by the KBS when some specific HW-TEE needs to be attested.

## `Attestation`

After receiving the attestation challenge, the KBC builds an attestation
evidence from the HW-TEE platform and organizes it into the following payload:

```json
{
    /*
     * A JWK-formatted public key, generated by the KBC running in the HW-TEE.
     * It is valid until the next time an attestation is required. Its hash must
     * be included in the HW-TEE evidence and signed by the HW-TEE hardware.
     */
    "tee-pubkey": $pubkey

    /* The attestation evidence. Its format is specified by Attestation-Service. */
    "tee-evidence": {}
}
```
> **Note:** the `/*...*/` comments are not valid in JSON, and must not be used.

The KBS matches the attestation evidence to an attestation challenge with the
HTTP Cookie that the KBC includes in the HTTP request that contains the
`Attestation` payload.

- `tee-pubkey`

After KBC receives the attestation challenge, an ephemeral asymmetric key pair
is generated in HW-TEE. The private key is stored in HW-TEE. The public key and
its description information are exported and placed in the `tee-pubkey` field
and sent to the KBS together with the attestation evidence. The hash of the
`tee-pubkey` field must be included in the custom field of HW-TEE evidence and
signed by HW-TEE hardware. This public key is valid until the next time the KBC
receives an attestation challenge from the KBS.

The `tee-pubkey` follows the  [JSON Web Key](https://www.rfc-editor.org/rfc/rfc7517)
format, as described in the [key format](#key-format) section.

- `tee-evidence`

The attestation evidence is generated by the HW-TEE platform software and hardware
in the KBC's execution environment.
The `tee-evidence` formats depend on the TEE and are typically defined by the
Attestation-Service.

The KBS does not parse or analyze the attestation evidence, it forwards it to
the Attestation-Service for verification.

## `Response`

Upon successful attestation, the KBC can request resources from the KBS, by
sending HTTP `GET` requests to it.

If the KBS approves the request, it responds to the KBC by sending a `Response`
payload that follows the [JSON Web Encryption](https://www.rfc-editor.org/rfc/rfc7516)
[flattened serialization format](https://www.rfc-editor.org/rfc/rfc7516#section-7.2.2):

``` json
{
    "protected": "$jose_header",
    "encrypted_key": "$encrypted_key",
    "iv": "$iv",
    "ciphertext": "$ciphertext",
    "tag": "$tag"
}

```

The above JWE JSON fields are defined as follows:

``` rust
let jose_header_string = format!(r#"{{"alg": "{}","enc": "{}"}}"#, alg, enc);
let jose_header = base64_url::encode(&jose_header_string);
let encrypted_key = base64_url::encode(enc_kbs_symkey);
let iv = base64_url::encode(initialization_vector);
let ciphertext = base64_url::encode(response_output);

// tag is optional and depends on the encryption algorithm.
tag = base64_url::encode(authentication_tag);

```

- `alg`

Algorithm used to encrypt the encryption key at `encrypted_key`.
Since the key is encrypted using the HW-TEE public key, `alg` must be the same
value as described in the [`Attestation`](#attestation)'s `tee-pubkey` field.

- `enc`

Encryption algorithm used to encrypt the output of the KBS service API.

- `ciphertext`

The output of the KBS service API. It must be encrypted with the KBS-generated
ephemeral key.

- `iv`

The input to a cryptographic primitive is used to provide the initial state.
If the algorithm described by `enc` used does not need it, this field is left
blank.

- `encrypted_key`

The encrypted symmetric key is used to encrypt `ciphertext`.
This key is encrypted with the HW-TEE's public key, using the algorithm defined
in `alg`.

## Key Format

### Public Key

The [`Attestation`](#attestation) and the [Token Resource](#token-resource)
`tee-pubkey` field contains a public key from a HW-TEE generated asymmetric
key pair.

This field follows the [JSON Web Key](https://www.rfc-editor.org/rfc/rfc7517)
format.

``` json
{
    "kty": "RSA",
    "alg": "$key_algorithm",
    "n": "$pubkey_modulus",
    "e": "$pubkey_exponent"
}
```

# HTTP Integration

KBS uses the HTTPS transport protocol to exchange the above described
attestation messages, as HTTP requests and responses payloads.

The first step in the HTTP-based KBS attestation protocol described here allows
for an attester to authenticate itself against a trusted Key Brokering Service.
The second step is when an attester requests one or more protected resources
from the KBS. The resources are delivered by the KBS back to the attester based
on the HTTP Cookie bound authentication results.

## Authentication

Before being able to request a protected resource (a key, a token, etc.), an
attester must authenticate itself against the remote KBS. Only after successfully
authenticated itself, it can request those resources.

The authentication service is provided by the KBS through two endpoints:

1. `/kbs/v0/auth` only accepts `POST` requests whose body is a [KBS Request](#request)
   JSON payload. This endpoint is for the attester to initiate the attestation
   protocol and authenticate itself against the KBS. The KBS reply HTTP response
   is composed of:
   1. A `Set-Cookie` header set to `kbs-session-id=<session>`. The KBS tracks
   the attester and its attestation results with that cookie.
   2. An attestation challenge for the attester to take. This is the content of
   the response, set to a [KBS Challenge](#challenge) JSON payload.
   3. In case of an error (such as if the KBS rejects the [KBS Request](#request) based
   on `version` compatibility), an HTTP response with a 401 (`Unauthorized`) status code
   together with ErrorInformation JSON payload.

2. `/kbs/v0/attest` only accepts `POST` requests whose body is a [KBS Attestation](#attestation)
   JSON payload and the header contains a `Cookie` set to the value received in
   step 1.i. This is how the attester replies to attestation challenge received
   in step 1.ii. If the attestation was successful, the KBS replies to that request with an 
   [Attestation Results Token](#attestation-results-token).

```
┌──────────┐                                          ┌─────┐
│ Attester │                                          │ KBS │
└────┳─────┘                                          └──┳──┘
     ┃                 ┌─────────────────┐               ┃
     ┃─────────────────│POST /kbs/v0/auth│──────────────▶┃
     ┃                ┌┴─────────────────┴┐              ┃
     ┃                │Header: No Cookie  │              ┃
     ┃                │Body: Request      │              ┃
     ┃                └───────────────────┘              ┃
     ┃                     ┌────────┐                    ┃
     ┃◀────────────────────│Response│────────────────────┃
     ┃      ┌──────────────┴────────┴───────────────┐    ┃
     ┃      │Header: "Set-Cookie kbs-session-id=123"│    ┃
     ┃      │Body: Challenge                        │    ┃
     ┃      └───────────────────────────────────────┘    ┃
     ┃                                                   ┃
     ┃                                                   ┃
     ┃                                                   ┃
     ┃                                                   ┃
     ┃                                                   ┃
     ┃                ┌───────────────────┐              ┃
     ┃────────────────│POST /kbs/v0/attest│─────────────▶┃
     ┃        ┌───────┴───────────────────┴───────┐      ┃
     ┃        │Header: "Cookie kbs-session-id=123"│      ┃
     ┃        │Body: Attestation                  │      ┃
     ┃        └───────────────────────────────────┘      ┃
     ┃                     ┌────────┐                    ┃
     ┃◀────────────────────│Response│────────────────────┃
     ┃      ┌──────────────┴────────┴───────────────┐    ┃
     ┃      │Header: "Set-Cookie kbs-session-id=123"│    ┃
     ┃      │Body: Attestation Results Token        │    ┃
     ┃      └───────────────────────────────────────┘    ┃
     ┃                                                   ┃
     ┃                                                   ┃
     ┃                                                   ┃
     ▽                                                   ▽
               Figure 1: KBS Authentication Phase

```

## Resource Requests

The [authentication](#authentication) phase is the first step of the overall KBS
protocol, where attesters authenticate themselves against a KBS implementation.
This leads to the second phase, during which authenticated attesters can request
protected resources from the KBS.

Attesters can access protected resources by providing the KBS with either the HTTP
cookie or the Attestation Results token returned as part of the Attestation HTTP
response. The former is usually short-lived and is typically used for one-time,
synchronous resources request. For longer KBS sessions, it is more convenient to
use the latter.    

### HTTP Cookie Authentication

The KBS implementation keeps track of attestation results and binds them to a
cookie identifier. During the second phase, the KBS can then decide if a
specific resource could be released to a given attester, by mapping the cookie
identifier the attester includes in its resource request message to its
attestation results.

To request a protected resource from the KBS, the attester sends a `GET` request
to a resource specific endpoint. If the attester is allowed to access the
resource, the KBS will respond to the `GET` request with an HTTP response which
content is set to a [KBS Response](#response) JSON payload:

```
┌──────────┐                                         ┌─────┐
│ Attester │                                         │ KBS │
└───┳──────┘                                         └──┳──┘
    ┃            ┌─────────────────────────┐            ┃
    ┃────────────│GET /kbs/v0/<resource_id>│───────────▶┃
    ┃      ┌─────┴─────────────────────────┴────┐       ┃
    ┃      │Header: "Cookie kbs-session-id=123" │       ┃
    ┃      │Body: N/A                           │       ┃
    ┃      └────────────────────────────────────┘       ┃
    ┃                    ┌────────┐                     ┃
    ┃◀───────────────────│Response│─────────────────────┃
    ┃     ┌──────────────└────────┘───────────────┐     ┃
    ┃     │Header: "Set-Cookie kbs-session-id=123"│     ┃
    ┃     │Body: Response                         │     ┃
    ┃     └───────────────────────────────────────┘     ┃
    ┃                                                   ┃
    ┃                                                   ┃
    ┃                                                   ┃
    ▽   Figure 2: KBS Resource Request Phase - Session  ▽
```

A request for protected resource can fail for three reasons:

1. The requester is not authenticated and thus can not provide the right cookie
   identifier. The KBS implementation sends an HTTP response with a 401
   (`Unauthorized`) status code.
2. The attester is authenticated but requests a resource that it's not allowed
   to receive. The KBS implementation sends an HTTP response with a 403
   (`Forbidden`) status code.
3. The requested resource does not exist. The KBS implementation sends an HTTP
   response with a 404 (`Not Found`) status code.

### Attestation Results Token Authentication

As part of the Authentication process, the requester generates a TEE asymmetric key 
pair. Upon successful Attestation, the KBS provisions a token that contains the
Attestation Results and endorsements for the TEE public key.

To request a protected resource from the KBS, the attester sends a `GET` request
to a resource specific endpoint with the token as the bearer authorization. If the
token passes verification, the KBS will respond to the `GET` request with an HTTP
response whose content is set to a [KBS Response](#response) JSON payload. The
symetric key inside the [KBS Response](#response) JSON payload will be wrapped by
the public key inside the token.

```
┌──────────┐                                         ┌─────┐
│ Attester │                                         │ KBS │
└───┳──────┘                                         └──┳──┘
    ┃            ┌─────────────────────────┐            ┃
    ┃────────────│GET /kbs/v0/<resource_id>│───────────▶┃
    ┃      ┌─────┴─────────────────────────┴────┐       ┃
    ┃      │Header: Authorization Bearer        │       ┃
    ┃      │Body: N/A                           │       ┃
    ┃      └────────────────────────────────────┘       ┃
    ┃                    ┌────────┐                     ┃
    ┃◀───────────────────│Response│─────────────────────┃
    ┃     ┌──────────────└────────┘───────────────┐     ┃
    ┃     │Header: No Cookie                      │     ┃
    ┃     │Body: Response                         │     ┃
    ┃     └───────────────────────────────────────┘     ┃
    ┃                                                   ┃
    ┃                                                   ┃
    ┃                                                   ┃
    ▽    Figure 3: KBS Resource Request Phase - Token   ▽
```

A request for protected resource can fail for three reasons:

1. The requester is not authenticated and thus can not provide the valid token.
   The KBS implementation sends an HTTP response with a 401 (`Unauthorized`) status code.
2. The attester is authenticated but requests a resource that it's not allowed
   to receive. The KBS implementation sends an HTTP response with a 403
   (`Forbidden`) status code.
3. The requested resource does not exist. The KBS implementation sends an HTTP
   response with a 404 (`Not Found`) status code.

### Secret Resource

KBS uses the following path format to locate secret resources:

```
/kbs/v0/resource/<repository>/<type>/<tag>
```

Where the URL path parameters are:

- `<repository>`: This is similar to the concept of container image repository (`docker.io/{repository}/{image_name}:{tag}`), 
which is used to facilitate users to manage different resource groups.
Its name should be completely set by users.
This parameter can be empty to use the default repository of KBS.
- `<type>`: To distinguish different resource types.
- `<tag>`: To distinguish different resource instances.

The decision to reply successfully to an attester resource request for a
specific resource instance belongs to the KBS and its underlying attestation service.
The decision is typically based on both the attestation evidence, results and
provisioned policies for a given attester.

#### Resource Registration (Experimental)

A POST request with the content of resource to `/kbs/v0/resource/<repository>/<type>/<tag>` can register the resource into the KBS.


### Attestation Results Token

Authenticated attesters can also receive an attestation token from the KBS in the response body of `/kbs/v0/attest`.
Attesters can use the attestation result token to request additional resources from external services, a.k.a. relying parties. 

The provided attestation results token follows the [JSON web token](https://datatracker.ietf.org/doc/html/rfc7519) standard and format.

##### Header

This is the Base64url encoding of a [JOSE](https://jose.readthedocs.io/en/latest/)
header.

It is JSON-formatted and contains both the token standard format (`typ`) and the
token signature algorithm (`alg`). For example:

```json
{
    "typ": "JWT",
    "alg": "RS256"
}

```

##### Payload

This is the Base64url encoding of a set of JSON-formatted claims, like the
following example:

``` json
{
    "exp": 1568187398,
    "iat": 1568158598,
    "iss": "https://xxxxxx",
    "jwk": $token-pubkey,

    "tee-pubkey": $pubkey,
    "tcb-status": $claims,
    "evaluation-report": $report,
}
```

The token payload is divided into registered and private claims sets. The KBS
might also include additional public claims set.

The registered claims set must include the `exp`, `iat`', `iss` and `jwk` names, which
respectively declare the expiration time, issuing time and issuer (KBS URL
address) of the token:

| Field | Description     | Type                    | Example              |
|-      |-                |-                        |-                     |
| `exp` | Expiration time | Seconds since the epoch | `99991231235959`     |
| `iat` | Issuing time    | Seconds since the epoch | `180322235959`       |
| `iss` | Issuer          | KBS URL                 | `https://my-kbs.io/` |
| `jwk` | Public key to verify token signature | RSA Json Web Key | |

The custom claims set must include the attestation result from the
`Attestation Service`, which include the TCB status and measurements.

The custom claims set can also include a `tee-pubkey` claim. This claim refers to
the HW-TEE's public key sent by the KBC along with the attestation evidence,
which is valid within the validity period of the token.

`evaluation-report` is the output of the policy engine of the `Attestation Service`,
it is AS policy's evaluation opinion on TEE evidence.

When the KBC uses this token to request resources or services from a relying
party service API, then the symmetric key used to encrypt the output payload can
be wrapped with the provided `tee-pubkey`.

### Set Attestation Policy
User of KBS can set an attestation verification policy through the following endpoint:

```
/kbs/v0/attestation-policy
```

The payload of the POST request should like:

```json
{
    "type": "rego",
    "policy_id": "default",
    "policy": <base64encoded policy>
}
```

Where `type` is the policy format (e.g. `rego` or `opa`), `policy_id` provides the policy ID
and `policy` is the base64 encoded policy content.
Only authenticated users can send a POST request to this endpoint.
KBS verifies the user identity with the user's private key signed JSON Web Token (JWT) that must be included in the request.

### Set Resource Policy
User of KBS can set an resource policy through the following endpoint:

```
/kbs/v0/resource-policy
```
 The payload of the POST request should like:

 ```json
 {
    "policy": <base64encoded policy>
 }
 ```

 Where `policy` is the base64 encoded policy content.
Only authenticated users can send a POST request to this endpoint.
KBS verifies the user identity with the user's private key signed JSON Web Token (JWT) that must be included in the request.

##### Signature

Using the algorithm described in the token header, the KBS signs the
concatenation of the token header and the token payload, separated by a dot
(`.`). The token signature is the Base64url encoded string for that
signature.

#### HTTP Response

The token is included in the `/kbs/v0/attest` `POST` HTTP response
body:
```json
{
    "token": <token>
}
```

A serialized token is built as follows:

``` rust
let jwt_header = base64_url::encode(r#"{{"alg": "RS256","typ": "JWT"}}"#);

let jwt_claims_string = format!(r#"{{"exp": {}, "iat": {}, "iss": {}, {}}}}"#, exp, iat, iss, claims);
let jwt_claims = base64_url::encode(&jwt_claims_string);

let jws_signature_input = format!("{}.{}", jwt_header, jwt_claims);
let jws_signature = base64_url::encode(rs256_key_pair.sign(&jws_signature_input));

let serialized_token = format!("{}.{}.{}", jwt_header, jwt_claims, jwt_signature);
```

## Error information

In addition to using the standard HTTPS status code to represent the returned
error type, it is also necessary to provide a detailed description of the
attestation error.
The [Problem Details for HTTP APIs](https://www.rfc-editor.org/rfc/rfc7807)
format is used for that purpose:

```json
{
    "type": "https://github.com/confidential-containers/kbs/errors/<problem-type>",
    "detail": "$detail"
}
```

## OpenAPI Description

The KBS HTTP endpoints and payloads are
[formally described](./kbs.yaml)
in an [OpenAPI](https://www.openapis.org/) compliant format.

# Acknowledgements

The following individuals were instrumental in the development of this protocol:

* Ding Ma (@Xynnn007)
* James O. D. Hunt (@jodh-intel)
* Jia Zhang (@jiazhang0)
* Jiale Zhang (@jialez0)
* Samuel Ortiz (@sameo)
* Sergio Lopez (@slp)
* Thomas Fossati (@thomas-fossati)
* Tobin Feldman-Fitzthum (@fitzthum)

