firmware_uefi/service/nvram/spec_services/
auth_var_crypto.rs1use super::ParsedAuthVar;
7use thiserror::Error;
8use uefi_nvram_specvars::signature_list;
9use zerocopy::IntoBytes;
10
11#[derive(Debug, Error)]
13pub enum FormatError {
14 #[error("parsing signature list from auth_var_data")]
15 SignatureList(#[source] signature_list::ParseError),
16 #[error("parsing x509 cert from signature list")]
17 SignatureListX509(#[source] crypto::x509::X509Error),
18 #[error("parsing auth var's pkcs7_data as pkcs#7 DER")]
19 AuthVarPkcs7Der(#[source] crypto::pkcs7::Pkcs7Error),
20 #[error("could not reconstruct signedData header for auth var's pkcs#7 data: {0:?}")]
21 AuthVarPkcs7DerHeader(der::Error),
22 #[error("PKCS#7 verification")]
23 AuthVarPkcs7Verify(#[source] crypto::pkcs7::Pkcs7VerifyError),
24}
25
26impl FormatError {
27 pub fn key_var_error(&self) -> bool {
29 match self {
30 FormatError::SignatureList(_) | FormatError::SignatureListX509(_) => true,
31 FormatError::AuthVarPkcs7Der(_)
32 | FormatError::AuthVarPkcs7DerHeader(_)
33 | FormatError::AuthVarPkcs7Verify(_) => false,
34 }
35 }
36}
37
38pub fn authenticate_variable(
41 signature_lists: &[u8],
42 var: ParsedAuthVar<'_>,
43) -> Result<bool, FormatError> {
44 let ParsedAuthVar {
45 name,
46 vendor,
47 attr,
48 timestamp,
49 pkcs7_data,
50 var_data,
51 } = var;
52
53 let var_pkcs7 = match crypto::pkcs7::Pkcs7SignedData::from_der(pkcs7_data) {
55 Ok(pkcs7) => pkcs7,
56 Err(_) => {
57 let buf = pkcs7_details::encapsulate_in_content_info(pkcs7_data)
73 .map_err(FormatError::AuthVarPkcs7DerHeader)?;
74 match crypto::pkcs7::Pkcs7SignedData::from_der(&buf) {
75 Ok(pkcs7) => pkcs7,
76 Err(e) => return Err(FormatError::AuthVarPkcs7Der(e)),
78 }
79 }
80 };
81
82 let mut trusted_certs = Vec::new();
84
85 let lists = signature_list::ParseSignatureLists::new(signature_lists);
86 for list in lists {
87 let list = list.map_err(FormatError::SignatureList)?;
88 if let signature_list::ParseSignatureList::X509(certs) = list {
90 for cert in certs {
91 let cert = cert.map_err(FormatError::SignatureList)?;
92 trusted_certs.push(
93 crypto::x509::X509Certificate::from_der(&cert.data.0)
94 .map_err(FormatError::SignatureListX509)?,
95 );
96 }
97 }
98 }
99
100 let mut verify_buf = Vec::new();
104 verify_buf.extend(name.as_bytes_without_nul());
105 verify_buf.extend(vendor.as_bytes());
106 verify_buf.extend(attr.as_bytes());
107 verify_buf.extend(timestamp.as_bytes());
108 verify_buf.extend(var_data);
109
110 var_pkcs7
112 .verify_uefi(&trusted_certs, &verify_buf)
113 .map_err(FormatError::AuthVarPkcs7Verify)
114}
115
116mod pkcs7_details {
117 use der::Encode;
118 use der::Sequence;
119 use der::TagMode;
120 use der::TagNumber;
121 use der::asn1::AnyRef;
122 use der::asn1::ContextSpecific;
123 use der::asn1::ObjectIdentifier;
124
125 #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence)]
126 struct ContentInfo<'a> {
127 pub content_type: ObjectIdentifier,
128 pub content: ContextSpecific<AnyRef<'a>>,
129 }
130
131 pub fn encapsulate_in_content_info(content: &[u8]) -> der::Result<Vec<u8>> {
143 const PKCS_7_SIGNED_DATA_OID: ObjectIdentifier =
145 ObjectIdentifier::new_unwrap("1.2.840.113549.1.7.2");
146
147 let content_info = ContentInfo {
148 content_type: PKCS_7_SIGNED_DATA_OID,
149 content: ContextSpecific {
150 tag_number: TagNumber(0),
151 value: AnyRef::try_from(content)?,
152 tag_mode: TagMode::Explicit,
153 },
154 };
155
156 Encode::to_der(&content_info)
157 }
158}