1#![forbid(unsafe_code)]
11
12extern crate alloc;
13
14pub mod cwcow;
16pub mod product_policy_helpers;
18pub mod sivm;
20pub mod uefi_security_policy;
22
23use alloc::vec::Vec;
24
25#[doc(hidden)]
26pub use paste::paste as __paste;
27
28#[derive(Debug, Clone, PartialEq, Default)]
33#[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
34#[cfg_attr(feature = "inspect", inspect(transparent))]
35pub struct MeasuredProductPolicy(Option<ProductPolicy>);
36
37impl MeasuredProductPolicy {
38 pub fn new(policy: Option<ProductPolicy>) -> Self {
40 Self(policy)
41 }
42
43 pub fn raw(&self) -> Option<&ProductPolicy> {
45 self.0.as_ref()
46 }
47}
48
49#[derive(mesh_protobuf::Protobuf)]
50struct ProductPolicyInternal {
51 #[mesh(1)]
52 magic: u64,
53 #[mesh(2)]
54 policy: ProductPolicy,
55}
56
57impl ProductPolicyInternal {
58 const MAGIC: u64 = 0x4F48434C504F4C00;
60}
61
62macro_rules! define_product_policy {
67 (
68 package = $pkg:literal ;
69 $(
70 $(#[$vmeta:meta])*
71 $tag:literal => $variant:ident ( $body:path )
72 );+ $(;)?
73 ) => {
74 #[derive(mesh_protobuf::Protobuf, Debug, Clone, PartialEq)]
77 #[cfg_attr(feature = "manifest", derive(serde::Serialize, serde::Deserialize))]
78 #[cfg_attr(
79 feature = "manifest",
80 serde(rename_all = "snake_case", deny_unknown_fields)
81 )]
82 #[cfg_attr(feature = "inspect", derive(inspect::Inspect))]
83 #[cfg_attr(feature = "inspect", inspect(external_tag))]
84 #[mesh(package = $pkg)]
85 pub enum ProductPolicy {
86 $(
87 $(#[$vmeta])*
88 #[mesh($tag)]
89 $variant($body),
90 )+
91 }
92
93 impl ProductPolicy {
94 pub fn name(&self) -> &'static str {
96 $crate::__paste! {
97 match self {
98 $( Self::$variant(_) => stringify!([<$variant:lower>]), )+
99 }
100 }
101 }
102 }
103
104 $crate::__paste! {
105 $(
106 impl $crate::MeasuredProductPolicy {
107 #[doc = concat!(
108 "Run `f` over the `",
109 stringify!($variant),
110 "` body if installed. Closure errors propagate via the outer `Result`; the inner `Option` signals whether the closure ran."
111 )]
112 pub fn [<$variant:lower>]<T>(
113 &self,
114 f: impl ::core::ops::FnOnce(&$body) -> ::anyhow::Result<T>,
115 ) -> ::anyhow::Result<::core::option::Option<T>> {
116 match self.raw() {
117 ::core::option::Option::Some(ProductPolicy::$variant(p)) => {
118 f(p).map(::core::option::Option::Some)
119 }
120 _ => ::core::result::Result::Ok(::core::option::Option::None),
121 }
122 }
123 }
124 )+
125 }
126 };
127}
128
129define_product_policy! {
130 package = "openhcl.product_policy";
131
132 1 => Sivm(sivm::SivmPolicy);
134
135 2 => Cwcow(cwcow::CwcowPolicy);
137}
138
139#[derive(Debug)]
143pub enum ProductPolicyDecodeError {
144 Mesh(mesh_protobuf::Error),
146 BadMagic,
148}
149
150impl core::fmt::Display for ProductPolicyDecodeError {
151 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
152 match self {
153 Self::Mesh(_) => write!(f, "product policy mesh decode error"),
154 Self::BadMagic => write!(f, "product policy magic header mismatch"),
155 }
156 }
157}
158
159impl core::error::Error for ProductPolicyDecodeError {
160 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
161 match self {
162 Self::Mesh(e) => Some(e),
163 Self::BadMagic => None,
164 }
165 }
166}
167
168pub fn encode_product_policy(policy: &ProductPolicy) -> Vec<u8> {
170 let policy = ProductPolicyInternal {
171 magic: ProductPolicyInternal::MAGIC,
172 policy: policy.clone(),
173 };
174 mesh_protobuf::encode(policy)
175}
176
177pub fn decode_product_policy(bytes: &[u8]) -> Result<ProductPolicy, ProductPolicyDecodeError> {
180 let data: ProductPolicyInternal =
181 mesh_protobuf::decode(bytes).map_err(ProductPolicyDecodeError::Mesh)?;
182
183 if data.magic != ProductPolicyInternal::MAGIC {
184 return Err(ProductPolicyDecodeError::BadMagic);
185 }
186
187 Ok(data.policy)
188}
189
190pub use uefi_security_policy::UefiSecurityPolicy;
191
192#[cfg(test)]
193mod tests;