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