-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathDdbMiddlewareConfig.dfy
142 lines (122 loc) · 5.19 KB
/
DdbMiddlewareConfig.dfy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
include "../Model/AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes.dfy"
module DdbMiddlewareConfig {
import opened Wrappers
import opened AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes
import DynamoDbItemEncryptor
import EncTypes = AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes
import DDBE = AwsCryptographyDbEncryptionSdkDynamoDbTypes
import SearchableEncryptionInfo
import DDB = ComAmazonawsDynamodbTypes
import HexStrings
datatype TableConfig = TableConfig(
physicalTableName: ComAmazonawsDynamodbTypes.TableName,
logicalTableName: string,
partitionKeyName: string,
sortKeyName: Option<string>,
itemEncryptor: DynamoDbItemEncryptor.DynamoDbItemEncryptorClient,
search : Option<SearchableEncryptionInfo.ValidSearchInfo>,
plaintextOverride: AwsCryptographyDbEncryptionSdkDynamoDbTypes.PlaintextOverride
)
// return true if records written to the table should NOT be encrypted or otherwise modified
predicate method IsPlainWrite(config : Config, tableName : string)
{
|| tableName !in config.tableEncryptionConfigs
|| config.tableEncryptionConfigs[tableName].plaintextOverride == AwsCryptographyDbEncryptionSdkDynamoDbTypes.PlaintextOverride.FORCE_PLAINTEXT_WRITE_ALLOW_PLAINTEXT_READ
}
predicate ValidTableConfig?(config: TableConfig) {
var encryptorConfig := config.itemEncryptor.config;
&& config.logicalTableName == encryptorConfig.logicalTableName
&& config.partitionKeyName == encryptorConfig.partitionKeyName
&& config.sortKeyName == encryptorConfig.sortKeyName
&& config.itemEncryptor.ValidState()
&& OneSearchValidState(config)
}
type ValidTableConfig = c: TableConfig | ValidTableConfig?(c) witness *
function OneSearchModifies(config : ValidTableConfig) : set<object>
{
if config.search.Some? then config.search.value.Modifies() else {}
}
function SearchModifies(config: Config) : set<object>
{
//set x, y | y in config.tableEncryptionConfigs && x in OneSearchModifies(config.tableEncryptionConfigs[y]) :: x
set versions <- set configValue <- config.tableEncryptionConfigs.Values | configValue.search.Some? :: configValue.search.value.versions,
keyStore <- set version <- versions :: version.keySource.store,
obj <- keyStore.Modifies | obj in keyStore.Modifies :: obj
}
predicate OneSearchValidState(config : TableConfig)
{
&& (config.search.Some? ==> config.search.value.ValidState())
}
predicate SearchValidState(config: Config)
{
forall k <- config.tableEncryptionConfigs :: OneSearchValidState(config.tableEncryptionConfigs[k])
}
function ModifiesConfig(config: Config) : set<object>
{
(set t <- config.tableEncryptionConfigs.Keys, o <- config.tableEncryptionConfigs[t].itemEncryptor.Modifies :: o)
+ (set t <- config.tableEncryptionConfigs.Keys, o <- OneSearchModifies(config.tableEncryptionConfigs[t]) :: o)
}
predicate ValidConfig?(config: Config)
{
&& (forall tableName <- config.tableEncryptionConfigs ::
config.tableEncryptionConfigs[tableName].physicalTableName == tableName)
//= specification/dynamodb-encryption-client/ddb-table-encryption-config.md#logical-table-name
//# When mapping [DynamoDB Table Names](#dynamodb-table-name) to [logical table name](#logical-table-name)
//# there MUST a one to one mapping between the two.
&& (forall
c1 <- config.tableEncryptionConfigs.Values,
c2 <- config.tableEncryptionConfigs.Values
| c1 != c2
:: c1.logicalTableName != c2.logicalTableName
)
}
datatype Config = Config(
tableEncryptionConfigs: map<string, ValidTableConfig>
)
function method AttrToString(attr : DDB.AttributeValue) : string
{
if attr.S? then
attr.S
else if attr.N? then
attr.N
else if attr.B? then
HexStrings.ToHexString(attr.B)
else
"unexpected key type"
}
// return human readable string containing primary keys
function method KeyString(config : ValidTableConfig, item : DDB.AttributeMap) : string
{
var partition :=
if config.partitionKeyName in item then
config.partitionKeyName + " = " + AttrToString(item[config.partitionKeyName])
else
"";
var sort :=
if config.sortKeyName.Some? && config.sortKeyName.value in item then
"; " + config.sortKeyName.value + " = " + AttrToString(item[config.sortKeyName.value])
else
"";
partition + sort
}
function method MapError<T>(r : Result<T, EncTypes.Error>) : Result<T, Error> {
r.MapFailure(e => AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptor(e))
}
function method MapString<T>(r : Result<T, string>) : Result<T, Error> {
r.MapFailure(e => Error.DynamoDbEncryptionTransformsException(message := e))
}
// string to Error
function method E(s : string) : Error {
DynamoDbEncryptionTransformsException(message := s)
}
function method MakeError<X>(s : string) : Result<X, Error>
{
Failure(Error.DynamoDbEncryptionTransformsException(message := s))
}
predicate SameOption<X>(x : Option<X>, y : Option<X>)
{
(x.Some? && y.Some?) || (x.None? && y.None?)
}
}