darkbio_crypto/cose/types.rs
1// crypto-rs: cryptography primitives and wrappers
2// Copyright 2025 Dark Bio AG. All rights reserved.
3//
4// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file.
6
7//! COSE structure types with CBOR serialization.
8
9use crate::cbor::Cbor;
10use crate::{xdsa, xhpke};
11
12/// Private COSE header label for Unix timestamp.
13pub const HEADER_TIMESTAMP: i64 = -70002;
14
15/// Protected header for COSE_Sign1.
16#[derive(Debug, Clone, PartialEq, Eq, Cbor)]
17pub struct SigProtectedHeader {
18 /// Algorithm identifier (COSE header label 1)
19 #[cbor(key = 1)]
20 pub algorithm: i64,
21 /// Critical headers that must be understood (COSE header label 2)
22 #[cbor(key = 2)]
23 pub crit: CritHeader,
24 /// Key identifier - signer's fingerprint (COSE header label 4)
25 #[cbor(key = 4)]
26 pub kid: xdsa::Fingerprint,
27 /// Unix timestamp in seconds (private header label)
28 #[cbor(key = -70002)]
29 pub timestamp: i64,
30}
31
32/// Critical headers list per RFC 9052.
33/// Implementations must reject messages with unknown crit labels.
34#[derive(Debug, Clone, PartialEq, Eq, Cbor)]
35#[cbor(array)]
36pub struct CritHeader {
37 /// HeaderTimestamp label - must be understood
38 pub timestamp: i64,
39}
40
41/// Protected header for COSE_Encrypt0.
42#[derive(Debug, Clone, PartialEq, Eq, Cbor)]
43pub struct EncProtectedHeader {
44 /// Algorithm identifier (COSE header label 1)
45 #[cbor(key = 1)]
46 pub algorithm: i64,
47 /// Key identifier - recipient's fingerprint (COSE header label 4)
48 #[cbor(key = 4)]
49 pub kid: xhpke::Fingerprint,
50}
51
52/// Empty unprotected header map (for COSE_Sign1).
53#[derive(Debug, Clone, PartialEq, Eq, Cbor)]
54pub struct EmptyHeader {}
55
56/// Unprotected header containing the encapsulated key (for COSE_Encrypt0).
57#[derive(Debug, Clone, PartialEq, Eq, Cbor)]
58pub struct EncapKeyHeader {
59 /// Encapsulated key (COSE header label -4)
60 #[cbor(key = -4)]
61 pub encap_key: Vec<u8>,
62}
63
64/// COSE_Sign1 structure per RFC 9052 Section 4.2.
65///
66/// ```text
67/// COSE_Sign1 = [
68/// protected: bstr,
69/// unprotected: header_map,
70/// payload: bstr / null,
71/// signature: bstr
72/// ]
73/// ```
74#[derive(Debug, Clone, PartialEq, Eq, Cbor)]
75#[cbor(array)]
76pub struct CoseSign1 {
77 /// Protected header (CBOR-encoded map, wrapped as bstr)
78 pub protected: Vec<u8>,
79 /// Unprotected header map (empty for signatures)
80 pub unprotected: EmptyHeader,
81 /// Payload bytes (null for detached payload)
82 pub payload: Option<Vec<u8>>,
83 /// Signature (fixed size for xDSA)
84 pub signature: xdsa::Signature,
85}
86
87/// COSE_Encrypt0 structure per RFC 9052 Section 5.2.
88///
89/// ```text
90/// COSE_Encrypt0 = [
91/// protected: bstr,
92/// unprotected: header_map,
93/// ciphertext: bstr
94/// ]
95/// ```
96#[derive(Debug, Clone, PartialEq, Eq, Cbor)]
97#[cbor(array)]
98pub struct CoseEncrypt0 {
99 /// Protected header (CBOR-encoded map, wrapped as bstr)
100 pub protected: Vec<u8>,
101 /// Unprotected header map (contains encapsulated key)
102 pub unprotected: EncapKeyHeader,
103 /// Ciphertext bytes
104 pub ciphertext: Vec<u8>,
105}
106
107/// Sig_structure for computing signatures per RFC 9052 Section 4.4.
108///
109/// ```text
110/// Sig_structure = [
111/// context: "Signature1",
112/// body_protected: bstr,
113/// external_aad: bstr,
114/// payload: bstr
115/// ]
116/// ```
117#[derive(Debug, Clone, Copy, PartialEq, Eq)]
118pub struct SigStructure<'a> {
119 pub context: &'static str,
120 pub protected: &'a [u8],
121 pub external_aad: &'a [u8],
122 pub payload: &'a [u8],
123}
124
125impl crate::cbor::Encode for SigStructure<'_> {
126 fn encode_cbor(&self) -> Vec<u8> {
127 let mut encoder = crate::cbor::Encoder::new();
128 encoder.encode_array_header(4);
129 encoder.encode_text(self.context);
130 encoder.encode_bytes(self.protected);
131 encoder.encode_bytes(self.external_aad);
132 encoder.encode_bytes(self.payload);
133 encoder.finish()
134 }
135}
136
137/// Enc_structure for computing AAD per RFC 9052 Section 5.3.
138///
139/// ```text
140/// Enc_structure = [
141/// context: "Encrypt0",
142/// protected: bstr,
143/// external_aad: bstr
144/// ]
145/// ```
146#[derive(Debug, Clone, Copy, PartialEq, Eq)]
147pub struct EncStructure<'a> {
148 pub context: &'static str,
149 pub protected: &'a [u8],
150 pub external_aad: &'a [u8],
151}
152
153impl crate::cbor::Encode for EncStructure<'_> {
154 fn encode_cbor(&self) -> Vec<u8> {
155 let mut encoder = crate::cbor::Encoder::new();
156 encoder.encode_array_header(3);
157 encoder.encode_text(self.context);
158 encoder.encode_bytes(self.protected);
159 encoder.encode_bytes(self.external_aad);
160 encoder.finish()
161 }
162}