0.3.0
- 0.3.0
- Introduce MRK Compatibility via KMS Configuration
- 0.2.0
- Update keystore structure and add encryption context option
- 0.1.0
- Initial record
Language | Confirmed Compatible with Spec Version | Minimum Version Confirmed | Implementation |
---|---|---|---|
Dafny | 0.3.0 | 1.3.0 | AwsCryptographyKeyStoreOperations.dfy |
Java | 0.3.0 | 1.3.0 | KeyStore.java |
.NET | 0.3.0 | 1.3.0 | KeyStore.cs |
A Keystore persists hierarchical data that allows customers to call AWS KMS less often. The Keystore persists branch keys in DynamoDb that wrap multiple data keys. This creates a hierarchy where a branch key wraps multiple data keys and facilitates caching. These branch keys are only generated using the AWS KMS API GenerateDataKeyWithoutPlaintext.
This Keystore interface defines operations that any implementation of its specification must support and implement.
- Branch Key(s): Data keys that are reused to wrap unique data keys for envelope encryption. For security considerations on when to rotate the branch key, refer to Appendix B.
- Beacon Key(s): A root key used to then derive different beacon keys per beacon.
- UUID: a universally unique identifier that can be represented as a byte sequence or a string.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
The following inputs MAY be specified to create a KeyStore:
The following inputs MUST be specified to create a KeyStore:
The Identifier for this KeyStore. If one is not supplied, then a version 4 UUID MUST be used.
A list of AWS KMS grant tokens.
The DynamoDb Client used to put and get keys from the backing DDB table.
If not provided, one will be created in the region of the supplied KMS Key ARN.
The KMS Client used when wrapping and unwrapping keys.
If not provided, one will be created in the region of the supplied KMS Key ARN.
On initialization the KeyStore MUST append a user agent string to the AWS KMS SDK Client with the
value aws-kms-hierarchy
.
The table name of the DynamoDb table that backs this Keystore.
A valid AWS KMS Key ARN that wraps and unwraps keys stored in Amazon DynamoDB.
The KMS Configuration MUST distinguish between Single Region Key ARN compatibility and Multi Region Key (MRK) ARN compatibility.
Both compatibility modes are allowed with both MRK ARN's and Single Region ARNs.
For two ARNs to be compatible:
If the AWS KMS Configuration designates single region ARN compatibility, then two ARNs are compatible if they are exactly equal.
If the AWS KMS Configuration designates MRK ARN compatibility, then two ARNs are compatible if they are equal in all parts other than the region. That is, they are compatible if AWS KMS MRK Match for Decrypt returns true.
This name is cryptographically bound to all data stored in this table, and logically separates data between different tables.
The logical keystore name MUST be bound to every created key.
There needs to be a one to one mapping between DynamoDB Table Names and the Logical KeyStore Name. This value can be set to the DynamoDB table name itself, but does not need to.
Controlling this value independently enables restoring from DDB table backups even when the table name after restoration is not exactly the same.
The Keystore MUST support the following operations:
- GetKeyStoreInfo
- CreateKeyStore
- CreateKey
- VersionKey
- GetActiveBranchKey
- GetBranchKeyVersion
- GetBeaconKey
This operation MUST return the keystore information in this keystore configuration.
This MUST include:
This operation MUST first calls the DDB::DescribeTable API with the configured tableName
.
If the response is successful, this operation validates that the table has the expected KeySchema as defined below. If the KeySchema does not match this operation MUST yield an error. The table MAY have additional information, like GlobalSecondaryIndex defined.
If the client responds with a ResourceNotFoundException
,
then this operation MUST continue and
MUST call AWS DDB CreateTable
with the following specifics:
- TableName is the configured tableName.
- KeySchema as defined below.
If the operation fails to create table, the operation MUST fail.
If the operation successfully creates a table, the operation MUST return the AWS DDB Table Arn back to the caller.
The following KeySchema MUST be configured on the table:
AttributeName | KeyType | Type |
---|---|---|
branch-key-id | Partition | S |
type | Sort | S |
The CreateKey caller MUST provide:
- An optional branch key id
- An optional encryption context
If an optional branch key id is provided and no encryption context keys are provided this operation MUST fail.
If no branch key id is provided, then this operation MUST create a version 4 UUID to be used as the branch key id.
This operation MUST create a branch key and a beacon key according to the Branch Key and Beacon Key Creation section.
If creation of the keys are successful, the operation MUST call Amazon DynamoDB TransactWriteItems according to the write key material section.
If writing to the keystore succeeds, the operation MUST return the branch-key-id that maps to both the branch key and the beacon key.
Otherwise, this operation MUST yield an error.
To create a branch key, this operation MUST take the following:
branchKeyId
: The identifierencryptionContext
: Additional encryption context to bind to the created keys
This operation needs to generate the following:
version
: a new guid. This guid MUST be version 4 UUIDtimestamp
: a timestamp for the current time. This timestamp MUST be in ISO 8601 format in UTC, to microsecond precision (e.g. “YYYY-MM-DDTHH:mm:ss.ssssssZ“)
The wrapped Branch Keys, DECRYPT_ONLY and ACTIVE, MUST be created according to Wrapped Branch Key Creation.
To create a beacon key, this operation will continue to use the branchKeyId
and timestamp
as the Branch Key.
The operation MUST call AWS KMS API GenerateDataKeyWithoutPlaintext. The call to AWS KMS GenerateDataKeyWithoutPlaintext MUST use the configured AWS KMS client to make the call. The operation MUST call AWS KMS GenerateDataKeyWithoutPlaintext with a request constructed as follows:
KeyId
MUST be compatible with the configuredAWS KMS Key ARN
in the AWS KMS Configuration for this keystore.NumberOfBytes
MUST be 32.EncryptionContext
MUST be the encryption context for beacon keys.GrantTokens
MUST be this keystore's grant tokens.
If the call to AWS KMS GenerateDataKeyWithoutPlaintext succeeds,
the operation MUST use the CiphertextBlob
as the wrapped Beacon Key.
Given a branchKeyId
, version
and timestamp
The operation MUST call AWS KMS API GenerateDataKeyWithoutPlaintext. The call to AWS KMS GenerateDataKeyWithoutPlaintext MUST use the configured AWS KMS client to make the call. The operation MUST call AWS KMS GenerateDataKeyWithoutPlaintext with a request constructed as follows:
KeyId
MUST be compatible with the configuredAWS KMS Key ARN
in the AWS KMS Configuration for this keystore.NumberOfBytes
MUST be 32.EncryptionContext
MUST be the DECRYPT_ONLY encryption context for branch keys.- GenerateDataKeyWithoutPlaintext
GrantTokens
MUST be this keystore's grant tokens.
If the call to AWS KMS GenerateDataKeyWithoutPlaintext succeeds,
the operation MUST use the GenerateDataKeyWithoutPlaintext result CiphertextBlob
as the wrapped DECRYPT_ONLY Branch Key.
The operation MUST call AWS KMS API ReEncrypt with a request constructed as follows:
SourceEncryptionContext
MUST be the DECRYPT_ONLY encryption context for branch keys.SourceKeyId
MUST be compatible with the configuredAWS KMS Key ARN
in the AWS KMS Configuration for this keystore.CiphertextBlob
MUST be the wrapped DECRYPT_ONLY Branch Key.- ReEncrypt
GrantTokens
MUST be this keystore's grant tokens. DestinationKeyId
MUST be compatible with the configuredAWS KMS Key ARN
in the AWS KMS Configuration for this keystore.DestinationEncryptionContext
MUST be the ACTIVE encryption context for branch keys.
If the call to AWS KMS ReEncrypt succeeds,
the operation MUST use the ReEncrypt result CiphertextBlob
as the wrapped ACTIVE Branch Key.
To add the branch keys and a beacon key to the keystore the operation MUST call Amazon DynamoDB API TransactWriteItems. The call to Amazon DynamoDB TransactWriteItems MUST use the configured Amazon DynamoDB Client to make the call. The operation MUST call Amazon DynamoDB TransactWriteItems with a request constructed as follows:
List of TransactWriteItem:
- PUT:
- Item:
- “branch-key-id” (S):
branchKeyId
, - “type“ (S): "branch:version:" +
version
, - “enc” (B): the wrapped DECRYPT_ONLY Branch Key
CiphertextBlob
from the KMS operation - “create-time” (S):
timestamp
- "kms-arn" (S): configured
KMS Key ARN
- “hierarchy-version” (N): 1
- “branch-key-id” (S):
- ConditionExpression:
attribute_not_exists(branch-key-id)
- TableName: the configured Table Name
- Item:
- PUT:
- Item:
- “branch-key-id” (S):
branchKeyId
, - “type“ (S): "branch:ACTIVE",
- “enc” (B): wrapped ACTIVE Branch Key
CiphertextBlob
from the KMS operation - “create-time” (S):
timestamp
- "kms-arn" (S): configured
KMS Key ARN
- “hierarchy-version” (N): 1
- “branch-key-id” (S):
- ConditionExpression:
attribute_not_exists(branch-key-id)
- TableName: the configured Table Name
- Item:
- PUT:
- Item:
- “branch-key-id” (S):
branchKeyId
, - “type“ (S): "beacon:ACTIVE",
- “enc” (B): the wrapped Beacon Key
CiphertextBlob
from the KMS operation - “create-time” (S):
timestamp
- "kms-arn" (S): configured
KMS Key ARN
- “hierarchy-version” (N): 1
- “branch-key-id” (S):
- ConditionExpression:
attribute_not_exists(branch-key-id)
- TableName is the configured Table Name
- Item:
TransactWriteItemRequest:
- TransactWriteItems: List of TransactWriteItem
If DDB TransactWriteItems is successful, this operation MUST return a successful response containing no additional data. Otherwise, this operation MUST yield an error.
On invocation, the caller:
- MUST supply a
branch-key-id
VersionKey MUST first get the active version for the branch key from the keystore
by calling AWS DDB GetItem
using the branch-key-id
as the Partition Key and "branch:ACTIVE"
value as the Sort Key.
The values on the AWS DDB response item MUST be authenticated according to authenticating a keystore item. If the item fails to authenticate this operation MUST fail.
The wrapped Branch Keys, DECRYPT_ONLY and ACTIVE, MUST be created according to Wrapped Branch Key Creation.
To add the new branch key to the keystore, the operation MUST call Amazon DynamoDB API TransactWriteItems. The call to Amazon DynamoDB TransactWriteItems MUST use the configured Amazon DynamoDB Client to make the call. The operation MUST call Amazon DynamoDB TransactWriteItems with a request constructed as follows:
List of TransactWriteItem:
- PUT:
- Item:
- “branch-key-id” (S):
branchKeyId
, - “type“ (S): "branch:version:" +
version
, - “enc” (B): the wrapped DECRYPT_ONLY Branch Key
CiphertextBlob
from the KMS operation - “create-time” (S):
timestamp
- "kms-arn" (S): configured
KMS Key ARN
- “hierarchy-version” (N): 1
- “branch-key-id” (S):
- ConditionExpression:
attribute_not_exists(branch-key-id)
- TableName: the configured Table Name
- Item:
- PUT:
- Item:
- “branch-key-id” (S):
branchKeyId
, - “type“ (S): "branch:ACTIVE",
- “enc” (B): wrapped ACTIVE Branch Key
CiphertextBlob
from the KMS operation - “create-time” (S):
timestamp
- "kms-arn" (S): configured
KMS Key ARN
- “hierarchy-version” (N): 1
- “branch-key-id” (S):
- ConditionExpression:
attribute_exists(branch-key-id)
- TableName: the configured Table Name
- Item:
TransactWriteItemRequest:
- TransactWriteItems: List of TransactWriteItem
If DDB TransactWriteItems is successful, this operation MUST return a successful response containing no additional data. Otherwise, this operation MUST yield an error.
The operation MUST use the configured KMS SDK Client
to authenticate the value of the keystore item.
Every attribute on the AWS DDB response item will be authenticated.
Every key in the constructed encryption context
except tableName
MUST exist as a string attribute in the AWS DDB response item.
Every value in the constructed encryption context
except the logical table name
MUST equal the value with the same key in the AWS DDB response item.
The key enc
MUST NOT exist in the constructed encryption context.
The operation MUST call AWS KMS API ReEncrypt with a request constructed as follows:
SourceEncryptionContext
MUST be the encryption context constructed aboveSourceKeyId
MUST be compatible with the configuredAWS KMS Key ARN
in the AWS KMS Configuration for this keystore.CiphertextBlob
MUST be theenc
attribute value on the AWS DDB response itemGrantTokens
MUST be the configured grant tokens.DestinationKeyId
MUST be compatible with the configuredAWS KMS Key ARN
in the AWS KMS Configuration for this keystore.DestinationEncryptionContext
MUST be the encryption context constructed above
On invocation, the caller:
- MUST supply a
branch-key-id
To get the active version for the branch key id from the keystore
this operation MUST call AWS DDB GetItem
using the branch-key-id
as the Partition Key and "branch:ACTIVE"
value as the Sort Key.
The AWS DDB response MUST contain the fields defined in the branch keystore record format. If the record does not contain the defined fields, this operation MUST fail.
The operation MUST decrypt the branch key according to the AWS KMS Branch Key Decryption section.
If the branch key fails to decrypt, GetActiveBranchKey MUST fail.
This GetActiveBranchKey MUST construct branch key materials according to Branch Key Materials From Authenticated Encryption Context.
This operation MUST return the constructed branch key materials.
On invocation, the caller:
- MUST supply a
branch-key-id
- MUST supply a
branchKeyVersion
To get a branch key from the keystore this operation MUST call AWS DDB GetItem
using the branch-key-id
as the Partition Key and "branch:version:" + branchKeyVersion
value as the Sort Key.
The AWS DDB response MUST contain the fields defined in the branch keystore record format. If the record does not contain the defined fields, this operation MUST fail.
The operation MUST decrypt the branch key according to the AWS KMS Branch Key Decryption section.
If the branch key fails to decrypt, this operation MUST fail.
This GetBranchKeyVersion MUST construct branch key materials according to Branch Key Materials From Authenticated Encryption Context.
This operation MUST return the constructed branch key materials.
On invocation, the caller:
- MUST supply a
branch-key-id
To get a branch key from the keystore this operation MUST call AWS DDB GetItem
using the branch-key-id
as the Partition Key and "beacon:ACTIVE" value as the Sort Key.
The AWS DDB response MUST contain the fields defined in the branch keystore record format. If the record does not contain the defined fields, this operation MUST fail.
The operation MUST decrypt the beacon key according to the AWS KMS Branch Key Decryption section.
If the beacon key fails to decrypt, this operation MUST fail.
This GetBeaconKey MUST construct beacon key materials from the decrypted branch key material
and the branchKeyId
from the returned branch-key-id
field.
This operation MUST return the constructed beacon key materials.
This section describes how the AWS KMS encryption context is built from the DynamoDB items that store the branch keys.
The following encryption context keys are shared:
- MUST have a
branch-key-id
attribute - The
branch-key-id
field MUST not be an empty string - MUST have a
type
attribute - The
type
field MUST not be an empty string - MUST have a
create-time
attribute - MUST have a
tablename
attribute to store the logicalKeyStoreName - MUST have a
kms-arn
attribute - MUST have a
hierarchy-version
- MUST NOT have a
enc
attribute
Any additionally attributes on the DynamoDB item MUST be added to the encryption context.
The ACTIVE branch key is a copy of the DECRYPT_ONLY with the same version
.
It is structured slightly differently so that the active version can be accessed quickly.
In addition to the encryption context:
The ACTIVE encryption context value of the type
attribute MUST equal to "branch:ACTIVE"
.
The ACTIVE encryption context MUST have a version
attribute.
The version
attribute MUST store the branch key version formatted like "branch:version:"
+ version
.
In addition to the encryption context:
The DECRYPT_ONLY encryption context MUST NOT have a version
attribute.
The type
attribute MUST stores the branch key version formatted like "branch:version:"
+ version
.
In addition to the encryption context:
The Beacon key encryption context value of the type
attribute MUST equal to "beacon:ACTIVE"
.
The Beacon key encryption context MUST NOT have a version
attribute.
If custom encryption context
is associated with the branch key these values MUST be added to the AWS KMS encryption context.
To avoid name collisions each added attribute from the custom encryption context
MUST be prefixed with aws-crypto-ec:
.
Across all versions of a Branch Key, the custom encryption context MUST be equal.
The operation MUST use the configured KMS SDK Client
to decrypt the value of the branch key field.
Every attribute except for enc
on the AWS DDB response item
MUST be authenticated in the decryption of enc
Every key in the constructed encryption context
except tableName
MUST exist as a string attribute in the AWS DDB response item.
Every value in the constructed encryption context
except the logical table name
MUST equal the value with the same key in the AWS DDB response item.
The key enc
MUST NOT exist in the constructed encryption context.
When calling AWS KMS Decrypt, the keystore operation MUST call with a request constructed as follows:
KeyId
MUST be compatible with the configuredAWS KMS Key ARN
in the AWS KMS Configuration for this keystore.CiphertextBlob
MUST be theenc
attribute value on the AWS DDB response itemEncryptionContext
MUST be the encryption context constructed aboveGrantTokens
MUST be this keystore's grant tokens.
A branch key record MUST include the following key-value pairs:
branch-key-id
: Unique identifier for a branch key; represented as AWS DDB Stringtype
: One of the following; represented as AWS DDB String- The string literal
"beacon:ACTIVE"
. Thenenc
is the wrapped beacon key. - The string
"branch:version:"
+version
, whereversion
is the Branch Key Version. Thenenc
is the wrapped branch key. - The string literal
"branch:ACTIVE"
. Thenenc
is the wrapped beacon key of the active version. Then
- The string literal
version
: Only exists iftype
is the string literal"branch:ACTIVE"
. Then it is the Branch Key Version. represented as AWS DDB Stringenc
: Encrypted version of the key; represented as AWS DDB Binarykms-arn
: The AWS KMS Key ARN used to generate theenc
value. represented as AWS DDB Stringcreate-time
: Timestamp in ISO 8601 format in UTC, to microsecond precision. Represented as AWS DDB Stringhierarchy-version
: Version of the hierarchical keyring; represented as AWS DDB Number
A branch key record MAY include custom encryption context key-value pairs.
These attributes should be prefixed with aws-crypto-ec:
the same way they are for AWS KMS encryption context.
The type
attribute MUST either be equal to "branch:ACTIVE"
or start with "branch:version:"
.
If the type
attribute is equal to "branch:ACTIVE"
then the authenticated encryption context MUST have a version
attribute
and the version string is this value.
If the type
attribute start with "branch:version:"
then the version string MUST be equal to this value.
To construct branch key materials from authenticated encryption context as follows:
- Branch Key MUST be the decrypted branch key material
- Branch Key Id MUST be the
branch-key-id
- Branch Key Version
The version string MUST start with
branch:version:
. The remaining string encoded as UTF8 bytes MUST be the Branch Key version. - Encryption Context MUST be constructed by Custom Encryption Context From Authenticated Encryption Context
The custom encryption context is stored as map of UTF8 Encoded bytes.
For every key in the encryption context
the string aws-crypto-ec:
+ the UTF8 decode of this key
MUST exist as a key in the authenticated encryption context.
Also, the value in the encryption context for this key
MUST equal the value in the authenticated encryption context
for the constructed key.
Given the simplified branch key material structure
BranchKeyMaterials(
branchKey := [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
branchKeyId := "bbb9baf1-03e6-4716-a586-6bf29995314b",
branchKeyVersion := "83eec007-5659-4554-bf11-699b90f41ac6",
encryptionContext := [ "department" := "admin"]
)
There would be three items in the keystore table. The DECRYPT_ONLY version, the ACTIVE version, and a beacon key.
The DECRYPT_ONLY simplified JavaScript JSON format would look like this
{
"branch-key-id" : "bbb9baf1-03e6-4716-a586-6bf29995314b",
"type" : "branch:version:83eec007-5659-4554-bf11-699b90f41ac6",
"enc" : "NnYwxJ/oiQCLnqRh/IcrCR2mmOnO4SAVLw2pspKJKd6rpa0H8z/4hGpGxcWozdb7VByebDFWb0VTWxaOUA8=",
"kms-arn" : "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab",
"create-time" : "2023-06-03T19:03:29.358Z",
"hierarchy-version" : "1",
"aws-crypto-ec:department" : "admin",
}
The ACTIVE simplified JavaScript JSON format would look like this
{
"branch-key-id" : "bbb9baf1-03e6-4716-a586-6bf29995314b",
"type" : ""branch:ACTIVE",
"version": "branch:version:83eec007-5659-4554-bf11-699b90f41ac6"
"enc" : "BiXHTm0j27+jsgJZ7yCnvI6yvjFyStMsHiC8fnR9KzKjwwhi0gB+5CZTfXFC2ufmBtCYX/sLvKsFnEITR+k=",
"kms-arn" : "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab",
"create-time" : "2023-06-03T19:03:29.358Z",
"hierarchy-version" : "1",
"aws-crypto-ec:department" : "admin",
}
The BEACON simplified JavaScript JSON format would look like this
{
"branch-key-id" : "bbb9baf1-03e6-4716-a586-6bf29995314b",
"type" : "beacon:ACTIVE",
"enc" : "hgb2RyDQinOCpzKWdi17E+t9WB9pRExQXpD/20bsu9hxr38HjQvGvihoYpL6sKuF0Ek+37B1UE9tK3SIOiE=",
"kms-arn" : "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab",
"create-time" : "2023-06-03T19:03:29.358Z",
"hierarchy-version" : "1",
"aws-crypto-ec:department" : "admin",
}