nitro_cli/enclave_proc/
commands.rs1#![deny(missing_docs)]
4#![deny(warnings)]
5
6use aws_nitro_enclaves_image_format::defs::EifIdentityInfo;
7use aws_nitro_enclaves_image_format::utils::eif_reader::EifReader;
8use aws_nitro_enclaves_image_format::utils::{get_pcrs, PcrSignatureChecker};
9use log::debug;
10use sha2::{Digest, Sha384};
11use std::collections::BTreeMap;
12use std::fs::File;
13use std::thread::JoinHandle;
14
15use crate::common::commands_parser::RunEnclavesArgs;
16use crate::common::construct_error_message;
17use crate::common::json_output::EnclaveTerminateInfo;
18use crate::common::{NitroCliErrorEnum, NitroCliFailure, NitroCliResult};
19use crate::enclave_proc::connection::Connection;
20use crate::enclave_proc::connection::{safe_conn_eprintln, safe_conn_println};
21use crate::enclave_proc::cpu_info::CpuInfo;
22use crate::enclave_proc::resource_manager::{EnclaveManager, EnclaveState};
23use crate::enclave_proc::utils::get_enclave_describe_info;
24use crate::new_nitro_cli_failure;
25
26pub struct DescribeThreadResult {
28 pub measurements: BTreeMap<String, String>,
30 pub metadata: Option<EifIdentityInfo>,
32}
33
34pub type DescribeThread = Option<JoinHandle<NitroCliResult<DescribeThreadResult>>>;
36
37pub struct RunEnclaveResult {
39 pub enclave_manager: EnclaveManager,
41 pub describe_thread: DescribeThread,
43}
44
45pub fn run_enclaves(
47 args: &RunEnclavesArgs,
48 connection: Option<&Connection>,
49) -> NitroCliResult<RunEnclaveResult> {
50 debug!("run_enclaves");
51
52 let eif_file = File::open(&args.eif_path).map_err(|e| {
53 new_nitro_cli_failure!(
54 &format!("Failed to open the EIF file: {e:?}"),
55 NitroCliErrorEnum::FileOperationFailure
56 )
57 .add_info(vec![&args.eif_path, "Open"])
58 })?;
59
60 let cpu_ids = CpuInfo::new()
61 .map_err(|e| e.add_subaction("Failed to construct CPU information".to_string()))?
62 .get_cpu_config(args)
63 .map_err(|e| e.add_subaction("Failed to get CPU configuration".to_string()))?;
64
65 let enclave_name = match &args.enclave_name {
66 Some(enclave_name) => enclave_name,
67 None => {
68 return Err(new_nitro_cli_failure!(
69 "Failed to set enclave name in the manager".to_string(),
70 NitroCliErrorEnum::FileOperationFailure
71 ))
72 }
73 };
74
75 let mut enclave_manager = EnclaveManager::new(
76 args.enclave_cid,
77 args.memory_mib,
78 cpu_ids,
79 eif_file,
80 args.debug_mode,
81 enclave_name.to_string(),
82 )
83 .map_err(|e| {
84 e.add_subaction("Failed to construct EnclaveManager with given arguments".to_string())
85 })?;
86
87 let mut signature_checker = PcrSignatureChecker::from_eif(&args.eif_path).map_err(|e| {
88 new_nitro_cli_failure!(
89 &format!("Failed to create EIF signature checker: {e:?}"),
90 NitroCliErrorEnum::EIFSignatureCheckerError
91 )
92 })?;
93
94 if !signature_checker.is_empty() {
96 signature_checker.verify().map_err(|e| {
97 new_nitro_cli_failure!(
98 &format!("Invalid signing certificate: {e:?}"),
99 NitroCliErrorEnum::EIFSignatureCheckerError
100 )
101 })?;
102 }
103
104 let path = args.eif_path.clone();
106 let handle = std::thread::spawn(move || {
107 let mut eif_reader = EifReader::from_eif(path).map_err(|e| {
108 new_nitro_cli_failure!(
109 &format!("Failed initialize EIF reader: {e:?}"),
110 NitroCliErrorEnum::EifParsingError
111 )
112 })?;
113 let measurements = get_pcrs(
114 &mut eif_reader.image_hasher,
115 &mut eif_reader.bootstrap_hasher,
116 &mut eif_reader.app_hasher,
117 &mut eif_reader.cert_hasher,
118 Sha384::new(),
119 eif_reader.signature_section.is_some(),
120 )
121 .map_err(|e| {
122 new_nitro_cli_failure!(
123 &format!("Failed to calculate PCRs: {e:?}"),
124 NitroCliErrorEnum::EifParsingError
125 )
126 })?;
127 Ok(DescribeThreadResult {
128 measurements,
129 metadata: eif_reader.get_metadata(),
130 })
131 });
132 enclave_manager
133 .run_enclave(connection)
134 .map_err(|e| e.add_subaction("Failed to run enclave".to_string()))?;
135 enclave_manager
136 .update_state(EnclaveState::Running)
137 .map_err(|e| e.add_subaction("Failed to update enclave state".to_string()))?;
138
139 Ok(RunEnclaveResult {
140 enclave_manager,
141 describe_thread: Some(handle),
142 })
143}
144
145pub fn terminate_enclaves(
147 enclave_manager: &mut EnclaveManager,
148 connection: Option<&Connection>,
149) -> NitroCliResult<()> {
150 let enclave_id = enclave_manager.enclave_id.clone();
151 let enclave_name = Some(enclave_manager.enclave_name.clone());
152
153 debug!("terminate_enclaves");
154 enclave_manager
155 .update_state(EnclaveState::Terminating)
156 .map_err(|e| e.add_subaction("Failed to update enclave state".to_string()))?;
157 if let Err(error_info) = enclave_manager.terminate_enclave() {
158 safe_conn_eprintln(
159 connection,
160 format!(
161 "Warning: Failed to stop enclave {}\nError message: {:?}",
162 enclave_manager.enclave_id,
163 construct_error_message(&error_info).as_str()
164 )
165 .as_str(),
166 )?;
167 return Err(error_info);
168 }
169
170 enclave_manager.update_state(EnclaveState::Empty)?;
171 safe_conn_eprintln(
172 connection,
173 format!(
174 "Successfully terminated enclave {}.",
175 enclave_manager.enclave_id
176 )
177 .as_str(),
178 )?;
179
180 safe_conn_println(
182 connection,
183 serde_json::to_string_pretty(&EnclaveTerminateInfo::new(enclave_name, enclave_id, true))
184 .map_err(|err| {
185 new_nitro_cli_failure!(
186 &format!("Failed to display enclave termination data: {err:?}"),
187 NitroCliErrorEnum::SerdeError
188 )
189 })?
190 .as_str(),
191 )
192}
193
194pub fn describe_enclaves(
196 enclave_manager: &EnclaveManager,
197 connection: &Connection,
198 with_metadata: bool,
199) -> NitroCliResult<()> {
200 debug!("describe_enclaves");
201
202 let info = get_enclave_describe_info(enclave_manager, with_metadata)
203 .map_err(|e| e.add_subaction(String::from("Execute Describe Enclave command")))?;
204
205 connection.println(
206 serde_json::to_string_pretty(&info)
207 .map_err(|err| {
208 new_nitro_cli_failure!(
209 &format!("Failed to display enclave describe data: {err:?}"),
210 NitroCliErrorEnum::SerdeError
211 )
212 })?
213 .as_str(),
214 )
215}