]> git.proxmox.com Git - proxmox-backup.git/blob - pbs-client/src/tools/key_source.rs
tree-wide: bump edition to 2021
[proxmox-backup.git] / pbs-client / src / tools / key_source.rs
1 use std::io::Read;
2 use std::os::unix::io::{FromRawFd, RawFd};
3 use std::path::PathBuf;
4
5 use anyhow::{bail, format_err, Error};
6 use serde_json::Value;
7
8 use proxmox_schema::*;
9 use proxmox_sys::fs::file_get_contents;
10 use proxmox_sys::linux::tty;
11
12 use pbs_api_types::CryptMode;
13
14 pub const DEFAULT_ENCRYPTION_KEY_FILE_NAME: &str = "encryption-key.json";
15 pub const DEFAULT_MASTER_PUBKEY_FILE_NAME: &str = "master-public.pem";
16
17 pub const KEYFILE_SCHEMA: Schema =
18 StringSchema::new("Path to encryption key. All data will be encrypted using this key.")
19 .schema();
20
21 pub const KEYFD_SCHEMA: Schema =
22 IntegerSchema::new("Pass an encryption key via an already opened file descriptor.")
23 .minimum(0)
24 .schema();
25
26 pub const MASTER_PUBKEY_FILE_SCHEMA: Schema = StringSchema::new(
27 "Path to master public key. The encryption key used for a backup will be encrypted using this key and appended to the backup.")
28 .schema();
29
30 pub const MASTER_PUBKEY_FD_SCHEMA: Schema =
31 IntegerSchema::new("Pass a master public key via an already opened file descriptor.")
32 .minimum(0)
33 .schema();
34
35 #[derive(Clone, Debug, Eq, PartialEq)]
36 pub enum KeySource {
37 DefaultKey,
38 Fd,
39 Path(String),
40 }
41
42 pub fn format_key_source(source: &KeySource, key_type: &str) -> String {
43 match source {
44 KeySource::DefaultKey => format!("Using default {} key..", key_type),
45 KeySource::Fd => format!("Using {} key from file descriptor..", key_type),
46 KeySource::Path(path) => format!("Using {} key from '{}'..", key_type, path),
47 }
48 }
49
50 #[derive(Clone, Debug, Eq, PartialEq)]
51 pub struct KeyWithSource {
52 pub source: KeySource,
53 pub key: Vec<u8>,
54 }
55
56 impl KeyWithSource {
57 pub fn from_fd(key: Vec<u8>) -> Self {
58 Self {
59 source: KeySource::Fd,
60 key,
61 }
62 }
63
64 pub fn from_default(key: Vec<u8>) -> Self {
65 Self {
66 source: KeySource::DefaultKey,
67 key,
68 }
69 }
70
71 pub fn from_path(path: String, key: Vec<u8>) -> Self {
72 Self {
73 source: KeySource::Path(path),
74 key,
75 }
76 }
77 }
78
79 #[derive(Debug, Eq, PartialEq)]
80 pub struct CryptoParams {
81 pub mode: CryptMode,
82 pub enc_key: Option<KeyWithSource>,
83 // FIXME switch to openssl::rsa::rsa<openssl::pkey::Public> once that is Eq?
84 pub master_pubkey: Option<KeyWithSource>,
85 }
86
87 pub fn crypto_parameters(param: &Value) -> Result<CryptoParams, Error> {
88 do_crypto_parameters(param, false)
89 }
90
91 pub fn crypto_parameters_keep_fd(param: &Value) -> Result<CryptoParams, Error> {
92 do_crypto_parameters(param, true)
93 }
94
95 fn do_crypto_parameters(param: &Value, keep_keyfd_open: bool) -> Result<CryptoParams, Error> {
96 let keyfile = match param.get("keyfile") {
97 Some(Value::String(keyfile)) => Some(keyfile),
98 Some(_) => bail!("bad --keyfile parameter type"),
99 None => None,
100 };
101
102 let key_fd = match param.get("keyfd") {
103 Some(Value::Number(key_fd)) => Some(
104 RawFd::try_from(
105 key_fd
106 .as_i64()
107 .ok_or_else(|| format_err!("bad key fd: {:?}", key_fd))?,
108 )
109 .map_err(|err| format_err!("bad key fd: {:?}: {}", key_fd, err))?,
110 ),
111 Some(_) => bail!("bad --keyfd parameter type"),
112 None => None,
113 };
114
115 let master_pubkey_file = match param.get("master-pubkey-file") {
116 Some(Value::String(keyfile)) => Some(keyfile),
117 Some(_) => bail!("bad --master-pubkey-file parameter type"),
118 None => None,
119 };
120
121 let master_pubkey_fd = match param.get("master-pubkey-fd") {
122 Some(Value::Number(key_fd)) => Some(
123 RawFd::try_from(
124 key_fd
125 .as_i64()
126 .ok_or_else(|| format_err!("bad master public key fd: {:?}", key_fd))?,
127 )
128 .map_err(|err| format_err!("bad public master key fd: {:?}: {}", key_fd, err))?,
129 ),
130 Some(_) => bail!("bad --master-pubkey-fd parameter type"),
131 None => None,
132 };
133
134 let mode: Option<CryptMode> = match param.get("crypt-mode") {
135 Some(mode) => Some(serde::Deserialize::deserialize(mode)?),
136 None => None,
137 };
138
139 let key = match (keyfile, key_fd) {
140 (None, None) => None,
141 (Some(_), Some(_)) => bail!("--keyfile and --keyfd are mutually exclusive"),
142 (Some(keyfile), None) => Some(KeyWithSource::from_path(
143 keyfile.clone(),
144 file_get_contents(keyfile)?,
145 )),
146 (None, Some(fd)) => {
147 let mut input = unsafe { std::fs::File::from_raw_fd(fd) };
148 let mut data = Vec::new();
149 let _len: usize = input.read_to_end(&mut data).map_err(|err| {
150 format_err!("error reading encryption key from fd {}: {}", fd, err)
151 })?;
152 if keep_keyfd_open {
153 // don't close fd if requested, and try to reset seek position
154 std::mem::forget(input);
155 unsafe {
156 libc::lseek(fd, 0, libc::SEEK_SET);
157 }
158 }
159 Some(KeyWithSource::from_fd(data))
160 }
161 };
162
163 let master_pubkey = match (master_pubkey_file, master_pubkey_fd) {
164 (None, None) => None,
165 (Some(_), Some(_)) => bail!("--keyfile and --keyfd are mutually exclusive"),
166 (Some(keyfile), None) => Some(KeyWithSource::from_path(
167 keyfile.clone(),
168 file_get_contents(keyfile)?,
169 )),
170 (None, Some(fd)) => {
171 let input = unsafe { std::fs::File::from_raw_fd(fd) };
172 let mut data = Vec::new();
173 let _len: usize = { input }
174 .read_to_end(&mut data)
175 .map_err(|err| format_err!("error reading master key from fd {}: {}", fd, err))?;
176 Some(KeyWithSource::from_fd(data))
177 }
178 };
179
180 let res = match mode {
181 // no crypt mode, enable encryption if keys are available
182 None => match (key, master_pubkey) {
183 // only default keys if available
184 (None, None) => match read_optional_default_encryption_key()? {
185 None => CryptoParams { mode: CryptMode::None, enc_key: None, master_pubkey: None },
186 enc_key => {
187 let master_pubkey = read_optional_default_master_pubkey()?;
188 CryptoParams {
189 mode: CryptMode::Encrypt,
190 enc_key,
191 master_pubkey,
192 }
193 },
194 },
195
196 // explicit master key, default enc key needed
197 (None, master_pubkey) => match read_optional_default_encryption_key()? {
198 None => bail!("--master-pubkey-file/--master-pubkey-fd specified, but no key available"),
199 enc_key => {
200 CryptoParams {
201 mode: CryptMode::Encrypt,
202 enc_key,
203 master_pubkey,
204 }
205 },
206 },
207
208 // explicit keyfile, maybe default master key
209 (enc_key, None) => CryptoParams { mode: CryptMode::Encrypt, enc_key, master_pubkey: read_optional_default_master_pubkey()? },
210
211 // explicit keyfile and master key
212 (enc_key, master_pubkey) => CryptoParams { mode: CryptMode::Encrypt, enc_key, master_pubkey },
213 },
214
215 // explicitly disabled encryption
216 Some(CryptMode::None) => match (key, master_pubkey) {
217 // no keys => OK, no encryption
218 (None, None) => CryptoParams { mode: CryptMode::None, enc_key: None, master_pubkey: None },
219
220 // --keyfile and --crypt-mode=none
221 (Some(_), _) => bail!("--keyfile/--keyfd and --crypt-mode=none are mutually exclusive"),
222
223 // --master-pubkey-file and --crypt-mode=none
224 (_, Some(_)) => bail!("--master-pubkey-file/--master-pubkey-fd and --crypt-mode=none are mutually exclusive"),
225 },
226
227 // explicitly enabled encryption
228 Some(mode) => match (key, master_pubkey) {
229 // no key, maybe master key
230 (None, master_pubkey) => match read_optional_default_encryption_key()? {
231 None => bail!("--crypt-mode without --keyfile and no default key file available"),
232 enc_key => {
233 log::info!("Encrypting with default encryption key!");
234 let master_pubkey = match master_pubkey {
235 None => read_optional_default_master_pubkey()?,
236 master_pubkey => master_pubkey,
237 };
238
239 CryptoParams {
240 mode,
241 enc_key,
242 master_pubkey,
243 }
244 },
245 },
246
247 // --keyfile and --crypt-mode other than none
248 (enc_key, master_pubkey) => {
249 let master_pubkey = match master_pubkey {
250 None => read_optional_default_master_pubkey()?,
251 master_pubkey => master_pubkey,
252 };
253
254 CryptoParams { mode, enc_key, master_pubkey }
255 },
256 },
257 };
258
259 Ok(res)
260 }
261
262 pub fn find_default_master_pubkey() -> Result<Option<PathBuf>, Error> {
263 super::find_xdg_file(
264 DEFAULT_MASTER_PUBKEY_FILE_NAME,
265 "default master public key file",
266 )
267 }
268
269 pub fn place_default_master_pubkey() -> Result<PathBuf, Error> {
270 super::place_xdg_file(
271 DEFAULT_MASTER_PUBKEY_FILE_NAME,
272 "default master public key file",
273 )
274 }
275
276 pub fn find_default_encryption_key() -> Result<Option<PathBuf>, Error> {
277 super::find_xdg_file(
278 DEFAULT_ENCRYPTION_KEY_FILE_NAME,
279 "default encryption key file",
280 )
281 }
282
283 pub fn place_default_encryption_key() -> Result<PathBuf, Error> {
284 super::place_xdg_file(
285 DEFAULT_ENCRYPTION_KEY_FILE_NAME,
286 "default encryption key file",
287 )
288 }
289
290 #[cfg(not(test))]
291 pub(crate) fn read_optional_default_encryption_key() -> Result<Option<KeyWithSource>, Error> {
292 find_default_encryption_key()?
293 .map(|path| file_get_contents(path).map(KeyWithSource::from_default))
294 .transpose()
295 }
296
297 #[cfg(not(test))]
298 pub(crate) fn read_optional_default_master_pubkey() -> Result<Option<KeyWithSource>, Error> {
299 find_default_master_pubkey()?
300 .map(|path| file_get_contents(path).map(KeyWithSource::from_default))
301 .transpose()
302 }
303
304 #[cfg(test)]
305 static mut TEST_DEFAULT_ENCRYPTION_KEY: Result<Option<Vec<u8>>, Error> = Ok(None);
306
307 #[cfg(test)]
308 pub(crate) fn read_optional_default_encryption_key() -> Result<Option<KeyWithSource>, Error> {
309 // not safe when multiple concurrent test cases end up here!
310 unsafe {
311 match &TEST_DEFAULT_ENCRYPTION_KEY {
312 Ok(Some(key)) => Ok(Some(KeyWithSource::from_default(key.clone()))),
313 Ok(None) => Ok(None),
314 Err(_) => bail!("test error"),
315 }
316 }
317 }
318
319 #[cfg(test)]
320 // not safe when multiple concurrent test cases end up here!
321 pub(crate) unsafe fn set_test_encryption_key(value: Result<Option<Vec<u8>>, Error>) {
322 TEST_DEFAULT_ENCRYPTION_KEY = value;
323 }
324
325 #[cfg(test)]
326 static mut TEST_DEFAULT_MASTER_PUBKEY: Result<Option<Vec<u8>>, Error> = Ok(None);
327
328 #[cfg(test)]
329 pub(crate) fn read_optional_default_master_pubkey() -> Result<Option<KeyWithSource>, Error> {
330 // not safe when multiple concurrent test cases end up here!
331 unsafe {
332 match &TEST_DEFAULT_MASTER_PUBKEY {
333 Ok(Some(key)) => Ok(Some(KeyWithSource::from_default(key.clone()))),
334 Ok(None) => Ok(None),
335 Err(_) => bail!("test error"),
336 }
337 }
338 }
339
340 #[cfg(test)]
341 // not safe when multiple concurrent test cases end up here!
342 pub(crate) unsafe fn set_test_default_master_pubkey(value: Result<Option<Vec<u8>>, Error>) {
343 TEST_DEFAULT_MASTER_PUBKEY = value;
344 }
345
346 pub fn get_encryption_key_password() -> Result<Vec<u8>, Error> {
347 // fixme: implement other input methods
348
349 if let Some(password) = super::get_secret_from_env("PBS_ENCRYPTION_PASSWORD")? {
350 return Ok(password.as_bytes().to_vec());
351 }
352
353 // If we're on a TTY, query the user for a password
354 if tty::stdin_isatty() {
355 return tty::read_password("Encryption Key Password: ");
356 }
357
358 bail!("no password input mechanism available");
359 }
360
361 #[cfg(test)]
362 fn create_testdir(name: &str) -> Result<String, Error> {
363 // FIXME:
364 //let mut testdir: PathBuf = format!("{}/testout", env!("CARGO_TARGET_TMPDIR")).into();
365 let mut testdir: PathBuf = "./target/testout".to_string().into();
366 testdir.push(std::module_path!());
367 testdir.push(name);
368
369 let _ = std::fs::remove_dir_all(&testdir);
370 let _ = std::fs::create_dir_all(&testdir);
371
372 Ok(testdir.to_str().unwrap().to_string())
373 }
374
375 #[test]
376 // WARNING: there must only be one test for crypto_parameters as the default key handling is not
377 // safe w.r.t. concurrency
378 fn test_crypto_parameters_handling() -> Result<(), Error> {
379 use proxmox_sys::fs::{replace_file, CreateOptions};
380 use serde_json::json;
381
382 let some_key = vec![1; 1];
383 let default_key = vec![2; 1];
384
385 let some_master_key = vec![3; 1];
386 let default_master_key = vec![4; 1];
387
388 let testdir = create_testdir("key_source")?;
389
390 let keypath = format!("{}/keyfile.test", testdir);
391 let master_keypath = format!("{}/masterkeyfile.test", testdir);
392 let invalid_keypath = format!("{}/invalid_keyfile.test", testdir);
393
394 let no_key_res = CryptoParams {
395 enc_key: None,
396 master_pubkey: None,
397 mode: CryptMode::None,
398 };
399 let some_key_res = CryptoParams {
400 enc_key: Some(KeyWithSource::from_path(
401 keypath.to_string(),
402 some_key.clone(),
403 )),
404 master_pubkey: None,
405 mode: CryptMode::Encrypt,
406 };
407 let some_key_some_master_res = CryptoParams {
408 enc_key: Some(KeyWithSource::from_path(
409 keypath.to_string(),
410 some_key.clone(),
411 )),
412 master_pubkey: Some(KeyWithSource::from_path(
413 master_keypath.to_string(),
414 some_master_key.clone(),
415 )),
416 mode: CryptMode::Encrypt,
417 };
418 let some_key_default_master_res = CryptoParams {
419 enc_key: Some(KeyWithSource::from_path(
420 keypath.to_string(),
421 some_key.clone(),
422 )),
423 master_pubkey: Some(KeyWithSource::from_default(default_master_key.clone())),
424 mode: CryptMode::Encrypt,
425 };
426
427 let some_key_sign_res = CryptoParams {
428 enc_key: Some(KeyWithSource::from_path(
429 keypath.to_string(),
430 some_key.clone(),
431 )),
432 master_pubkey: None,
433 mode: CryptMode::SignOnly,
434 };
435 let default_key_res = CryptoParams {
436 enc_key: Some(KeyWithSource::from_default(default_key.clone())),
437 master_pubkey: None,
438 mode: CryptMode::Encrypt,
439 };
440 let default_key_sign_res = CryptoParams {
441 enc_key: Some(KeyWithSource::from_default(default_key.clone())),
442 master_pubkey: None,
443 mode: CryptMode::SignOnly,
444 };
445
446 replace_file(&keypath, &some_key, CreateOptions::default(), false)?;
447 replace_file(
448 &master_keypath,
449 &some_master_key,
450 CreateOptions::default(),
451 false,
452 )?;
453
454 // no params, no default key == no key
455 let res = crypto_parameters(&json!({}));
456 assert_eq!(res.unwrap(), no_key_res);
457
458 // keyfile param == key from keyfile
459 let res = crypto_parameters(&json!({ "keyfile": keypath }));
460 assert_eq!(res.unwrap(), some_key_res);
461
462 // crypt mode none == no key
463 let res = crypto_parameters(&json!({"crypt-mode": "none"}));
464 assert_eq!(res.unwrap(), no_key_res);
465
466 // crypt mode encrypt/sign-only, no keyfile, no default key == Error
467 assert!(crypto_parameters(&json!({"crypt-mode": "sign-only"})).is_err());
468 assert!(crypto_parameters(&json!({"crypt-mode": "encrypt"})).is_err());
469
470 // crypt mode none with explicit key == Error
471 assert!(crypto_parameters(&json!({"crypt-mode": "none", "keyfile": keypath})).is_err());
472
473 // crypt mode sign-only/encrypt with keyfile == key from keyfile with correct mode
474 let res = crypto_parameters(&json!({"crypt-mode": "sign-only", "keyfile": keypath}));
475 assert_eq!(res.unwrap(), some_key_sign_res);
476 let res = crypto_parameters(&json!({"crypt-mode": "encrypt", "keyfile": keypath}));
477 assert_eq!(res.unwrap(), some_key_res);
478
479 // invalid keyfile parameter always errors
480 assert!(crypto_parameters(&json!({ "keyfile": invalid_keypath })).is_err());
481 assert!(crypto_parameters(&json!({"keyfile": invalid_keypath, "crypt-mode": "none"})).is_err());
482 assert!(
483 crypto_parameters(&json!({"keyfile": invalid_keypath, "crypt-mode": "sign-only"})).is_err()
484 );
485 assert!(
486 crypto_parameters(&json!({"keyfile": invalid_keypath, "crypt-mode": "encrypt"})).is_err()
487 );
488
489 // now set a default key
490 unsafe {
491 set_test_encryption_key(Ok(Some(default_key)));
492 }
493
494 // and repeat
495
496 // no params but default key == default key
497 let res = crypto_parameters(&json!({}));
498 assert_eq!(res.unwrap(), default_key_res);
499
500 // keyfile param == key from keyfile
501 let res = crypto_parameters(&json!({ "keyfile": keypath }));
502 assert_eq!(res.unwrap(), some_key_res);
503
504 // crypt mode none == no key
505 let res = crypto_parameters(&json!({"crypt-mode": "none"}));
506 assert_eq!(res.unwrap(), no_key_res);
507
508 // crypt mode encrypt/sign-only, no keyfile, default key == default key with correct mode
509 let res = crypto_parameters(&json!({"crypt-mode": "sign-only"}));
510 assert_eq!(res.unwrap(), default_key_sign_res);
511 let res = crypto_parameters(&json!({"crypt-mode": "encrypt"}));
512 assert_eq!(res.unwrap(), default_key_res);
513
514 // crypt mode none with explicit key == Error
515 assert!(crypto_parameters(&json!({"crypt-mode": "none", "keyfile": keypath})).is_err());
516
517 // crypt mode sign-only/encrypt with keyfile == key from keyfile with correct mode
518 let res = crypto_parameters(&json!({"crypt-mode": "sign-only", "keyfile": keypath}));
519 assert_eq!(res.unwrap(), some_key_sign_res);
520 let res = crypto_parameters(&json!({"crypt-mode": "encrypt", "keyfile": keypath}));
521 assert_eq!(res.unwrap(), some_key_res);
522
523 // invalid keyfile parameter always errors
524 assert!(crypto_parameters(&json!({ "keyfile": invalid_keypath })).is_err());
525 assert!(crypto_parameters(&json!({"keyfile": invalid_keypath, "crypt-mode": "none"})).is_err());
526 assert!(
527 crypto_parameters(&json!({"keyfile": invalid_keypath, "crypt-mode": "sign-only"})).is_err()
528 );
529 assert!(
530 crypto_parameters(&json!({"keyfile": invalid_keypath, "crypt-mode": "encrypt"})).is_err()
531 );
532
533 // now make default key retrieval error
534 unsafe {
535 set_test_encryption_key(Err(format_err!("test error")));
536 }
537
538 // and repeat
539
540 // no params, default key retrieval errors == Error
541 assert!(crypto_parameters(&json!({})).is_err());
542
543 // keyfile param == key from keyfile
544 let res = crypto_parameters(&json!({ "keyfile": keypath }));
545 assert_eq!(res.unwrap(), some_key_res);
546
547 // crypt mode none == no key
548 let res = crypto_parameters(&json!({"crypt-mode": "none"}));
549 assert_eq!(res.unwrap(), no_key_res);
550
551 // crypt mode encrypt/sign-only, no keyfile, default key error == Error
552 assert!(crypto_parameters(&json!({"crypt-mode": "sign-only"})).is_err());
553 assert!(crypto_parameters(&json!({"crypt-mode": "encrypt"})).is_err());
554
555 // crypt mode none with explicit key == Error
556 assert!(crypto_parameters(&json!({"crypt-mode": "none", "keyfile": keypath})).is_err());
557
558 // crypt mode sign-only/encrypt with keyfile == key from keyfile with correct mode
559 let res = crypto_parameters(&json!({"crypt-mode": "sign-only", "keyfile": keypath}));
560 assert_eq!(res.unwrap(), some_key_sign_res);
561 let res = crypto_parameters(&json!({"crypt-mode": "encrypt", "keyfile": keypath}));
562 assert_eq!(res.unwrap(), some_key_res);
563
564 // invalid keyfile parameter always errors
565 assert!(crypto_parameters(&json!({ "keyfile": invalid_keypath })).is_err());
566 assert!(crypto_parameters(&json!({"keyfile": invalid_keypath, "crypt-mode": "none"})).is_err());
567 assert!(
568 crypto_parameters(&json!({"keyfile": invalid_keypath, "crypt-mode": "sign-only"})).is_err()
569 );
570 assert!(
571 crypto_parameters(&json!({"keyfile": invalid_keypath, "crypt-mode": "encrypt"})).is_err()
572 );
573
574 // now remove default key again
575 unsafe {
576 set_test_encryption_key(Ok(None));
577 }
578 // set a default master key
579 unsafe {
580 set_test_default_master_pubkey(Ok(Some(default_master_key)));
581 }
582
583 // and use an explicit master key
584 assert!(crypto_parameters(&json!({ "master-pubkey-file": master_keypath })).is_err());
585 // just a default == no key
586 let res = crypto_parameters(&json!({}));
587 assert_eq!(res.unwrap(), no_key_res);
588
589 // keyfile param == key from keyfile
590 let res = crypto_parameters(&json!({"keyfile": keypath, "master-pubkey-file": master_keypath}));
591 assert_eq!(res.unwrap(), some_key_some_master_res);
592 // same with fallback to default master key
593 let res = crypto_parameters(&json!({ "keyfile": keypath }));
594 assert_eq!(res.unwrap(), some_key_default_master_res);
595
596 // crypt mode none == error
597 assert!(crypto_parameters(
598 &json!({"crypt-mode": "none", "master-pubkey-file": master_keypath})
599 )
600 .is_err());
601 // with just default master key == no key
602 let res = crypto_parameters(&json!({"crypt-mode": "none"}));
603 assert_eq!(res.unwrap(), no_key_res);
604
605 // crypt mode encrypt without enc key == error
606 assert!(crypto_parameters(
607 &json!({"crypt-mode": "encrypt", "master-pubkey-file": master_keypath})
608 )
609 .is_err());
610 assert!(crypto_parameters(&json!({"crypt-mode": "encrypt"})).is_err());
611
612 // crypt mode none with explicit key == Error
613 assert!(crypto_parameters(
614 &json!({"crypt-mode": "none", "keyfile": keypath, "master-pubkey-file": master_keypath})
615 )
616 .is_err());
617 assert!(crypto_parameters(&json!({"crypt-mode": "none", "keyfile": keypath})).is_err());
618
619 // crypt mode encrypt with keyfile == key from keyfile with correct mode
620 let res = crypto_parameters(
621 &json!({"crypt-mode": "encrypt", "keyfile": keypath, "master-pubkey-file": master_keypath}),
622 );
623 assert_eq!(res.unwrap(), some_key_some_master_res);
624 let res = crypto_parameters(&json!({"crypt-mode": "encrypt", "keyfile": keypath}));
625 assert_eq!(res.unwrap(), some_key_default_master_res);
626
627 // invalid master keyfile parameter always errors when a key is passed, even with a valid
628 // default master key
629 assert!(
630 crypto_parameters(&json!({"keyfile": keypath, "master-pubkey-file": invalid_keypath}))
631 .is_err()
632 );
633 assert!(crypto_parameters(
634 &json!({"keyfile": keypath, "master-pubkey-file": invalid_keypath,"crypt-mode": "none"})
635 )
636 .is_err());
637 assert!(crypto_parameters(&json!({"keyfile": keypath, "master-pubkey-file": invalid_keypath,"crypt-mode": "sign-only"})).is_err());
638 assert!(crypto_parameters(
639 &json!({"keyfile": keypath, "master-pubkey-file": invalid_keypath,"crypt-mode": "encrypt"})
640 )
641 .is_err());
642
643 Ok(())
644 }