Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(decrypt): specify behavior on decrypt with encryption context #261

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

josecorella
Copy link
Contributor

Issue #, if available:

Description of changes:

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Check any applicable:

  • Were any files moved? Moving files changes their URL, which breaks all hyperlinks to the files.

@josecorella josecorella requested a review from a team as a code owner September 27, 2023 23:22
Comment on lines 33 to 35
It MUST be required that the decryption materials obtained from the underlying CMM's MUST
contain all configured encryption context keys in its encryption context and the values MUST remain
unchanged.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what this means. What is a "configured encryption conext key? How do we enforce they remain unchanged?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"configured encryption conext key" this should be "required encryption context key"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am trying to get at is that if the CMM returns encryption context which IS stored AND one of the keys in the required encryption context is also in this encryption context then the value in their key-value pair mapping MUST remain unchanged

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we break down what's in the PR:

contain all required encryption context key in (the decryption material's) encryption context

This is already a requirement on decryption materials. If a "key" is required, that key-value pair must exist in the encryption context on those materials.

the values (of the required encryption context keys? or all EC values?) MUST remain unchanged (from what?)

Which values? (it should be the values corresponding to the required encryption context keys)

What does "unchanged" mean? Unchanged from what? (Unchanged from the EC in the header, if that key also exists in the header)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
It MUST be required that the decryption materials obtained from the underlying CMM's MUST
contain all configured encryption context keys in its encryption context and the values MUST remain
unchanged.
The decryption materials obtained from the underlying CMM's MUST
contain all required encryption context keys in its encryption context and the values MUST remain
unchanged.

Is the problem that https://github.com/awslabs/aws-encryption-sdk-specification/blob/master/framework/cmm-interface.md#decrypt-materials

The CMM MUST validate the Encryption Context by comparing it to the customer supplied Reproduced Encryption Context in decrypt materials request. For every key that exists in both Reproduced Encryption Context and Encryption Context, the values MUST be equal or the operation MUST fail.

is not a post condition?

### Test Different Encryption Context on Decrypt Failure

Encrypt with and store all encryption context in the message header.
On Decrypt will supply additional encryption context not stored in the header.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is testing a total disjoint between expected EC and inputted EC. We should seperately test "inputted EC is missing a pair", "inputted EC has an incorrect value for one pair", and "inputted EC has an extra pair".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the tests below, I think we cover all of these except "inputted EC has an extra pair"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding in latest revision

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As set up, this could fail due to either:

  • reproduced EC missing required key-value pairs
  • reproduced EC including an extra key-value pair

Which one do we want this test to target?

// Test supply same encryption context on encrypt and decrypt NO filtering
var encryptionContext := map[ keyA := valA, keyB := valB ];
var reproducedAdditionalEncryptionContext := map[ keyA := valB, keyB := valA ];
var requiredEncryptionContextKeys := [keyA, keyB];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this was testing context that is in the header?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup good catch

changes/2023-09-26_encryption-context-decrypt/change.md Outdated Show resolved Hide resolved
NOT some key-value pair that the underlying CMM MAY have modified.

If required keys exist, match stored encryption context, AND decryption succeeds
Decrypt MUST return both the Encryption Context stored in the header AND the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This "AND" is ambiguous. I believe it should be the union of these maps.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, should it just replicate our logic for inclusion in the header validation?
i.e. Every key-value pair in the header, and every "required" key-value pair in the EC?

client-apis/decrypt.md Outdated Show resolved Hide resolved
Comment on lines 20 to 25
Decrypt returns Encryption Context.
This requirement may be satisfied by returning the parsed header that contains this value.

With the addition of the [required encryption context cmm](../../framework/required-encryption-context-cmm.md),
the encrypt API is able to filter out encryption context key-value pairs that
are not stored on the message.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'd flip the order of these and edit it to say that we used to be able to satisfy the requirement by just returning the header, but that is no longer the case, as the header may not contain all EC values used to authenticate the message anymore.

Comment on lines 33 to 35
It MUST be required that the decryption materials obtained from the underlying CMM's MUST
contain all configured encryption context keys in its encryption context and the values MUST remain
unchanged.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we break down what's in the PR:

contain all required encryption context key in (the decryption material's) encryption context

This is already a requirement on decryption materials. If a "key" is required, that key-value pair must exist in the encryption context on those materials.

the values (of the required encryption context keys? or all EC values?) MUST remain unchanged (from what?)

Which values? (it should be the values corresponding to the required encryption context keys)

What does "unchanged" mean? Unchanged from what? (Unchanged from the EC in the header, if that key also exists in the header)


On Encrypt will write all encryption context supplied to the message.
On Decrypt will have a Required Encryption Context CMM that requires all encryption context
on Decrypt.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This MUST succeed.

### Test Different Encryption Context on Decrypt Failure

Encrypt with and store all encryption context in the message header.
On Decrypt will supply additional encryption context not stored in the header.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As set up, this could fail due to either:

  • reproduced EC missing required key-value pairs
  • reproduced EC including an extra key-value pair

Which one do we want this test to target?


// Test supply same encryption context on encrypt and decrypt NO filtering
var encryptionContext := map[ keyA := valA, keyB := valB ];
var reproducedAdditionalEncryptionContext := map[ keyA := valA, keyB := valB, keyC := valC ];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To test mismatch, don't you want this to be something like map[ keyA := valA, keyB := valC ];? i.e. the keys are correct but the values are not? Otherwise this is testing "extra unexpected key-value pair" again.


Encrypt will NOT store all encryption context.
Decrypt will NOT supply reproduced encryption context.
This operation MUST fail.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this failing due to the Required Encryption Context CMM, or is authentication failing? Which are we trying to put under test? These descriptions should make clear whether or not the REC CMM is involved or not.

:: decryptionMaterials[k] == headerEncryptionContext[k]
```

## Testing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking more about this, I think it would be better to more clearly define what the matrix is we care about, as opposed to listing out the different tests and code for them. I would prefer we cut the example code, but make it extremely clear what every case we need to check is in a way that makes it easy to reason that it is complete. For example, maybe frame it like this:


First, suppose we have a message where {A:B,C:D} is in the header, and {E:F} is not stored, but is included in the authentication.

For this message, go through the following test cases:

  • customer supplies correct required key-value {E:F} (SUCCESS)
  • customer supplies correct required key-value and additional correct header value {A:B,E:F} (SUCCESS)
  • customer supplies does not supply required key-value {} (FAILURE)
  • customer supplies incorrect value for required key-value {E:X} (FAILURE)
  • customer supplies correct required key-value and additional incorrect header value {A:X,E:F} (FAILURE)
  • customer supplies correct required key-value and additional incorrect, non-header key-value {E:F,X:Y} (FAILURE)

For every one of the above cases, attempt to decrypt using both a Default CMM, and a REC CMM with E configured as a "required key".

Next, suppose we have a message where {A:B,C:D,E:F} is in the header, and there is no additional non-stored key-values authenticated with the message.

For this message, go through the following test cases:

  • customer supplies no reproduced context {} (SUCCESS)
  • customer supplies additional correct header values {A:B,C:D,E:F} (SUCCESS)
  • customer supplies incorrect value for key in header {A:X} (FAILURE)
  • customer supplies incorrect, non-header key-value {X:Y} (FAILURE)

For each of these use a Default CMM.


This is more test cases than we currently have, and we may be able to convince ourselves that some of those test cases are not actually useful. However, I would prefer if this document focused on listing the parameters for the test cases in a way that is easy for readers to see whether we are missing any (And if we decide any are not useful, say why). If we do this, I don't think we need to give example code for each test case.

@@ -162,6 +164,8 @@ that implementation SHOULD NOT provide an API that allows the caller to stream t

The [encryption context](../framework/structures.md#encryption-context) that is used as
additional authenticated data during the decryption of the input [encrypted message](#encrypted-message).
Specifically, it MUST be the union of the encryption context serialized into the message header and
the encryption context for authentication only, if available.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

encryption context for authentication only Can we point to the definition of this somewhere?

Comment on lines 33 to 35
It MUST be required that the decryption materials obtained from the underlying CMM's MUST
contain all configured encryption context keys in its encryption context and the values MUST remain
unchanged.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
It MUST be required that the decryption materials obtained from the underlying CMM's MUST
contain all configured encryption context keys in its encryption context and the values MUST remain
unchanged.
The decryption materials obtained from the underlying CMM's MUST
contain all required encryption context keys in its encryption context and the values MUST remain
unchanged.

Is the problem that https://github.com/awslabs/aws-encryption-sdk-specification/blob/master/framework/cmm-interface.md#decrypt-materials

The CMM MUST validate the Encryption Context by comparing it to the customer supplied Reproduced Encryption Context in decrypt materials request. For every key that exists in both Reproduced Encryption Context and Encryption Context, the values MUST be equal or the operation MUST fail.

is not a post condition?

Comment on lines 37 to 38
The Decrypt API MUST return the set of the union of the encryption context stored in the header and the encryption
context used for authentication only.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree but this feels like a jump.

The Decrypt API MUST return the set of the union of the encryption context stored in the header and the encryption
context used for authentication only.

### What changes to the existing Required Encryption Context CMM are required?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any changes to the CMM interface?

Comment on lines 36 to 37
Decrypt MUST verify that if the keys in the required encryption context keys exist in the reproduced encryption context
AND they are stored in the message header, they MUST have the same value as the reproduced encryption context supplied.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not how you have change the spec:

- If a [required encryption context key](../framework/structures.md#required-encryption-context-keys) in
  the decryption materials' response exists in the [message header body](../data-format/message-header.md#header-body)
  the value in the decryption materials' encryption context MUST equal the value stored in the message header body.

If you want what you have specified, then I think you need:

Suggested change
Decrypt MUST verify that if the keys in the required encryption context keys exist in the reproduced encryption context
AND they are stored in the message header, they MUST have the same value as the reproduced encryption context supplied.
For required encryption context keys the value in stored in the message header
MUST equal the value in decryption materials encryption context.

A poorly designed CMM could theoretically return materials with an "incorrect" encryption context
that contradicts the encryption context in the header of the message.

The `decrypt` API SHOULD not check if the encryption context that was stored on the message matches
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The `decrypt` API SHOULD not check if the encryption context that was stored on the message matches
The `decrypt` API SHOULD NOT check if the encryption context that was stored on the message matches


The `decrypt` API SHOULD not check if the encryption context that was stored on the message matches
what it receives from the CMMs DecryptMaterials because the current implementation
of the `encrypt` API used with the built-in CMMs is not able to write a message
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stronger than built-in.
It constructs the 2 sets of EC from a single set.
So these 2 sets (stored/not stored) MUST be disjoint.

- `{ b: b, c: c}`
- `{ a: a, b: b, c: c }`

### Message: `{a: a, b: b}` / `{}`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can further wordsmith these tables to simplify.
But this is a good start!

- Stored EC -- EC stored in the header
- Not stored EC -- EC authenticated to the header but not stored
- CMM Material EC -- EC on the decryption material
- Required keys -- Keys for the EC that MAY be only authenticated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As described by the CMM in the decryption materials? Otherwise this is "the same" as "Not stored EC"

- `{a: a, b: b}` / `{a}`
- `{a: a, b: b}` / `{a,b}`
- `{a: a, b: c}` / `{a}`
- `{a: a, b: b}` / `{c}`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The specification for decryption materials doesn't allow this case.

| CMM Material/Required Keys &rarr; <br/>Reproduced EC &darr; | `{a: a, b: b}` / `{}` | `{a: a, b: b}` / `{a}` | `{a: a, b: b}` / `{a,b}` | `{a: a, b: c}` / `{a}` | `{a: a, b: b}` / `{c}` |
| ----------------------------------------------------------- | --------------------- | ---------------------- | ------------------------ | ---------------------- | ---------------------- |
| `{}` | pass | fail | fail | fail | fail |
| `{ a: a }` | pass | pass | fail | fail | fail |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should expect every column except for the first to always fail during the header authentication step, regardless of the inputted reproduced encryption context. ('a' or 'b' would be incorrectly appended to the header authentication).

Comment on lines +165 to +166
Specifically, it MUST be the union of the encryption context serialized into the message header and
the [encryption context for authentication only](#encryption-context-to-only-authenticate), if available.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We know that by the time you are returning a result that these maps are disjoint, but this won't be something we will be able to prove in dafny... I'm unsure whether we want to specifically make a note in the spec of this expectation or not.


### Message: `{a: a}` / `{b: b}`

| CMM Material/Required Keys &rarr; <br/>Reproduced EC &darr; | `{a: a, b: b}` / `{}` | `{a: a, b: b}` / `{a}` | `{a: a, b: b}` / `{a,b}` | `{a: a, b: c}` / `{a}` | `{a: a, b: b}` / `{c}` |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you actually want the message to be {b: b} /{a: a} Otherwise, all of these columns should always fail, as the header auth won't ever correctly append a 'b' value during verification, regardless of the reproduced encryption context.


| CMM Material/Required Keys &rarr; <br/>Reproduced EC &darr; | `{a: a, b: b}` / `{}` | `{a: a, b: b}` / `{a}` | `{a: a, b: b}` / `{a,b}` | `{a: a, b: c}` / `{a}` | `{a: a, b: b}` / `{c}` |
| ----------------------------------------------------------- | --------------------- | ---------------------- | ------------------------ | ---------------------- | ---------------------- |
| `{}` | fail | fail | fail | fail | fail |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want to represent some of these as N/As. For example, if the reproduced context does not contain b, how would the CMM ever be able to return a 'b'.

It may be easier to reason about this matrix if we represent the obviously wrong values with something like x, to better indicate that this is just some junk value, and is possible for the CMM to add to the EC.


### Message:`{}` / `{a: a, b: b}`

| CMM Material/Required Keys &rarr; <br/>Reproduced EC &darr; | `{a: a, b: b}` / `{}` | `{a: a, b: b}` / `{a}` | `{a: a, b: b}` / `{a,b}` | `{a: a, b: c}` / `{a}` | `{a: a, b: b}` / `{c}` |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the other tables, I think that {a: a, b: b} / {} is the only column that could ever succeed.

- `{a: a}` / `{b: b}`
- `{}` / `{a: a, b: b}`

CMM Material/Required Keys
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is missing:

  • {a: a, b: b, x: x} / {a}
  • {a: x, b: b} / {a}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants