Skip to content

feat: add more attributes to encryption context #719

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

Merged
merged 64 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
80d4078
feat: add more attributes to encryption context
ajewellamz Jan 16, 2024
b1bb844
m
ajewellamz Jan 16, 2024
f020cda
m
ajewellamz Jan 16, 2024
875e24c
Merge branch 'main' into ajewell/more-context
ajewellamz Jan 17, 2024
c57dfa1
m
ajewellamz Jan 17, 2024
3a35e4d
m
ajewellamz Jan 22, 2024
1fb5c82
Merge branch 'main' into ajewell/more-context
ajewellamz Jan 22, 2024
a4b27ef
m
ajewellamz Jan 22, 2024
7d584fa
m
ajewellamz Jan 23, 2024
4bc9dc3
m
ajewellamz Jan 23, 2024
59f4032
m
ajewellamz Jan 23, 2024
a2cd600
m
ajewellamz Jan 23, 2024
34a82c2
m
ajewellamz Jan 25, 2024
82ba1e1
m
ajewellamz Jan 25, 2024
84a03e9
m
ajewellamz Jan 25, 2024
86c7067
m
ajewellamz Jan 25, 2024
44355cb
m
ajewellamz Jan 25, 2024
03ead71
m
ajewellamz Jan 26, 2024
857a8b2
m
ajewellamz Jan 26, 2024
6a2f20d
m
ajewellamz Jan 29, 2024
5ac8553
m
ajewellamz Jan 30, 2024
1e26bac
m
ajewellamz Jan 30, 2024
71b4335
m
ajewellamz Jan 31, 2024
4388a11
m
ajewellamz Feb 1, 2024
25d2a3d
m
ajewellamz Feb 2, 2024
75e646e
m
ajewellamz Feb 2, 2024
eceb065
m
ajewellamz Feb 2, 2024
0b88cbb
m
ajewellamz Feb 3, 2024
7a9cd93
m
ajewellamz Feb 4, 2024
d213719
m
ajewellamz Feb 5, 2024
2ac0621
m
ajewellamz Feb 5, 2024
c383d86
Update specification/changes/2024-02-29-encryption-context/change.md
ajewellamz Feb 7, 2024
2880835
Update specification/changes/2024-02-29-encryption-context/change.md
ajewellamz Feb 7, 2024
7fb4437
Update specification/changes/2024-02-29-encryption-context/change.md
ajewellamz Feb 7, 2024
42c50f6
Update specification/changes/2024-02-29-encryption-context/change.md
ajewellamz Feb 7, 2024
06fed58
Update DynamoDbEncryption/dafny/DynamoDbItemEncryptor/src/Util.dfy
ajewellamz Feb 7, 2024
e6e98db
m
ajewellamz Feb 7, 2024
0a8109b
m
ajewellamz Feb 8, 2024
6997b8e
m
ajewellamz Feb 8, 2024
2517ac7
m
ajewellamz Feb 8, 2024
09398d1
m
ajewellamz Feb 8, 2024
a176b7f
feat: support context_and_sign in enhanced client (#724)
ajewellamz Feb 10, 2024
d00c5e5
Makefiles
ajewellamz Feb 13, 2024
d107b6e
no sign-and-include for GSI keys
ajewellamz Feb 15, 2024
cbc14f2
Merge branch 'main' into ajewell/more-context
ajewellamz Feb 15, 2024
6571759
m
ajewellamz Feb 17, 2024
7e4de93
changes.md
ajewellamz Feb 18, 2024
69ec293
m
ajewellamz Feb 20, 2024
37fa00b
feat: better support of single table design (#736)
ajewellamz Feb 27, 2024
a87ef0e
Merge branch 'main' into ajewell/more-context
ajewellamz Feb 27, 2024
cb21c00
feat: add query to enhanced client example (#766)
ajewellamz Feb 27, 2024
e800cbd
test denormalized number
ajewellamz Mar 4, 2024
037d84c
signAndInclude in Example
ajewellamz Mar 11, 2024
50af82a
m
ajewellamz Mar 11, 2024
8fedcc4
m
ajewellamz Mar 11, 2024
69116f9
m
ajewellamz Mar 11, 2024
925140e
m
ajewellamz Mar 11, 2024
52930c0
m
ajewellamz Mar 11, 2024
1aa5398
Merge branch 'main' into ajewell/more-context
ajewellamz Mar 13, 2024
c0a7624
distingush primary keys from other index keys
ajewellamz Mar 13, 2024
7c0b16a
m
ajewellamz Mar 13, 2024
7cdef68
Merge branch 'main' into ajewell/more-context
ajewellamz Mar 15, 2024
5b5a48f
Merge branch 'main' into ajewell/more-context
ajewellamz Mar 18, 2024
17fe3c4
guard against duplicate EC entry
ajewellamz Mar 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,12 @@ module AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorOperations refines Abs
else if action == CSE.ENCRYPT_AND_SIGN then
"ENCRYPT_AND_SIGN"
else
assert action != CSE.DO_NOTHING;
assert action != CSE.SIGN_ONLY;
assert action != CSE.SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT;
assert action != CSE.ENCRYPT_AND_SIGN;
assert false;
assert false by {
assert action != CSE.DO_NOTHING;
assert action != CSE.SIGN_ONLY;
assert action != CSE.SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT;
assert action != CSE.ENCRYPT_AND_SIGN;
}
"internal error"
}

Expand Down Expand Up @@ -731,8 +732,8 @@ module AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorOperations refines Abs
//# [SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT](../structured-encryption/structures.md#contextandsign)
//# then this item MUST include an Attribute with that name.
ensures output.Success? ==>
forall k <- config.attributeActionsOnEncrypt :: (config.attributeActionsOnEncrypt[k] == CSE.SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT) ==> (k in input.plaintextItem)
// ContextAttrsExist(config.attributeActionsOnEncrypt, input.plaintextItem)
forall k <- config.attributeActionsOnEncrypt :: (config.attributeActionsOnEncrypt[k] == CSE.SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT) ==> (k in input.plaintextItem)
// ContextAttrsExist(config.attributeActionsOnEncrypt, input.plaintextItem)

ensures
&& output.Success?
Expand Down Expand Up @@ -782,6 +783,16 @@ module AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorOperations refines Abs
&& SE.IsAuthAttr(parsedHeaderMap[k].content.Action))
&& var maybeCryptoSchema := ConvertCryptoSchemaToAttributeActions(config, structuredEncParsed.cryptoSchema);
&& maybeCryptoSchema.Success?
&& ConvertContextForSelector(structuredEncParsed.encryptionContext).Success?
&& var selectorContext := ConvertContextForSelector(structuredEncParsed.encryptionContext).value;
&& output.value.parsedHeader.value == ParsedHeader(
attributeActionsOnEncrypt := maybeCryptoSchema.value,
algorithmSuiteId := structuredEncParsed.algorithmSuiteId,
storedEncryptionContext := structuredEncParsed.storedEncryptionContext,
encryptedDataKeys := structuredEncParsed.encryptedDataKeys,
encryptionContext := structuredEncParsed.encryptionContext,
selectorContext := selectorContext
)

//= specification/dynamodb-encryption-client/encrypt-item.md#behavior
//= type=implication
Expand Down Expand Up @@ -993,6 +1004,16 @@ module AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorOperations refines Abs
&& SE.IsAuthAttr(structuredEncParsed.cryptoSchema.content.SchemaMap[k].content.Action))
&& var maybeCryptoSchema := ConvertCryptoSchemaToAttributeActions(config, structuredEncParsed.cryptoSchema);
&& maybeCryptoSchema.Success?
&& ConvertContextForSelector(structuredEncParsed.encryptionContext).Success?
&& var selectorContext := ConvertContextForSelector(structuredEncParsed.encryptionContext).value;
&& output.value.parsedHeader.value == ParsedHeader(
attributeActionsOnEncrypt := maybeCryptoSchema.value,
algorithmSuiteId := structuredEncParsed.algorithmSuiteId,
storedEncryptionContext := structuredEncParsed.storedEncryptionContext,
encryptedDataKeys := structuredEncParsed.encryptedDataKeys,
encryptionContext := structuredEncParsed.encryptionContext,
selectorContext := selectorContext
)

//= specification/dynamodb-encryption-client/decrypt-item.md#behavior
//= type=implication
Expand Down
147 changes: 84 additions & 63 deletions DynamoDbEncryption/dafny/DynamoDbItemEncryptor/src/Util.dfy
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,31 @@ module DynamoDbItemEncryptorUtil {
const SELECTOR_PARTITION_NAME : DDB.AttributeName := "aws_dbe_partition_name"
const SELECTOR_SORT_NAME : DDB.AttributeName := "aws_dbe_sort_name"

method GetLiteralValue(x : seq<uint8>) returns (ret : Result<DDB.AttributeValue, string>)
function method GetLiteralValue(x : seq<uint8>) : (ret : Result<DDB.AttributeValue, string>)
{
var str :- UTF8.Decode(x);
if str == SE.TRUE_STR {
return Success(DDB.AttributeValue.BOOL(true));
} else if str == SE.FALSE_STR {
return Success(DDB.AttributeValue.BOOL(false));
} else if str == SE.NULL_STR {
return Success(DDB.AttributeValue.NULL(true));
} else {
return Failure("Encryption Context literal value has unexpected value : '" + str + "'.");
}
if str == SE.TRUE_STR then
Success(DDB.AttributeValue.BOOL(true))
else if str == SE.FALSE_STR then
Success(DDB.AttributeValue.BOOL(false))
else if str == SE.NULL_STR then
Success(DDB.AttributeValue.NULL(true))
else
Failure("Encryption Context literal value has unexpected value : '" + str + "'.")
}

method ConvertContextForSelector(context : MPL.EncryptionContext)
returns (output: Result<DDB.Key, string>)
function method GetSortKey(context : MPL.EncryptionContext) : Result<Option<UTF8.ValidUTF8Bytes>, string>
{
if SORT_NAME in context.Keys then
var sortName := SE.EC_ATTR_PREFIX + context[SORT_NAME];
:- Need(UTF8.ValidUTF8Seq(sortName), "Internal Error : bad utf8 in sortName");
Success(Some(sortName))
else
Success(None)
}

function method ConvertContextForSelector(context : MPL.EncryptionContext)
: (output: Result<DDB.Key, string>)
//= specification/dynamodb-encryption-client/ddb-encryption-branch-key-id-supplier.md#behavior
//= type=implication
//# - If the partition name does not exist in the encryption context, this operation MUST fail.
Expand Down Expand Up @@ -111,75 +120,86 @@ module DynamoDbItemEncryptorUtil {
var partitionValueKey := SE.EC_ATTR_PREFIX + partitionName;
:- Need(partitionValueKey in context.Keys, "Invalid encryption context: Missing partition value");

if SORT_NAME in context.Keys {
var sortName := context[SORT_NAME];
var sortValueKey := SE.EC_ATTR_PREFIX + sortName;
:- Need(sortValueKey in context.Keys, "Invalid encryption context: Missing sort value");
}
var sortValueKey :- GetSortKey(context);
:- Need(sortValueKey.None? || sortValueKey.value in context, "Invalid encryption context: Missing sort value");

var attrMap: DDB.AttributeMap := map[];
var keys : seq<UTF8.ValidUTF8Bytes> := SortedSets.ComputeSetToOrderedSequence2(context.Keys, SE.ByteLess);

//= specification/dynamodb-encryption-client/ddb-encryption-branch-key-id-supplier.md#behavior
//# - If the field "aws-crypto-legend" exists in the encryption context,
//# it MUST [deserialize](./ddb-attribute-serialization.md), all values with keys beginning "aws-crypto-attr.",
//# and create a Key with these values, using names with the "aws-crypto-attr." removed.
if SE.LEGEND_UTF8 in context {
if SE.LEGEND_UTF8 in context then
var legend :- UTF8.Decode(context[SE.LEGEND_UTF8]);

var attrPos := 0;
for i := 0 to |keys|
invariant attrPos <= i
{
var key : UTF8.ValidUTF8Bytes := keys[i];
if SE.EC_ATTR_PREFIX < key {
:- Need(|legend| > attrPos, "Encryption Context Legend is too short.");
var ddbAttrName :- GetAttributeName(key);
var ch := legend[attrPos];
if ch == SE.LEGEND_STRING {
var value :- UTF8.Decode(context[key]);
attrMap := attrMap[ddbAttrName := DDB.AttributeValue.S(value)];
} else if ch == SE.LEGEND_NUMBER {
var value :- UTF8.Decode(context[key]);
attrMap := attrMap[ddbAttrName := DDB.AttributeValue.N(value)];
} else if ch == SE.LEGEND_LITERAL {
var value :- GetLiteralValue(context[key]);
attrMap := attrMap[ddbAttrName := value];
} else if ch == SE.LEGEND_BINARY {
attrMap :- AddAttributeToMap(key, context[key], attrMap);
} else {
return Failure("Encryption Context Legend has unexpected character : '" + [legend[attrPos]] + "'.");
}
attrPos := attrPos + 1;
}
}
:- Need(|legend| == attrPos, "Encryption Context Legend is too long.");
var attrMap :- GetV2AttrMap(keys, context, legend);

:- Need(TABLE_NAME in context, "Internal error, table name not in encryption context.");
var tableName :- UTF8.Decode(context[TABLE_NAME]);
attrMap := attrMap[SELECTOR_TABLE_NAME := DDB.AttributeValue.S(tableName)];
var attrMap2 := attrMap[SELECTOR_TABLE_NAME := DDB.AttributeValue.S(tableName)];

:- Need(PARTITION_NAME in context, "Internal error, table name not in encryption context.");
var partitionName :- UTF8.Decode(context[PARTITION_NAME]);
attrMap := attrMap[SELECTOR_PARTITION_NAME := DDB.AttributeValue.S(partitionName)];
var attrMap3 := attrMap2[SELECTOR_PARTITION_NAME := DDB.AttributeValue.S(partitionName)];

if SORT_NAME in context {
if SORT_NAME in context then
var sortName :- UTF8.Decode(context[SORT_NAME]);
attrMap := attrMap[SELECTOR_SORT_NAME := DDB.AttributeValue.S(sortName)];
}
//= specification/dynamodb-encryption-client/ddb-encryption-branch-key-id-supplier.md#behavior
//# - If the field "aws-crypto-legend" does not exist in the encryption context, it MUST [deserialize the partition (and optionally sort) value](./ddb-attribute-serialization.md), and create a Key with these values.
} else {
for i := 0 to |keys| {
var key : UTF8.ValidUTF8Bytes := keys[i];
if SE.EC_ATTR_PREFIX < key {
attrMap :- AddAttributeToMap(key, context[key], attrMap);
}
}
}
return Success(attrMap);
Success(attrMap3[SELECTOR_SORT_NAME := DDB.AttributeValue.S(sortName)])
else
Success(attrMap3)

//= specification/dynamodb-encryption-client/ddb-encryption-branch-key-id-supplier.md#behavior
//# - If the field "aws-crypto-legend" does not exist in the encryption context, it MUST [deserialize the partition (and optionally sort) value](./ddb-attribute-serialization.md), and create a Key with these values.
else if sortValueKey.None? then
AddAttributeToMap(partitionValueKey, context[partitionValueKey], map[])
else
var attrMap :- AddAttributeToMap(partitionValueKey, context[partitionValueKey], map[]);
AddAttributeToMap(sortValueKey.value, context[sortValueKey.value], attrMap)
}

function method GetAttrValue(ecValue : UTF8.ValidUTF8Bytes, legend : char)
: Result<DDB.AttributeValue, string>
{
if legend == SE.LEGEND_STRING then
var value :- UTF8.Decode(ecValue);
Success(DDB.AttributeValue.S(value))
else if legend == SE.LEGEND_NUMBER then
var value :- UTF8.Decode(ecValue);
Success(DDB.AttributeValue.N(value))
else if legend == SE.LEGEND_LITERAL then
var value :- GetLiteralValue(ecValue);
Success(value)
else if legend == SE.LEGEND_BINARY then
var terminal :- SE.DecodeTerminal(ecValue);
var ddbAttrValue :- DynamoToStruct.BytesToAttr(terminal.value, terminal.typeId, false);
Success(ddbAttrValue.val)
else
Failure("Encryption Context Legend has unexpected character : '" + [legend] + "'.")
}

function method GetV2AttrMap(
keys : seq<UTF8.ValidUTF8Bytes>,
context : MPL.EncryptionContext,
legend : string,
attrMap : DDB.AttributeMap := map[]
)
: Result<DDB.AttributeMap, string>
requires forall k <- keys :: k in context
{
if |keys| == 0 then
if |legend| == 0 then
Success(attrMap)
else
Failure("Encryption Context Legend is too long.")
else
var key : UTF8.ValidUTF8Bytes := keys[0];
if SE.EC_ATTR_PREFIX < key then
:- Need(0 < |legend|, "Encryption Context Legend is too short.");
var attrName :- GetAttributeName(key);
var attrValue :- GetAttrValue(context[key], legend[0]);
GetV2AttrMap(keys[1..], context, legend[1..], attrMap[attrName := attrValue])
else
GetV2AttrMap(keys[1..], context, legend, attrMap)
}

function method GetAttributeName(ddbAttrKey: UTF8.ValidUTF8Bytes)
: (res: Result<DDB.AttributeName, string>)
Expand All @@ -191,6 +211,7 @@ module DynamoDbItemEncryptorUtil {
:- Need(DDB.IsValid_AttributeName(ddbAttrName), "Invalid serialization of DDB Attribute in encryption context.");
Success(ddbAttrName)
}

function method AddAttributeToMap(ddbAttrKey: UTF8.ValidUTF8Bytes, encodedAttrValue: UTF8.ValidUTF8Bytes, attrMap: DDB.AttributeMap)
: (res: Result<DDB.AttributeMap, string>)
requires |ddbAttrKey| >= |SE.EC_ATTR_PREFIX|
Expand Down
Loading