diff --git a/changes/2025-06-30_branch_keys_version_2/background.md b/changes/2025-06-30_branch_keys_version_2/background.md new file mode 100644 index 00000000..ab3d1dd7 --- /dev/null +++ b/changes/2025-06-30_branch_keys_version_2/background.md @@ -0,0 +1,328 @@ +[//]: # "Copyright Amazon.com Inc. or its affiliates. All Rights Reserved." +[//]: # "SPDX-License-Identifier: CC-BY-SA-4.0" + +# Customers should control encryption context + +# Definitions + +## Conventions used in this document + +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](https://tools.ietf.org/html/rfc2119). + +## HV-1 + +The Branch Key Store's Branch Keys are designated as `"hierarchy-version" : "1"`. + +This document proposes changes to theses Branch Keys; +when HV-1 is written, +we mean a Branch Key Item written by the Branch Key Store v0.2.0 to v0.7.0. + +## Branch Key's Cryptographic Material + +Cryptographic material (AES-256 bit key) generated and protected by KMS. + +## Branch Key's Properities + +These three values are stored on every +Active, +Version, +and Beacon Key Item in the Branch Key Store's Storage. + +They are also present in the KMS Encryption Context. + +```json +"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", +``` + +The Active has an additional field: + +```json +"version": "branch:version:83eec007-5659-4554-bf11-699b90f41ac6" +``` + +## Branch Key's Location + +These two values are stored on every +Active, +Version, +and Beacon Key Item in the Branch Key Store's Storage. + +For Active: + +```json +"branch-key-id" : "bbb9baf1-03e6-4716-a586-6bf29995314b", +"type" : "branch:ACTIVE" +``` + +For Version: + +```json +"branch-key-id" : "bbb9baf1-03e6-4716-a586-6bf29995314b", +"type": "branch:version:83eec007-5659-4554-bf11-699b90f41ac6" +``` + +For Beacon: + +```json +"branch-key-id" : "bbb9baf1-03e6-4716-a586-6bf29995314b", +"type": "beacon:ACTIVE" +``` + +However, +the Logical Key Store Name is also included in the KMS Encryption Context. + +```json +"branch-key-id" : "bbb9baf1-03e6-4716-a586-6bf29995314b", +"type" : "branch:ACTIVE", +"tablename": "KeyStore" +``` + +These three values describe where the Branch Key is stored; however, the tablename is a logical description, not a physical description. +At this time, no cryptography binds the Branch Key to the physical table. + +```json +"branch-key-id" : "bbb9baf1-03e6-4716-a586-6bf29995314b", +"tablename": "KeyStore" +``` + +These two values label the Branch Key, seperating it from all other Branch Keys. + +## Branch Key's Encryption Context + +These values are determined by the Branch Key Creator +or last Branch Key Mutator. + +In DynamoDB and in KMS Encryption Requests for HV-1, +their keys are prefixed with `aws-crypto-ec:`. + +```json +"aws-crypto-ec:department" : "admin" +``` + +However, +when returned to the requesters of the Branch Key Store's +`Get*Key*` operations, +the prefix is removed. + +## Branch Key's Context + +The union of the Branch Key's: + +- Properities +- Location (including logical key store name) +- Encryption Context + +# Background + +The current Branch Key Store's Branch Keys use KMS Encryption Context +to cryptographically bind the Branch Key's cryptographic material to +the Branch Key's Context. + +This cryptographic binding mitigates a number of threats around +storing the Branch Keys +and is vital to the safe usage of the Hierarchal Keyring. + +However, +it is not clear that this is the best use of KMS Encryption Context, +as it interferes with customers ability to use KMS Key Policies to +constrain Key Usage. + +Further more, +Encryption Context evaluation can be customized by the calling principles authorization; +KMS Key Grants can have restricted but unique conditions. + +Many potential Branch Key Customers are prevented from using +the Hierarchy Keyring, +as they have pre-existing Key Policies with their tenants +that cannot be met if the KMS Encryption Context is populated +by the Branch Key's Context. + +# Requirements + +1. Branch Key's Context be cryptographically bound to the Branch Key's Cryptographic Material + +2. Branch Key's Encryption Context, untransformed in any way, is the KMS Encryption Context + +3. Support for all of Behaviors of the current Branch Key Store (Create, Version, Get\*) + +# Out of Scope + +- Abstracting away from KMS +- Supporting any Branch Key protection Scheme via the DB-ESDK, much like the DDBEC's MetaStore. + +## Why not Abstract away from KMS + +Over the past year, +Crypto Tools has spent a significant amount of our time +supporting services integrating with KMS for multi-tenant applications. + +While we MAY eventually want to support GCP or Azure, +we MUST focus on the fasting growing customer base we have; +AWS Services and Software-as-a-service providers integrating with KMS. + +## Why not the MetaStore approach? + +The MetaStore was the predecessor to the Branch Key Store; +it is the "caching" solution for the legacy DynamoDB Encryption Client (DDBEC). +The MetaStore used the DDBEC itself to protect the hierarchical material with KMS; +this affords for some flexibility, +as the MetaStore was an interface that exposes the full breadth of DDBEC functionality. +This gives customers significant freedom on what data is bound to a Branch Key Item's material and how that binding is facilitated. + +However, our customers have complained that the DB-ESDK is complicated; +using the DB-ESDK to protect the materials used by the DB-ESDK and the ESDK is NOT +a step towards simplification. + +While such a feature MAY provide the greatest flexibility to +our customers, +it is not a simplification of the Hierarchy Keyring, +but a complication to it. +It also would make the DB-ESDK a dependency of the ESDK, +and introduce a circular dependency between the MPL and the DB-ESDK. + +# Design Questions + +## 1 How can the Branch Key's Context be protected without using KMS EC? + +See [protect_branch_key_without_kms_ec.md](./protect_branch_key_without_kms_ec.md). + +## 2 How are we going to offer operation in a mixed mode? + +UPDATE: 2.1 was rejected. +There will be no Policy (2.2). + +### 2.1 `hierarchy-version-policy` + +Much like [Key Commitment](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#key-commitment), +we could introduce a policy that +would allow for mixed usage or restricting to one or the other. + +Something like `hierarchy-version-policy`: + +- ALLOW_V1 +- ALLOW_V2 +- ALLOW_V1_OR_V2 +- ANY + +This policy would be part of (all) Branch Key Store configuration. + +(all: Branch Key Store, any future Branch Key Store Usage client.) + +This allows our customers to +restrict to one KMS Encryption Context +experience or another. + +The effort to implement and test this is very low, +relative to other code paths in this effort. + +### 2.2 Do Nothing + +UPDATE: We are going with Do Nothing + +There is no immediate customer demand for a policy like this. +In general, +the Branch Key in the table, +in combination with KMS, +the authority of it's treatment. + +However, +given the low effort required to implement/support this, +and the aid it gives our customers in having +a consistent KMS Encryption Context experience, +I suggest we implement the policy. + +### 2.3 Pros of 2.1 + +**Update Readers, than Writers**: +To use HV-2, +customers already using the H-Keyring will need +to update their readers before they start creating +or mutating Branch Keys to HV-2. + +i.e: They need to update their readers before they update their writers. + +This alone is justification for the policy. + +**Consistent KMS Encryption Context**: +The arguments for the HV-1 Encryption Context suggest +users SHOULD be able to restrict their Branch Key Store clients +to a HV-1 such that they know any IAM or KMS Key Policies +they created that depend on HV-1's Encryption Context +are still valid. + +### 2.4 Cons + +**Additional Development work and documentation**: +Nothing is free; +we would need to implement, document, test, and maintain this policy. + +Still, +the migration benefit justifies this cost. + +## 3 Branch Key Creation + +UPDATE: The team decided that the Branch Key Store would create and version both HV-1 and HV-2 BKs. + +UPDATE: The team changed their mind; the Branch Key Store WILL support HV-2 Branch Key Creation, via a flag. + +Customers MUST be able to chose which `hierarchy-version` +new Branch Keys are created with. + +The question is what should the UX be. + +### 3.1 Specify the `hierarchy-version` at Creation + +Currently, our library has one Branch Key Creation operations: + +- `BranchKeyStore#CreateKey` + +To this operation, +we add a flag that dictates the `hierarchy-version` to be created with. + +If that flag conflicts with `hierarchy-version-policy`, +then FAIL (update: `hierarchy-version-policy` was rejected, see [section 2](#2-how-are-we-going-to-offer-operation-in-a-mixed-mode)). + +Otherwise, respect the flag. + +**Plumbing through `GenerateRandom`**: +UPDATE: `kms:GenerateDataKey` closed this negative consequence. + +### 3.2 Follow the Configuration + +This does not work if the configuration is `ALLOW\_V1\_OR_V2`; +this is not recommended. + +### 3.3 New Operation or Client + +We could leave the old Branch Key Store alone, +and introduce a new Branch Key Store V2. + +The UX advantage here is that we can introduce new error types +without breaking customers. + +For example, +the creation of the `hierarchy-version-policy` implies +that we will need an error type for rejecting a Branch Key +that does not match. + +Particularly if we went down the additional KMS approaches (1.2, 1.3), +new error types will need to be created to represent +failures from the additional KMS key. + +But we have committed to 1.4; +this limits the failure modes/additional errors +to the point that I do not think new client +or operation is needed. + +### 3.4 Author's conclusion + +Unless someone can think of something else, +3.1. + +## 4 Branch Key Versioning (Rotation) + +Branch key store can VersionKey for HV-1 or HV-2 based on schema version (equivalent to hierarchical version) of the branch key item. diff --git a/changes/2025-06-30_branch_keys_version_2/protect_branch_key_without_kms_ec.md b/changes/2025-06-30_branch_keys_version_2/protect_branch_key_without_kms_ec.md new file mode 100644 index 00000000..5c30682a --- /dev/null +++ b/changes/2025-06-30_branch_keys_version_2/protect_branch_key_without_kms_ec.md @@ -0,0 +1,382 @@ +[//]: # "Copyright Amazon.com Inc. or its affiliates. All Rights Reserved." +[//]: # "SPDX-License-Identifier: CC-BY-SA-4.0" + +# How can the Branch Key's Context be protected without using KMS EC? + +# Definitions + +See [Definitions](./background.md#definitions). + +# 1 Plain-text Commitment instead of KMS Encryption Context + +The KMS RSA Keyring has already solved the need +to substitute KMS Encryption Context; +we need only adapt that solution and apply it here. + +## 1.1 Branch Key Creation + +The KMS RSA Keyring, in `OnEncrypt`, +[establishes an "Encryption Context Digest" by](https://github.com/awslabs/aws-encryption-sdk-specification/blob/8d6bb5665c1017bd64989e4bd66bd8759f1e4b1c/framework/aws-kms/aws-kms-rsa-keyring.md?plain=1#L95-L100): + +> 1. Serializing the [encryption context](../../framework/structures.md#encryption-context) from the input [encryption materials](../../framework/structures.md#encryption-materials) according to the [encryption context serialization specification](../../framework/structures.md#serialization). + +> 2. Taking the SHA-384 Digest of this concatenation. + +Adapting this same pattern to Branch Keys, +rather than working with the encryption context from the encryption materials, +HV-2 will serialize the Branch Key's Context according +to the [encryption context serialization specification](../../framework/../framework/structures.md#serialization), +and then take a SHA-384 Digest of these bytes, +creating the Branch Key's **Branch Key Context Digest**. + +This **Branch Key Context Digest** is 48 bytes long, +and MUST be bound to the Branch Key Cryptographic Materials. + +1.3 & 1.4 talk about options that use KMS Encrypt to protect the **Branch Key Context Digest**; +thus, without KMS Encrypt access, +an actor cannot modify the **Branch Key Context Digest**. + +1.5 considers a local HMAC operation, +with the plain-text AES-256 being the key. + +## 1.2 Getting Branch Keys + +The Branch Key Item is read from DDB table; +assuming the read Item is allowed by the Branch Key Store client +(KMS Config restriction; [`hierarchy-version-policy`](./background.md#3-how-are-we-going-to-offer-operation-in-a-mixed-mode)) +the **Branch Key Context Digest** is recreated on the read values. + +`kms:Decrypt` is called. + +If (1.3) or (1.4), +break the plain-text response into +the **protected Branch Key Context Digest** and the plain-text AES-256. + +Compare the **protected Branch Key Context Digest** to the **Branch Key Context Digest**; +if not equal, fail, else, succeed. + +If we go with (1.5), +then we need to use the plain-text AES-256 +to verify the MAC. + +## 1.3 Binding the **Branch Key Context Digest** via KMS Encrypt + +One option is to refactor Branch Key Creation to use `kms:GenerateDataKey` +to get a plain text cryptographic materials. + +This **Branch Key Context Digest** is then concatenated with +the plain-text material in a deterministic fashion. +The result of concatenation is then encrypted with KMS Encrypt. + +The option to use local entropy instead of `kms:GenerateDataKey` was rejected primarily because +if this local entropy fails to be random then cryptographic integrity of +ALL the messages/items protected by the Branch Key Item is compromised. +[//]: # "TODO: Detail more of the GDK vs Local Entropy discussion" + +## 1.4 KMS Random and then Bind the **Branch Key Context Digest** via KMS Encrypt + +KMS provides the kms:GenerateRandom operation, which generates random bytes without using a specific KMS key. +Unlike operations that use KMS keys, the kms:GenerateRandom operation does not involve any specific KMS key. +As a result, the access control for this operation is only managed through IAM policies, which can either allow or deny the kms:GenerateRandom permission. + +Multi-tenant Branch Key Store users +MAY have an obligation to use +tenant specific credentials or IAM roles to access a tenant specific KMS Key. +However, these credentials or IAM roles are unlikely to grant `kms:GenerateRandom` permission, +as it is not related to a KMS Key. +Thus, +these multi-tenant users would need a separate KMS client, +which would use non-tenant related credentials or IAM role. +This approach leads to a "clunkier" interface, +as it involves managing more KMS clients. +Hence, Option 1.4 is rejected. + +## 1.5 Use Branch Key's cryptographic material in an HMAC on the Branch Key's Metadata and Location + +Rather than appending the **Branch Key Context Digest** to the plain-text AES-256, +we can use the plain-text AES-256 as the key +for a HMAC. + +In this scenario, +the **Branch Key Context Digest** is passed to an HMAC function with the plain-text AES-256; +the result is a `MAC` (Message Authentication Code) which can be included +on the Branch Key Item as binary field. + +**HMAC does not add value compared to a protected digest**: +The HMAC is created with the plain-text AES-256; +the plain-text AES-256 is avabile to both +Branch Key Store Admins and Branch Key Store Users. + +In contrast to the plain-text AES-256, +`kms:Encrypt` access can be restricted to ONLY +Branch Key Store Admins; +Branch Key Store Users have no need of `kms:Encrypt`. + +Thus, +the option that affords distinction between +Admin and Users are 1.3 & 1.4. + +As such, 1.3 is the recommended path. + +**Doing both HAMC and a "protected digest" adds complexity but does not add value**: +To the author's knowledge, +there is no threat mitigated by doing +an HMAC and committing the `mac` +with the plain-text AES-256 +via the `kms:Encrypt` call +that is not mitigated by committing +just the **Branch Key Context Digest**. + +## 1.6 Downsides to Plain-text Commitment + +**Exposure**: +The plain-text AES-256 is now exposed to the Creating Agent, +where as in HV-1 the plain-text AES-256 is never exposed +to the Creating agent. + +However, +conversations with Security Engineers have generally +regarded any plain-text material +access outside of KMS to be equivalent. +Thus, +considering this exposure a risk is questionable at best. + +**Change of KMS Permissions**: +HV-1 never required `kms:Encrypt` and `kms:GenerateDataKey` permission. +Migrating to HV-2 will thus need a permission change. + +_Note_: `kms:GenerateRandom` permission is required, +but not to any resource (i.e: KMS Key), +only to the calling principle in general. + +**Feature Requests to KMS/LockBox**: +We could also ask KMS or LockBox to consider this use case of +Generate Data Key and Encrypt Payload; +we should not block on that, +but it could be useful for the future. + +**KMS Key/IAM Policies Cannot Evaluate Branch Key Location/Metadata**: +See [Appendix 1](./appendix.md#1-kms-key-admin-policy-downsides-and-rebuttals) and [Appendix 2](./appendix.md#2-mpl-consumer-key-policy-downsides-and-rebuttal). + +## 2 KMS HMAC Key + +Rather than using the Branch Key's KMS Key to protect all the Branch Key's metadata, +we could use a KMS HAMC Key to protect/validate the metadata, +and only the Branch Key's AES-256 would be protected by the Branch Key's KMS Key. + +## 2.1 Branch Key Creation + +MPL Consumers (users of the library), +when creating/versioning/mutation Branch Keys, +would provide two KMS Key ARNs: + +- An HMAC Key ARN (name subject to bike-shedding) that points to a KMS Key with a Key Spec of HMAC_384 +- A KMS Key ARN that points to a KMS Key with a Key Spec of SYMMETRIC_DEFAULT + +The Branch Key's AES-256 can than be created by +a `kms:GenerateDataKeyWithoutPlaintext` request, +with the MPL Consumer supplied Encryption Context (unmodified, "foo": "baz"); +the responses' `CiphertextBlob` is put into a variable, `enc`. + +The HAMC key's ARN is added to the metadata as `kms-hmac-arn`. +All the Branch Key's data, +including the `enc` (so metadata + `enc`) +is then normalized to a byte representation, +which we can call `hmac-input`. + +A `kms:GenerateMac` request is constructed +with the `KeyId` of `kms-hamc-arn`, +the `MacAlgorithm` of `HMAC_SHA_384`, +and `Message` of `hmac-input`; +we will call responses `Mac` the `mac`. + +The `mac` is added to the metadata, +and all of the metadata and the `enc` are written to DynamoDB. + +## 2.2 Getting Branch Keys + +The usage Branch Key Store will need +to be configured with a `hmac-key`, +or probably a list of `hamc-key`s, `hamc-keys`. + +The process for getting the item is then: + +1. Read the item from DDB +2. Ensure the `kms-hmac-arn` is in `hmac-keys`; if not, fail +3. Ensure the `kmsArn` is acceptable to the KMS Configuration; if not, fail +4. re-calculate the `hamc-input` +5. issue a `kms:VerifyMac` request, with `KeyId` of `kms-mac-arn`, `MacAlgorithm` of `HMAC_SHA_384`, `Message` of `hamc-input`, & `Mac` of `mac`; if KMS returns `KMSInvalidMacException`, then the Branch Key has been tampered with, and fail +6. Otherwise, issue a `kms:Decrypt` with `CiphertextBlob` of `enc`, `KeyId` of `kms-arn`, and the Encryption Context +7. If that succeeds, return the plain-text AES-256 as we have been doing + +## 2.3 Cons + +**More Complicated Permissions**: +Customers would need to configure and manage +a KMS HMAC Key, the backing DDB table, & the tenant or default KMS Key(s). +This is only one more KMS Key than they already use, +but it is additional complexity. + +**Additional Web/KMS Request for Gets Complicate Failures**: +Whenever fetching Branch Keys, +two KMS requests MUST succeed: + +- `kms:VerifyMac` +- `kms:Decrypt` + +These SHOULD be serial requests, +or the plain-text material MAY be retrieved +before the metadata has been validated. + +(The library could withhold the plain-text material +until both calls, issued in parallel, succeed, +but then we need to consider memory access/thread safety issues; +it is simpler and safer to ensure the calls are sequential.) + +Web requests transitively fail for any number of reasons; +Crypto Tools will need to introduce errors that differentiate +between a KMS signing key error and KMS symmetric default error, +and we will need to document that for our customers. + +That is effort on both Crypto Tools and it's customers; +HV-1 Branch Keys will fail on one group of conditions, +while HV-2 Branch Keys will fail on a larger group of conditions. + +This challenge could be overcome by a couple of means +(error hierarchies, +re-using existing error types but with additional messaging details, +offering [Requirement 5. Support for operating in a mixed HV-1, HV-2 state]() +as a multi-keyring) +but it will be effort. + +**Additional Web/KMS Request for Gets Increases Latency**: + +The Branch Key Store's `Get*` operations are used by +Amazon Services, and presumably external services, +to service latency sensitive requests. + +While working with such services, +Crypto Tools has observed that the KMS requests +are generally the largest driver of latency. + +An additional KMS request to use Branch Keys is, +potentially, +a significant increase in latency for these customers. + +It is not clear that the KMS HMAC key justifies this cost. + +## 2.4 Pros + +**An Additional Hurdle For Malicious Writers**: +The Branch Key Store/Hierarchy Keyring is the only +"data key caching" solution for Client Side of Encryption (CSE) +of DynamoDB items via the AWS Database Encryption SDK for DynamoDB +(DB-ESDK). + +The KMS HMAC Key is exclusively managed by the application; +if the application does not want to trust DynamoDB/data base administrators, +but is not the administrators of all the KMS Keys used by the Key Store +(i.e: multi-tenant) +and does not want to utilize strict Branch Key Stores +(as they do not scale well with many KMS Keys), +they can trust their KMS HMAC Key and NOT DynamoDB/the database. + +This is a very strong argument FOR using a KMS HMAC Key, +and potentially justifies the additional latency cost, +error complications, +and development complexities. + +**Static KMS Symmetric Default Permissions**: +If Crypto Tools requires the usage of a KMS HMAC Key, +then we can keep the KMS operations that +use the KMS Symmetric Default Key as they are in HV-1. + +This simplifies customers who want to transition from HV-1 to HV-2. + +# 3 Expand System Key/Double Encryption + +This option is much like [2 KMS HMAC Key](#2-kms-hmac-key), +but it allows the MPL Consumers to write +KMS Key/IAM Policies constraints against +the Branch Key's Metadata. + +## 3.1 Branch Key Creation + +MPL Consumers (users of the library), +when creating/versioning/mutation of Branch Keys, +would provide two KMS Key ARNs: + +- A System Key ARN (name subject to bike-shedding) that points to a KMS Key with a Key Spec of SYMMETRIC_DEFAULT +- A KMS Key ARN that points to a KMS Key with a Key Spec of SYMMETRIC_DEFAULT + +The Branch Key's AES-256 can than be created by +a `kms:GenerateDataKeyWithoutPlaintext` request against the KMS Key ARN, +with the MPL Consumer supplied Encryption Context (unmodified, "foo": "baz"); +the responses' `CiphertextBlob` is put into a variable, `enc`. + +`system-key-arn` is added to the Branch Key's Metadata. + +All of the Branch Key's Metadata is then put into the `EncryptionContext` of a +`kms:Encrypt` request against the `system-key-arn` with no plain-text. + +The resulting `CiphertextBlob` is added +to the Branch Key Item as `aad`, +and the Branch Key is written to storage as normal. + +## 3.2 Getting Branch Keys + +The usage Branch Key Store will need +to be configured with a `system-kms-arn`, +or probably a list of `system-kms-arn`s, `system-kms-arns`. + +The process for getting the item is then: + +1. Read the item from DDB +2. Ensure the `system-kms-arn` is in `system-kms-arns`; if not, fail +3. Ensure the `kmsArn` is acceptable to the KMS Configuration; if not, fail +4. issue a `kms:Decrypt` request, with `KeyId` of `system-kms-arn`, `EncryptionContext` of the Branch Key's Metadata, `CiphertextBlob` of `aad`; if KMS returns `KMSInvalidCiphertextException`, then the Branch Key has been tampered with, and fail +5. Otherwise, issue a `kms:Decrypt` with `CiphertextBlob` of `enc`, `KeyId` of `kms-arn`, and the Encryption Context +6. If that succeeds, return the plain-text AES-256 as we have been doing + +## 3.3 Cons + +Everything in 2.3 applies here, +modulo that the KMS requests are both `kms:Decrypt`. + +## 3.4 Pros + +Everything in 2.4 applies here, +AND we allow MPL Consumers to write KMS Key/IAM Policies against +the Branch Key Metadata. + +# 4 No Protection + +Do not protect the Branch Key Metadata. + +## 4.1 Pros + +None. + +## 4.2 Cons + +**A new threat model**: +We would need to re-write the Branch Key Store's +threat model basically from scratch, +likely accepting a number of confused deputy threats. + +We would then need to get AppSec sign off for this +more vulnerable iteration (hint: Sanders and Filip were not keen) +and then document this for our customers, +which would require extensive documentation work. + +# 5 Binding the **Branch Key Context Digest** via KMS Encryption Context + +We could put the **Branch Key Context Digest** into the KMS Encryption Context. + +## Pro and Con + +This lets us use `kms:GenerateDataKeyWithoutPlaintext`. +But it violates the Requirement 2. +Given the feedback we have been given from PEs across AWS, +including KMS', +we should not violate Requirement 2. diff --git a/framework/branch-key-store.md b/framework/branch-key-store.md index 479f086d..8bf34496 100644 --- a/framework/branch-key-store.md +++ b/framework/branch-key-store.md @@ -5,10 +5,12 @@ ## Version -0.9.0 +0.10.0 ### Changelog +- 0.10.0 + - Add [hierarchy version 2](../changes/2025-06-30_branch_keys_version_2/background.md) - 0.9.0 - Re-add [Mitigate Version Race Condition in the Branch Key Store](../changes/2025-01-16_key-store-mitigate-update-race/background.md) with DynamoDB as the only branch key storage option - 0.8.0 @@ -43,7 +45,7 @@ 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](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKeyWithoutPlaintext.html). +These branch keys are generated using the [AWS KMS API GenerateDataKeyWithoutPlaintext](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKeyWithoutPlaintext.html) in Hierarchy Version `v1` or [AWS KMS API GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html) in Hierarchy Version `v2`. By creating and persisting a data key to an accesbile medium, such as a DynamoDb table, @@ -64,6 +66,21 @@ This Keystore interface defines operations that any implementation of its specif A root key used to then derive different beacon keys per beacon. - [UUID](https://www.ietf.org/rfc/rfc4122.txt): a universally unique identifier that can be represented as a byte sequence or a string. +#### kms-arn + +`kms-arn` is the configured `AWS KMS Key ARN` in the [AWS KMS Configuration](#aws-kms-configuration) for this keystore. + +#### Hierarchy Version + +Schema Version of the Branch Key. +All items of the same Branch Key Identifier SHOULD have the same hierarchy-version. +The hierarchy-version determines how the Branch Key Store protects and validates the branch key with KMS. + +There are two hierarchy versions: + +- v1 +- v2 + ### Conventions used in this document The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" @@ -287,6 +304,7 @@ The CreateKey caller MUST provide: - An optional branch key id - An optional encryption context +- An optional hierarchy-version If an optional branch key id is provided and no encryption context is provided this operation MUST fail. @@ -298,6 +316,15 @@ If no branch key id is provided, then this operation MUST create a [version 4 UUID](https://www.ietf.org/rfc/rfc4122.txt) to be used as the branch key id. +If no Hierarchy-Version is provided, +then this operation MUST use `v1`. + +This operation needs to generate the following: + +- `version`: a new guid. This guid MUST be [version 4 UUID](https://www.ietf.org/rfc/rfc4122.txt) +- `timestamp`: 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“) + This operation MUST create a [branch key](structures.md#branch-key) and a [beacon key](structures.md#beacon-key) according to the [Branch Key and Beacon Key Creation](#branch-key-and-beacon-key-creation) section. @@ -315,15 +342,19 @@ Otherwise, this operation MUST yield an error. To create a branch key, this operation MUST take the following: - `branchKeyId`: The identifier -- `encryptionContext`: Additional encryption context to bind to the created keys - -This operation needs to generate the following: +- `encryption-context`: Additional encryption context to bind to the created keys +- `hierarchy-version`: The hierarchy-version determined by the input -- `version`: a new guid. This guid MUST be [version 4 UUID](https://www.ietf.org/rfc/rfc4122.txt) -- `timestamp`: 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“) +If the `hierarchy-version` is `v1`, +the wrapped beacon key MUST be created according to [Wrapped Beacon Key Creation `v1`](#wrapped-beacon-key-creation-v1) and +the wrapped branch keys MUST be created according to +[Wrapped Branch Key Creation `v1`](#wrapped-branch-key-creation-v1); +else the `hierarchy-version` MUST be `v2`, +the wrapped beacon Key MUST be created according to [Wrapped Beacon Key Creation `v2`](#wrapped-beacon-key-creation-v2) and +the wrapped branch keys MUST be created according to +[Wrapped Branch Key Creation `v2`](#wrapped-branch-key-creation-v2). -The wrapped Branch Keys, DECRYPT_ONLY and ACTIVE, MUST be created according to [Wrapped Branch Key Creation](#wrapped-branch-key-creation). +##### Wrapped Beacon Key Creation `v1` To create a beacon key, this operation will continue to use the `branchKeyId` and `timestamp` as the [Branch Key](structures.md#branch-key). @@ -333,15 +364,59 @@ The operation MUST call AWS KMS GenerateDataKeyWithoutPlaintext with a request c - `KeyId` MUST be the configured `AWS KMS Key ARN` in the [AWS KMS Configuration](#aws-kms-configuration) for this keystore. - `NumberOfBytes` MUST be 32. -- `EncryptionContext` MUST be the [encryption context for beacon keys](#beacon-key-encryption-context). +- `EncryptionContext` MUST be the [branch key context for beacon keys](#beacon-branch-key-context). - `GrantTokens` MUST be this keystore's [grant tokens](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#grant_token). If the call to AWS KMS GenerateDataKeyWithoutPlaintext succeeds, the operation MUST use the `CiphertextBlob` as the wrapped Beacon Key. -#### Wrapped Branch Key Creation +##### Wrapped Beacon Key Creation `v2` + +The operation MUST create a map of strings, +the [branch key context for beacon keys](#beacon-key-branch-key-context). + +The operation MUST calculate the **SHA-384 Digest for the beacon key** +by [serializing](../structures.md#serialization) the [branch key context for beacon keys](#beacon-key-branch-key-context); +the serialization MUST be done according to the [encryption context serialization specification](../structures.md#serialization). + +The operation MUST call [AWS KMS API GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html). +The call to AWS KMS GenerateDataKey MUST use the configured AWS KMS client to make the call. +The operation MUST call AWS KMS GenerateDataKey with a request constructed as follows: + +- `KeyId` MUST be the `kms-arn` +- `NumberOfBytes` MUST be 32. +- `EncryptionContext` MUST be the `encryption-context` +- `GrantTokens` MUST be this keystore's [grant tokens](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#grant_token). + +If the call to AWS KMS GenerateDataKey succeeds, +the operation MUST use the `Plaintext` from GenerateDataKey result +as the plain-text Beacon Key. + +The operation MUST concatenate the **SHA-384 Digest for the beacon key** +with the plain-text Beacon Key, +creating the **beacon plain-text tuple**. + +The operation MUST call [AWS KMS API Encrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Encrypt.html) +with a request constructed as follows: + +- `Plaintext` Must be the **beacon plain-text tuple** +- `KeyId` MUST be the `kms-arn`. +- `GrantTokens` MUST be this keystore's [grant tokens](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#grant_token). +- `EncryptionContext` MUST be the `encryption-context` + +If the call to AWS KMS Encrypt succeeds, +the operation MUST use the Encrypt result `CiphertextBlob` +as the wrapped Beacon Key. + +#### Wrapped Branch Key Creation `v1` -Given a `branchKeyId`, `version` and `timestamp` +The operation MUST generate a map of strings, +the [DECRYPT_ONLY branch context for branch keys](#decrypt_only-branch-key-context), +using the `branchKeyId`, `version`, `timestamp`, `kms-arn`, `encryption-context`, and `hierarchy-version`. + +The operation MUST generate a map of strings, +the [ACTIVE branch context for branch keys](#active-branch-key-context) +using the `branchKeyId`, `version`, `timestamp`, `kms-arn`, `encryption-context`, and `hierarchy-version`. The operation MUST call [AWS KMS API GenerateDataKeyWithoutPlaintext](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKeyWithoutPlaintext.html). The call to AWS KMS GenerateDataKeyWithoutPlaintext MUST use the configured AWS KMS client to make the call. @@ -349,8 +424,8 @@ The operation MUST call AWS KMS GenerateDataKeyWithoutPlaintext with a request c - `KeyId` MUST be the configured `AWS KMS Key ARN` in the [AWS KMS Configuration](#aws-kms-configuration) for this keystore. - `NumberOfBytes` MUST be 32. -- `EncryptionContext` MUST be the [DECRYPT_ONLY encryption context for branch keys](#decrypt_only-encryption-context). -- GenerateDataKeyWithoutPlaintext `GrantTokens` MUST be this keystore's [grant tokens](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#grant_token). +- `EncryptionContext` MUST be the [DECRYPT_ONLY branch context for branch keys](#decrypt_only-branch-key-context). +- `GrantTokens` MUST be this keystore's [grant tokens](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#grant_token). If the call to AWS KMS GenerateDataKeyWithoutPlaintext succeeds, the operation MUST use the GenerateDataKeyWithoutPlaintext result `CiphertextBlob` @@ -359,21 +434,83 @@ as the wrapped DECRYPT_ONLY Branch Key. The operation MUST call [AWS KMS API ReEncrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_ReEncrypt.html) with a request constructed as follows: -- `SourceEncryptionContext` MUST be the [DECRYPT_ONLY encryption context for branch keys](#decrypt_only-encryption-context). -- `SourceKeyId` MUST be the configured `AWS KMS Key ARN` in the [AWS KMS Configuration](#aws-kms-configuration) for this keystore. +- `SourceEncryptionContext` MUST be the [DECRYPT_ONLY branch key context for branch keys](#decrypt_only-branch-key-context). +- `SourceKeyId` MUST be the `kms-arn`. - `CiphertextBlob` MUST be the wrapped DECRYPT_ONLY Branch Key. -- ReEncrypt `GrantTokens` MUST be this keystore's [grant tokens](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#grant_token). -- `DestinationKeyId` MUST be the configured `AWS KMS Key ARN` in the [AWS KMS Configuration](#aws-kms-configuration) for this keystore. -- `DestinationEncryptionContext` MUST be the [ACTIVE encryption context for branch keys](#active-encryption-context). +- `GrantTokens` MUST be this keystore's [grant tokens](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#grant_token). +- `DestinationKeyId` MUST be the `kms-arn`. +- `DestinationEncryptionContext` MUST be the [ACTIVE branch key context for branch keys](#active-branch-key-context). If the call to AWS KMS ReEncrypt succeeds, the operation MUST use the ReEncrypt result `CiphertextBlob` as the wrapped ACTIVE Branch Key. -#### Writing Branch Key and Beacon Key to Keystore +#### Wrapped Branch Key Creation `v2` + +The operation MUST generate a map of strings, +the [`DECRYPT_ONLY` branch key context for branch keys](#decrypt_only-branch-key-context). + +The operation MUST calculate the **SHA-384 Digest for the `DECRYPT_ONLY`** +by [serializing](../structures.md#serialization) the [`DECRYPT_ONLY` branch key context for branch keys](#decrypt_only-branch-key-context); +the serialization MUST be done according to the [encryption context serialization specification](../structures.md#serialization). + +The operation MUST generate a map of strings, +the [ACTIVE branch key context for branch keys](#active-branch-key-context). + +The operation MUST calculate the **SHA-384 Digest for the `ACTIVE`** +by [serializing](../structures.md#serialization) the [`ACTIVE` branch key context for branch keys](#active-branch-key-context); +the serialization MUST be done according to the [encryption context serialization specification](../structures.md#serialization). + +The operation MUST call [AWS KMS API GenerateDataKey](https://docs.aws.amazon.com/kms/latest/APIReference/API_GenerateDataKey.html). +The call to AWS KMS GenerateDataKey MUST use the configured AWS KMS client to make the call. +The operation MUST call AWS KMS GenerateDataKey with a request constructed as follows: + +- `KeyId` MUST be the `kms-arn` +- `NumberOfBytes` MUST be 32. +- `EncryptionContext` MUST be the `encryption-context` +- `GrantTokens` MUST be this keystore's [grant tokens](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#grant_token). + +If the call to AWS KMS GenerateDataKey succeeds, +the operation MUST use the `Plaintext` from GenerateDataKey result +as the plain-text Branch Key. + +The operation MUST concatenate the **SHA-384 Digest for the `DECRYPT_ONLY`** +with the plain-text Branch Key, +creating the **`DECRYPT_ONLY` plain-text tuple**. + +The operation MUST call [AWS KMS API Encrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_ReEncrypt.html) +with a request constructed as follows: + +- `Plaintext` **the `DECRYPT_ONLY` plain-text tuple** +- `KeyId` MUST be the `kms-arn`. +- `GrantTokens` MUST be this keystore's [grant tokens](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#grant_token). +- `EncryptionContext` MUST be the `encryption-context` + +If the call to AWS KMS Encrypt succeeds, +the operation MUST use the Encrypt result `CiphertextBlob` +as the wrapped `DECRYPT_ONLY` Branch Key. + +The operation MUST concatenate the **SHA-384 Digest for the `ACTIVE`** +with the plain-text Branch Key, +creating the **the `ACTIVE` plain-text tuple**. + +The operation MUST call [AWS KMS API Encrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_Encrypt.html) +with a request constructed as follows: + +- `Plaintext` **the `ACTIVE` plain-text tuple** +- `KeyId` MUST be the `kms-arn`. +- `GrantTokens` MUST be this keystore's [grant tokens](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#grant_token). +- `EncryptionContext` MUST be the `encryption-context` + +If the call to AWS KMS Encrypt succeeds, +the operation MUST use the Encrypt result `CiphertextBlob` +as the wrapped `ACTIVE` Branch Key. + +#### Writing Branch Key and Beacon Key to Branch Key Store table To add the branch keys and a beacon key to the keystore the operation MUST call [Amazon DynamoDB API TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html). + 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: @@ -386,8 +523,8 @@ List of TransactWriteItem: - “enc” (B): the wrapped DECRYPT_ONLY Branch Key `CiphertextBlob` from the KMS operation - “create-time” (S): `timestamp` - "kms-arn" (S): configured KMS Key - - “hierarchy-version” (N): 1 - - Every key-value pair of the custom [encryption context](./structures.md#encryption-context-3) that is associated with the branch key + - “hierarchy-version” (N): either `1` or `2`, depending on the `hierarchy-version` + - Every key-value pair in the input `encryption-context` MUST be added with an Attribute Name of `aws-crypto-ec:` + the Key and Attribute Value (S) of the value. - ConditionExpression: `attribute_not_exists(branch-key-id)` - TableName: the configured Table Name @@ -398,8 +535,8 @@ List of TransactWriteItem: - “enc” (B): wrapped ACTIVE Branch Key `CiphertextBlob` from the KMS operation - “create-time” (S): `timestamp` - "kms-arn" (S): configured KMS Key - - “hierarchy-version” (N): 1 - - Every key-value pair of the custom [encryption context](./structures.md#encryption-context-3) that is associated with the branch key + - “hierarchy-version” (N): either `1` or `2`, depending on the `hierarchy-version` + - Every key-value pair in the input `encryption-context` MUST be added with an Attribute Name of `aws-crypto-ec:` + the Key and Attribute Value (S) of the value. - ConditionExpression: `attribute_not_exists(branch-key-id)` - TableName: the configured Table Name @@ -410,8 +547,8 @@ List of TransactWriteItem: - “enc” (B): the wrapped Beacon Key `CiphertextBlob` from the KMS operation - “create-time” (S): `timestamp` - "kms-arn" (S): configured KMS Key - - “hierarchy-version” (N): 1 - - Every key-value pair of the custom [encryption context](./structures.md#encryption-context-3) that is associated with the branch key + - “hierarchy-version” (N): either `1` or `2`, depending on the `hierarchy-version` + - Every key-value pair in the input `encryption-context` MUST be added with an Attribute Name of `aws-crypto-ec:` + the Key and Attribute Value (S) of the value. - ConditionExpression: `attribute_not_exists(branch-key-id)` - TableName is the configured Table Name @@ -444,10 +581,13 @@ even if the KeyStore is configured with a `KMS MRKey ARN` that does not exactly If such were allowed, clients using non-MRK KeyStores might suddenly stop working. The values on the AWS DDB response item -MUST be authenticated according to [authenticating a keystore item](#authenticating-a-keystore-item). +MUST be authenticated according to [authenticating a keystore item for item with hierarchy version v1](#authenticating-a-branch-keystore-item-for-item-with-hierarchy-version-v1) or [authenticating a keystore item for item with hierarchy version v2](#authenticating-a-branch-keystore-item-for-item-with-hierarchy-version-v2) based on schema version of the branch key 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](#wrapped-branch-key-creation). +If the `hierarchy-version` is `v1`, +the wrapped Branch Keys, DECRYPT_ONLY and ACTIVE, MUST be created according to [Wrapped Beacon Key Creation `v1`](#wrapped-beacon-key-creation-v1); +else the `hierarchy-version` MUST be `v2`, +[Wrapped Branch Key Creation `v2`](#wrapped-branch-key-creation-v2). To add the new branch key to the keystore, the operation MUST call [Amazon DynamoDB API TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html). @@ -463,9 +603,8 @@ List of TransactWriteItem: - “enc” (B): the wrapped DECRYPT_ONLY Branch Key `CiphertextBlob` from the KMS operation - “create-time” (S): `timestamp` - "kms-arn" (S): configured KMS Key - - “hierarchy-version” (N): 1 - - Every key-value pair of the custom [encryption context](./structures.md#encryption-context-3) that is associated with the branch key - MUST be added with an Attribute Name of `aws-crypto-ec:` + the Key and Attribute Value (S) of the value. + - “hierarchy-version” (N): either `1` or `2`, depending on the `hierarchy-version` + - Every other key-value pair in the [branch key context](./structures.md#branch-key-context). - ConditionExpression: `attribute_not_exists(branch-key-id)` - TableName: the configured Table Name - PUT: @@ -475,8 +614,8 @@ List of TransactWriteItem: - “enc” (B): wrapped ACTIVE Branch Key `CiphertextBlob` from the KMS operation - “create-time” (S): `timestamp` - "kms-arn" (S): configured KMS Key - - “hierarchy-version” (N): 1 - - Every key-value pair of the custom [encryption context](./structures.md#encryption-context-3) that is associated with the branch key + - “hierarchy-version” (N): either `1` or `2`, depending on the `hierarchy-version` + - Every key-value pair in the [encryption context](./structures.md#encryption-context) provided by users and is associated with the branch key MUST be added with an Attribute Name of `aws-crypto-ec:` + the Key and Attribute Value (S) of the value. - ConditionExpression: `attribute_exists(branch-key-id) AND enc = :encOld` - ExpressionAttributeValues: `{":encOld" := DDB.AttributeValue.B(oldCiphertextBlob)}` @@ -493,29 +632,35 @@ The condition expression for the Active Input ensures the Active Item in DynamoDB has not changed since it was read. This prevents overwrites due to a race in updating the Active Item. -#### Authenticating a Keystore item +#### Authenticating a Branch Keystore item for item with `hierarchy-version` v1 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](#encryption-context) -except `tableName` -MUST exist as a string attribute in the AWS DDB response item. -Every value in the constructed [encryption context](#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](#encryption-context). +This operation MUST call AWS DDB `GetItem`. +Every attribute except `enc` on the AWS DDB response item MUST be converted to a set of key value pairs +which is the [branch key context](#branch-key-context). The operation MUST call [AWS KMS API ReEncrypt](https://docs.aws.amazon.com/kms/latest/APIReference/API_ReEncrypt.html) with a request constructed as follows: -- `SourceEncryptionContext` MUST be the [encryption context](#encryption-context) constructed above +- `SourceEncryptionContext` MUST be the [branch key context](#branch-key-context) constructed above - `SourceKeyId` MUST be [compatible with](#aws-key-arn-compatibility) the configured KMS Key in the [AWS KMS Configuration](#aws-kms-configuration) for this keystore. - `CiphertextBlob` MUST be the `enc` attribute value on the AWS DDB response item - `GrantTokens` MUST be the configured [grant tokens](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#grant_token). - `DestinationKeyId` MUST be [compatible with](#aws-key-arn-compatibility) the configured KMS Key in the [AWS KMS Configuration](#aws-kms-configuration) for this keystore. -- `DestinationEncryptionContext` MUST be the [encryption context](#encryption-context) constructed above +- `DestinationEncryptionContext` MUST be the [branch key context](#branch-key-context) constructed above + +#### Authenticating a Branch Keystore item for item with `hierarchy-version` v2 + +The operation MUST use the configured `KMS SDK Client` to authenticate the value of the keystore item. + +This operation MUST call AWS DDB `GetItem`. +Every attribute except `enc` on the AWS DDB response item MUST be converted to a set of key value pairs (a Map) +which is the [branch key context](#branch-key-context). +Every key in the constructed branch key context except tableName MUST exist as a string attribute in the AWS DDB response item. +The [AWS KMS Encryption Context](#aws-kms-encryption-context) MUST be the [encryption context](#encryption-context), which is built from the branch key context by extracting the keys with prefix `aws-crypto-ec:` and then dropping the prefix. See [Encryption Context From Authenticated Branch Key Context](#encryption-context-from-authenticated-branch-key-context). + +The operation MUST follow [AWS KMS Branch Key Decryption](#aws-kms-branch-key-decryption) to decrypt and authentication the branch key context. ### GetActiveBranchKey @@ -530,19 +675,24 @@ using the `branch-key-id` as the Partition Key and `"branch:ACTIVE"` value as th The AWS DDB response MUST contain the fields defined in the [branch keystore record format](#record-format). If the record does not contain the defined fields, this operation MUST fail. +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](#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](#aws-kms-branch-key-decryption) section. If the branch key fails to decrypt, GetActiveBranchKey MUST fail. This GetActiveBranchKey MUST construct [branch key materials](./structures.md#branch-key-materials) -according to [Branch Key Materials From Authenticated Encryption Context](#branch-key-materials-from-authenticated-encryption-context). +according to [Branch Key Materials From Authenticated Branch Key Context](#branch-key-materials-from-authenticated-branch-key-context). This operation MUST return the constructed [branch key materials](./structures.md#branch-key-materials). ### GetBranchKeyVersion -On invocation, the caller: - - MUST supply a `branch-key-id` - MUST supply a `branchKeyVersion` @@ -552,12 +702,18 @@ using the `branch-key-id` as the Partition Key and "branch:version:" + `branchKe The AWS DDB response MUST contain the fields defined in the [branch keystore record format](#record-format). If the record does not contain the defined fields, this operation MUST fail. +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](#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](#aws-kms-branch-key-decryption) section. If the branch key fails to decrypt, this operation MUST fail. This GetBranchKeyVersion MUST construct [branch key materials](./structures.md#branch-key-materials) -according to [Branch Key Materials From Authenticated Encryption Context](#branch-key-materials-from-authenticated-encryption-context). +according to [Branch Key Materials From Authenticated Branch Key Context](#branch-key-materials-from-authenticated-branch-key-context). This operation MUST return the constructed [branch key materials](./structures.md#branch-key-materials). @@ -573,6 +729,12 @@ using the `branch-key-id` as the Partition Key and "beacon:ACTIVE" value as the The AWS DDB response MUST contain the fields defined in the [branch keystore record format](#record-format). If the record does not contain the defined fields, this operation MUST fail. +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](#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](#aws-kms-branch-key-decryption) section. If the beacon key fails to decrypt, this operation MUST fail. @@ -582,73 +744,71 @@ and the `branchKeyId` from the returned `branch-key-id` field. This operation MUST return the constructed [beacon key materials](./structures.md#beacon-key-materials). -## Encryption Context +## Branch Key Context -This section describes how the AWS KMS encryption context is built -from the DynamoDB items that store the branch keys. +Branch Key Context is a set of key value pairs (a Map) that contain contextual information about the Branch Key Item. -The following encryption context keys are shared: +The Branch Key Context: -- 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 +- MUST have a `branch-key-id` key who's value MUST not be an empty string +- MUST have a `type` key who's value MUST not be an empty string +- MUST have a `create-time` key with a value in ISO 8601 format in UTC +- MUST have a `tablename` key who's value is the logicalKeyStoreName +- MUST have a `kms-arn` key who's value is valid KMS ARN +- MUST have a `hierarchy-version` key who's value is either "1" or "2" +- MUST NOT have a `enc` key +- MAY have one or more keys prefixed with `aws-crypto-ec:` which is the encyption context send by the customer. + The `aws-crypto-ec:` prefix is prepended by the library +- MUST NOT have any other keys apart from the ones mentioned above if `hierarchy-version` is "2" -Any additionally attributes on the DynamoDB item -MUST be added to the encryption context. - -### ACTIVE Encryption Context +### ACTIVE Branch Key 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](#encryption-context): +In addition to the [branch key context](#branch-key-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`. +The ACTIVE branch key context value of the `type`key MUST equal to `"branch:ACTIVE"`. +The ACTIVE branch key context MUST have a `version` key. +The `version` key MUST store the branch key version formatted like `"branch:version:"` + ``. -### DECRYPT_ONLY Encryption Context +### DECRYPT_ONLY Branch Key Context -In addition to the [encryption context](#encryption-context): +In addition to the [branch key context](#branch-key-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`. +The DECRYPT_ONLY branch key context MUST NOT have a `version` key. +The `type` value MUST store the branch key version formatted like `"branch:version:"` + ``. -### Beacon Key Encryption Context +### Beacon Branch Key Context -In addition to the [encryption context](#encryption-context): +In addition to the [branch key context](#branch-key-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. +The Beacon key branch key context MUST includes a key `type` and the value MUST be `"beacon:ACTIVE"`. +The Beacon key branch key context MUST NOT have a `version` key. -### Custom Encryption Context +## AWS KMS Encryption Context -If custom [encryption context](./structures.md#encryption-context-3) -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](./structures.md#encryption-context-3) -MUST be prefixed with `aws-crypto-ec:`. -Across all versions of a Branch Key, the custom encryption context MUST be equal. +If the `hierarchy-version` is v1, AWS KMS encryption context MUST be same as [branch key context](#branch-key-context). +If the `hierarchy-version` is v2, AWS KMS encryption context MUST be the [encryption context from authenticated branch key context](#encryption-context-from-authenticated-branch-key-context) without any transformation. This requirement applies regardless of the Branch Key Item's `type`. ## AWS KMS Branch Key Decryption The operation MUST use the configured `KMS SDK Client` to decrypt the value of the branch key field. +To get attributes in branch key item from the keystore +this operation MUST call AWS DDB `GetItem`. 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](#encryption-context) +Every key in the constructed [branch key context](#branch-key-context) except `tableName` -MUST exist as a string attribute in the AWS DDB response item. -Every value in the constructed [encryption context](#encryption-context) +MUST exist as a attribute in the AWS DDB response item. +All attributes in the AWS DynamoDB response item MUST be of type string, +with the exception of hierarchy-version, which MUST be of type number. +Every value in the constructed [branch key context](#branch-key-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](#encryption-context). +The key `enc` MUST NOT exist in the constructed [branch key context](#branch-key-context). If the Keystore's [AWS KMS Configuration](#aws-kms-configuration) is `KMS Key ARN` or `KMS MRKey ARN`, the `kms-arn` field of the DDB response item MUST be @@ -669,9 +829,12 @@ the keystore operation MUST call with a request constructed as follows: If the KMS Configuration is MRDiscovery, `KeyId` MUST be the `kms-arn` attribute value of the AWS DDB response item, with the region replaced by the configured region. Otherwise, it MUST BE the Keystore's configured KMS Key. - `CiphertextBlob` MUST be the `enc` attribute value on the AWS DDB response item -- `EncryptionContext` MUST be the [encryption context](#encryption-context) constructed above +- `EncryptionContext` MUST be the [encryption context from authenticated branch key context](#encryption-context-from-authenticated-branch-key-context) - `GrantTokens` MUST be this keystore's [grant tokens](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#grant_token). +For authentication of attributes except for `enc` on AWS DDB response item in Hierarchy Version `v2`, +the operation MUST match the first 48 bytes of `Plaintext` returned by AWS KMS Decrypt operation with SHA-384 Digest for the branch key of serialization of the [branch key context](#branch-key-context). + ## Record Format A branch key record MUST include the following key-value pairs: @@ -692,19 +855,19 @@ A branch key record MUST include the following key-value pairs: 1. `hierarchy-version`: Version of the hierarchical keyring; represented as [AWS DDB Number](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes) -A branch key record MAY include [custom encryption context](#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](#encryption-context). +A branch key record MAY include [encryption context](./structures.md#encryption-context) key-value pairs. +These attributes MUST be prefixed with `aws-crypto-ec:` regardless of the item's `hierarchy-version`. -### Branch Key Materials From Authenticated Encryption Context +### Branch Key Materials From Authenticated Branch key 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 +then the authenticated branch key 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](./structures.md#branch-key-materials) from authenticated encryption context as follows: +To construct [branch key materials](./structures.md#branch-key-materials) from authenticated branch key context as follows: - [Branch Key](./structures.md#branch-key) MUST be the [decrypted branch key material](#aws-kms-branch-key-decryption) - [Branch Key Id](./structures.md#branch-key-id) MUST be the `branch-key-id` @@ -712,18 +875,18 @@ To construct [branch key materials](./structures.md#branch-key-materials) from a The version string MUST start with `branch:version:`. The remaining string encoded as UTF8 bytes MUST be the Branch Key version. - [Encryption Context](./structures.md#encryption-context-3) MUST be constructed by - [Custom Encryption Context From Authenticated Encryption Context](#custom-encryption-context-from-authenticated-encryption-context) + [Encryption Context From Authenticated Branch Key Context](#encryption-context-from-authenticated-branch-key-context) -### Custom Encryption Context From Authenticated Encryption Context +### Encryption Context From Authenticated Branch Key Context -The custom encryption context is stored as map of UTF8 Encoded bytes. +The [encryption context](./structures.md#encryption-context) is stored as map of UTF8 Encoded bytes. -For every key in the [encryption context](./structures.md#encryption-context-3) +For every key in the [encryption context](./structures.md#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](./structures.md#encryption-context-3) for this key -MUST equal the value in the authenticated encryption context -for the constructed key. +MUST exist as a key in the authenticated branch key context. +Also, the value in the [encryption context](./structures.md#encryption-context) for this key +MUST equal the value in the authenticated branch key context +for the prefixed key. ### Example diff --git a/framework/structures.md b/framework/structures.md index 34c6f088..5ce1610f 100644 --- a/framework/structures.md +++ b/framework/structures.md @@ -5,10 +5,14 @@ ## Version -0.6.0 +0.7.0 ### Changelog +- 0.7.0 + + - Update Branch Key Structures to include KMS ARN, Create Time, and Hierarchy Version + - 0.6.0 - Update keystore structure and add encryption context options @@ -386,6 +390,9 @@ This structure MUST include all of the following fields: - [Branch Key Id](#branch-key-id) - [Branch Key Version](#branch-key-version) - [Encryption Context](#encryption-context-3) +- [KMS ARN](#kms-arn) +- [Create Time](#create-time) +- [Hierarchy Version](#hierarchy-version) ##### Branch Key @@ -407,7 +414,19 @@ This value MUST be a version 4 [UUID](https://www.ietf.org/rfc/rfc4122.txt). ##### Encryption Context -The [custom encryption context](#encryption-context) associated with this branch key. +The [encryption context](./structures.md#encryption-context) associated with all the items of this Branch Key. + +##### KMS ARN + +The AWS KMS Key ARN used to protect these materials. + +##### Create Time + +Timestamp in ISO 8601 format in UTC, to microsecond precision, of when the material was generated. + +##### Hierarchy Version + +[Schema Version of the Branch Key](branch-key-store.md#hierarchy-version). ## Beacon Key Materials @@ -427,6 +446,9 @@ This structure MUST include the following fields: - [Beacon Key Id](#beacon-key-id) - [Encryption Context](#encryption-context-4) +- [KMS ARN](#kms-arn) +- [Create Time](#create-time) +- [Hierarchy Version](#hierarchy-version) This structure MAY include the following fields: @@ -445,7 +467,19 @@ the beacon key can be discarded. ##### Encryption Context -The [custom encryption context](#encryption-context) associated with this beacon key. +The [encryption context](./structures.md#encryption-context) is a key-value pair provided by users and is associated with the beacon key. + +##### KMS ARN + +The AWS KMS Key ARN used to protect these materials. + +##### Create Time + +Timestamp in ISO 8601 format in UTC, to microsecond precision, that the Material was generated. + +##### Hierarchy Version + +[Schema Version of the Branch Key](branch-key-store.md#hierarchy-version). ##### Beacon Key Id