cardano_message_signing/
lib.rs

1// This library was partially code-generated using an experimental CDDL to rust tool:
2// https://github.com/Emurgo/cddl-codegen
3
4use std::io::{BufRead, Write};
5use linked_hash_map::LinkedHashMap;
6
7use cbor_event::{self, de::Deserializer, se::{Serialize, Serializer}};
8
9pub mod builders;
10pub mod cbor;
11mod crypto;
12pub mod error;
13mod serialization;
14#[macro_use]
15pub mod utils;
16
17use builders::*;
18use cbor::*;
19use error::*;
20use utils::*;
21
22
23#[derive(Clone, Debug)]
24pub struct ProtectedHeaderMap(Vec<u8>);
25
26to_from_bytes!(ProtectedHeaderMap);
27
28
29impl ProtectedHeaderMap {
30    pub fn new_empty() -> Self {
31        Self(Vec::new())
32    }
33
34    // COSE spec specifies that we SHOULD encode 0 length as 0 byte string rather than 0 length map
35    pub fn new(header_map: &HeaderMap) -> Self {
36        if header_map.keys().len() == 0 {
37            Self::new_empty()
38        } else {
39            Self(header_map.to_bytes())
40        }
41    }
42
43    pub fn deserialized_headers(&self) -> HeaderMap {
44        if self.0.is_empty() {
45            HeaderMap::new()
46        } else {
47            HeaderMap::from_bytes(self.0.clone())
48                .expect("ProtectedHeaderMap shouldn't be able to be constructed without being valid HeaderMap bytes")
49        }
50    }
51}
52
53
54#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
55pub enum LabelKind {
56    Int,
57    Text,
58}
59
60#[derive(Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
61enum LabelEnum {
62    Int(Int),
63    Text(String),
64}
65
66
67#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
68pub struct Label(LabelEnum);
69
70to_from_bytes!(Label);
71
72
73impl Label {
74    pub fn new_int(int: &Int) -> Self {
75        Self(LabelEnum::Int(int.clone()))
76    }
77
78    pub fn new_text(text: String) -> Self {
79        Self(LabelEnum::Text(text))
80    }
81
82    pub fn kind(&self) -> LabelKind {
83        match &self.0 {
84            LabelEnum::Int(_) => LabelKind::Int,
85            LabelEnum::Text(_) => LabelKind::Text,
86        }
87    }
88
89    pub fn as_int(&self) -> Option<Int> {
90        match &self.0 {
91            LabelEnum::Int(x) => Some(x.clone()),
92            _ => None,
93        }
94    }
95
96    pub fn as_text(&self) -> Option<String> {
97        match &self.0 {
98            LabelEnum::Text(x) => Some(x.clone()),
99            _ => None,
100        }
101    }
102
103    // we need to put these here instead of the label enum macros due to rust
104    // restrictions on concat_idents!
105
106    pub fn from_algorithm_id(id: AlgorithmId) -> Self {
107        id.into()
108    }
109
110    pub fn from_key_type(key_type: KeyType) -> Self {
111        key_type.into()
112    }
113
114    pub fn from_ec_key(ec_key: ECKey) -> Self {
115        ec_key.into()
116    }
117
118    pub fn from_curve_type(curve_type: CurveType)-> Self {
119        curve_type.into()
120    }
121
122    pub fn from_key_operation(key_op: KeyOperation) -> Self {
123        key_op.into()
124    }
125}
126
127
128#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
129pub struct Labels(Vec<Label>);
130
131to_from_bytes!(Labels);
132
133
134impl Labels {
135    pub fn new() -> Self {
136        Self(Vec::new())
137    }
138
139    pub fn len(&self) -> usize {
140        self.0.len()
141    }
142
143    pub fn get(&self, index: usize) -> Label {
144        self.0[index].clone()
145    }
146
147    pub fn add(&mut self, elem: &Label) {
148        self.0.push(elem.clone());
149    }
150}
151
152
153#[derive(Clone, Debug)]
154pub struct COSESignatures(Vec<COSESignature>);
155
156to_from_bytes!(COSESignatures);
157
158
159impl COSESignatures {
160    pub fn new() -> Self {
161        Self(Vec::new())
162    }
163
164    pub fn len(&self) -> usize {
165        self.0.len()
166    }
167
168    pub fn get(&self, index: usize) -> COSESignature {
169        self.0[index].clone()
170    }
171
172    pub fn add(&mut self, elem: &COSESignature) {
173        self.0.push(elem.clone());
174    }
175}
176
177
178#[derive(Clone, Debug)]
179pub struct CounterSignature(COSESignatures);
180
181to_from_bytes!(CounterSignature);
182
183
184impl CounterSignature {
185    pub fn new_single(cose_signature: &COSESignature) -> Self {
186        let mut sigs = COSESignatures::new();
187        sigs.add(cose_signature);
188        Self(sigs)
189    }
190
191    pub fn new_multi(cose_signatures: &COSESignatures) -> Self {
192        Self(cose_signatures.clone())
193    }
194
195    pub fn signatures(&self) -> COSESignatures {
196        self.0.clone()
197    }
198}
199
200
201#[derive(Clone, Debug)]
202pub struct HeaderMap {
203    // INT(1) key type
204    algorithm_id: Option<Label>,
205    // INT(2) key type
206    criticality: Option<Labels>,
207    // INT(3) key type
208    content_type: Option<Label>,
209    // INT(4) key type
210    key_id: Option<Vec<u8>>,
211    // INT(5) key type
212    init_vector: Option<Vec<u8>>,
213    // INT(6) key type
214    partial_init_vector: Option<Vec<u8>>,
215    // INT(7) key type
216    counter_signature: Option<Box<CounterSignature>>,
217    // all other headers not listed above. Does NOT contian the above, but the accessor functions do
218    other_headers: LinkedHashMap<Label, CBORValue>,
219}
220
221to_from_bytes!(HeaderMap);
222
223
224impl HeaderMap {
225    pub fn set_algorithm_id(&mut self, algorithm_id: &Label) {
226        self.algorithm_id = Some(algorithm_id.clone())
227    }
228
229    pub fn algorithm_id(&self) -> Option<Label> {
230        self.algorithm_id.clone()
231    }
232
233    pub fn set_criticality(&mut self, criticality: &Labels) {
234        self.criticality = Some(criticality.clone())
235    }
236
237    pub fn criticality(&self) -> Option<Labels> {
238        self.criticality.clone()
239    }
240
241    pub fn set_content_type(&mut self, content_type: &Label) {
242        self.content_type = Some(content_type.clone())
243    }
244
245    pub fn content_type(&self) -> Option<Label> {
246        self.content_type.clone()
247    }
248
249    pub fn set_key_id(&mut self, key_id: Vec<u8>) {
250        self.key_id = Some(key_id)
251    }
252
253    pub fn key_id(&self) -> Option<Vec<u8>> {
254        self.key_id.clone()
255    }
256
257    pub fn set_init_vector(&mut self, init_vector: Vec<u8>) {
258        self.init_vector = Some(init_vector)
259    }
260
261    pub fn init_vector(&self) -> Option<Vec<u8>> {
262        self.init_vector.clone()
263    }
264
265    pub fn set_partial_init_vector(&mut self, partial_init_vector: Vec<u8>) {
266        self.partial_init_vector = Some(partial_init_vector)
267    }
268
269    pub fn partial_init_vector(&self) -> Option<Vec<u8>> {
270        self.partial_init_vector.clone()
271    }
272
273    pub fn set_counter_signature(&mut self, counter_signature: &CounterSignature) {
274        self.counter_signature = Some(Box::new(counter_signature.clone()))
275    }
276
277    pub fn counter_signature(&self) -> Option<CounterSignature> {
278        use std::ops::Deref;
279        self.counter_signature.as_ref().map(|sig| sig.deref().clone())
280    }
281
282    pub fn header(&self, label: &Label) -> Option<CBORValue> {
283        match label.0 {
284            LabelEnum::Int(Int(1)) => self.algorithm_id.as_ref().map(label_to_value),
285            LabelEnum::Int(Int(2)) => self.criticality.as_ref().map(labels_to_value),
286            LabelEnum::Int(Int(3)) => self.content_type.as_ref().map(label_to_value),
287            LabelEnum::Int(Int(4)) => self.key_id.as_ref().map(|kid| CBORValue::new_bytes(kid.clone())),
288            LabelEnum::Int(Int(5)) => self.init_vector.as_ref().map(|iv| CBORValue::new_bytes(iv.clone())),
289            LabelEnum::Int(Int(6)) => self.partial_init_vector.as_ref().map(|piv| CBORValue::new_bytes(piv.clone())),
290            LabelEnum::Int(Int(7)) => {
291                let bytes = self.counter_signature.as_ref()?.to_bytes();
292                let mut raw = Deserializer::from(std::io::Cursor::new(bytes));
293                Some(CBORValue::deserialize(&mut raw).unwrap())
294            },
295            _ => self.other_headers.get(label).map(|val| val.clone()),
296        }
297    }
298
299    pub fn set_header(&mut self, label: &Label, value: &CBORValue) -> Result<(), JsError> {
300        match label.0 {
301            LabelEnum::Int(Int(1)) => {
302                self.algorithm_id = Some(value_to_label(value)?);
303            },
304            LabelEnum::Int(Int(2)) => {
305                let labels = match &value.0 { 
306                    CBORValueEnum::Array(vals) => vals,
307                    _ => return Err(JsError::from_str(&format!("Expected array of labels, found: {:?}", value))),
308                }.values.iter().map(value_to_label).collect::<Result<_, JsError>>()?;
309                self.criticality = Some(Labels(labels));
310            },
311            LabelEnum::Int(Int(3)) => {
312                self.content_type = Some(value_to_label(value)?);
313            },
314            LabelEnum::Int(Int(4)) => {
315                self.key_id = Some(value_to_bytes(value)?);
316            },
317            LabelEnum::Int(Int(5)) => {
318                self.init_vector = Some(value_to_bytes(value)?);
319            },
320            LabelEnum::Int(Int(6)) => {
321                self.partial_init_vector = Some(value_to_bytes(value)?);
322            },
323            LabelEnum::Int(Int(7)) => {
324                let mut buf = Serializer::new_vec();
325                value.serialize(&mut buf).unwrap();
326                let bytes = buf.finalize();
327                self.counter_signature = Some(Box::new(CounterSignature::from_bytes(bytes)?));
328            },
329            _ => {
330                self.other_headers.insert(label.clone(), value.clone());
331            },
332        }
333        Ok(())
334    }
335
336    pub fn keys(&self) -> Labels {
337        let mut keys = self.other_headers.keys().into_iter().map(|k| k.clone()).collect::<Vec<Label>>();
338        if self.algorithm_id.is_some() {
339            keys.push(Label::new_int(&Int::new_i32(1)));
340        }
341        if self.criticality.is_some() {
342            keys.push(Label::new_int(&Int::new_i32(2)));
343        }
344        if self.content_type.is_some() {
345            keys.push(Label::new_int(&Int::new_i32(3)));
346        }
347        if self.key_id.is_some() {
348            keys.push(Label::new_int(&Int::new_i32(4)));
349        }
350        if self.init_vector.is_some() {
351            keys.push(Label::new_int(&Int::new_i32(5)));
352        }
353        if self.partial_init_vector.is_some() {
354            keys.push(Label::new_int(&Int::new_i32(6)));
355        }
356        if self.counter_signature.is_some() {
357            keys.push(Label::new_int(&Int::new_i32(7)));
358        }
359        Labels(keys)
360    }
361
362    pub fn new() -> Self {
363        Self {
364            algorithm_id: None,
365            criticality: None,
366            content_type: None,
367            key_id: None,
368            init_vector: None,
369            partial_init_vector: None,
370            counter_signature: None,
371            other_headers: LinkedHashMap::new(),
372        }
373    }
374}
375
376
377#[derive(Clone, Debug)]
378pub struct Headers {
379    protected: ProtectedHeaderMap,
380    unprotected: HeaderMap,
381}
382
383to_from_bytes!(Headers);
384
385
386impl Headers {
387    pub fn protected(&self) -> ProtectedHeaderMap {
388        self.protected.clone()
389    }
390
391    pub fn unprotected(&self) -> HeaderMap {
392        self.unprotected.clone()
393    }
394
395    pub fn new(protected_: &ProtectedHeaderMap, unprotected_: &HeaderMap) -> Self {
396        Self {
397            protected: protected_.clone(),
398            unprotected: unprotected_.clone(),
399        }
400    }
401}
402
403
404#[derive(Clone, Debug)]
405pub struct COSESignature {
406    headers: Headers,
407    signature: Vec<u8>,
408}
409
410to_from_bytes!(COSESignature);
411
412
413impl COSESignature {
414    pub fn headers(&self) -> Headers {
415        self.headers.clone()
416    }
417
418    pub fn signature(&self) -> Vec<u8> {
419        self.signature.clone()
420    }
421
422    pub fn new(headers: &Headers, signature: Vec<u8>) -> Self {
423        Self {
424            headers: headers.clone(),
425            signature: signature,
426        }
427    }
428}
429
430
431#[derive(Clone, Debug)]
432pub struct COSESign1 {
433    headers: Headers,
434    payload: Option<Vec<u8>>,
435    signature: Vec<u8>,
436}
437
438to_from_bytes!(COSESign1);
439
440
441impl COSESign1 {
442    pub fn headers(&self) -> Headers {
443        self.headers.clone()
444    }
445
446    pub fn payload(&self) -> Option<Vec<u8>> {
447        self.payload.clone()
448    }
449
450    pub fn signature(&self) -> Vec<u8> {
451        self.signature.clone()
452    }
453
454    /// For verifying, we will want to reverse-construct this SigStructure to check the signature against
455    /// # Arguments
456    /// * `external_aad` - External application data - see RFC 8152 section 4.3. Set to None if not using this.
457    pub fn signed_data(&self, external_aad: Option<Vec<u8>>, external_payload: Option<Vec<u8>>) -> Result<SigStructure, JsError> {
458        let payload = match external_payload {
459            Some(p) => p.clone(),
460            None => self.payload.clone().ok_or_else(|| JsError::from_str("Payload was not present but no external payload supplied"))?,
461        };
462        Ok(SigStructure::new(
463            SigContext::Signature1,
464            &self.headers.protected,
465            external_aad.clone().unwrap_or(vec![]),
466            payload))
467    }
468
469    pub fn new(headers: &Headers, payload: Option<Vec<u8>>, signature: Vec<u8>) -> Self {
470        Self {
471            headers: headers.clone(),
472            payload: payload,
473            signature: signature,
474        }
475    }
476}
477
478
479#[derive(Clone, Debug)]
480pub struct COSESign {
481    headers: Headers,
482    payload: Option<Vec<u8>>,
483    signatures: COSESignatures,
484}
485
486to_from_bytes!(COSESign);
487
488
489impl COSESign {
490    pub fn headers(&self) -> Headers {
491        self.headers.clone()
492    }
493
494    pub fn payload(&self) -> Option<Vec<u8>> {
495        self.payload.clone()
496    }
497
498    pub fn signatures(&self) -> COSESignatures {
499        self.signatures.clone()
500    }
501
502    pub fn new(headers: &Headers, payload: Option<Vec<u8>>, signatures: &COSESignatures) -> Self {
503        Self {
504            headers: headers.clone(),
505            payload: payload,
506            signatures: signatures.clone(),
507        }
508    }
509}
510
511
512#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
513pub enum SignedMessageKind {
514    COSESIGN,
515    COSESIGN1,
516}
517
518#[derive(Clone, Debug)]
519enum SignedMessageEnum {
520    COSESIGN(COSESign),
521    COSESIGN1(COSESign1),
522}
523
524
525#[derive(Clone, Debug)]
526pub struct SignedMessage(SignedMessageEnum);
527
528to_from_bytes!(SignedMessage);
529
530
531impl SignedMessage {
532    pub fn new_cose_sign(cose_sign: &COSESign) -> Self {
533        Self(SignedMessageEnum::COSESIGN(cose_sign.clone()))
534    }
535
536    pub fn new_cose_sign1(cose_sign1: &COSESign1) -> Self {
537        Self(SignedMessageEnum::COSESIGN1(cose_sign1.clone()))
538    }
539
540    pub fn from_user_facing_encoding(s: &str) -> Result<SignedMessage, JsError> {
541        use std::io::Cursor;
542        use byteorder::{BigEndian, ReadBytesExt};
543
544        if !s.starts_with("cms_") {
545            return Err(JsError::from_str("SignedMessage user facing encoding must start with \"cms_\""));
546        }
547        let without_prefix = &s[4..];
548        // we need to (potentialy) strip the padding, if it exists on the checksum, in order to
549        // figure out which parts of the string are from the base64url of the checksum as this
550        // could be either 6 (no padding) or 8 (padding) to get the 4 bytes in the checksum
551        let without_checksum_padding = without_prefix.trim_end_matches('=');
552        // 6 for checksum base64url (4 bytes) + at least 2 for body base64url (at least 1 byte)
553        if without_checksum_padding.len() < 8 {
554            return Err(JsError::from_str("insufficient length - missing checksum"));
555        }
556        let (body_base64, checksum_base64) = without_checksum_padding.split_at(without_checksum_padding.len() - 6);
557        let body_bytes = base64_url::decode(body_base64)
558            .map_err(|e| JsError::from_str(&format!("Could not decode body from base64url: {:?}", e)))?;
559        let checksum_bytes = base64_url::decode(checksum_base64)
560            .map_err(|e| JsError::from_str(&format!("Could not decode checksum from base64url: {:?}", e)))?;
561        let expected_checksum = Cursor::new(checksum_bytes).read_u32::<BigEndian>().unwrap();
562        let computed_checksum = crypto::fnv32a(&body_bytes);
563        if expected_checksum != computed_checksum {
564            return Err(JsError::from_str(&format!("checksum does not match body. shown: {}, computed from body: {}", expected_checksum, computed_checksum)));
565        }
566        Self::from_bytes(body_bytes).map_err(|e| JsError::from_str(&format!("Invalid body: {:?}", e)))
567    }
568
569    pub fn to_user_facing_encoding(&self) -> String {
570        use byteorder::{BigEndian, WriteBytesExt};
571
572        let body_bytes = self.to_bytes();
573        let checksum = crypto::fnv32a(&body_bytes);
574        let mut checksum_bytes = vec![];
575        checksum_bytes.write_u32::<BigEndian>(checksum).unwrap();
576        format!("cms_{}{}", base64_url::encode(&body_bytes), base64_url::encode(&checksum_bytes))
577    }
578
579    pub fn kind(&self) -> SignedMessageKind {
580        match &self.0 {
581            SignedMessageEnum::COSESIGN(_) => SignedMessageKind::COSESIGN,
582            SignedMessageEnum::COSESIGN1(_) => SignedMessageKind::COSESIGN1,
583        }
584    }
585
586    pub fn as_cose_sign(&self) -> Option<COSESign> {
587        match &self.0 {
588            SignedMessageEnum::COSESIGN(x) => Some(x.clone()),
589            _ => None,
590        }
591    }
592
593    pub fn as_cose_sign1(&self) -> Option<COSESign1> {
594        match &self.0 {
595            SignedMessageEnum::COSESIGN1(x) => Some(x.clone()),
596            _ => None,
597        }
598    }
599}
600
601
602#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
603pub enum SigContext {
604    Signature,
605    Signature1,
606    CounterSignature
607}
608
609
610// We sign this structure's to_bytes() serialization instead of signing of messages directly
611
612#[derive(Clone, Debug)]
613pub struct SigStructure {
614    context: SigContext,
615    body_protected: ProtectedHeaderMap,
616    sign_protected: Option<ProtectedHeaderMap>,
617    external_aad: Vec<u8>,
618    payload: Vec<u8>,
619}
620
621to_from_bytes!(SigStructure);
622
623
624impl SigStructure {
625    pub fn context(&self) -> SigContext {
626        self.context.clone()
627    }
628
629    pub fn body_protected(&self) -> ProtectedHeaderMap {
630        self.body_protected.clone()
631    }
632
633    pub fn sign_protected(&self) -> Option<ProtectedHeaderMap> {
634        self.sign_protected.clone()
635    }
636
637    pub fn external_aad(&self) -> Vec<u8> {
638        self.external_aad.clone()
639    }
640
641    pub fn payload(&self) -> Vec<u8> {
642        self.payload.clone()
643    }
644
645    pub fn set_sign_protected(&mut self, sign_protected: &ProtectedHeaderMap) {
646        self.sign_protected = Some(sign_protected.clone());
647    }
648
649    pub fn new(context: SigContext, body_protected: &ProtectedHeaderMap, external_aad: Vec<u8>, payload: Vec<u8>) -> Self {
650        Self {
651            context,
652            body_protected: body_protected.clone(),
653            sign_protected: None,
654            external_aad,
655            payload,
656        }
657    }
658}
659
660
661#[derive(Clone, Debug)]
662pub struct COSEEncrypt0 {
663    headers: Headers,
664    ciphertext: Option<Vec<u8>>,
665}
666
667to_from_bytes!(COSEEncrypt0);
668
669
670impl COSEEncrypt0 {
671    pub fn headers(&self) -> Headers {
672        self.headers.clone()
673    }
674
675    pub fn ciphertext(&self) -> Option<Vec<u8>> {
676        self.ciphertext.clone()
677    }
678
679    pub fn new(headers: &Headers, ciphertext: Option<Vec<u8>>) -> Self {
680        Self {
681            headers: headers.clone(),
682            ciphertext: ciphertext,
683        }
684    }
685}
686
687
688#[derive(Clone, Debug)]
689pub struct PasswordEncryption(COSEEncrypt0);
690
691to_from_bytes!(PasswordEncryption);
692
693
694impl PasswordEncryption {
695    pub fn new(data: &COSEEncrypt0) -> Self {
696        Self(data.clone())
697    }
698}
699
700
701#[derive(Clone, Debug)]
702pub struct COSERecipients(Vec<COSERecipient>);
703
704to_from_bytes!(COSERecipients);
705
706
707impl COSERecipients {
708    pub fn new() -> Self {
709        Self(Vec::new())
710    }
711
712    pub fn len(&self) -> usize {
713        self.0.len()
714    }
715
716    pub fn get(&self, index: usize) -> COSERecipient {
717        self.0[index].clone()
718    }
719
720    pub fn add(&mut self, elem: &COSERecipient) {
721        self.0.push(elem.clone());
722    }
723}
724
725
726#[derive(Clone, Debug)]
727pub struct COSEEncrypt {
728    headers: Headers,
729    ciphertext: Option<Vec<u8>>,
730    recipients: COSERecipients,
731}
732
733to_from_bytes!(COSEEncrypt);
734
735
736impl COSEEncrypt {
737    pub fn headers(&self) -> Headers {
738        self.headers.clone()
739    }
740
741    pub fn ciphertext(&self) -> Option<Vec<u8>> {
742        self.ciphertext.clone()
743    }
744
745    pub fn recipients(&self) -> COSERecipients {
746        self.recipients.clone()
747    }
748
749    pub fn new(headers: &Headers, ciphertext: Option<Vec<u8>>, recipients: &COSERecipients) -> Self {
750        Self {
751            headers: headers.clone(),
752            ciphertext: ciphertext,
753            recipients: recipients.clone(),
754        }
755    }
756}
757
758
759#[derive(Clone, Debug)]
760pub struct COSERecipient {
761    headers: Headers,
762    ciphertext: Option<Vec<u8>>,
763}
764
765to_from_bytes!(COSERecipient);
766
767
768impl COSERecipient {
769    pub fn headers(&self) -> Headers {
770        self.headers.clone()
771    }
772
773    pub fn ciphertext(&self) -> Option<Vec<u8>> {
774        self.ciphertext.clone()
775    }
776
777    pub fn new(headers: &Headers, ciphertext: Option<Vec<u8>>) -> Self {
778        Self {
779            headers: headers.clone(),
780            ciphertext: ciphertext,
781        }
782    }
783}
784
785
786#[derive(Clone, Debug)]
787pub struct PubKeyEncryption(COSEEncrypt);
788
789to_from_bytes!(PubKeyEncryption);
790
791
792impl PubKeyEncryption {
793    pub fn new(data: &COSEEncrypt) -> Self {
794        Self(data.clone())
795    }
796}
797
798
799#[derive(Clone, Debug)]
800pub struct COSEKey {
801    // INT(1) key type, See KeyType enum (OKP, ECS, etc)
802    key_type: Label,
803    // INT(2)
804    key_id: Option<Vec<u8>>,
805    // INT(3) algorithm identifier. See AlgorithmIds enum (EdDSA, ChaChaPoly, etc)
806    algorithm_id: Option<Label>,
807    // INT(4) opertions that this key is valid for if this field exists
808    key_ops: Option<Labels>,
809    // INT(5)
810    base_init_vector: Option<Vec<u8>>,
811    // all other headers not listed above. Does NOT contian the above, but the accessor functions do
812    other_headers: LinkedHashMap<Label, CBORValue>,
813}
814
815to_from_bytes!(COSEKey);
816
817
818impl COSEKey {
819    pub fn set_key_type(&mut self, key_type: &Label) {
820        self.key_type = key_type.clone()
821    }
822
823    pub fn key_type(&self) -> Label {
824        self.key_type.clone()
825    }
826
827    pub fn set_key_id(&mut self, key_id: Vec<u8>) {
828        self.key_id = Some(key_id)
829    }
830
831    pub fn key_id(&self) -> Option<Vec<u8>> {
832        self.key_id.clone()
833    }
834    
835    pub fn set_algorithm_id(&mut self, algorithm_id: &Label) {
836        self.algorithm_id = Some(algorithm_id.clone())
837    }
838
839    pub fn algorithm_id(&self) -> Option<Label> {
840        self.algorithm_id.clone()
841    }
842
843    pub fn set_key_ops(&mut self, key_ops: &Labels) {
844        self.key_ops = Some(key_ops.clone())
845    }
846
847    pub fn key_ops(&self) -> Option<Labels> {
848        self.key_ops.clone()
849    }
850
851    pub fn set_base_init_vector(&mut self, base_init_vector: Vec<u8>) {
852        self.base_init_vector = Some(base_init_vector)
853    }
854
855    pub fn base_init_vector(&self) -> Option<Vec<u8>> {
856        self.base_init_vector.clone()
857    }
858
859    pub fn header(&self, label: &Label) -> Option<CBORValue> {
860        fn label_to_value(label: &Label) -> CBORValue {
861            match &label.0 {
862                LabelEnum::Int(x) => CBORValue::new_int(x),
863                LabelEnum::Text(x) => CBORValue::new_text(x.to_string()),
864            }
865        }
866        match label.0 {
867            LabelEnum::Int(Int(1)) => Some(label_to_value(&self.key_type)),
868            LabelEnum::Int(Int(2)) => self.key_id.as_ref().map(|kid| CBORValue::new_bytes(kid.clone())),
869            LabelEnum::Int(Int(3)) => self.algorithm_id.as_ref().map(label_to_value),
870            LabelEnum::Int(Int(4)) => self.key_ops.as_ref().map(labels_to_value),
871            LabelEnum::Int(Int(5)) => self.base_init_vector.as_ref().map(|biv| CBORValue::new_bytes(biv.clone())),
872            _ => self.other_headers.get(label).map(|val| val.clone()),
873        }
874    }
875
876    pub fn set_header(&mut self, label: &Label, value: &CBORValue) -> Result<(), JsError> {
877        match label.0 {
878            LabelEnum::Int(Int(1)) => {
879                self.key_type = value_to_label(value)?;
880            },
881            LabelEnum::Int(Int(2)) => {
882                self.key_id = Some(value_to_bytes(value)?);
883            },
884            LabelEnum::Int(Int(3)) => {
885                self.algorithm_id = Some(value_to_label(value)?);
886            },
887            LabelEnum::Int(Int(4)) => {
888                let labels = match &value.0 { 
889                    CBORValueEnum::Array(vals) => vals,
890                    _ => return Err(JsError::from_str(&format!("Expected array of labels, found: {:?}", value))),
891                }.values.iter().map(value_to_label).collect::<Result<_, JsError>>()?;
892                self.key_ops = Some(Labels(labels));
893            },
894            LabelEnum::Int(Int(5)) => {
895                self.base_init_vector = Some(value_to_bytes(value)?);
896            },
897            _ => {
898                self.other_headers.insert(label.clone(), value.clone());
899            },
900        }
901        Ok(())
902    }
903
904    pub fn new(key_type: &Label) -> Self {
905        Self {
906            key_type: key_type.clone(),
907            key_id: None,
908            algorithm_id: None,
909            key_ops: None,
910            base_init_vector: None,
911            other_headers: LinkedHashMap::new(),
912        }
913    }
914}
915
916#[cfg(test)]
917mod tests {
918    use super::*;
919
920    fn label_int(x: i32) -> Label {
921        Label::new_int(&Int::new_i32(x))
922    }
923
924    fn label_str(s: &str) -> Label {
925        Label::new_text(String::from(s))
926    }
927
928    #[test]
929    fn cose_key_other_headers_overlap() {
930        let kty1 = label_str("key type 1");
931        let kid1 = vec![1u8, 2u8, 5u8, 10u8, 20u8, 40u8, 50u8];
932        let alg1 = label_int(-10);
933        let mut ops1 = Labels::new();
934        ops1.add(&label_str("dfdsfds"));
935        ops1.add(&label_int(-130));
936        let biv1 = vec![0u8; 128];
937
938        let kty1_value = CBORValue::new_text(String::from("key type 1"));
939        let kid1_value = CBORValue::new_bytes(kid1.clone());
940        let alg1_value = CBORValue::new_int(&Int::new_i32(-10));
941        let ops1_value = CBORValue::new_array(&vec![CBORValue::new_text(String::from("dfdsfds")), CBORValue::new_int(&Int::new_i32(-130))].into());
942        let biv1_value = CBORValue::new_bytes(biv1.clone());
943
944        let kty2 = label_int(352);
945        let kid2 = vec![7u8; 23];
946        let alg2 = label_str("algorithm 2");
947        let mut ops2 = Labels::new();
948        ops2.add(&label_str("89583249384"));
949        let biv2 = vec![10u8, 0u8, 5u8, 9u8, 50u8, 100u8, 30u8];
950
951        let kty2_value = CBORValue::new_int(&Int::new_i32(352));
952        let kid2_value = CBORValue::new_bytes(kid2.clone());
953        let alg2_value = CBORValue::new_text(String::from("algorithm 2"));
954        let ops2_value = CBORValue::new_array(&vec![CBORValue::new_text(String::from("89583249384"))].into());
955        let biv2_value = CBORValue::new_bytes(biv2.clone());
956        
957        let mut ck = COSEKey::new(&kty1);
958        ck.set_key_id(kid1.clone());
959        ck.set_algorithm_id(&alg1);
960        ck.set_key_ops(&ops1);
961        ck.set_base_init_vector(biv1.clone());
962
963        assert_eq!(ck.header(&label_int(1)), Some(kty1_value));
964        assert_eq!(ck.header(&label_int(2)), Some(kid1_value));
965        assert_eq!(ck.header(&label_int(3)), Some(alg1_value));
966        assert_eq!(ck.header(&label_int(4)), Some(ops1_value));
967        assert_eq!(ck.header(&label_int(5)), Some(biv1_value));
968
969        ck.set_header(&label_int(1), &kty2_value).unwrap();
970        ck.set_header(&label_int(2), &kid2_value).unwrap();
971        ck.set_header(&label_int(3), &alg2_value).unwrap();
972        ck.set_header(&label_int(4), &ops2_value).unwrap();
973        ck.set_header(&label_int(5), &biv2_value).unwrap();
974
975        assert_eq!(ck.key_type(), kty2);
976        assert_eq!(ck.key_id(), Some(kid2));
977        assert_eq!(ck.algorithm_id(), Some(alg2));
978        assert_eq!(ck.key_ops(), Some(ops2));
979        assert_eq!(ck.base_init_vector(), Some(biv2));
980    }
981
982    #[test]
983    fn signed_message_user_facing_encoding() {
984        // round-trip testing
985        let mut header_map = HeaderMap::new();
986        header_map.set_content_type(&Label::new_int(&Int::new_i32(-1000)));
987        let headers = Headers::new(&ProtectedHeaderMap::new_empty(), &header_map);
988        let signed_message = SignedMessage::new_cose_sign1(&COSESign1::new(&headers, Some(vec![64u8; 39]), vec![1u8, 2u8, 100u8]));
989        let user_facing_encoding = signed_message.to_user_facing_encoding();
990        let from_ufe = SignedMessage::from_user_facing_encoding(&user_facing_encoding).unwrap();
991        assert_eq!(from_ufe.to_bytes(), signed_message.to_bytes());
992        // test acceptance of padding or lack thereof in data and/or checksum
993        let pad1 = SignedMessage::from_user_facing_encoding("cms_hEChAzkD51gnQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQwECZACyaZmw==").unwrap();
994        let pad2 = SignedMessage::from_user_facing_encoding("cms_hEChAzkD51gnQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQwECZA==CyaZmw").unwrap();
995        let pad3 = SignedMessage::from_user_facing_encoding("cms_hEChAzkD51gnQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQwECZA==CyaZmw==").unwrap();
996        assert_eq!(signed_message.to_bytes(), pad1.to_bytes());
997        assert_eq!(pad1.to_bytes(), pad2.to_bytes());
998        assert_eq!(pad2.to_bytes(), pad3.to_bytes());
999    }
1000}