diff --git a/g3fcgen/src/backend/mod.rs b/g3fcgen/src/backend/mod.rs index 41f12db8..4c32cb48 100644 --- a/g3fcgen/src/backend/mod.rs +++ b/g3fcgen/src/backend/mod.rs @@ -21,7 +21,7 @@ use anyhow::anyhow; use openssl::pkey::{PKey, Private}; use openssl::x509::X509; -use g3_tls_cert::builder::ServerCertBuilder; +use g3_tls_cert::builder::{ServerCertBuilder, TlsServerCertBuilder}; use g3_types::net::Host; use crate::frontend::ResponseData; @@ -49,7 +49,7 @@ pub(crate) struct OpensslBackend { impl OpensslBackend { pub(crate) fn new(config: &Arc) -> anyhow::Result { - let builder = ServerCertBuilder::new_ec256()?; + let builder = TlsServerCertBuilder::new_ec256()?; Ok(OpensslBackend { config: Arc::clone(config), builder, diff --git a/g3mkcert/src/main.rs b/g3mkcert/src/main.rs index 1abbb367..61ada895 100644 --- a/g3mkcert/src/main.rs +++ b/g3mkcert/src/main.rs @@ -27,7 +27,9 @@ use openssl::x509::{X509Name, X509}; use g3_tls_cert::builder::{ ClientCertBuilder, IntermediateCertBuilder, RootCertBuilder, ServerCertBuilder, - SubjectNameBuilder, + SubjectNameBuilder, TlcpClientEncCertBuilder, TlcpClientSignCertBuilder, + TlcpServerEncCertBuilder, TlcpServerSignCertBuilder, TlsClientCertBuilder, + TlsServerCertBuilder, }; use g3_types::net::Host; @@ -40,6 +42,10 @@ const ARG_ROOT: &str = "root"; const ARG_INTERMEDIATE: &str = "intermediate"; const ARG_TLS_SERVER: &str = "tls-server"; const ARG_TLS_CLIENT: &str = "tls-client"; +const ARG_TLCP_SERVER_SIGN: &str = "tlcp-server-sign"; +const ARG_TLCP_SERVER_ENC: &str = "tlcp-server-enc"; +const ARG_TLCP_CLIENT_SIGN: &str = "tlcp-client-sign"; +const ARG_TLCP_CLIENT_ENC: &str = "tlcp-client-enc"; const ARG_RSA: &str = "rsa"; const ARG_EC224: &str = "ec224"; @@ -93,6 +99,14 @@ fn main() -> anyhow::Result<()> { generate_tls_server(args) } else if args.get_flag(ARG_TLS_CLIENT) { generate_tls_client(args) + } else if args.get_flag(ARG_TLCP_SERVER_SIGN) { + generate_tlcp_server_sign(args) + } else if args.get_flag(ARG_TLCP_SERVER_ENC) { + generate_tlcp_server_enc(args) + } else if args.get_flag(ARG_TLCP_CLIENT_SIGN) { + generate_tlcp_client_sign(args) + } else if args.get_flag(ARG_TLCP_CLIENT_ENC) { + generate_tlcp_client_enc(args) } else { unreachable!() } @@ -153,6 +167,46 @@ fn build_cli_args() -> Command { .requires(ARG_CA_KEY) .requires(ARG_HOST), ) + .arg( + Arg::new(ARG_TLCP_SERVER_SIGN) + .help("Generate end entity sign certificate for TLCP server") + .num_args(0) + .long(ARG_TLCP_SERVER_SIGN) + .action(ArgAction::SetTrue) + .requires(ARG_CA_CERT) + .requires(ARG_CA_KEY) + .requires(ARG_HOST), + ) + .arg( + Arg::new(ARG_TLCP_SERVER_ENC) + .help("Generate end entity enc certificate for TLCP server") + .num_args(0) + .long(ARG_TLCP_SERVER_ENC) + .action(ArgAction::SetTrue) + .requires(ARG_CA_CERT) + .requires(ARG_CA_KEY) + .requires(ARG_HOST), + ) + .arg( + Arg::new(ARG_TLCP_CLIENT_SIGN) + .help("Generate end entity sign certificate for TLCP client") + .num_args(0) + .long(ARG_TLCP_CLIENT_SIGN) + .action(ArgAction::SetTrue) + .requires(ARG_CA_CERT) + .requires(ARG_CA_KEY) + .requires(ARG_HOST), + ) + .arg( + Arg::new(ARG_TLCP_CLIENT_ENC) + .help("Generate end entity enc certificate for TLCP client") + .num_args(0) + .long(ARG_TLCP_CLIENT_ENC) + .action(ArgAction::SetTrue) + .requires(ARG_CA_CERT) + .requires(ARG_CA_KEY) + .requires(ARG_HOST), + ) .group( ArgGroup::new(ARG_GROUP_TYPE) .args([ @@ -160,6 +214,10 @@ fn build_cli_args() -> Command { ARG_INTERMEDIATE, ARG_TLS_SERVER, ARG_TLS_CLIENT, + ARG_TLCP_SERVER_SIGN, + ARG_TLCP_SERVER_ENC, + ARG_TLCP_CLIENT_SIGN, + ARG_TLCP_CLIENT_ENC, ARG_VERSION, ARG_COMPLETION, ]) @@ -498,30 +556,62 @@ fn generate_intermediate(args: ArgMatches) -> anyhow::Result<()> { } fn generate_tls_server(args: ArgMatches) -> anyhow::Result<()> { - let mut builder = if let Some(bits) = args.get_one::(ARG_RSA) { - ServerCertBuilder::new_rsa(*bits)? + let builder = if let Some(bits) = args.get_one::(ARG_RSA) { + TlsServerCertBuilder::new_rsa(*bits)? } else if args.get_flag(ARG_X448) { - ServerCertBuilder::new_x448()? + TlsServerCertBuilder::new_x448()? } else if args.get_flag(ARG_X25519) { - ServerCertBuilder::new_x25519()? + TlsServerCertBuilder::new_x25519()? } else if args.get_flag(ARG_ED448) { - ServerCertBuilder::new_ed448()? + TlsServerCertBuilder::new_ed448()? } else if args.get_flag(ARG_ED25519) { - ServerCertBuilder::new_ed25519()? + TlsServerCertBuilder::new_ed25519()? } else if args.get_flag(ARG_SM2) { - ServerCertBuilder::new_sm2()? + TlsServerCertBuilder::new_sm2()? } else if args.get_flag(ARG_EC521) { - ServerCertBuilder::new_ec521()? + TlsServerCertBuilder::new_ec521()? } else if args.get_flag(ARG_EC384) { - ServerCertBuilder::new_ec384()? + TlsServerCertBuilder::new_ec384()? } else if args.get_flag(ARG_EC256) { - ServerCertBuilder::new_ec256()? + TlsServerCertBuilder::new_ec256()? } else if args.get_flag(ARG_EC224) { - ServerCertBuilder::new_ec224()? + TlsServerCertBuilder::new_ec224()? } else { - ServerCertBuilder::new_ec256()? + TlsServerCertBuilder::new_ec256()? }; + generate_server(builder, args) +} + +fn generate_tlcp_server_sign(args: ArgMatches) -> anyhow::Result<()> { + let builder = if let Some(bits) = args.get_one::(ARG_RSA) { + TlcpServerSignCertBuilder::new_rsa(*bits)? + } else if args.get_flag(ARG_SM2) { + TlcpServerSignCertBuilder::new_sm2()? + } else if args.contains_id(ARG_GROUP_ALGORITHM) { + return Err(anyhow!("unsupported signature algorithm")); + } else { + TlcpServerSignCertBuilder::new_sm2()? + }; + + generate_server(builder, args) +} + +fn generate_tlcp_server_enc(args: ArgMatches) -> anyhow::Result<()> { + let builder = if let Some(bits) = args.get_one::(ARG_RSA) { + TlcpServerEncCertBuilder::new_rsa(*bits)? + } else if args.get_flag(ARG_SM2) { + TlcpServerEncCertBuilder::new_sm2()? + } else if args.contains_id(ARG_GROUP_ALGORITHM) { + return Err(anyhow!("unsupported signature algorithm")); + } else { + TlcpServerEncCertBuilder::new_sm2()? + }; + + generate_server(builder, args) +} + +fn generate_server(mut builder: ServerCertBuilder, args: ArgMatches) -> anyhow::Result<()> { let (ca_cert, ca_key) = get_ca_cert_and_key(&args)?; let (subject_name, subject_alt_name) = get_subject_with_host(&args, builder.subject_builder_mut())?; @@ -542,30 +632,62 @@ fn generate_tls_server(args: ArgMatches) -> anyhow::Result<()> { } fn generate_tls_client(args: ArgMatches) -> anyhow::Result<()> { - let mut builder = if let Some(bits) = args.get_one::(ARG_RSA) { - ClientCertBuilder::new_rsa(*bits)? + let builder = if let Some(bits) = args.get_one::(ARG_RSA) { + TlsClientCertBuilder::new_rsa(*bits)? } else if args.get_flag(ARG_X448) { - ClientCertBuilder::new_x448()? + TlsClientCertBuilder::new_x448()? } else if args.get_flag(ARG_X25519) { - ClientCertBuilder::new_x25519()? + TlsClientCertBuilder::new_x25519()? } else if args.get_flag(ARG_ED448) { - ClientCertBuilder::new_ed448()? + TlsClientCertBuilder::new_ed448()? } else if args.get_flag(ARG_ED25519) { - ClientCertBuilder::new_ed25519()? + TlsClientCertBuilder::new_ed25519()? } else if args.get_flag(ARG_SM2) { - ClientCertBuilder::new_sm2()? + TlsClientCertBuilder::new_sm2()? } else if args.get_flag(ARG_EC521) { - ClientCertBuilder::new_ec521()? + TlsClientCertBuilder::new_ec521()? } else if args.get_flag(ARG_EC384) { - ClientCertBuilder::new_ec384()? + TlsClientCertBuilder::new_ec384()? } else if args.get_flag(ARG_EC256) { - ClientCertBuilder::new_ec256()? + TlsClientCertBuilder::new_ec256()? } else if args.get_flag(ARG_EC224) { - ClientCertBuilder::new_ec224()? + TlsClientCertBuilder::new_ec224()? } else { - ClientCertBuilder::new_ec256()? + TlsClientCertBuilder::new_ec256()? }; + generate_client(builder, args) +} + +fn generate_tlcp_client_sign(args: ArgMatches) -> anyhow::Result<()> { + let builder = if let Some(bits) = args.get_one::(ARG_RSA) { + TlcpClientSignCertBuilder::new_rsa(*bits)? + } else if args.get_flag(ARG_SM2) { + TlcpClientSignCertBuilder::new_sm2()? + } else if args.contains_id(ARG_GROUP_ALGORITHM) { + return Err(anyhow!("unsupported signature algorithm")); + } else { + TlcpClientSignCertBuilder::new_sm2()? + }; + + generate_client(builder, args) +} + +fn generate_tlcp_client_enc(args: ArgMatches) -> anyhow::Result<()> { + let builder = if let Some(bits) = args.get_one::(ARG_RSA) { + TlcpClientEncCertBuilder::new_rsa(*bits)? + } else if args.get_flag(ARG_SM2) { + TlcpClientEncCertBuilder::new_sm2()? + } else if args.contains_id(ARG_GROUP_ALGORITHM) { + return Err(anyhow!("unsupported signature algorithm")); + } else { + TlcpClientEncCertBuilder::new_sm2()? + }; + + generate_client(builder, args) +} + +fn generate_client(mut builder: ClientCertBuilder, args: ArgMatches) -> anyhow::Result<()> { let (ca_cert, ca_key) = get_ca_cert_and_key(&args)?; let (subject_name, subject_alt_name) = get_subject_with_host(&args, builder.subject_builder_mut())?; diff --git a/lib/g3-tls-cert/src/builder/client.rs b/lib/g3-tls-cert/src/builder/client.rs index 2ff45bf1..ebbd3edf 100644 --- a/lib/g3-tls-cert/src/builder/client.rs +++ b/lib/g3-tls-cert/src/builder/client.rs @@ -40,40 +40,105 @@ pub struct ClientCertBuilder { subject_builder: SubjectNameBuilder, } -macro_rules! impl_new { +pub struct TlsClientCertBuilder {} + +macro_rules! tls_impl_new { ($f:ident) => { - pub fn $f() -> anyhow::Result { + pub fn $f() -> anyhow::Result { let pkey = super::pkey::$f()?; - ClientCertBuilder::with_pkey(pkey) + TlsClientCertBuilder::with_pkey(pkey) } }; } -impl ClientCertBuilder { - impl_new!(new_ec224); - impl_new!(new_ec256); - impl_new!(new_ec384); - impl_new!(new_ec521); - impl_new!(new_sm2); - impl_new!(new_ed25519); - impl_new!(new_ed448); - impl_new!(new_x25519); - impl_new!(new_x448); +impl TlsClientCertBuilder { + tls_impl_new!(new_ec224); + tls_impl_new!(new_ec256); + tls_impl_new!(new_ec384); + tls_impl_new!(new_ec521); + tls_impl_new!(new_sm2); + tls_impl_new!(new_ed25519); + tls_impl_new!(new_ed448); + tls_impl_new!(new_x25519); + tls_impl_new!(new_x448); - pub fn new_rsa(bits: u32) -> anyhow::Result { + pub fn new_rsa(bits: u32) -> anyhow::Result { let pkey = super::pkey::new_rsa(bits)?; - ClientCertBuilder::with_pkey(pkey) + TlsClientCertBuilder::with_pkey(pkey) } - fn with_pkey(pkey: PKey) -> anyhow::Result { - let serial = super::serial::random_16()?; - + fn with_pkey(pkey: PKey) -> anyhow::Result { let key_usage = KeyUsage::new() .critical() .digital_signature() .key_encipherment() .build() .map_err(|e| anyhow!("failed to build KeyUsage extension: {e}"))?; + ClientCertBuilder::new(pkey, key_usage) + } +} + +pub struct TlcpClientSignCertBuilder {} + +macro_rules! tlcp_sign_impl_new { + ($f:ident) => { + pub fn $f() -> anyhow::Result { + let pkey = super::pkey::$f()?; + TlcpClientSignCertBuilder::with_pkey(pkey) + } + }; +} + +impl TlcpClientSignCertBuilder { + tlcp_sign_impl_new!(new_sm2); + + pub fn new_rsa(bits: u32) -> anyhow::Result { + let pkey = super::pkey::new_rsa(bits)?; + TlcpClientSignCertBuilder::with_pkey(pkey) + } + + fn with_pkey(pkey: PKey) -> anyhow::Result { + let key_usage = KeyUsage::new() + .critical() + .digital_signature() + .build() + .map_err(|e| anyhow!("failed to build KeyUsage extension: {e}"))?; + ClientCertBuilder::new(pkey, key_usage) + } +} + +pub struct TlcpClientEncCertBuilder {} + +macro_rules! tlcp_enc_impl_new { + ($f:ident) => { + pub fn $f() -> anyhow::Result { + let pkey = super::pkey::$f()?; + TlcpClientEncCertBuilder::with_pkey(pkey) + } + }; +} + +impl TlcpClientEncCertBuilder { + tlcp_enc_impl_new!(new_sm2); + + pub fn new_rsa(bits: u32) -> anyhow::Result { + let pkey = super::pkey::new_rsa(bits)?; + TlcpClientEncCertBuilder::with_pkey(pkey) + } + + fn with_pkey(pkey: PKey) -> anyhow::Result { + let key_usage = KeyUsage::new() + .critical() + .key_encipherment() + .build() + .map_err(|e| anyhow!("failed to build KeyUsage extension: {e}"))?; + ClientCertBuilder::new(pkey, key_usage) + } +} + +impl ClientCertBuilder { + pub fn new(pkey: PKey, key_usage: X509Extension) -> anyhow::Result { + let serial = super::serial::random_16()?; let ext_key_usage = ExtendedKeyUsage::new() .client_auth() diff --git a/lib/g3-tls-cert/src/builder/intermediate.rs b/lib/g3-tls-cert/src/builder/intermediate.rs index 11889c46..b60f077a 100644 --- a/lib/g3-tls-cert/src/builder/intermediate.rs +++ b/lib/g3-tls-cert/src/builder/intermediate.rs @@ -67,6 +67,7 @@ impl IntermediateCertBuilder { let key_usage = KeyUsage::new() .critical() .key_cert_sign() + .crl_sign() .build() .map_err(|e| anyhow!("failed to build KeyUsage extension: {e}"))?; diff --git a/lib/g3-tls-cert/src/builder/mod.rs b/lib/g3-tls-cert/src/builder/mod.rs index ff83b2ec..22c0617d 100644 --- a/lib/g3-tls-cert/src/builder/mod.rs +++ b/lib/g3-tls-cert/src/builder/mod.rs @@ -24,10 +24,14 @@ mod time; use time::asn1_time_from_chrono; mod server; -pub use server::ServerCertBuilder; +pub use server::{ + ServerCertBuilder, TlcpServerEncCertBuilder, TlcpServerSignCertBuilder, TlsServerCertBuilder, +}; mod client; -pub use client::ClientCertBuilder; +pub use client::{ + ClientCertBuilder, TlcpClientEncCertBuilder, TlcpClientSignCertBuilder, TlsClientCertBuilder, +}; mod root; pub use root::RootCertBuilder; diff --git a/lib/g3-tls-cert/src/builder/root.rs b/lib/g3-tls-cert/src/builder/root.rs index 55382555..78f33388 100644 --- a/lib/g3-tls-cert/src/builder/root.rs +++ b/lib/g3-tls-cert/src/builder/root.rs @@ -66,6 +66,7 @@ impl RootCertBuilder { let key_usage = KeyUsage::new() .critical() .key_cert_sign() + .crl_sign() .build() .map_err(|e| anyhow!("failed to build KeyUsage extension: {e}"))?; diff --git a/lib/g3-tls-cert/src/builder/server.rs b/lib/g3-tls-cert/src/builder/server.rs index b4ed5bcf..5e9919bd 100644 --- a/lib/g3-tls-cert/src/builder/server.rs +++ b/lib/g3-tls-cert/src/builder/server.rs @@ -40,40 +40,105 @@ pub struct ServerCertBuilder { subject_builder: SubjectNameBuilder, } -macro_rules! impl_new { +pub struct TlsServerCertBuilder {} + +macro_rules! tls_impl_new { ($f:ident) => { - pub fn $f() -> anyhow::Result { + pub fn $f() -> anyhow::Result { let pkey = super::pkey::$f()?; - ServerCertBuilder::with_pkey(pkey) + TlsServerCertBuilder::with_pkey(pkey) } }; } -impl ServerCertBuilder { - impl_new!(new_ec224); - impl_new!(new_ec256); - impl_new!(new_ec384); - impl_new!(new_ec521); - impl_new!(new_sm2); - impl_new!(new_ed25519); - impl_new!(new_ed448); - impl_new!(new_x25519); - impl_new!(new_x448); +impl TlsServerCertBuilder { + tls_impl_new!(new_ec224); + tls_impl_new!(new_ec256); + tls_impl_new!(new_ec384); + tls_impl_new!(new_ec521); + tls_impl_new!(new_sm2); + tls_impl_new!(new_ed25519); + tls_impl_new!(new_ed448); + tls_impl_new!(new_x25519); + tls_impl_new!(new_x448); - pub fn new_rsa(bits: u32) -> anyhow::Result { + pub fn new_rsa(bits: u32) -> anyhow::Result { let pkey = super::pkey::new_rsa(bits)?; - ServerCertBuilder::with_pkey(pkey) + TlsServerCertBuilder::with_pkey(pkey) } - fn with_pkey(pkey: PKey) -> anyhow::Result { - let serial = super::serial::random_16()?; - + fn with_pkey(pkey: PKey) -> anyhow::Result { let key_usage = KeyUsage::new() .critical() .digital_signature() .key_encipherment() .build() .map_err(|e| anyhow!("failed to build KeyUsage extension: {e}"))?; + ServerCertBuilder::new(pkey, key_usage) + } +} + +pub struct TlcpServerSignCertBuilder {} + +macro_rules! tlcp_sign_impl_new { + ($f:ident) => { + pub fn $f() -> anyhow::Result { + let pkey = super::pkey::$f()?; + TlcpServerSignCertBuilder::with_pkey(pkey) + } + }; +} + +impl TlcpServerSignCertBuilder { + tlcp_sign_impl_new!(new_sm2); + + pub fn new_rsa(bits: u32) -> anyhow::Result { + let pkey = super::pkey::new_rsa(bits)?; + TlcpServerSignCertBuilder::with_pkey(pkey) + } + + fn with_pkey(pkey: PKey) -> anyhow::Result { + let key_usage = KeyUsage::new() + .critical() + .digital_signature() + .build() + .map_err(|e| anyhow!("failed to build KeyUsage extension: {e}"))?; + ServerCertBuilder::new(pkey, key_usage) + } +} + +pub struct TlcpServerEncCertBuilder {} + +macro_rules! tlcp_enc_impl_new { + ($f:ident) => { + pub fn $f() -> anyhow::Result { + let pkey = super::pkey::$f()?; + TlcpServerEncCertBuilder::with_pkey(pkey) + } + }; +} + +impl TlcpServerEncCertBuilder { + tlcp_enc_impl_new!(new_sm2); + + pub fn new_rsa(bits: u32) -> anyhow::Result { + let pkey = super::pkey::new_rsa(bits)?; + TlcpServerEncCertBuilder::with_pkey(pkey) + } + + fn with_pkey(pkey: PKey) -> anyhow::Result { + let key_usage = KeyUsage::new() + .critical() + .key_encipherment() + .build() + .map_err(|e| anyhow!("failed to build KeyUsage extension: {e}"))?; + ServerCertBuilder::new(pkey, key_usage) + } +} + +impl ServerCertBuilder { + pub fn new(pkey: PKey, key_usage: X509Extension) -> anyhow::Result { + let serial = super::serial::random_16()?; let ext_key_usage = ExtendedKeyUsage::new() .server_auth()