1#![allow(unexpected_cfgs)] pub extern crate serde_derive;
8
9pub mod mbedtls_hyper;
10
11pub mod utils;
12
13use em_node_agent_client::{models, Api, Client};
14use mbedtls::hash;
15use pkix::types::Name;
16use rustc_serialize::hex::FromHex;
17use std::borrow::Cow;
18use uuid::Uuid;
19
20mod platform;
21
22pub mod csr;
23pub use csr::*;
24
25pub mod error;
26pub use error::*;
27use yasna::models::TaggedDerValue;
28use yasna::tags::TAG_UTF8STRING;
29use sdkms::api_model::Blob;
30
31type Result<T> = std::result::Result<T, Error>;
32
33pub struct FortanixEmCertificate {
35 pub attestation_certificate_der: Option<Vec<u8>>,
37
38 pub node_certificate_der: Option<Vec<u8>>,
40
41 pub certificate_response: models::IssueCertificateResponse,
43}
44
45pub fn common_name_to_subject(common_name: &str) -> Name {
46 vec![(
47 pkix::oid::commonName.clone(),
48 TaggedDerValue::from_tag_and_bytes(TAG_UTF8STRING, common_name.as_bytes().to_vec()),
49 )]
50 .into()
51}
52
53pub fn get_certificate_status(url: &str, task_id: Uuid) -> Result<models::IssueCertificateResponse> {
54 let client = Client::try_new_http(url).map_err(|e| Error::NodeAgentClient(Box::new(e)))?;
55 client.get_issue_certificate_response(task_id).map_err(|e| Error::NodeAgentClient(Box::new(e)))
56}
57
58pub fn get_fortanix_em_certificate_subject(
59 url: &str,
60 subject: &Name,
61 signer: &mut dyn CsrSigner,
62) -> Result<FortanixEmCertificate> {
63 get_certificate_subject(url, subject, signer, None, None)
64}
65
66pub fn get_fortanix_em_certificate(
67 url: &str,
68 common_name: &str,
69 signer: &mut dyn CsrSigner,
70) -> Result<FortanixEmCertificate> {
71 get_certificate(url, common_name, signer, None, None)
72}
73
74
75pub fn get_certificate_subject(
76 url: &str,
77 subject: &Name,
78 signer: &mut dyn CsrSigner,
79 alt_names: Option<Vec<Cow<str>>>,
80 config_id: Option<&str>,
81) -> Result<FortanixEmCertificate> {
82 let pub_key = signer.get_public_key_der()?;
83 let user_data = get_user_data(&pub_key, config_id)?;
84
85 let (attestation_certificate_der, node_certificate_der, csr_pem) =
86 platform::get_remote_attestation_parameters_subject(
87 signer, url, subject, &user_data, alt_names,
88 )?;
89
90 let certificate_response = request_issue_certificate(url, csr_pem)?;
91
92 Ok(FortanixEmCertificate {
93 attestation_certificate_der,
94 node_certificate_der,
95 certificate_response,
96 })
97}
98
99pub fn get_certificate(
100 url: &str,
101 common_name: &str,
102 signer: &mut dyn CsrSigner,
103 alt_names: Option<Vec<Cow<str>>>,
104 config_id: Option<&str>,
105) -> Result<FortanixEmCertificate> {
106 let subject = common_name_to_subject(common_name);
107 get_certificate_subject(url, &subject, signer, alt_names, config_id)
108}
109
110pub fn get_remote_attestation_csr_subject(
111 url: &str,
112 subject: &Name,
113 signer: &mut dyn CsrSigner,
114 alt_names: Option<Vec<Cow<str>>>,
115 config_id: Option<&str>,
116) -> Result<String> {
117 let pub_key = signer.get_public_key_der()?;
118 let user_data = get_user_data(&pub_key, config_id)?;
119 let (_, _, csr_pem) = platform::get_remote_attestation_parameters_subject(
120 signer, url, subject, &user_data, alt_names,
121 )?;
122 Ok(csr_pem)
123}
124
125pub fn get_remote_attestation_csr(
126 url: &str,
127 common_name: &str,
128 signer: &mut dyn CsrSigner,
129 alt_names: Option<Vec<Cow<str>>>,
130 config_id: Option<&str>,
131) -> Result<String> {
132 let subject = common_name_to_subject(common_name);
133 get_remote_attestation_csr_subject(url, &subject, signer, alt_names, config_id)
134}
135
136pub fn request_issue_certificate(url: &str, csr_pem: String) -> Result<models::IssueCertificateResponse> {
137 let client = Client::try_new_http(url).map_err(|e| Error::NodeAgentClient(Box::new(e)))?;
138 let request = models::IssueCertificateRequest { csr: Some(csr_pem) };
139 client.issue_certificate(request).map_err(|e| Error::NodeAgentClient(Box::new(e)))
140}
141
142pub fn compute_app_config_hash(app_config: &str, hash_type: hash::Type) -> Result<Blob> {
144 let mut digest = vec![0; 32];
145 hash::Md::hash(hash_type, app_config.as_bytes(), &mut digest).map_err(|e| Error::TargetReportHash(Box::new(e)))?;
146
147 Ok(Blob::from(digest.to_vec()))
148}
149
150fn get_user_data(pub_key: &Vec<u8>, config_id: Option<&str>) -> Result<[u8;64]> {
151 let mut data=[0u8;64];
152 hash::Md::hash(hash::Type::Sha256, &pub_key, &mut data).map_err(|e| Error::TargetReportHash(Box::new(e)))?;
153
154 if let Some(id) = config_id {
155 let id = id.from_hex().map_err(|e| Error::ConfigIdIssue(format!("Failed decoding config ID: {}", e)))?;
156 if id.len() != 32 {
157 return Err(Error::ConfigIdIssue(format!("config ID is invalid, length: {}, expected length: 32", id.len())));
158 }
159
160 let mut payload=[0u8;65];
161 payload[0] = 1;
162 payload[1..33].copy_from_slice(&data[0..32]);
163 payload[33..65].copy_from_slice(&id[0..32]);
164
165 hash::Md::hash(hash::Type::Sha256, &payload, &mut data[0..32]).map_err(|e| Error::TargetReportHash(Box::new(e)))?;
169
170 data[32..64].copy_from_slice(&id[0..32]);
172 }
173 Ok(data)
176}