Skip to content

Commit 7454b9b

Browse files
committed
cose: support verify/open _at for testing purposes too
1 parent cb6edc9 commit 7454b9b

File tree

1 file changed

+103
-11
lines changed

1 file changed

+103
-11
lines changed

src/cose/mod.rs

Lines changed: 103 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -206,19 +206,44 @@ pub fn sign_at<E: Encode, A: Encode>(
206206

207207
/// verify_detached validates a COSE_Sign1 digital signature with a detached payload.
208208
///
209+
/// Uses the current system time for drift checking. For testing or custom
210+
/// timestamps, use [`verify_detached_at`].
211+
///
209212
/// - `msg_to_check`: The serialized COSE_Sign1 structure (with null payload)
210213
/// - `msg_to_auth`: The same message used during signing (verified but not embedded)
211214
/// - `verifier`: The xDSA public key to verify against
212215
/// - `domain`: Application domain for replay protection
213216
/// - `max_drift`: Signatures more in the past or future are rejected
214-
///
215-
/// Returns `()` if verification succeeds.
216217
pub fn verify_detached<A: Encode>(
217218
msg_to_check: &[u8],
218219
msg_to_auth: A,
219220
verifier: &xdsa::PublicKey,
220221
domain: &[u8],
221222
max_drift: Option<u64>,
223+
) -> Result<(), Error> {
224+
let now = SystemTime::now()
225+
.duration_since(UNIX_EPOCH)
226+
.expect("system time before Unix epoch")
227+
.as_secs() as i64;
228+
verify_detached_at(msg_to_check, msg_to_auth, verifier, domain, max_drift, now)
229+
}
230+
231+
/// verify_detached_at validates a COSE_Sign1 digital signature with a detached payload
232+
/// and an explicit current time for drift checking.
233+
///
234+
/// - `msg_to_check`: The serialized COSE_Sign1 structure (with null payload)
235+
/// - `msg_to_auth`: The same message used during signing (verified but not embedded)
236+
/// - `verifier`: The xDSA public key to verify against
237+
/// - `domain`: Application domain for replay protection
238+
/// - `max_drift`: Signatures more in the past or future are rejected
239+
/// - `now`: Unix timestamp in seconds to use for drift checking
240+
pub fn verify_detached_at<A: Encode>(
241+
msg_to_check: &[u8],
242+
msg_to_auth: A,
243+
verifier: &xdsa::PublicKey,
244+
domain: &[u8],
245+
max_drift: Option<u64>,
246+
now: i64,
222247
) -> Result<(), Error> {
223248
// Restrict the user's domain to the context of this library
224249
let info = [DOMAIN_PREFIX, domain].concat();
@@ -236,10 +261,6 @@ pub fn verify_detached<A: Encode>(
236261

237262
// Check signature timestamp drift if max_drift is specified
238263
if let Some(max) = max_drift {
239-
let now = SystemTime::now()
240-
.duration_since(UNIX_EPOCH)
241-
.expect("system time before Unix epoch")
242-
.as_secs() as i64;
243264
let drift = (now - header.timestamp).unsigned_abs();
244265
if drift > max {
245266
return Err(Error::StaleSignature(drift, max));
@@ -265,6 +286,9 @@ pub fn verify_detached<A: Encode>(
265286

266287
/// verify validates a COSE_Sign1 digital signature and returns the embedded payload.
267288
///
289+
/// Uses the current system time for drift checking. For testing or custom
290+
/// timestamps, use [`verify_at`].
291+
///
268292
/// - `msg_to_check`: The serialized COSE_Sign1 structure
269293
/// - `msg_to_auth`: The same additional authenticated data used during signing
270294
/// - `verifier`: The xDSA public key to verify against
@@ -278,6 +302,32 @@ pub fn verify<E: Decode, A: Encode>(
278302
verifier: &xdsa::PublicKey,
279303
domain: &[u8],
280304
max_drift: Option<u64>,
305+
) -> Result<E, Error> {
306+
let now = SystemTime::now()
307+
.duration_since(UNIX_EPOCH)
308+
.expect("system time before Unix epoch")
309+
.as_secs() as i64;
310+
verify_at(msg_to_check, msg_to_auth, verifier, domain, max_drift, now)
311+
}
312+
313+
/// verify_at validates a COSE_Sign1 digital signature and returns the embedded payload,
314+
/// using an explicit current time for drift checking.
315+
///
316+
/// - `msg_to_check`: The serialized COSE_Sign1 structure
317+
/// - `msg_to_auth`: The same additional authenticated data used during signing
318+
/// - `verifier`: The xDSA public key to verify against
319+
/// - `domain`: Application domain for replay protection
320+
/// - `max_drift`: Signatures more in the past or future are rejected
321+
/// - `now`: Unix timestamp in seconds to use for drift checking
322+
///
323+
/// Returns the CBOR-decoded embedded payload if verification succeeds.
324+
pub fn verify_at<E: Decode, A: Encode>(
325+
msg_to_check: &[u8],
326+
msg_to_auth: A,
327+
verifier: &xdsa::PublicKey,
328+
domain: &[u8],
329+
max_drift: Option<u64>,
330+
now: i64,
281331
) -> Result<E, Error> {
282332
// Restrict the user's domain to the context of this library
283333
let info = [DOMAIN_PREFIX, domain].concat();
@@ -294,10 +344,6 @@ pub fn verify<E: Decode, A: Encode>(
294344

295345
// Check signature timestamp drift if max_drift is specified
296346
if let Some(max) = max_drift {
297-
let now = SystemTime::now()
298-
.duration_since(UNIX_EPOCH)
299-
.expect("system time before Unix epoch")
300-
.as_secs() as i64;
301347
let drift = (now - header.timestamp).unsigned_abs();
302348
if drift > max {
303349
return Err(Error::StaleSignature(drift, max));
@@ -420,6 +466,9 @@ pub fn seal_at<E: Encode, A: Encode>(
420466

421467
/// open decrypts and verifies a sealed message.
422468
///
469+
/// Uses the current system time for drift checking. For testing or custom
470+
/// timestamps, use [`open_at`].
471+
///
423472
/// - `msg_to_open`: The serialized COSE_Encrypt0 structure
424473
/// - `msg_to_auth`: The same additional authenticated data used during sealing
425474
/// - `recipient`: The xHPKE secret key to decrypt with
@@ -435,6 +484,42 @@ pub fn open<E: Decode, A: Encode>(
435484
sender: &xdsa::PublicKey,
436485
domain: &[u8],
437486
max_drift: Option<u64>,
487+
) -> Result<E, Error> {
488+
let now = SystemTime::now()
489+
.duration_since(UNIX_EPOCH)
490+
.expect("system time before Unix epoch")
491+
.as_secs() as i64;
492+
open_at(
493+
msg_to_open,
494+
msg_to_auth,
495+
recipient,
496+
sender,
497+
domain,
498+
max_drift,
499+
now,
500+
)
501+
}
502+
503+
/// open_at decrypts and verifies a sealed message with an explicit current time
504+
/// for drift checking.
505+
///
506+
/// - `msg_to_open`: The serialized COSE_Encrypt0 structure
507+
/// - `msg_to_auth`: The same additional authenticated data used during sealing
508+
/// - `recipient`: The xHPKE secret key to decrypt with
509+
/// - `sender`: The xDSA public key to verify the signature against
510+
/// - `domain`: Application domain for HPKE key derivation
511+
/// - `max_drift`: Signatures more in the past or future are rejected
512+
/// - `now`: Unix timestamp in seconds to use for drift checking
513+
///
514+
/// Returns the CBOR-decoded payload if decryption and verification succeed.
515+
pub fn open_at<E: Decode, A: Encode>(
516+
msg_to_open: &[u8],
517+
msg_to_auth: A,
518+
recipient: &xhpke::SecretKey,
519+
sender: &xdsa::PublicKey,
520+
domain: &[u8],
521+
max_drift: Option<u64>,
522+
now: i64,
438523
) -> Result<E, Error> {
439524
// Pre-encode for EncStructure (which needs raw bytes for external_aad)
440525
let msg_to_auth = cbor::encode(msg_to_auth);
@@ -474,7 +559,14 @@ pub fn open<E: Decode, A: Encode>(
474559
.map_err(|e| Error::DecryptionFailed(e.to_string()))?;
475560

476561
// Verify the signature and extract the payload
477-
let raw: Raw = verify::<Raw, _>(&msg_to_check, &Raw(msg_to_auth), sender, domain, max_drift)?;
562+
let raw: Raw = verify_at::<Raw, _>(
563+
&msg_to_check,
564+
&Raw(msg_to_auth),
565+
sender,
566+
domain,
567+
max_drift,
568+
now,
569+
)?;
478570
Ok(cbor::decode(&raw.0)?)
479571
}
480572

0 commit comments

Comments
 (0)