Skip to content

Commit 04a41ae

Browse files
Deprecate methods that are easy to misuse (#115)
Various helper methods have documented requirements on their inputs, but for some of them it's too easy for library users to miss the requirement and include code that panics on invalid input. For example, the obvious code to parse and validate a `CoseMac0`: ``` let mac = CoseMac0::from_slice(data); mac.verify_tag(&aad, |t, d| verify(t, d, k))?; ``` misses the required check that `mac.payload.is_some()`, and so can panic on invalid input. So deprecate the helpers that are susceptible to this, in favour of equivalent methods that explicitly check the prerequisites.
1 parent ebfaf53 commit 04a41ae

File tree

5 files changed

+254
-36
lines changed

5 files changed

+254
-36
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
- Breaking change: alter type of `crit` field in `Header` to support private-use labels (in accordance with
66
[9052 §3.1](https://datatracker.ietf.org/doc/html/rfc9052#name-common-cose-header-paramete)).
7+
- Deprecate `CoseMac[0]::verify_tag` in favour of `verify_payload_tag`.
8+
- Deprecate `CoseEncrypt[0]::decrypt`, `CoseRecipient::decrypt` in favour of `decrypt_ciphertext`.
79

810
## 0.3.8 - 2024-07-24
911

src/encrypt/mod.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ impl CoseRecipient {
102102
///
103103
/// This function will panic if no `ciphertext` is available. It will also panic
104104
/// if the `context` parameter does not refer to a recipient context.
105+
#[deprecated = "Use decrypt_ciphertext() to ensure ciphertext is present"]
105106
pub fn decrypt<F, E>(
106107
&self,
107108
context: EncryptionContext,
@@ -121,6 +122,38 @@ impl CoseRecipient {
121122
let aad = enc_structure_data(context, self.protected.clone(), external_aad);
122123
cipher(ct, &aad)
123124
}
125+
126+
/// Decrypt the `ciphertext` value with an AEAD, using `cipher` to decrypt the cipher text and
127+
/// combined AAD as per RFC 8152 section 5.3. Returns `missing_ciphertext_error()` if the
128+
/// `ciphertext` is not set.
129+
///
130+
/// # Panics
131+
///
132+
/// This function will panic if the `context` parameter does not refer to a recipient context.
133+
pub fn decrypt_ciphertext<F, E, G>(
134+
&self,
135+
context: EncryptionContext,
136+
external_aad: &[u8],
137+
missing_ciphertext_error: G,
138+
cipher: F,
139+
) -> Result<Vec<u8>, E>
140+
where
141+
F: FnOnce(&[u8], &[u8]) -> Result<Vec<u8>, E>,
142+
G: FnOnce() -> E,
143+
{
144+
let ct = self
145+
.ciphertext
146+
.as_ref()
147+
.ok_or_else(missing_ciphertext_error)?;
148+
match context {
149+
EncryptionContext::EncRecipient
150+
| EncryptionContext::MacRecipient
151+
| EncryptionContext::RecRecipient => {}
152+
_ => panic!("unsupported encryption context {:?}", context), // safe: documented
153+
}
154+
let aad = enc_structure_data(context, self.protected.clone(), external_aad);
155+
cipher(ct, &aad)
156+
}
124157
}
125158

126159
/// Builder for [`CoseRecipient`] objects.
@@ -267,6 +300,7 @@ impl CoseEncrypt {
267300
/// # Panics
268301
///
269302
/// This function will panic if no `ciphertext` is available.
303+
#[deprecated = "Use decrypt_ciphertext() to ensure ciphertext is present"]
270304
pub fn decrypt<F, E>(&self, external_aad: &[u8], cipher: F) -> Result<Vec<u8>, E>
271305
where
272306
F: FnOnce(&[u8], &[u8]) -> Result<Vec<u8>, E>,
@@ -279,6 +313,30 @@ impl CoseEncrypt {
279313
);
280314
cipher(ct, &aad)
281315
}
316+
317+
/// Decrypt the `ciphertext` value with an AEAD, using `cipher` to decrypt the cipher text and
318+
/// combined AAD. Returns `missing_ciphertext_error()` if the `ciphertext` is not set.
319+
pub fn decrypt_ciphertext<F, E, G>(
320+
&self,
321+
external_aad: &[u8],
322+
missing_ciphertext_error: G,
323+
cipher: F,
324+
) -> Result<Vec<u8>, E>
325+
where
326+
F: FnOnce(&[u8], &[u8]) -> Result<Vec<u8>, E>,
327+
G: FnOnce() -> E,
328+
{
329+
let ct = self
330+
.ciphertext
331+
.as_ref()
332+
.ok_or_else(missing_ciphertext_error)?;
333+
let aad = enc_structure_data(
334+
EncryptionContext::CoseEncrypt,
335+
self.protected.clone(),
336+
external_aad,
337+
);
338+
cipher(ct, &aad)
339+
}
282340
}
283341

284342
/// Builder for [`CoseEncrypt`] objects.
@@ -395,6 +453,7 @@ impl CoseEncrypt0 {
395453
/// # Panics
396454
///
397455
/// This function will panic if no `ciphertext` is available.
456+
#[deprecated = "Use decrypt_ciphertext() to ensure ciphertext is present"]
398457
pub fn decrypt<F, E>(&self, external_aad: &[u8], cipher: F) -> Result<Vec<u8>, E>
399458
where
400459
F: FnOnce(&[u8], &[u8]) -> Result<Vec<u8>, E>,
@@ -407,6 +466,30 @@ impl CoseEncrypt0 {
407466
);
408467
cipher(ct, &aad)
409468
}
469+
470+
/// Decrypt the `ciphertext` value with an AEAD, using `cipher` to decrypt the cipher text and
471+
/// combined AAD. Returns `missing_ciphertext_error()` if the `ciphertext` is not set.
472+
pub fn decrypt_ciphertext<F, E, G>(
473+
&self,
474+
external_aad: &[u8],
475+
missing_ciphertext_error: G,
476+
cipher: F,
477+
) -> Result<Vec<u8>, E>
478+
where
479+
F: FnOnce(&[u8], &[u8]) -> Result<Vec<u8>, E>,
480+
G: FnOnce() -> E,
481+
{
482+
let ct = self
483+
.ciphertext
484+
.as_ref()
485+
.ok_or_else(missing_ciphertext_error)?;
486+
let aad = enc_structure_data(
487+
EncryptionContext::CoseEncrypt0,
488+
self.protected.clone(),
489+
external_aad,
490+
);
491+
cipher(ct, &aad)
492+
}
410493
}
411494

412495
/// Builder for [`CoseEncrypt0`] objects.

0 commit comments

Comments
 (0)