diff --git a/Cargo.toml b/Cargo.toml index 31835de5..a9a0d34d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,6 +94,7 @@ proxmox-http = { version = "0.2.1", features = [ "client", "http-helpers", "webs #proxmox-http = { version = "0.2.0", path = "../proxmox/proxmox-http", features = [ "client", "http-helpers", "websocket" ] } proxmox-openid = "0.6.0" +pbs-api-types = { path = "pbs-api-types" } pbs-buildcfg = { path = "pbs-buildcfg" } pbs-datastore = { path = "pbs-datastore" } pbs-runtime = { path = "pbs-runtime" } diff --git a/Makefile b/Makefile index 58678ce7..d513af07 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ RESTORE_BIN := \ proxmox-restore-daemon SUBCRATES := \ + pbs-api-types \ pbs-buildcfg \ pbs-datastore \ pbs-runtime \ diff --git a/pbs-api-types/Cargo.toml b/pbs-api-types/Cargo.toml new file mode 100644 index 00000000..0a9f7ea7 --- /dev/null +++ b/pbs-api-types/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "pbs-api-types" +version = "0.1.0" +authors = ["Proxmox Support Team "] +edition = "2018" +description = "general API type helpers for PBS" + +[dependencies] +lazy_static = "1.4" +regex = "1.2" + +proxmox = { version = "0.11.5", default-features = false, features = [ "api-macro" ] } diff --git a/pbs-api-types/src/lib.rs b/pbs-api-types/src/lib.rs new file mode 100644 index 00000000..0e3d5c39 --- /dev/null +++ b/pbs-api-types/src/lib.rs @@ -0,0 +1,14 @@ +use proxmox::api::schema::{ApiStringFormat, Schema, StringSchema}; +use proxmox::const_regex; + +const_regex! { + pub FINGERPRINT_SHA256_REGEX = r"^(?:[0-9a-fA-F][0-9a-fA-F])(?::[0-9a-fA-F][0-9a-fA-F]){31}$"; +} + +pub const FINGERPRINT_SHA256_FORMAT: ApiStringFormat = + ApiStringFormat::Pattern(&FINGERPRINT_SHA256_REGEX); + +pub const CERT_FINGERPRINT_SHA256_SCHEMA: Schema = + StringSchema::new("X509 certificate fingerprint (sha256).") + .format(&FINGERPRINT_SHA256_FORMAT) + .schema(); diff --git a/pbs-datastore/Cargo.toml b/pbs-datastore/Cargo.toml index aca6bbad..eed3a1d7 100644 --- a/pbs-datastore/Cargo.toml +++ b/pbs-datastore/Cargo.toml @@ -12,6 +12,7 @@ endian_trait = { version = "0.6", features = [ "arrays" ] } nix = "0.19.1" openssl = "0.10" serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" zstd = { version = "0.6", features = [ "bindgen" ] } pathpatterns = "0.1.2" @@ -19,4 +20,5 @@ pxar = { version = "0.10.1", features = [ "tokio-io" ] } proxmox = { version = "0.11.5", default-features = false, features = [ "api-macro" ] } +pbs-api-types = { path = "../pbs-api-types" } pbs-tools = { path = "../pbs-tools" } diff --git a/src/backup/key_derivation.rs b/pbs-datastore/src/key_derivation.rs similarity index 93% rename from src/backup/key_derivation.rs rename to pbs-datastore/src/key_derivation.rs index 7276e4e2..be5c077f 100644 --- a/src/backup/key_derivation.rs +++ b/pbs-datastore/src/key_derivation.rs @@ -1,15 +1,66 @@ -use anyhow::{bail, format_err, Context, Error}; - -use serde::{Deserialize, Serialize}; - -use crate::backup::{CryptConfig, Fingerprint}; use std::io::Write; use std::path::Path; +use anyhow::{bail, format_err, Context, Error}; +use serde::{Deserialize, Serialize}; + +use proxmox::api::api; use proxmox::tools::fs::{file_get_contents, replace_file, CreateOptions}; use proxmox::try_block; -use crate::api2::types::{KeyInfo, Kdf}; +use pbs_api_types::CERT_FINGERPRINT_SHA256_SCHEMA; + +use crate::crypt_config::{CryptConfig, Fingerprint}; + +#[api(default: "scrypt")] +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +#[serde(rename_all = "lowercase")] +/// Key derivation function for password protected encryption keys. +pub enum Kdf { + /// Do not encrypt the key. + None, + /// Encrypt they key with a password using SCrypt. + Scrypt, + /// Encrtypt the Key with a password using PBKDF2 + PBKDF2, +} + +impl Default for Kdf { + #[inline] + fn default() -> Self { + Kdf::Scrypt + } +} + +#[api( + properties: { + kdf: { + type: Kdf, + }, + fingerprint: { + schema: CERT_FINGERPRINT_SHA256_SCHEMA, + optional: true, + }, + }, +)] +#[derive(Deserialize, Serialize)] +/// Encryption Key Information +pub struct KeyInfo { + /// Path to key (if stored in a file) + #[serde(skip_serializing_if="Option::is_none")] + pub path: Option, + pub kdf: Kdf, + /// Key creation time + pub created: i64, + /// Key modification time + pub modified: i64, + /// Key fingerprint + #[serde(skip_serializing_if="Option::is_none")] + pub fingerprint: Option, + /// Password hint + #[serde(skip_serializing_if="Option::is_none")] + pub hint: Option, +} /// Key derivation function configuration #[derive(Deserialize, Serialize, Clone, Debug)] diff --git a/pbs-datastore/src/lib.rs b/pbs-datastore/src/lib.rs index 0a24176d..c6981cc1 100644 --- a/pbs-datastore/src/lib.rs +++ b/pbs-datastore/src/lib.rs @@ -190,6 +190,7 @@ pub mod data_blob_reader; pub mod data_blob_writer; pub mod file_formats; pub mod index; +pub mod key_derivation; pub use checksum_reader::ChecksumReader; pub use checksum_writer::ChecksumWriter; @@ -197,3 +198,7 @@ pub use chunker::Chunker; pub use crypt_config::{CryptConfig, CryptMode}; pub use crypt_reader::CryptReader; pub use crypt_writer::CryptWriter; +pub use key_derivation::{ + decrypt_key, load_and_decrypt_key, rsa_decrypt_key_config, rsa_encrypt_key_config, +}; +pub use key_derivation::{Kdf, KeyConfig, KeyDerivationConfig, KeyInfo}; diff --git a/src/api2/config/tape_encryption_keys.rs b/src/api2/config/tape_encryption_keys.rs index 31be0ed1..e1b42fb8 100644 --- a/src/api2/config/tape_encryption_keys.rs +++ b/src/api2/config/tape_encryption_keys.rs @@ -12,6 +12,8 @@ use proxmox::{ tools::fs::open_file_locked, }; +use pbs_datastore::{KeyInfo, Kdf}; + use crate::{ config::{ acl::{ @@ -31,8 +33,6 @@ use crate::{ TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA, PROXMOX_CONFIG_DIGEST_SCHEMA, PASSWORD_HINT_SCHEMA, - KeyInfo, - Kdf, }, backup::{ KeyConfig, diff --git a/src/api2/types/mod.rs b/src/api2/types/mod.rs index c9ba6db6..91a64798 100644 --- a/src/api2/types/mod.rs +++ b/src/api2/types/mod.rs @@ -40,6 +40,12 @@ pub use file_restore::*; mod acme; pub use acme::*; +pub use pbs_api_types::{ + CERT_FINGERPRINT_SHA256_SCHEMA, + FINGERPRINT_SHA256_FORMAT, + FINGERPRINT_SHA256_REGEX, +}; + // File names: may not contain slashes, may not start with "." pub const FILENAME_FORMAT: ApiStringFormat = ApiStringFormat::VerifyFn(|name| { if name.starts_with('.') { @@ -112,8 +118,6 @@ const_regex!{ pub BACKUP_REPO_URL_REGEX = concat!(r"^^(?:(?:(", USER_ID_REGEX_STR!(), "|", APITOKEN_ID_REGEX_STR!(), ")@)?(", DNS_NAME!(), "|", IPRE_BRACKET!() ,"):)?(?:([0-9]{1,5}):)?(", PROXMOX_SAFE_ID_REGEX_STR!(), r")$"); - pub FINGERPRINT_SHA256_REGEX = r"^(?:[0-9a-fA-F][0-9a-fA-F])(?::[0-9a-fA-F][0-9a-fA-F]){31}$"; - pub ACL_PATH_REGEX = concat!(r"^(?:/|", r"(?:/", PROXMOX_SAFE_ID_REGEX_STR!(), ")+", r")$"); pub SUBSCRIPTION_KEY_REGEX = concat!(r"^pbs(?:[cbsp])-[0-9a-f]{10}$"); @@ -156,9 +160,6 @@ pub const IP_FORMAT: ApiStringFormat = pub const PVE_CONFIG_DIGEST_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&SHA256_HEX_REGEX); -pub const FINGERPRINT_SHA256_FORMAT: ApiStringFormat = - ApiStringFormat::Pattern(&FINGERPRINT_SHA256_REGEX); - pub const PROXMOX_SAFE_ID_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX); @@ -225,12 +226,6 @@ pub const PBS_PASSWORD_SCHEMA: Schema = StringSchema::new("User Password.") .max_length(64) .schema(); -pub const CERT_FINGERPRINT_SHA256_SCHEMA: Schema = StringSchema::new( - "X509 certificate fingerprint (sha256)." -) - .format(&FINGERPRINT_SHA256_FORMAT) - .schema(); - pub const TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA: Schema = StringSchema::new( "Tape encryption key fingerprint (sha256)." ) @@ -1449,56 +1444,6 @@ pub const PASSWORD_HINT_SCHEMA: Schema = StringSchema::new("Password hint.") .max_length(64) .schema(); -#[api(default: "scrypt")] -#[derive(Clone, Copy, Debug, Deserialize, Serialize)] -#[serde(rename_all = "lowercase")] -/// Key derivation function for password protected encryption keys. -pub enum Kdf { - /// Do not encrypt the key. - None, - /// Encrypt they key with a password using SCrypt. - Scrypt, - /// Encrtypt the Key with a password using PBKDF2 - PBKDF2, -} - -impl Default for Kdf { - #[inline] - fn default() -> Self { - Kdf::Scrypt - } -} - -#[api( - properties: { - kdf: { - type: Kdf, - }, - fingerprint: { - schema: CERT_FINGERPRINT_SHA256_SCHEMA, - optional: true, - }, - }, -)] -#[derive(Deserialize, Serialize)] -/// Encryption Key Information -pub struct KeyInfo { - /// Path to key (if stored in a file) - #[serde(skip_serializing_if="Option::is_none")] - pub path: Option, - pub kdf: Kdf, - /// Key creation time - pub created: i64, - /// Key modification time - pub modified: i64, - /// Key fingerprint - #[serde(skip_serializing_if="Option::is_none")] - pub fingerprint: Option, - /// Password hint - #[serde(skip_serializing_if="Option::is_none")] - pub hint: Option, -} - #[api] #[derive(Deserialize, Serialize)] /// RSA public key information diff --git a/src/backup/mod.rs b/src/backup/mod.rs index 3340ae55..dcfb4bd4 100644 --- a/src/backup/mod.rs +++ b/src/backup/mod.rs @@ -178,12 +178,14 @@ pub fn backup_group() -> Result { } } -pub use pbs_datastore::catalog::*; pub use pbs_datastore::catalog; -pub use pbs_datastore::file_formats::*; -pub use pbs_datastore::file_formats; -pub use pbs_datastore::index::*; -pub use pbs_datastore::index; +pub use pbs_datastore::catalog::*; +pub use pbs_datastore::checksum_reader; +pub use pbs_datastore::checksum_reader::*; +pub use pbs_datastore::checksum_writer; +pub use pbs_datastore::checksum_writer::*; +pub use pbs_datastore::chunker; +pub use pbs_datastore::chunker::*; pub use pbs_datastore::crypt_config; pub use pbs_datastore::crypt_config::*; pub use pbs_datastore::crypt_reader; @@ -196,15 +198,12 @@ pub use pbs_datastore::data_blob_reader; pub use pbs_datastore::data_blob_reader::*; pub use pbs_datastore::data_blob_writer; pub use pbs_datastore::data_blob_writer::*; -pub use pbs_datastore::checksum_reader; -pub use pbs_datastore::checksum_reader::*; -pub use pbs_datastore::checksum_writer; -pub use pbs_datastore::checksum_writer::*; -pub use pbs_datastore::chunker; -pub use pbs_datastore::chunker::*; - -mod key_derivation; -pub use key_derivation::*; +pub use pbs_datastore::file_formats; +pub use pbs_datastore::file_formats::*; +pub use pbs_datastore::index; +pub use pbs_datastore::index::*; +pub use pbs_datastore::key_derivation; +pub use pbs_datastore::key_derivation::*; mod manifest; pub use manifest::*; diff --git a/src/bin/proxmox_backup_client/key.rs b/src/bin/proxmox_backup_client/key.rs index 39ff44d2..49afcccb 100644 --- a/src/bin/proxmox_backup_client/key.rs +++ b/src/bin/proxmox_backup_client/key.rs @@ -13,8 +13,10 @@ use proxmox::api::router::ReturnType; use proxmox::sys::linux::tty; use proxmox::tools::fs::{file_get_contents, replace_file, CreateOptions}; +use pbs_datastore::{KeyInfo, Kdf}; + use proxmox_backup::{ - api2::types::{Kdf, KeyInfo, RsaPubKeyInfo, PASSWORD_HINT_SCHEMA}, + api2::types::{RsaPubKeyInfo, PASSWORD_HINT_SCHEMA}, backup::{rsa_decrypt_key_config, KeyConfig}, tools, tools::paperkey::{generate_paper_key, PaperkeyFormat}, diff --git a/src/bin/proxmox_tape/encryption_key.rs b/src/bin/proxmox_tape/encryption_key.rs index 6fcd2877..e3c93704 100644 --- a/src/bin/proxmox_tape/encryption_key.rs +++ b/src/bin/proxmox_tape/encryption_key.rs @@ -11,6 +11,8 @@ use proxmox::{ sys::linux::tty, }; +use pbs_datastore::Kdf; + use proxmox_backup::{ tools::{ paperkey::{ @@ -25,7 +27,6 @@ use proxmox_backup::{ DRIVE_NAME_SCHEMA, TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA, PASSWORD_HINT_SCHEMA, - Kdf, }, }, backup::Fingerprint,