From 7c824aaf2119e8a1ef0e86d5afde9eef4e9d9be9 Mon Sep 17 00:00:00 2001 From: Alex Chew Date: Tue, 14 Jul 2020 22:48:08 -0700 Subject: [PATCH 1/3] doc: specify how caching CMM should handle max plaintext length in Get Encryption Materials --- .../change.md | 153 ++++++++++++++++++ framework/caching-cmm.md | 28 +++- 2 files changed, 175 insertions(+), 6 deletions(-) create mode 100644 changes/2020-07-13_caching-cmm-max-plaintext-length/change.md diff --git a/changes/2020-07-13_caching-cmm-max-plaintext-length/change.md b/changes/2020-07-13_caching-cmm-max-plaintext-length/change.md new file mode 100644 index 00000000..de0f5ffd --- /dev/null +++ b/changes/2020-07-13_caching-cmm-max-plaintext-length/change.md @@ -0,0 +1,153 @@ +[//]: # "Copyright Amazon.com Inc. or its affiliates. All Rights Reserved." +[//]: # "SPDX-License-Identifier: CC-BY-SA-4.0" + +# Enforce Safe Handling of Max Plaintext Length in Caching Cryptographic Materials Manager + +## Affected Features + +| Feature | +| ------------------------------------------------------------------------- | +| [Caching Cryptographic Materials Manager](../../framework/caching-cmm.md) | + +## Affected Specifications + +| Specification | +| ------------------------------------------------------------------------- | +| [Caching Cryptographic Materials Manager](../../framework/caching-cmm.md) | + +## Affected Implementations + +| Language | Repository | +| ---------- | ------------------------------------------------------------------------------------- | +| C | [aws-encryption-sdk-c](https://github.com/aws/aws-encryption-sdk-c) | +| Java | [aws-encryption-sdk-java](https://github.com/aws/aws-encryption-sdk-java) | +| JavaScript | [aws-encryption-sdk-javascript](https://github.com/aws/aws-encryption-sdk-javascript) | +| Python | [aws-encryption-sdk-python](https://github.com/aws/aws-encryption-sdk-python) | + +## 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). + +## Summary + +The Get Encryption Materials operation accepts an optional `max plaintext length` parameter, +but the specification does not state how the caching CMM should behave +when the caller does not provide the parameter value. +This change specifies that the caching CMM should bypass the cache in this case. + +Also, when the caching CMM is performing a Get Encryption Materials operation +for which no materials are cached, +it MUST call its underlying CMM's Get Encryption Materials operation. +The specification does not state what value of `max plaintext length` (if any) +the caching CMM should pass to its underlying CMM. +This change specifies that the caching CMM should pass its `byte limit` value +as the `max plaintext length` parameter of the call to the underlying CMM. + +## Out of Scope + +- Changing the shape of any CMM APIs is out of scope. + +## Motivation + +### Fulfulling Encryption Materials Requests Without `max plaintext length` + +The Get Encryption Materials operation of the Cryptographic Materials Manager (CMM) +accepts an Encryption Materials Request that MAY specify a `max plaintext length` field, +indicating the maximum length of plaintext +that the caller intends to encrypt using the returned materials. +The caching Cryptographic Materials Manager (caching CMM) +aims to prevent its users from using encryption materials +to encrypt more bytes than its configured `byte limit`, +and existing implementations do so by bypassing the cache +whenever it does not know their users' `max plaintext length`. +This behavior is safe but previously unspecified, +and this change mandates that implementations implement it. + +### Setting `max plaintext length` for Underlying CMM's Get Encryption Materials + +The CMM interface specification implicitly allows an underlying CMM +to produce encryption materials using logic +that depends on the `max plaintext length` of its Encryption Materials Request. +Suppose the caching CMM passes a `max plaintext length` value of `N` +to its underlying CMM's Get Encryption Materials operation, +and caches the materials that it receives. +If a later Get Encryption Materials operation fetches those materials from the cache, +but has a `max plaintext length` value that exceeds `N`, +then the caching CMM returns those materials unsafely. + +It is therefore important that the caching CMM +carefully selects the `max plaintext length` parameter to pass to its underlying CMM. +This change mandates that the caching CMM passes its configured `byte limit` value +as the `max plaintext length` parameter to the underlying CMM, +whereas previously, the caching CMM could choose any value. +With this change in place, +even if the underlying CMM produces materials using plaintext-length-dependent logic, +the caching CMM receives and caches materials +that are safe to use for up to `byte limit` bytes of plaintext. +It follows that if a later Get Encryption Materials operation's `max plaintext length` +does not exceed the caching CMM's `byte limit`, +then it is also safe for the caching CMM to return corresponding cached materials. + +## Drawbacks + +Bypassing the cache in the caching CMM on Get Encryption Materials operations +that do not specify `max plaintext length` +could be confusing to the user. +Warning the user when this happens could help prevent users from running into +unexpected (and potentially expensive) calls to the underlying CMM, +but we leave this as an implementation choice. + +## Security Implications + +This change SHOULD NOT have any security implications. + +## Operational Implications + +This change will break any customer use case +that depends on the Caching CMM passing no `max plaintext length` parameter +to the underlying CMM on Get Encryption Materials calls. + +## Guide-level Explanation + +When you make a Get Encryption Materials call to the caching CMM, +you may optionally specify a value for the `max plaintext length` parameter, +which indicates the maximum number of bytes you will encrypt +with the materials you receive from the call. +If you do not specify a `max plaintext length` value, +then the caching CMM will neither use cached materials +nor cache materials from its underlying CMM. +This helps to ensure that you do not exceed the `byte limit` +that you configure on the caching CMM. +So in order to maximize the benefits of caching, +you should specify the `max plaintext length` value +whenever you know an appropriate upper bound for bytes you will encrypt. + +If you customize the underlying CMM of a caching CMM, +then whenever the caching CMM makes a Get Encryption Materials call +to your customized underlying CMM, +the Encryption Materials Request will have a `max plaintext length` value +equal to the `byte limit` value configured on the caching CMM. +This helps to ensure that the caching CMM can safely cache materials +that it receives from the customized underlying CMM. + +## Reference-level Explanation + +When the caching CMM is performing the Get Encryption Materials operation +for an Encryption Materials Request that does not specify a `max plaintext length`, + +- The caching CMM MUST NOT return materials from its CMC. +- If the caching CMM calls its underlying CMM's Get Encryption Materials operation + in order to obtain encryption materials, + it MUST NOT cache the encryption materials in its CMC. + +When the caching CMM calls its underlying CMM's Get Encryption Materials operation +in order to obtain encryption materials, +it MUST use its configured `byte limit` value +as the `max plaintext length` field of the Encryption Materials Request +that it sends to the underlying CMM. diff --git a/framework/caching-cmm.md b/framework/caching-cmm.md index dd383497..660cf269 100644 --- a/framework/caching-cmm.md +++ b/framework/caching-cmm.md @@ -5,15 +5,24 @@ ## Version -0.1.0-preview +0.2.0 + +### Changelog + +- 0.2.0 + - [Enforce Safe Handling of Max Plaintext Length in Caching Cryptographic Materials Manager](../changes/2020-07-13_caching-cmm-max-plaintext-length/change.md) +- 0.1.0-preview + - Initial record ## Implementations -- [C](https://github.com/aws/aws-encryption-sdk-c/blob/master/include/aws/cryptosdk/cache.h) -- [Python](https://github.com/aws/aws-encryption-sdk-python/blob/master/src/aws_encryption_sdk/materials_managers/caching.py) -- [Java](https://github.com/aws/aws-encryption-sdk-java/blob/master/src/main/java/com/amazonaws/encryptionsdk/caching/CachingCryptoMaterialsManager.java) -- [NodeJS](https://github.com/awslabs/aws-encryption-sdk-javascript/blob/master/modules/caching-materials-manager-node/src/caching_materials_manager_node.ts) -- [Browser JS](https://github.com/awslabs/aws-encryption-sdk-javascript/blob/master/modules/caching-materials-manager-browser/src/caching_materials_manager_browser.ts) +| Language | Confirmed Compatible with Spec Version | Minimum Version Confirmed | Implementation | +| ---------- | -------------------------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| C | 0.1.0-preview | 0.1.0 | [cache.h](https://github.com/aws/aws-encryption-sdk-c/blob/master/include/aws/cryptosdk/cache.h) | +| NodeJS | 0.1.0-preview | 0.1.0 | [caching_materials_manager_node.ts](https://github.com/awslabs/aws-encryption-sdk-javascript/blob/master/modules/caching-materials-manager-node/src/caching_materials_manager_node.ts) | +| Browser JS | 0.1.0-preview | 0.1.0 | [caching_materials_manager_browser.ts](https://github.com/awslabs/aws-encryption-sdk-javascript/blob/master/modules/caching-materials-manager-browser/src/caching_materials_manager_browser.ts) | +| Python | 0.1.0-preview | 1.3.0 | [materials_managers/caching.py](https://github.com/aws/aws-encryption-sdk-python/blob/master/src/aws_encryption_sdk/materials_managers/caching.py) | +| Java | 0.1.0-preview | 1.3.0 | [CachingCryptoMaterialsManager.java](https://github.com/aws/aws-encryption-sdk-java/blob/master/src/main/java/com/amazonaws/encryptionsdk/caching/CachingCryptoMaterialsManager.java) | ## Overview @@ -113,6 +122,7 @@ The number of bytes encrypted by the [encryption](structures.md#encryption-mater ### Get Encryption Materials If the [algorithm suite](algorithm-suites.md) requested contains a [Identity KDF](algorithm-suites.md#identity-kdf), +or if the request does not include a [Max Plaintext Length](cmm-interface.md#encryption-materials-request) value, the caching CMM MUST obtain the encryption materials by making a call to the underlying CMM's [Get Encryption Materials](cmm-interface.md#get-encryption-materials) function. Otherwise, the caching CMM MUST attempt to find the [encryption materials](structures.md#encryption-materials) @@ -122,10 +132,16 @@ If a cache entry is found, the caching CMM MUST return the encryption materials If a cache entry is not found, the caching CMM MUST then attempt to obtain the encryption materials by making a call to the underlying CMM's [Get Encryption Materials](cmm-interface.md#get-encryption-materials). +If the caching CMM makes a call to the underlying CMM's [Get Encryption Materials](cmm-interface.md#get-encryption-materials) operation, +then it MUST include a [Max Plaintext Length](cmm-interface.md#encryption-materials-request) value, +which MUST be equal to its [Limit Bytes](#limit-bytes) value. + If the [algorithm suite](algorithm-suites.md) requested does not contain an [Identity KDF](algorithm-suites.md#identity-kdf), +and if the request includes a [Max Plaintext Length](cmm-interface.md#encryption-materials-request) value, the caching CMM MUST add the encryption materials obtained from the underlying CMM into the underlying CMC. If the [algorithm suite](algorithm-suites.md) requested contains an Identity KDF, +or if the request does not include a [Max Plaintext Length](cmm-interface.md#encryption-materials-request) value, the caching CMM MUST NOT store the encryption materials in the underlying CMC. ### Decrypt Materials From 524f7a15bdb6d3459d4b645e26265324a30ad9f4 Mon Sep 17 00:00:00 2001 From: Alex Chew Date: Thu, 16 Jul 2020 11:28:01 -0700 Subject: [PATCH 2/3] Apply copy edits from code review --- .../change.md | 51 ++++++++++--------- framework/caching-cmm.md | 10 ++-- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/changes/2020-07-13_caching-cmm-max-plaintext-length/change.md b/changes/2020-07-13_caching-cmm-max-plaintext-length/change.md index de0f5ffd..e3a85e9f 100644 --- a/changes/2020-07-13_caching-cmm-max-plaintext-length/change.md +++ b/changes/2020-07-13_caching-cmm-max-plaintext-length/change.md @@ -37,16 +37,17 @@ in this document are to be interpreted as described in ## Summary The Get Encryption Materials operation accepts an optional `max plaintext length` parameter, -but the specification does not state how the caching CMM should behave -when the caller does not provide the parameter value. -This change specifies that the caching CMM should bypass the cache in this case. +but the specification does not state +how the caching Cryptographic Materials Manager (caching CMM) +should behave when the caller does not provide the parameter value. +This change specifies that the caching CMM MUST bypass the cache in this case. Also, when the caching CMM is performing a Get Encryption Materials operation for which no materials are cached, it MUST call its underlying CMM's Get Encryption Materials operation. The specification does not state what value of `max plaintext length` (if any) the caching CMM should pass to its underlying CMM. -This change specifies that the caching CMM should pass its `byte limit` value +This change specifies that the caching CMM MUST pass its `byte limit` value as the `max plaintext length` parameter of the call to the underlying CMM. ## Out of Scope @@ -57,15 +58,14 @@ as the `max plaintext length` parameter of the call to the underlying CMM. ### Fulfulling Encryption Materials Requests Without `max plaintext length` -The Get Encryption Materials operation of the Cryptographic Materials Manager (CMM) -accepts an Encryption Materials Request that MAY specify a `max plaintext length` field, +The Get Encryption Materials operation of the CMM +accepts an Encryption Materials Request that MUST optionally include a `max plaintext length` field, indicating the maximum length of plaintext that the caller intends to encrypt using the returned materials. -The caching Cryptographic Materials Manager (caching CMM) -aims to prevent its users from using encryption materials +The caching CMM aims to prevent its users from using encryption materials to encrypt more bytes than its configured `byte limit`, and existing implementations do so by bypassing the cache -whenever it does not know their users' `max plaintext length`. +whenever it does not know the `max plaintext length`. This behavior is safe but previously unspecified, and this change mandates that implementations implement it. @@ -73,7 +73,7 @@ and this change mandates that implementations implement it. The CMM interface specification implicitly allows an underlying CMM to produce encryption materials using logic -that depends on the `max plaintext length` of its Encryption Materials Request. +that depends on the `max plaintext length` of an Encryption Materials Request. Suppose the caching CMM passes a `max plaintext length` value of `N` to its underlying CMM's Get Encryption Materials operation, and caches the materials that it receives. @@ -91,8 +91,11 @@ even if the underlying CMM produces materials using plaintext-length-dependent l the caching CMM receives and caches materials that are safe to use for up to `byte limit` bytes of plaintext. It follows that if a later Get Encryption Materials operation's `max plaintext length` -does not exceed the caching CMM's `byte limit`, -then it is also safe for the caching CMM to return corresponding cached materials. +does not exceed the remaining number of bytes for which the cached materials can be safely used +(i.e., +the difference between the caching CMM's `byte limit` +and the sum of `max plaintext length` values from past uses of the cached materials), +then it is also safe for the caching CMM to return the cached materials. ## Drawbacks @@ -115,22 +118,22 @@ to the underlying CMM on Get Encryption Materials calls. ## Guide-level Explanation -When you make a Get Encryption Materials call to the caching CMM, -you may optionally specify a value for the `max plaintext length` parameter, -which indicates the maximum number of bytes you will encrypt -with the materials you receive from the call. -If you do not specify a `max plaintext length` value, +When making a Get Encryption Materials call to the caching CMM, +the user may optionally specify a value for the `max plaintext length` parameter, +which indicates the maximum number of bytes the user intends to encrypt +with the materials received from the call. +If the user does not specify a `max plaintext length` value, then the caching CMM will neither use cached materials nor cache materials from its underlying CMM. -This helps to ensure that you do not exceed the `byte limit` -that you configure on the caching CMM. -So in order to maximize the benefits of caching, -you should specify the `max plaintext length` value -whenever you know an appropriate upper bound for bytes you will encrypt. +This helps to ensure that the number of bytes encrypted with the materials +does not exceed the `byte limit` that the user configures on the caching CMM, +while also maximizing the benefits of caching. +So whenever the user can determine an appropriate upper bound for bytes they will encrypt, +they should specify the `max plaintext length` value. -If you customize the underlying CMM of a caching CMM, +If the user customizes the underlying CMM of a caching CMM, then whenever the caching CMM makes a Get Encryption Materials call -to your customized underlying CMM, +to the customized underlying CMM, the Encryption Materials Request will have a `max plaintext length` value equal to the `byte limit` value configured on the caching CMM. This helps to ensure that the caching CMM can safely cache materials diff --git a/framework/caching-cmm.md b/framework/caching-cmm.md index 660cf269..ae3d8f04 100644 --- a/framework/caching-cmm.md +++ b/framework/caching-cmm.md @@ -121,7 +121,7 @@ The number of bytes encrypted by the [encryption](structures.md#encryption-mater ### Get Encryption Materials -If the [algorithm suite](algorithm-suites.md) requested contains a [Identity KDF](algorithm-suites.md#identity-kdf), +If the [algorithm suite](algorithm-suites.md) requested contains a [Identity KDF](algorithm-suites.md#identity-kdf) or if the request does not include a [Max Plaintext Length](cmm-interface.md#encryption-materials-request) value, the caching CMM MUST obtain the encryption materials by making a call to the underlying CMM's [Get Encryption Materials](cmm-interface.md#get-encryption-materials) function. @@ -133,14 +133,14 @@ If a cache entry is not found, the caching CMM MUST then attempt to obtain the e by making a call to the underlying CMM's [Get Encryption Materials](cmm-interface.md#get-encryption-materials). If the caching CMM makes a call to the underlying CMM's [Get Encryption Materials](cmm-interface.md#get-encryption-materials) operation, -then it MUST include a [Max Plaintext Length](cmm-interface.md#encryption-materials-request) value, -which MUST be equal to its [Limit Bytes](#limit-bytes) value. +then the request MUST include a [Max Plaintext Length](cmm-interface.md#encryption-materials-request) +with a value equal to its [Limit Bytes](#limit-bytes) value. -If the [algorithm suite](algorithm-suites.md) requested does not contain an [Identity KDF](algorithm-suites.md#identity-kdf), +If the [algorithm suite](algorithm-suites.md) requested does not contain an [Identity KDF](algorithm-suites.md#identity-kdf) and if the request includes a [Max Plaintext Length](cmm-interface.md#encryption-materials-request) value, the caching CMM MUST add the encryption materials obtained from the underlying CMM into the underlying CMC. -If the [algorithm suite](algorithm-suites.md) requested contains an Identity KDF, +If the [algorithm suite](algorithm-suites.md) requested contains an Identity KDF or if the request does not include a [Max Plaintext Length](cmm-interface.md#encryption-materials-request) value, the caching CMM MUST NOT store the encryption materials in the underlying CMC. From 89024b396dbe2bc77db9bedb247343dd4b4e1323 Mon Sep 17 00:00:00 2001 From: Alex Chew Date: Thu, 16 Jul 2020 11:56:54 -0700 Subject: [PATCH 3/3] Clarify unsafe max plaintext length example --- .../change.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/changes/2020-07-13_caching-cmm-max-plaintext-length/change.md b/changes/2020-07-13_caching-cmm-max-plaintext-length/change.md index e3a85e9f..fbba816b 100644 --- a/changes/2020-07-13_caching-cmm-max-plaintext-length/change.md +++ b/changes/2020-07-13_caching-cmm-max-plaintext-length/change.md @@ -77,9 +77,12 @@ that depends on the `max plaintext length` of an Encryption Materials Request. Suppose the caching CMM passes a `max plaintext length` value of `N` to its underlying CMM's Get Encryption Materials operation, and caches the materials that it receives. -If a later Get Encryption Materials operation fetches those materials from the cache, -but has a `max plaintext length` value that exceeds `N`, -then the caching CMM returns those materials unsafely. +This signals to the underlying CMM that it intends to use the materials +to _only_ encrypt up to `N` bytes. +If a later Get Encryption Materials operation has a `max plaintext length` greater than `N`, +and if the caching CMM returns the cached materials, +then the user may use the materials to encrypt _more_ than `N` bytes. +The caching CMM violates its prior intent, which is unsafe. It is therefore important that the caching CMM carefully selects the `max plaintext length` parameter to pass to its underlying CMM.