• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! The cert validator library provides validation functions for the CBOR-CDDL
2 //! based certificate request, allowing validation of BCC certificate chain,
3 //! deviceinfo among other things.
4 
5 pub mod bcc;
6 pub mod deviceinfo;
7 pub mod dice;
8 pub mod publickey;
9 pub mod valueas;
10 
11 use anyhow::{Context, Result};
12 use ciborium::{de::from_reader, value::Value};
13 
14 /// Reads the provided binary cbor-encoded file and returns a
15 /// ciborium::Value struct wrapped in Result.
file_value(fname: &str) -> Result<Value>16 pub fn file_value(fname: &str) -> Result<Value> {
17     let f = std::fs::File::open(fname)?;
18     from_reader(f).with_context(|| format!("Decoding {}", fname))
19 }
20 
21 #[cfg(test)]
22 mod tests {
23     use super::*;
24     use crate::valueas::ValueAs;
25     use coset::{iana, Header, Label, RegisteredLabel};
26 
27     #[test]
test_bcc_payload_check()28     fn test_bcc_payload_check() {
29         let payload = bcc::entry::Payload::from_sign1(
30             &bcc::entry::read("testdata/open-dice/_CBOR_Ed25519_cert_full_cert_chain_0.cert")
31                 .unwrap(),
32         );
33         assert!(payload.is_ok());
34 
35         let payload = payload.unwrap();
36         assert!(payload.check().is_ok());
37     }
38 
39     #[test]
test_bcc_payload_check_sign1()40     fn test_bcc_payload_check_sign1() {
41         let payload = bcc::entry::Payload::from_sign1(
42             &bcc::entry::read("testdata/open-dice/_CBOR_Ed25519_cert_full_cert_chain_0.cert")
43                 .unwrap(),
44         );
45         assert!(payload.is_ok(), "Payload not okay: {:?}", payload);
46         let payload = payload.unwrap().check_sign1(
47             &bcc::entry::read("testdata/open-dice/_CBOR_Ed25519_cert_full_cert_chain_1.cert")
48                 .unwrap(),
49         );
50         assert!(payload.is_ok(), "Payload not okay: {:?}", payload);
51         let payload = payload.unwrap().check_sign1(
52             &bcc::entry::read("testdata/open-dice/_CBOR_Ed25519_cert_full_cert_chain_2.cert")
53                 .unwrap(),
54         );
55         assert!(payload.is_ok(), "Payload not okay: {:?}", payload);
56     }
57 
58     #[test]
test_check_sign1_cert_chain()59     fn test_check_sign1_cert_chain() {
60         let arr: Vec<&str> = vec![
61             "testdata/open-dice/_CBOR_Ed25519_cert_full_cert_chain_0.cert",
62             "testdata/open-dice/_CBOR_Ed25519_cert_full_cert_chain_1.cert",
63             "testdata/open-dice/_CBOR_Ed25519_cert_full_cert_chain_2.cert",
64         ];
65         assert!(bcc::entry::check_sign1_cert_chain(&arr).is_ok());
66     }
67 
68     #[test]
test_check_sign1_cert_chain_invalid()69     fn test_check_sign1_cert_chain_invalid() {
70         let arr: Vec<&str> = vec![
71             "testdata/open-dice/_CBOR_Ed25519_cert_full_cert_chain_0.cert",
72             "testdata/open-dice/_CBOR_Ed25519_cert_full_cert_chain_2.cert",
73         ];
74         assert!(bcc::entry::check_sign1_cert_chain(&arr).is_err());
75     }
76 
77     #[test]
test_check_sign1_chain_array()78     fn test_check_sign1_chain_array() {
79         let cbor_file = &file_value("testdata/open-dice/_CBOR_bcc_entry_cert_array.cert").unwrap();
80         let cbor_arr = ValueAs::as_array(cbor_file).unwrap();
81         assert_eq!(cbor_arr.len(), 3);
82         assert!(bcc::entry::check_sign1_chain_array(cbor_arr).is_ok());
83     }
84 
85     #[test]
test_check_chain_valid() -> Result<()>86     fn test_check_chain_valid() -> Result<()> {
87         let chain = bcc::Chain::read("testdata/bcc/valid.chain").unwrap();
88         let payloads = chain.check()?;
89         assert_eq!(payloads.len(), 8);
90         Ok(())
91     }
92 
93     #[test]
test_check_chain_valid_p256() -> Result<()>94     fn test_check_chain_valid_p256() -> Result<()> {
95         let chain = bcc::Chain::read("testdata/bcc/valid_p256.chain").unwrap();
96         let payloads = chain.check()?;
97         assert_eq!(payloads.len(), 3);
98         Ok(())
99     }
100 
101     #[test]
test_check_chain_bad_p256()102     fn test_check_chain_bad_p256() {
103         let chain = bcc::Chain::read("testdata/bcc/bad_p256.chain").unwrap();
104         assert!(chain.check().is_err());
105     }
106 
107     #[test]
test_check_chain_bad_pub_key()108     fn test_check_chain_bad_pub_key() {
109         let chain = bcc::Chain::read("testdata/bcc/bad_pub_key.chain").unwrap();
110         assert!(chain.check().is_err());
111     }
112 
113     #[test]
test_check_chain_bad_final_signature()114     fn test_check_chain_bad_final_signature() {
115         let chain = bcc::Chain::read("testdata/bcc/bad_final_signature.chain").unwrap();
116         assert!(chain.check().is_err());
117     }
118 
119     #[test]
deviceinfo_validation()120     fn deviceinfo_validation() {
121         let val = &file_value("testdata/device-info/_CBOR_device_info_0.cert").unwrap();
122         let deviceinfo = deviceinfo::extract(val);
123         assert!(deviceinfo.is_ok());
124         assert!(deviceinfo::check(deviceinfo.unwrap()).is_ok());
125     }
126 
127     #[test]
test_check_bcc_entry_protected_header() -> Result<()>128     fn test_check_bcc_entry_protected_header() -> Result<()> {
129         let eddsa = Some(coset::Algorithm::Assigned(iana::Algorithm::EdDSA));
130         let header = Header { alg: (&eddsa).clone(), ..Default::default() };
131         bcc::entry::check_protected_header(&eddsa, &header).context("Only alg allowed")?;
132         let header = Header { alg: Some(coset::Algorithm::PrivateUse(1000)), ..Default::default() };
133         assert!(bcc::entry::check_protected_header(&eddsa, &header).is_err());
134         let mut header = Header { alg: (&eddsa).clone(), ..Default::default() };
135         header.rest.push((Label::Int(1000), Value::from(2000u16)));
136         bcc::entry::check_protected_header(&eddsa, &header).context("non-crit header allowed")?;
137         let mut header = Header { alg: (&eddsa).clone(), ..Default::default() };
138         header.crit.push(RegisteredLabel::Assigned(iana::HeaderParameter::Alg));
139         bcc::entry::check_protected_header(&eddsa, &header).context("OK to say alg is critical")?;
140         let mut header = Header { alg: (&eddsa).clone(), ..Default::default() };
141         header.crit.push(RegisteredLabel::Assigned(iana::HeaderParameter::CounterSignature));
142         assert!(bcc::entry::check_protected_header(&eddsa, &header).is_err());
143         Ok(())
144     }
145 }
146