Skip to content

Configuring Conclave to use a key from a Key Derivation Service

Conclave enclaves are able to use a key from a Key Derivation Service (KDS) for encrypting data that will be persisted outside the enclave. Using a key from a KDS allows the encrypted data that is persisted by an enclave to be accessed by the enclave even if it is moved to another physical machine. Without the KDS, moving an enclave to a different physical machine renders any encrypted persisted data unreadable, effectively cryptographically erasing the data.

R3 provides an instance of a Conclave Key Derivation Service (KDS) as part of the Conclave Platform that can be used by any Conclave enclave to obtain stable keys for persisting data regardless of what physical system the enclave is running on.

This page describes how to configure your enclave project to use a KDS key. For a more detailed description of how this works and the reasons behind using a KDS, please take a look here.

Configuring the KDS URL

For an enclave to obtain a key from the KDS, the URL of the KDS and the specification of the key to obtain must both be configured by the developer.

The KDS connection is configured in the host application. The configuration consists of parameters that specify the URL to use to connect to the KDS, and a duration after which an unresponsive connection to the KDS will timeout.

Note

If you configure your enclave to use a KDS key but do not provide a KDS configuration for the host then enclaves built in release mode will not start. Enclaves built in non-release modes will start but will use a key derived from the signer of the enclave, bound to the CPU of the system. This allows for development without a connection to the KDS.

If you are using the web host then you can specify the KDS connection parameters on the command line when starting your service:

1
2
--kds.url=https://kds.dev.conclave.cloud
--kds.connection.timeout.seconds=60

Otherwise if you are developing your own host application you use KDSConfiguration to specify these parameters then pass the configuration to EnclaveHost.start:

1
2
3
4
5
6
7
import com.r3.conclave.host.kds.KDSConfiguration;

...

KDSConfiguration kdsConfiguration = new KDSConfiguration("https://kds.dev.conclave.cloud");
EnclaveHost enclaveHost = EnclaveHost.load("com.example.MyEnclave");
enclaveHost.start(null, null, null, kdsConfiguration) {}

Note

The URL for the public preview of the R3 hosted KDS is https://kds.dev.conclave.cloud. This is URL might be changed in a later deployment of the KDS.

Configuring the key specification

The key specification to use within an enclave is configured in the build configuration for that enclave. The state of the configuration is included in the enclave binary and, as such, its measurement is included in the EnclaveInstanceInfo remote attestation report for the enclave. This ensures the key specification is not tampered with.

The key specification is defined in the build configuration as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
conclave {
  ...
  kds {
    kdsEnclaveConstraint = "S:4924CA3A9C8241A3C0AA1A24A407AA86401D2B79FA9FF84932DA798A942166D4 PROD:1 SEC:STALE"
    keySpec {
      masterKeyType = "debug"
      policyConstraint {
        constraint = "<your policy constraints>"
        useOwnCodeHash = (true|false)                 // Optional
        useOwnCodeSignerAndProductID = (true|false)   // Optional
      }
    }
  }
  ...
}

Taking a look at the configuration above, we first have a kds {} section which contains all KDS related configuration. This section contains the kdsEnclaveConstraint property, which defines the enclave constraints to use during attestation when getting a key from the KDS enclave.

Warning

A sample key is intentionally being used to sign the KDS as it is not ready for production. The sample key used is the same signing key that is used in the hello-world sample but this will change when the KDS goes into production.

Next we have the keySpec {} section. This section contains parameters which define how the KDS generates keys. This section contains the masterKeyType property, which defines the type of master key to use (for now, only "debug" is supported).

Finally, we have the policyConstraint {} section, which defines the constraints which the enclave must meet in order to access the key generated by the KDS. This section contains the constraint, useOwnCodeHash, and useOwnCodeSignerAndProductID properties. Read on for more information regarding usage of these properties.

Defining the PolicyConstraint

The key policy constraint can be thought of as similar to the EnclaveConstraint object which is used during attestation to define the minimum security attributes of an enclave's EnclaveInstanceInfo object before initiating communication. It can be configured in much the same way by setting the constraint property using the enclave constraint DSL. In this case however, the KDS imposes the key policy constraint on the EnclaveInstanceInfo of the requesting enclave before releasing a key to it.

As noted before, the measurement of the key policy constraint is included in the EnclaveInstanceInfo for the enclave. This poses a problem as the enclave code measurement and signer of the enclave are not known at build time. To get around this, the policyConstraint section allows the constraint to be defined programmatically using the useOwnCodeHash and useOwnCodeSignerAndProductID properties.

