1use serde::{Deserialize, Serialize};
12
13#[derive(Debug, Serialize, Deserialize)]
15pub struct TdfManifest {
16 pub payload: Payload,
17 #[serde(rename = "encryptionInformation")]
18 pub encryption_information: EncryptionInformation,
19 #[serde(rename = "schemaVersion", skip_serializing_if = "Option::is_none")]
20 pub schema_version: Option<String>,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct Payload {
26 #[serde(rename = "type")]
27 pub payload_type: String,
28 pub url: String,
29 pub protocol: String,
30 #[serde(rename = "isEncrypted")]
31 pub is_encrypted: bool,
32 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
33 pub mime_type: Option<String>,
34 #[serde(rename = "tdf_spec_version", skip_serializing_if = "Option::is_none")]
35 pub tdf_spec_version: Option<String>,
36}
37
38impl Default for Payload {
39 fn default() -> Self {
40 Self {
41 payload_type: "reference".to_string(),
42 url: "0.payload".to_string(),
43 protocol: "zip".to_string(),
44 is_encrypted: true,
45 mime_type: Some("application/octet-stream".to_string()),
46 tdf_spec_version: None,
50 }
51 }
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct EncryptionInformation {
57 #[serde(rename = "type")]
58 pub encryption_type: String,
59 #[serde(rename = "keyAccess")]
60 pub key_access: Vec<KeyAccess>,
61 pub method: EncryptionMethod,
62 #[serde(rename = "integrityInformation")]
63 pub integrity_information: IntegrityInformation,
64 pub policy: String,
65}
66
67#[derive(Debug, Serialize, Deserialize, Clone)]
69pub struct PolicyBinding {
70 pub alg: String,
71 pub hash: String,
72}
73
74pub mod key_access_type {
76 pub const WRAPPED: &str = "wrapped";
78 pub const EC_WRAPPED: &str = "ec-wrapped";
80 pub const REMOTE: &str = "remote";
82 pub const REMOTE_WRAPPED: &str = "remoteWrapped";
84}
85
86#[derive(Debug, Serialize, Deserialize, Clone)]
88pub struct KeyAccess {
89 #[serde(rename = "type")]
90 pub access_type: String,
91 pub url: String,
92 #[serde(skip_serializing_if = "Option::is_none")]
93 pub kid: Option<String>,
94 pub protocol: String,
95 #[serde(rename = "wrappedKey")]
96 pub wrapped_key: String,
97 #[serde(rename = "policyBinding")]
98 pub policy_binding: PolicyBinding,
99 #[serde(rename = "encryptedMetadata", skip_serializing_if = "Option::is_none")]
100 pub encrypted_metadata: Option<String>,
101 #[serde(rename = "schemaVersion", skip_serializing_if = "Option::is_none")]
102 pub schema_version: Option<String>,
103 #[serde(rename = "ephemeralPublicKey", skip_serializing_if = "Option::is_none")]
105 pub ephemeral_public_key: Option<String>,
106}
107
108impl KeyAccess {
109 pub fn new(url: String) -> Self {
111 KeyAccess {
112 access_type: key_access_type::WRAPPED.to_string(),
113 url,
114 kid: None,
115 protocol: "kas".to_string(),
116 wrapped_key: String::new(),
117 policy_binding: PolicyBinding {
118 alg: "HS256".to_string(),
119 hash: String::new(),
120 },
121 encrypted_metadata: None,
122 schema_version: Some("1.0".to_string()),
123 ephemeral_public_key: None,
124 }
125 }
126
127 pub fn new_ec_wrapped(url: String) -> Self {
129 KeyAccess {
130 access_type: key_access_type::EC_WRAPPED.to_string(),
131 url,
132 kid: None,
133 protocol: "kas".to_string(),
134 wrapped_key: String::new(),
135 policy_binding: PolicyBinding {
136 alg: "HS256".to_string(),
137 hash: String::new(),
138 },
139 encrypted_metadata: None,
140 schema_version: Some("1.0".to_string()),
141 ephemeral_public_key: None,
142 }
143 }
144
145 pub fn is_ec_wrapped(&self) -> bool {
147 self.access_type == key_access_type::EC_WRAPPED
148 }
149
150 pub fn is_rsa_wrapped(&self) -> bool {
152 self.access_type == key_access_type::WRAPPED
153 }
154
155 pub fn set_ephemeral_public_key(&mut self, pem: String) {
157 self.ephemeral_public_key = Some(pem);
158 }
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct EncryptionMethod {
164 pub algorithm: String,
165 #[serde(rename = "isStreamable")]
166 pub is_streamable: bool,
167 pub iv: String,
168}
169
170impl Default for EncryptionMethod {
171 fn default() -> Self {
172 Self {
173 algorithm: "AES-256-GCM".to_string(),
174 is_streamable: true,
175 iv: String::new(),
176 }
177 }
178}
179
180#[derive(Debug, Clone, Serialize, Deserialize)]
182pub struct IntegrityInformation {
183 #[serde(rename = "rootSignature")]
184 pub root_signature: RootSignature,
185 #[serde(rename = "segmentHashAlg")]
186 pub segment_hash_alg: String,
187 pub segments: Vec<Segment>,
188 #[serde(rename = "segmentSizeDefault")]
189 pub segment_size_default: u64,
190 #[serde(rename = "encryptedSegmentSizeDefault")]
191 pub encrypted_segment_size_default: u64,
192}
193
194impl Default for IntegrityInformation {
195 fn default() -> Self {
196 Self {
197 root_signature: RootSignature::default(),
198 segment_hash_alg: "GMAC".to_string(),
199 segments: Vec::new(),
200 segment_size_default: 1024 * 1024, encrypted_segment_size_default: 1024 * 1024 + 28, }
203 }
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
208pub struct RootSignature {
209 pub alg: String,
210 pub sig: String,
211}
212
213impl Default for RootSignature {
214 fn default() -> Self {
215 Self {
216 alg: "HS256".to_string(),
217 sig: String::new(),
218 }
219 }
220}
221
222#[derive(Debug, Clone, Serialize, Deserialize)]
224pub struct Segment {
225 pub hash: String,
226 #[serde(rename = "segmentSize", skip_serializing_if = "Option::is_none")]
227 pub segment_size: Option<u64>,
228 #[serde(
229 rename = "encryptedSegmentSize",
230 skip_serializing_if = "Option::is_none"
231 )]
232 pub encrypted_segment_size: Option<u64>,
233}
234
235impl TdfManifest {
236 pub fn new(payload_url: String, kas_url: String) -> Self {
238 TdfManifest {
239 payload: Payload {
240 payload_type: "reference".to_string(),
241 url: payload_url,
242 protocol: "zip".to_string(),
243 is_encrypted: true,
244 mime_type: Some("application/octet-stream".to_string()),
245 tdf_spec_version: None,
247 },
248 encryption_information: EncryptionInformation {
249 encryption_type: "split".to_string(),
250 key_access: vec![KeyAccess::new(kas_url)],
251 method: EncryptionMethod {
252 algorithm: "AES-256-GCM".to_string(),
253 is_streamable: true,
254 iv: String::new(),
255 },
256 integrity_information: IntegrityInformation {
257 root_signature: RootSignature {
258 alg: "HS256".to_string(),
259 sig: String::new(),
260 },
261 segment_hash_alg: "GMAC".to_string(),
262 segments: Vec::new(),
263 segment_size_default: 1024 * 1024, encrypted_segment_size_default: 1024 * 1024 + 28, },
266 policy: String::new(),
267 },
268 schema_version: Some("3.0.0".to_string()),
269 }
270 }
271
272 pub fn set_policy_raw(&mut self, policy: &str) {
274 use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};
275 self.encryption_information.policy = BASE64.encode(policy);
276 }
277
278 pub fn get_policy_raw(&self) -> Result<String, base64::DecodeError> {
280 use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};
281 let bytes = BASE64.decode(&self.encryption_information.policy)?;
282 String::from_utf8(bytes)
283 .map_err(|err| base64::DecodeError::InvalidByte(err.utf8_error().valid_up_to(), 0))
284 }
285
286 pub fn add_segment(
288 &mut self,
289 hash: String,
290 segment_size: Option<u64>,
291 encrypted_segment_size: Option<u64>,
292 ) {
293 self.encryption_information
294 .integrity_information
295 .segments
296 .push(Segment {
297 hash,
298 segment_size,
299 encrypted_segment_size,
300 });
301 }
302
303 pub fn to_json(&self) -> Result<String, serde_json::Error> {
305 serde_json::to_string(self)
306 }
307
308 pub fn from_json(json: &str) -> Result<Self, serde_json::Error> {
310 serde_json::from_str(json)
311 }
312}
313
314impl KeyAccess {
315 pub fn set_encrypted_metadata(&mut self, metadata: &str) {
317 use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};
318 self.encrypted_metadata = Some(BASE64.encode(metadata));
319 }
320
321 pub fn clear_encrypted_metadata(&mut self) {
323 self.encrypted_metadata = None;
324 }
325}