From 48e6e16e4297d28909c71aee65431b5364d91c66 Mon Sep 17 00:00:00 2001 From: TommyLike Date: Tue, 28 Mar 2023 23:00:15 +0800 Subject: [PATCH] Add x509 generation in prepare script --- Cargo.toml | 2 +- README.md | 1 + scripts/initialize-user-and-keys.sh | 14 ++++- src/client/sign_identity.rs | 2 +- ...l_admin.rs => control_admin_entrypoint.rs} | 57 +++++++++++++++---- src/infra/sign_plugin/mod.rs | 1 + src/infra/sign_plugin/openpgp.rs | 27 +-------- src/infra/sign_plugin/util.rs | 41 +++++++++++++ src/infra/sign_plugin/x509.rs | 18 +----- .../handler/control/model/datakey/dto.rs | 1 - 10 files changed, 107 insertions(+), 57 deletions(-) rename src/{control_admin.rs => control_admin_entrypoint.rs} (62%) create mode 100644 src/infra/sign_plugin/util.rs diff --git a/Cargo.toml b/Cargo.toml index 15b4f83..31df309 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,7 +84,7 @@ path = "src/control_server_entrypoint.rs" [[bin]] name = "control-admin" -path = "src/control_admin.rs" +path = "src/control_admin_entrypoint.rs" [profile.release] strip = "debuginfo" \ No newline at end of file diff --git a/README.md b/README.md index 301dcb8..10c888e 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,7 @@ Pay attention to the command output: [Result]: Administrator tommylikehu@gmail.com has been successfully created with token XmUICsVV48EjfkWYv3ch1eutRJOQh7mp3bRfmQDL will expire 2023-09-23 11:20:33 UTC ...skipped output [Result]: Keys 'default-pgp' type pgp has been successfully generated +[Result]: Keys 'default-x509' type x509 has been successfully generated ``` Now you can use this token to debug the control service API or use the pgp keys for signing rpm packages with client. ```shell diff --git a/scripts/initialize-user-and-keys.sh b/scripts/initialize-user-and-keys.sh index 48435ad..b21b7b6 100755 --- a/scripts/initialize-user-and-keys.sh +++ b/scripts/initialize-user-and-keys.sh @@ -22,7 +22,15 @@ 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 + 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 +} + + + +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 } echo "Preparing basic keys for signatrust......" @@ -33,4 +41,6 @@ echo "===========================================" create_default_admin -create_default_openpgp_keys \ No newline at end of file +create_default_openpgp_keys + +create_default_x509_keys \ No newline at end of file diff --git a/src/client/sign_identity.rs b/src/client/sign_identity.rs index d4ca30a..5fce614 100644 --- a/src/client/sign_identity.rs +++ b/src/client/sign_identity.rs @@ -38,7 +38,7 @@ impl Display for FileType { } } -#[derive(clap::ValueEnum, Clone, Debug)] +#[derive(clap::ValueEnum, Clone, Debug, PartialEq)] pub enum KeyType { PGP, X509, diff --git a/src/control_admin.rs b/src/control_admin_entrypoint.rs similarity index 62% rename from src/control_admin.rs rename to src/control_admin_entrypoint.rs index 169d89e..d1f4ac2 100644 --- a/src/control_admin.rs +++ b/src/control_admin_entrypoint.rs @@ -23,7 +23,6 @@ use crate::util::error::{Result}; use clap::{Parser, Subcommand}; use clap::{Args}; use crate::client::sign_identity; -use crate::client::cmd::traits::SignCommand; use crate::domain::datakey::entity::{DataKey}; use crate::domain::user::entity::User; use crate::presentation::handler::control::model::datakey::dto::DataKeyDTO; @@ -81,20 +80,60 @@ pub struct CommandGenerateKeys { #[arg(help = "specify the the description of this key pairs")] description: String, #[arg(long)] - #[arg(help = "specify the type of internal key used for this key pairs, ie, rsa")] + #[arg(help = "specify the type of internal key used for keys generation, ie, rsa")] param_key_type: String, #[arg(long)] - #[arg(help = "specify the type of internal key size used for this key pairs, ie, 1024")] + #[arg(help = "specify the type of internal key used for keys generation, ie, 1024")] param_key_size: String, + //pgp specific parameters + #[arg(long)] + #[arg(help = "specify the email used for openPGP key generation. ")] + param_pgp_email: Option, + //x509 specific parameters + #[arg(long)] + #[arg(help = "specify the 'CommonName' used for x509 key generation. ")] + param_x509_common_name: Option, + #[arg(long)] + #[arg(help = "specify the 'OrganizationalUnit' used for x509 key generation. ")] + param_x509_organizational_unit: Option, + #[arg(long)] + #[arg(help = "specify the 'Organization' used for x509 key generation. ")] + param_x509_organization: Option, + #[arg(long)] + #[arg(help = "specify the 'Locality' used for x509 key generation. ")] + param_x509_locality: Option, + #[arg(long)] + #[arg(help = "specify the 'ProvinceName' used for x509 key generation. ")] + param_x509_province_name: Option, + #[arg(long)] + #[arg(help = "specify the 'CountryName' used for x509 key generation. ")] + param_x509_country_name: Option, #[arg(long)] #[arg(help = "specify the email of admin which this key bounds to")] email: String, #[arg(long)] #[arg(value_enum)] - #[arg(help = "specify the key type for generating")] + #[arg(help = "specify th type of key")] key_type: sign_identity::KeyType, } +fn generate_keys_parameters(command: &CommandGenerateKeys) -> HashMap { + let mut attributes = HashMap::new(); + attributes.insert("key_type".to_string(), command.param_key_type.clone()); + attributes.insert("key_length".to_string(), command.param_key_size.clone()); + if command.key_type == sign_identity::KeyType::PGP { + attributes.insert("email".to_string(), command.param_pgp_email.clone().unwrap()); + } else if command.key_type == sign_identity::KeyType::X509 { + attributes.insert("common_name".to_string(), command.param_x509_common_name.clone().unwrap()); + attributes.insert("country_name".to_string(), command.param_x509_country_name.clone().unwrap()); + attributes.insert("locality".to_string(), command.param_x509_locality.clone().unwrap()); + attributes.insert("province_name".to_string(), command.param_x509_province_name.clone().unwrap()); + attributes.insert("organization".to_string(), command.param_x509_organization.clone().unwrap()); + attributes.insert("organizational_unit".to_string(), command.param_x509_organizational_unit.clone().unwrap()); + } + attributes +} + #[tokio::main] async fn main() -> Result<()> { //prepare config and logger @@ -112,17 +151,15 @@ async fn main() -> Result<()> { } Some(Commands::GenerateKeys(generate_keys)) => { let user = control_server.get_user_by_email(&generate_keys.email).await?; - let mut attributes = HashMap::new(); - attributes.insert("key_type".to_string(), generate_keys.param_key_type); - attributes.insert("key_length".to_string(), generate_keys.param_key_size); + let now = Utc::now(); let key = DataKeyDTO { id: 0, - name: generate_keys.name, - description: generate_keys.description, + name: generate_keys.name.clone(), + description: generate_keys.description.clone(), user: user.id, email: user.email.clone(), - attributes, + attributes: generate_keys_parameters(&generate_keys), key_type: generate_keys.key_type.to_string(), create_at: format!("{}", now), expire_at: format!("{}", now + Duration::days(30)), diff --git a/src/infra/sign_plugin/mod.rs b/src/infra/sign_plugin/mod.rs index 73fcdc5..b3288e8 100644 --- a/src/infra/sign_plugin/mod.rs +++ b/src/infra/sign_plugin/mod.rs @@ -1,3 +1,4 @@ pub mod openpgp; pub mod x509; pub mod signers; +pub mod util; diff --git a/src/infra/sign_plugin/openpgp.rs b/src/infra/sign_plugin/openpgp.rs index 11b8b19..8bedb31 100644 --- a/src/infra/sign_plugin/openpgp.rs +++ b/src/infra/sign_plugin/openpgp.rs @@ -39,6 +39,7 @@ use std::str::from_utf8; use validator::{Validate, ValidationError}; use pgp::composed::StandaloneSignature; use crate::domain::datakey::entity::SecDataKey; +use super::util::{validate_utc_time_not_expire, validate_utc_time}; const DETACHED_SIGNATURE: &str = "detached"; @@ -89,32 +90,6 @@ fn validate_key_size(key_size: &str) -> std::result::Result<(), ValidationError> Ok(()) } -fn validate_utc_time_not_expire(expire: &str) -> std::result::Result<(), ValidationError> { - let now = Utc::now(); - match expire.parse::>() { - Ok(expire) => { - if expire <= now { - return Err(ValidationError::new("expire time less than current time")) - } - Ok(()) - }, - Err(_e) => { - return Err(ValidationError::new("failed to parse time string to utc")); - } - } -} - -fn validate_utc_time(expire: &str) -> std::result::Result<(), ValidationError> { - match expire.parse::>() { - Ok(_) => { - Ok(()) - }, - Err(_) => { - return Err(ValidationError::new("failed to parse time string to utc")); - } - } -} - pub struct OpenPGPPlugin { secret_key: SignedSecretKey, public_key: SignedPublicKey, diff --git a/src/infra/sign_plugin/util.rs b/src/infra/sign_plugin/util.rs new file mode 100644 index 0000000..bbe8fc1 --- /dev/null +++ b/src/infra/sign_plugin/util.rs @@ -0,0 +1,41 @@ +/* + * // Copyright (c) 2023 Huawei Technologies Co.,Ltd. All rights reserved. + * // + * // signatrust is licensed under Mulan PSL v2. + * // You can use this software according to the terms and conditions of the Mulan + * // PSL v2. + * // You may obtain a copy of Mulan PSL v2 at: + * // http://license.coscl.org.cn/MulanPSL2 + * // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY + * // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO + * // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * // See the Mulan PSL v2 for more details. + */ +use validator::{ValidationError}; +use chrono::{DateTime, Utc}; + +pub fn validate_utc_time_not_expire(expire: &str) -> Result<(), ValidationError> { + let now = Utc::now(); + match expire.parse::>() { + Ok(expire) => { + if expire <= now { + return Err(ValidationError::new("expire time less than current time")) + } + Ok(()) + }, + Err(_e) => { + return Err(ValidationError::new("failed to parse time string to utc")); + } + } +} + +pub fn validate_utc_time(expire: &str) -> Result<(), ValidationError> { + match expire.parse::>() { + Ok(_) => { + Ok(()) + }, + Err(_) => { + return Err(ValidationError::new("failed to parse time string to utc")); + } + } +} \ No newline at end of file diff --git a/src/infra/sign_plugin/x509.rs b/src/infra/sign_plugin/x509.rs index 485845d..ecc7506 100644 --- a/src/infra/sign_plugin/x509.rs +++ b/src/infra/sign_plugin/x509.rs @@ -31,6 +31,7 @@ use validator::{Validate, ValidationError}; use crate::domain::datakey::entity::SecDataKey; use crate::util::error::{Error, Result}; use crate::domain::sign_plugin::SignPlugins; +use super::util::{validate_utc_time_not_expire, validate_utc_time}; #[derive(Debug, Validate, Deserialize)] pub struct X509KeyGenerationParameter { @@ -52,7 +53,7 @@ pub struct X509KeyGenerationParameter { key_length: String, #[validate(custom(function = "validate_utc_time", message="invalid x509 attribute 'created_at'"))] create_at: String, - #[validate(custom(function= "validate_utc_time", message="invalid x509 attribute 'expire_at'"))] + #[validate(custom(function= "validate_utc_time_not_expire", message="invalid x509 attribute 'expire_at'"))] expire_at: String, } @@ -93,21 +94,6 @@ fn validate_x509_key_size(key_size: &str) -> std::result::Result<(), ValidationE Ok(()) } -fn validate_utc_time(expire: &str) -> std::result::Result<(), ValidationError> { - let now = Utc::now(); - match expire.parse::>() { - Ok(expire) => { - if expire <= now { - return Err(ValidationError::new("expire time less than current time")) - } - }, - Err(_e) => { - return Err(ValidationError::new("failed to parse time string to utc")); - } - } - Ok(()) -} - fn days_in_duration(time: &str) -> Result { let start = Utc::now(); let end = time.parse::>()?; diff --git a/src/presentation/handler/control/model/datakey/dto.rs b/src/presentation/handler/control/model/datakey/dto.rs index dee09d3..59f1009 100644 --- a/src/presentation/handler/control/model/datakey/dto.rs +++ b/src/presentation/handler/control/model/datakey/dto.rs @@ -62,7 +62,6 @@ impl DataKey { pub fn convert_from(dto: DataKeyDTO, identity: UserIdentity) -> Result { let mut combined_attributes = dto.attributes.clone(); combined_attributes.insert("name".to_string(), dto.name.clone()); - combined_attributes.insert("email".to_string(), dto.email.clone()); combined_attributes.insert("create_at".to_string(), dto.create_at.clone()); combined_attributes.insert("expire_at".to_string(), dto.expire_at.clone()); Ok(DataKey { -- Gitee