Skip to content

Commit 2d9cb7c

Browse files
committed
feat: check column configuration against encrypted column before decrypt
1 parent adb080f commit 2d9cb7c

File tree

4 files changed

+63
-3
lines changed

4 files changed

+63
-3
lines changed

docs/errors.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
- [Unknown column](#encrypt-unknown-column)
2222
- [Unknown table](#encrypt-unknown-table)
2323
- [Unknown index term](#encrypt-unknown-index-term)
24+
- [Column configuration mismatch](#encrypt-column-config-mismatch)
2425

2526
- Decrypt errors:
2627
- [Column could not be deserialised](#encrypt-column-could-not-be-deserialised)
@@ -392,6 +393,34 @@ Unknown Index Term for column '{column_name}' in table '{table_name}'.
392393

393394

394395
<!-- ---------------------------------------------------------------------------------------------------- -->
396+
<!-- ---------------------------------------------------------------------------------------------------- -->
397+
398+
399+
## Column configuration mismatch <a id='encrypt-column-config-mismatch'></a>
400+
401+
A returned encrypted column does not match the column configuration.
402+
403+
### Error message
404+
405+
```
406+
Column configuration for column '{column_name}' in table '{table_name}' does not match the encrypted column.
407+
```
408+
409+
### Notes
410+
411+
CipherStash Proxy validates that encrypted columns match the configuration before decrypting any data.
412+
If the table and column are not the same, this error is returned.
413+
The check is there to help prevent "confused deputy" issues and the error should *never* appear during normal operation.
414+
415+
If the error persists, please contact CipherStash [support](https://cipherstash.com/support).
416+
417+
418+
### Further reading
419+
420+
[AWS: The confused deputy problem](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html)
421+
[Wikipedia: Confused deputy problem](https://en.wikipedia.org/wiki/Confused_deputy_problem)
422+
423+
<!-- ---------------------------------------------------------------------------------------------------- -->
395424

396425

397426

docs/how-to.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ This will output the version of EQL installed.
163163
In your existing PostgreSQL database, you store your data in tables and columns.
164164
Those columns have types like `integer`, `text`, `timestamp`, and `boolean`.
165165
When storing encrypted data in PostgreSQL with Proxy, you use a special column type called `eql_v1_encrypted`, which is [provided by EQL](#setting-up-the-database-schema).
166-
`eql_v1_encrypted` is a container column type that can be used for any type of encrypted data you want to store or search, whether they are numbers (`int`, `small_int`, `big_int`), text (`text`), dates and times (`date`), or booleans (`boolean`).
166+
`eql_v1_encrypted` is a container column type that can be used for any type of encrypted data you want to store or search, whether they are numbers (`int`, `small_int`, `big_int`), text (`text`), dates and times (`date`. `timestamp`), or booleans (`boolean`).
167167

168168
Create a table with an encrypted column for `email`:
169169

packages/cipherstash-proxy/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ pub enum EncryptError {
214214
#[error("Column '{column}' in table '{table}' could not be encrypted. For help visit {}#encrypt-column-could-not-be-encrypted", ERROR_DOC_BASE_URL)]
215215
ColumnCouldNotBeEncrypted { table: String, column: String },
216216

217+
#[error("Column configuration for column '{column}' in table '{table}' does not match the encrypted column. For help visit {}#encrypt-column-config-mismatch", ERROR_DOC_BASE_URL)]
218+
ColumnConfigurationMismatch { table: String, column: String },
219+
217220
/// This should in practice be unreachable
218221
#[error("Missing encrypt configuration for column type `{plaintext_type}`. For help visit {}#encrypt-missing-encrypt-configuration", ERROR_DOC_BASE_URL)]
219222
MissingEncryptConfiguration { plaintext_type: String },

packages/cipherstash-proxy/src/postgresql/backend.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use super::messages::BackendCode;
77
use crate::connect::Sender;
88
use crate::encrypt::Encrypt;
99
use crate::eql::EqlEncrypted;
10-
use crate::error::Error;
11-
use crate::log::{DEVELOPMENT, MAPPER, PROTOCOL};
10+
use crate::error::{EncryptError, Error};
11+
use crate::log::{DECRYPT, DEVELOPMENT, MAPPER, PROTOCOL};
1212
use crate::postgresql::context::Portal;
1313
use crate::postgresql::messages::data_row::DataRow;
1414
use crate::postgresql::messages::param_description::ParamDescription;
@@ -270,6 +270,34 @@ where
270270

271271
let start = Instant::now();
272272

273+
for (col, ct) in projection_columns.iter().zip(&ciphertexts) {
274+
debug!(target: DECRYPT, client_id = self.context.client_id, ?col, ?ct);
275+
276+
match (col, ct) {
277+
(Some(col), Some(ct)) => {
278+
if col.identifier != ct.identifier {
279+
return Err(EncryptError::ColumnConfigurationMismatch {
280+
table: col.identifier.table.to_owned(),
281+
column: col.identifier.column.to_owned(),
282+
}
283+
.into());
284+
}
285+
}
286+
// configured column with NULL ciphertext
287+
(Some(_), None) => {}
288+
// unconfigured column *should* have no ciphertext,
289+
(None, None) => {}
290+
// ciphertext with no column configuration is bad
291+
(None, Some(ct)) => {
292+
return Err(EncryptError::ColumnConfigurationMismatch {
293+
table: ct.identifier.table.to_owned(),
294+
column: ct.identifier.column.to_owned(),
295+
}
296+
.into());
297+
}
298+
}
299+
}
300+
273301
// Decrypt CipherText -> Plaintext
274302
let plaintexts = self.encrypt.decrypt(ciphertexts).await.inspect_err(|_| {
275303
counter!(DECRYPTION_ERROR_TOTAL).increment(1);

0 commit comments

Comments
 (0)