oasis_core_runtime/
policy.rs1use std::sync::Arc;
4
5use anyhow::{bail, Result};
6use slog::{debug, Logger};
7use thiserror::Error;
8
9use crate::{
10 common::{logger::get_logger, namespace::Namespace, sgx::QuotePolicy, version::Version},
11 consensus::{
12 keymanager::SignedPolicySGX,
13 registry::{SGXConstraints, TEEHardware},
14 state::{
15 beacon::ImmutableState as BeaconState,
16 keymanager::{ImmutableState as KeyManagerState, Status},
17 registry::ImmutableState as RegistryState,
18 },
19 verifier::Verifier,
20 },
21 future::block_on,
22};
23
24#[derive(Error, Debug)]
26pub enum PolicyVerifierError {
27 #[error("missing runtime descriptor")]
28 MissingRuntimeDescriptor,
29 #[error("no corresponding runtime deployment")]
30 NoDeployment,
31 #[error("bad TEE constraints")]
32 BadTEEConstraints,
33 #[error("policy mismatch")]
34 PolicyMismatch,
35 #[error("policy hasn't been published")]
36 PolicyNotPublished,
37 #[error("status mismatch")]
38 StatusMismatch,
39 #[error("status hasn't been published")]
40 StatusNotPublished,
41 #[error("configured runtime hardware mismatch")]
42 HardwareMismatch,
43 #[error("runtime doesn't use key manager")]
44 NoKeyManager,
45}
46
47pub struct PolicyVerifier {
49 consensus_verifier: Arc<dyn Verifier>,
50 logger: Logger,
51}
52
53impl PolicyVerifier {
54 pub fn new(consensus_verifier: Arc<dyn Verifier>) -> Self {
56 let logger = get_logger("runtime/policy_verifier");
57 Self {
58 consensus_verifier,
59 logger,
60 }
61 }
62
63 pub fn quote_policy(
67 &self,
68 runtime_id: &Namespace,
69 version: Option<Version>,
70 ) -> Result<QuotePolicy> {
71 let consensus_state = block_on(self.consensus_verifier.latest_state())?;
74 let registry_state = RegistryState::new(&consensus_state);
75 let runtime = registry_state
76 .runtime(runtime_id)?
77 .ok_or(PolicyVerifierError::MissingRuntimeDescriptor)?;
78
79 let ad = match version {
80 Some(version) => runtime
81 .deployment_for_version(version)
82 .ok_or(PolicyVerifierError::NoDeployment)?,
83 None => {
84 let beacon_state = BeaconState::new(&consensus_state);
85 let epoch = beacon_state.epoch()?;
86
87 runtime
88 .active_deployment(epoch)
89 .ok_or(PolicyVerifierError::NoDeployment)?
90 }
91 };
92
93 let policy = match runtime.tee_hardware {
94 TEEHardware::TEEHardwareIntelSGX => {
95 let sc: SGXConstraints = ad
96 .try_decode_tee()
97 .map_err(|_| PolicyVerifierError::BadTEEConstraints)?;
98 sc.policy()
99 }
100 _ => bail!(PolicyVerifierError::HardwareMismatch),
101 };
102
103 Ok(policy)
104 }
105
106 pub fn verify_quote_policy(
108 &self,
109 policy: QuotePolicy,
110 runtime_id: &Namespace,
111 version: Option<Version>,
112 ) -> Result<QuotePolicy> {
113 let published_policy = self.quote_policy(runtime_id, version)?;
114
115 if policy != published_policy {
116 debug!(
117 self.logger,
118 "quote policy mismatch";
119 "untrusted" => ?policy,
120 "published" => ?published_policy,
121 );
122 return Err(PolicyVerifierError::PolicyMismatch.into());
123 }
124
125 Ok(published_policy)
126 }
127
128 pub fn key_manager_status(&self, key_manager: Namespace) -> Result<Status> {
130 let consensus_state = block_on(self.consensus_verifier.latest_state())?;
132 let km_state = KeyManagerState::new(&consensus_state);
133 km_state
134 .status(key_manager)?
135 .ok_or_else(|| PolicyVerifierError::StatusNotPublished.into())
136 }
137
138 pub fn verify_key_manager_status(
140 &self,
141 status: Status,
142 key_manager: Namespace,
143 ) -> Result<Status> {
144 let published_status = self.key_manager_status(key_manager)?;
145
146 if status != published_status {
147 debug!(
148 self.logger,
149 "key manager status mismatch";
150 "untrusted" => ?status,
151 "published" => ?published_status,
152 );
153 return Err(PolicyVerifierError::StatusMismatch.into());
154 }
155
156 Ok(published_status)
157 }
158
159 pub fn key_manager_policy(&self, key_manager: Namespace) -> Result<SignedPolicySGX> {
161 self.key_manager_status(key_manager)?
162 .policy
163 .ok_or_else(|| PolicyVerifierError::PolicyNotPublished.into())
164 }
165
166 pub fn verify_key_manager_policy(
168 &self,
169 policy: SignedPolicySGX,
170 key_manager: Namespace,
171 ) -> Result<SignedPolicySGX> {
172 let published_policy = self.key_manager_policy(key_manager)?;
173
174 if policy != published_policy {
175 debug!(
176 self.logger,
177 "key manager policy mismatch";
178 "untrusted" => ?policy,
179 "published" => ?published_policy,
180 );
181 return Err(PolicyVerifierError::PolicyMismatch.into());
182 }
183
184 Ok(published_policy)
185 }
186
187 pub fn key_manager(&self, runtime_id: &Namespace) -> Result<Namespace> {
189 let consensus_state = block_on(self.consensus_verifier.latest_state())?;
191 let registry_state = RegistryState::new(&consensus_state);
192 let runtime = registry_state
193 .runtime(runtime_id)?
194 .ok_or(PolicyVerifierError::MissingRuntimeDescriptor)?;
195 let key_manager = runtime
196 .key_manager
197 .ok_or(PolicyVerifierError::NoKeyManager)?;
198
199 Ok(key_manager)
200 }
201}