From a39e616f50f918f3bc07141fb2d0a3b59b4dc16b Mon Sep 17 00:00:00 2001 From: TommyLike Date: Sat, 1 Apr 2023 10:24:23 +0800 Subject: [PATCH] Support specify digest algo when creating key pairs --- config/server.toml | 2 +- scripts/initialize-user-and-keys.sh | 4 +-- src/client/file_handler/kernel_module.rs | 3 ++ src/control_admin_entrypoint.rs | 4 +++ src/domain/datakey/entity.rs | 4 ++- src/domain/sign_plugin.rs | 4 +-- src/infra/sign_backend/memory/backend.rs | 2 +- src/infra/sign_plugin/openpgp.rs | 43 ++++++++++++++++++++---- src/infra/sign_plugin/signers.rs | 2 +- src/infra/sign_plugin/x509.rs | 39 +++++++++++++++++---- 10 files changed, 85 insertions(+), 22 deletions(-) diff --git a/config/server.toml b/config/server.toml index 2c04876..b7510a2 100644 --- a/config/server.toml +++ b/config/server.toml @@ -10,7 +10,7 @@ server_ip = "0.0.0.0" server_port = "8080" cookie_key = "2B5AEC57F7CC4FF8B4120AA7E4527C7B597CAF43183E453A9B981991E6FACB76" redis_connection = "redis://:signatrust-redis@127.0.0.1:6379" -limits_per_minute = 10 +limits_per_minute = 100 [oidc] client_id = "" client_secret = "" diff --git a/scripts/initialize-user-and-keys.sh b/scripts/initialize-user-and-keys.sh index b21b7b6..b1db961 100755 --- a/scripts/initialize-user-and-keys.sh +++ b/scripts/initialize-user-and-keys.sh @@ -22,7 +22,7 @@ function create_default_admin { function create_default_openpgp_keys { echo "start to create default openpgp keys identified with default-pgp" - RUST_LOG=info ./target/debug/control-admin --config ./config/server.toml generate-keys --name default-pgp --description "used for test purpose only" --key-type pgp --email tommylikehu@gmail.com --param-key-type rsa --param-key-size 2048 --param-pgp-email infra@openeuler.org + RUST_LOG=info ./target/debug/control-admin --config ./config/server.toml generate-keys --name default-pgp --description "used for test purpose only" --key-type pgp --email tommylikehu@gmail.com --param-key-type rsa --param-key-size 2048 --param-pgp-email infra@openeuler.org --digest-algorithm sha2_256 } @@ -30,7 +30,7 @@ function create_default_openpgp_keys { function create_default_x509_keys { echo "start to create default x509 keys identified with default-x509" RUST_LOG=info ./target/debug/control-admin --config ./config/server.toml generate-keys --name default-x509 --description "used for test purpose only" --key-type x509 --email tommylikehu@gmail.com --param-key-type rsa --param-key-size 2048 \ - --param-x509-common-name Infra --param-x509-organization Huawei --param-x509-locality ShenZhen --param-x509-province-name GuangDong --param-x509-country-name CN --param-x509-organizational-unit Infra + --param-x509-common-name Infra --param-x509-organization Huawei --param-x509-locality ShenZhen --param-x509-province-name GuangDong --param-x509-country-name CN --param-x509-organizational-unit Infra --digest-algorithm sha2_256 } echo "Preparing basic keys for signatrust......" diff --git a/src/client/file_handler/kernel_module.rs b/src/client/file_handler/kernel_module.rs index 1b41a07..5edaa76 100644 --- a/src/client/file_handler/kernel_module.rs +++ b/src/client/file_handler/kernel_module.rs @@ -99,6 +99,9 @@ impl KernelModuleFileHandler { pub fn file_unsigned(&self, path: &PathBuf) -> Result { let mut file = fs::File::open(path)?; + if file.metadata()?.len() <= MAGIC_NUMBER_SIZE as u64 { + return Ok(true) + } file.seek(io::SeekFrom::End((MAGIC_NUMBER_SIZE as i64) * -1))?; let mut signature_ending: [u8; MAGIC_NUMBER_SIZE] = [0; MAGIC_NUMBER_SIZE]; file.read(&mut signature_ending)?; diff --git a/src/control_admin_entrypoint.rs b/src/control_admin_entrypoint.rs index d1f4ac2..99776d5 100644 --- a/src/control_admin_entrypoint.rs +++ b/src/control_admin_entrypoint.rs @@ -85,6 +85,9 @@ pub struct CommandGenerateKeys { #[arg(long)] #[arg(help = "specify the type of internal key used for keys generation, ie, 1024")] param_key_size: String, + #[arg(long)] + #[arg(help = "specify the type of digest algorithm used for signing, ie, sha1")] + digest_algorithm: String, //pgp specific parameters #[arg(long)] #[arg(help = "specify the email used for openPGP key generation. ")] @@ -121,6 +124,7 @@ fn generate_keys_parameters(command: &CommandGenerateKeys) -> HashMap, pub public_key: SecVec, pub certificate: SecVec, - pub identity: String + pub identity: String, + pub attributes: HashMap } impl SecDataKey { @@ -145,6 +146,7 @@ impl SecDataKey { public_key: SecVec::new(engine.decode(data_key.public_key.clone()).await?), certificate: SecVec::new(engine.decode(data_key.certificate.clone()).await?), identity: data_key.get_identity(), + attributes: data_key.attributes.clone(), }) } } diff --git a/src/domain/sign_plugin.rs b/src/domain/sign_plugin.rs index 462ee42..772f9d1 100644 --- a/src/domain/sign_plugin.rs +++ b/src/domain/sign_plugin.rs @@ -19,7 +19,7 @@ use std::collections::HashMap; use crate::domain::datakey::entity::SecDataKey; pub trait SignPlugins: Send + Sync { - fn new(db: &SecDataKey) -> Result + fn new(db: SecDataKey) -> Result where Self: Sized; fn parse_attributes( @@ -30,7 +30,7 @@ pub trait SignPlugins: Send + Sync { where Self: Sized; fn generate_keys( - value: &HashMap, + attributes: &HashMap, ) -> Result<(Vec, Vec, Vec)> where Self: Sized; diff --git a/src/infra/sign_backend/memory/backend.rs b/src/infra/sign_backend/memory/backend.rs index 293e176..2a94dd0 100644 --- a/src/infra/sign_backend/memory/backend.rs +++ b/src/infra/sign_backend/memory/backend.rs @@ -89,7 +89,7 @@ impl SignBackend for MemorySignBackend { async fn sign(&self, data_key: &DataKey, content: Vec, options: HashMap) -> Result> { let sec_key = SecDataKey::load(data_key, &self.engine).await?; - Signers::load_from_data_key(&data_key.key_type, &sec_key)?.sign(content, options) + Signers::load_from_data_key(&data_key.key_type, sec_key)?.sign(content, options) } async fn decode_public_keys(&self, data_key: &mut DataKey) -> Result<()> { diff --git a/src/infra/sign_plugin/openpgp.rs b/src/infra/sign_plugin/openpgp.rs index 8bedb31..e3fd969 100644 --- a/src/infra/sign_plugin/openpgp.rs +++ b/src/infra/sign_plugin/openpgp.rs @@ -53,6 +53,8 @@ pub struct PgpKeyGenerationParameter { key_type: String, #[validate(custom(function = "validate_key_size", message="invalid openpgp attribute 'key_length'"))] key_length: String, + #[validate(custom(function= "validate_digest_algorithm_type", message="invalid digest algorithm"))] + digest_algorithm: String, #[validate(custom(function = "validate_utc_time", message="invalid openpgp attribute 'created_at'"))] create_at: String, #[validate(custom(function= "validate_utc_time_not_expire", message="invalid openpgp attribute 'expire_at'"))] @@ -71,6 +73,23 @@ impl PgpKeyGenerationParameter { }; } + pub fn get_digest_algorithm(&self) -> Result { + return match self.digest_algorithm.as_str() { + "none" => Ok(HashAlgorithm::None), + "md5" => Ok(HashAlgorithm::MD5), + "sha1" => Ok(HashAlgorithm::SHA1), + "sha2_256" => Ok(HashAlgorithm::SHA2_256), + "sha2_384" => Ok(HashAlgorithm::SHA2_384), + "sha2_512" => Ok(HashAlgorithm::SHA2_512), + "sha2_224" => Ok(HashAlgorithm::SHA2_224), + "sha3_256" => Ok(HashAlgorithm::SHA3_256), + "sha3_512" => Ok(HashAlgorithm::SHA3_512), + _ => Err(Error::ParameterError( + "invalid digest algorithm for openpgp".to_string(), + )), + }; + } + pub fn get_user_id(&self) -> String { format!("{} <{}>", self.name, self.email) } @@ -78,14 +97,21 @@ impl PgpKeyGenerationParameter { fn validate_key_type(key_type: &str) -> std::result::Result<(), ValidationError> { if !vec!["rsa", "ecdh", "eddsa"].contains(&key_type) { - return Err(ValidationError::new("invalid key type")); + return Err(ValidationError::new("invalid key type, possible values are rsa/ecdh/eddsa")); + } + Ok(()) +} + +fn validate_digest_algorithm_type(key_type: &str) -> std::result::Result<(), ValidationError> { + if !vec!["none", "md5", "sha1", "sha1", "sha2_256", "sha2_384","sha2_512","sha2_224","sha3_256", "sha3_512"].contains(&key_type) { + return Err(ValidationError::new("invalid hash algorithm, possible values are none/md5/sha1/sha1/sha2_256/sha2_384/sha2_512/sha2_224/sha3_256/sha3_512")); } Ok(()) } fn validate_key_size(key_size: &str) -> std::result::Result<(), ValidationError> { if !vec!["2048", "3072", "4096"].contains(&key_size) { - return Err(ValidationError::new("invalid key size")); + return Err(ValidationError::new("invalid key size, possible values are 2048/3072/4096")); } Ok(()) } @@ -94,6 +120,7 @@ pub struct OpenPGPPlugin { secret_key: SignedSecretKey, public_key: SignedPublicKey, identity: String, + attributes: HashMap } impl OpenPGPPlugin { @@ -108,7 +135,7 @@ impl OpenPGPPlugin { } impl SignPlugins for OpenPGPPlugin { - fn new(db: &SecDataKey) -> Result { + fn new(db: SecDataKey) -> Result { let private = from_utf8(&db.private_key.unsecure()).map_err(|e| Error::KeyParseError(e.to_string()))?; let (secret_key, _) = SignedSecretKey::from_string(private).map_err(|e| Error::KeyParseError(e.to_string()))?; @@ -119,6 +146,7 @@ impl SignPlugins for OpenPGPPlugin { secret_key, public_key, identity: db.identity.clone(), + attributes: db.attributes.clone(), }) } @@ -131,9 +159,9 @@ impl SignPlugins for OpenPGPPlugin { } fn generate_keys( - value: &HashMap, + attributes: &HashMap, ) -> Result<(Vec, Vec, Vec)> { - let parameter = OpenPGPPlugin::attributes_validate(value)?; + let parameter = OpenPGPPlugin::attributes_validate(attributes)?; let mut key_params = SecretKeyParamsBuilder::default(); let create_at = parameter.create_at.parse()?; let expire :DateTime = parameter.expire_at.parse()?; @@ -144,7 +172,7 @@ impl SignPlugins for OpenPGPPlugin { .can_sign(true) .primary_user_id(parameter.get_user_id()) .preferred_symmetric_algorithms(smallvec![SymmetricKeyAlgorithm::AES256,]) - .preferred_hash_algorithms(smallvec![HashAlgorithm::SHA2_256,]) + .preferred_hash_algorithms(smallvec![parameter.get_digest_algorithm()?]) .preferred_compression_algorithms(smallvec![CompressionAlgorithm::ZLIB,]) .created_at(create_at) .expiration(Some(duration)); @@ -162,13 +190,14 @@ impl SignPlugins for OpenPGPPlugin { } fn sign(&self, content: Vec, options: HashMap) -> Result> { + let parameter = OpenPGPPlugin::attributes_validate(&self.attributes)?; let passwd_fn = String::new; let now = Utc::now(); let sig_cfg = SignatureConfig { version: SignatureVersion::V4, typ: SignatureType::Binary, pub_alg: self.public_key.primary_key.algorithm(), - hash_alg: HashAlgorithm::SHA2_256, + hash_alg: parameter.get_digest_algorithm()?, issuer: Some(self.secret_key.key_id()), created: Some(now), unhashed_subpackets: vec![], diff --git a/src/infra/sign_plugin/signers.rs b/src/infra/sign_plugin/signers.rs index 193071b..2bab8f3 100644 --- a/src/infra/sign_plugin/signers.rs +++ b/src/infra/sign_plugin/signers.rs @@ -28,7 +28,7 @@ pub struct Signers {} impl Signers { //get responding sign plugin for data signing - pub fn load_from_data_key(key_type: &KeyType, data_key: &SecDataKey) -> Result> { + pub fn load_from_data_key(key_type: &KeyType, data_key: SecDataKey) -> Result> { match key_type { KeyType::OpenPGP => Ok(Box::new(OpenPGPPlugin::new(data_key)?)), KeyType::X509 => Ok(Box::new(X509Plugin::new(data_key)?)), diff --git a/src/infra/sign_plugin/x509.rs b/src/infra/sign_plugin/x509.rs index ecc7506..48d0545 100644 --- a/src/infra/sign_plugin/x509.rs +++ b/src/infra/sign_plugin/x509.rs @@ -51,6 +51,8 @@ pub struct X509KeyGenerationParameter { key_type: String, #[validate(custom(function = "validate_x509_key_size", message="invalid x509 attribute 'key_length'"))] key_length: String, + #[validate(custom(function= "validate_x509_digest_algorithm_type", message="invalid digest algorithm"))] + digest_algorithm: String, #[validate(custom(function = "validate_utc_time", message="invalid x509 attribute 'created_at'"))] create_at: String, #[validate(custom(function= "validate_utc_time_not_expire", message="invalid x509 attribute 'expire_at'"))] @@ -68,6 +70,21 @@ impl X509KeyGenerationParameter { }; } + pub fn get_digest_algorithm(&self) -> Result { + return match self.digest_algorithm.as_str() { + "none" => Ok(MessageDigest::null()), + "md5" => Ok(MessageDigest::md5()), + "sha1" => Ok(MessageDigest::sha1()), + "sha2_256" => Ok(MessageDigest::sha224()), + "sha2_384" => Ok(MessageDigest::sha256()), + "sha2_512" => Ok(MessageDigest::sha384()), + "sha2_224" => Ok(MessageDigest::sha512()), + _ => Err(Error::ParameterError( + "invalid digest algorithm for openpgp".to_string(), + )), + }; + } + pub fn get_subject_name(&self) -> Result { let mut x509_name = x509::X509NameBuilder::new()?; x509_name.append_entry_by_text("CN", &self.common_name)?; @@ -82,14 +99,14 @@ impl X509KeyGenerationParameter { fn validate_x509_key_type(key_type: &str) -> std::result::Result<(), ValidationError> { if !vec!["rsa", "dsa"].contains(&key_type) { - return Err(ValidationError::new("invalid key type")); + return Err(ValidationError::new("invalid key type, possible values are rsa/dsa")); } Ok(()) } fn validate_x509_key_size(key_size: &str) -> std::result::Result<(), ValidationError> { if !vec!["2048", "3072", "4096"].contains(&key_size) { - return Err(ValidationError::new("invalid key size")); + return Err(ValidationError::new("invalid key size, possible values are 2048/3072/4096")); } Ok(()) } @@ -100,11 +117,19 @@ fn days_in_duration(time: &str) -> Result { Ok((end - start).num_days()) } +fn validate_x509_digest_algorithm_type(key_type: &str) -> std::result::Result<(), ValidationError> { + if !vec!["none", "md5", "sha1", "sha1", "sha2_256","sha2_384","sha2_512","sha2_224"].contains(&key_type) { + return Err(ValidationError::new("invalid hash algorithm, possible values are none/md5/sha1/sha1/sha2_256/sha2_384/sha2_512/sha2_224")); + } + Ok(()) +} + pub struct X509Plugin { private_key: SecVec, public_key: SecVec, certificate: SecVec, identity: String, + attributes: HashMap } impl X509Plugin { @@ -119,12 +144,13 @@ impl X509Plugin { } impl SignPlugins for X509Plugin { - fn new(db: &SecDataKey) -> Result { + fn new(db: SecDataKey) -> Result { Ok(Self { private_key: db.private_key.clone(), public_key: db.public_key.clone(), certificate: db.certificate.clone(), identity: db.identity.clone(), + attributes: db.attributes.clone() }) } @@ -137,19 +163,18 @@ impl SignPlugins for X509Plugin { } fn generate_keys( - value: &HashMap, + attributes: &HashMap, ) -> Result<(Vec, Vec, Vec)> { - let parameter = X509Plugin::attributes_validate(value)?; + let parameter = X509Plugin::attributes_validate(attributes)?; let keys = parameter.get_key()?; let mut generator = x509::X509Builder::new()?; - let hash = MessageDigest::sha256(); generator.set_subject_name(parameter.get_subject_name()?.as_ref())?; generator.set_issuer_name(parameter.get_subject_name()?.as_ref())?; generator.set_pubkey(keys.as_ref())?; generator.set_version(2)?; generator.set_not_before(Asn1Time::days_from_now(days_in_duration(¶meter.create_at)? as u32)?.as_ref())?; generator.set_not_after(Asn1Time::days_from_now(days_in_duration(¶meter.expire_at)? as u32)?.as_ref())?; - generator.sign(keys.as_ref(), hash)?; + generator.sign(keys.as_ref(), parameter.get_digest_algorithm()?)?; let cert = generator.build(); Ok(( keys.private_key_to_pem_pkcs8()?, -- Gitee