The effect of these properties is to constrain access to the key in different ways. If you want to include the enclave measurement in the constraint, effectively tying the key to an exact version of the enclave code, then this can be done by setting the useOwnCodeHash property to true. Alternatively, if you want subsequent versions of an enclave to be able to access data persisted by previous versions of that enclave, then you can set useOwnCodeSignerAndProductID to true instead. This will effectively tie the key to a specific product and signer, but not to a specific version of the enclave code. These parameters may be used together to generate keys which are unique to both the enclave signer & product ID, and the specific version of the enclave.

What PolicyConstraint should I specify?

The policyConstraint section defines exactly which enclaves can access the key defined by the specification. It is important to choose a constraint which is strict enough to prevent unauthorised enclaves from accessing the key, but also one that is lenient enough to allow for upgrades of enclave code and data migration if required. This will vary depending on the needs of the project.

The constraint is specified by adding constraint parameters by calling the functions described below, or by adding rules in the EnclaveConstraint defined inside the PolicyConstraint. When calling functions on PolicyConstraint, each function returns the current PolicyConstraint so can be chained together to define a combination of constraints.

Parameter
Implications
policyConstraint { useOwnCodeHash = true } Only enclaves with exactly the same code hash as the currently loaded enclave will have access to the key. If the enclave code is modified in any way then a different key will be derived by the KDS causing any data persisted with the original key to be inaccessible in the new enclave.
policyConstraint { constraint = "C:<code hash>" } Only enclaves with the specified code hash will have access to the key. Due to the fact that it is impossible for an enclave to know its own code hash until it is built, this configuration cannot be used for authorising the current enclave. Instead use useOwnCodeHash() without arguments. This option can be used for allowing two or more different enclaves access to the same key. As many code hashes as necessary can be added by chaining calls to useOwnCodeHash(hash)
policyConstraint { useOwnCodeSignerAndProductID = true } Any enclave that is signed with the same key as the one used to sign this enclave and has the same product ID as this enclave can access the key. When used in isolation, this allows for easy upgrade of enclaves as any enclave signed with the same key and having the same product number will result in the same key being derived by the KDS, allowing persisted data to be shared between all versions of the enclave.
policyConstraint { constraint = "S:<code signing key hash> PROD:<product id>" } Any enclave that is signed with the specified signing key hash and has the specified product ID can access the key. Please note that although multiple signers can be added, Conclave constraints currently only support a single product ID.
policyConstraint { constraint = "REVOKE:<min revocation level>" } Specifying a value for the minimum revocation level ensures that an enclave will only be given access to a key if the revocationLevel field defined when the enclave was built is greater than or equal to the value specified in this constraint. Whenever you release a new version of your enclave that fixes any bugs or security issues, you should increment the revocationLevel for the new enclave and update this constraint to match the new version.
policyConstraint { constraint = "SEC:<security level>" } Any enclave is running on a platform that meets at a minimum the specified security level will be allowed access to the key. For a production enclave built in release mode you should set the minimum security level to STALE or SECURE

Example PolicyConstraint configurations

Exact version of an enclave running on a secure platform

This example shows how to ensure that a key is only accessible to an exact version of an enclave. If any code is changed within the enclave and it is rebuilt then the modified enclave will not have access to the original key.

In addition, the enclave must be running on a fully patched, up-to-date Intel SGX capable system. If any new security updates are available for the platform, even if the platform is not considered insecure, then the key will not be provided to the enclave.

When using this configuration it is not possible to migrate data to a new version of the enclave, unless the developer included functionality in the original enclave to explicitly export data encrypted using a different key.

1
2
3
4
5
6
7
8
kds {
  keySpec {
    policyConstraint {
      constraint = "SEC:SECURE"
      useOwnCodeHash = true
    }
  }
}

Exact version of an enclave running on a platform that may need updating

This example is similar to above, but allows the key to be provided to an enclave running on a platform where a security update is available, as long as the platform has not been flagged as insecure. This will allow the service that uses the enclave to continue running whilst giving the system administrator time to deploy the patch to the system, bringing it back to the SECURE state.

1
2
3
4
5
6
7
8
kds {
  keySpec {
    policyConstraint {
      constraint = "SEC:STALE"
      useOwnCodeHash = true
    }
  }
}

Any enclave for a particular product signed using the same key

This example allows any enclave running any code to access the key as long as it is signed with the same signing key, is part of the same product and is running on a secure platform.

The combination of a signing key and a product ID allows for unique keys to be generated per product, but shared with all versions of enclaves within an single product.

This makes it easy to release new versions of enclaves, or allows multiple different services to share access to persisted data. However, the owner of the code signing key must be trusted enclave clients because they have the ability to author a new enclave that is able to perform any action on data protected using the signing key.

This example is probably most suitable where the service author is trusted, or when using an external auditor to validate enclave code and sign the enclave on the developer's behalf.

1
2
3
4
5
6
7
8
kds {
  keySpec {
    policyConstraint {
      constraint = "SEC:SECURE"
      useOwnCodeSignerAndProductID = true
    }
  }
}