diff --git a/src/ca.rs b/src/ca.rs index 055bcf7..145f0da 100644 --- a/src/ca.rs +++ b/src/ca.rs @@ -144,7 +144,20 @@ pub fn sign_host_cert( privkey: &PrivateKey, alias: &[&str], ) -> Result { - sign_cert(hostname, pubkey, duration, privkey, alias, CertType::Host) + let now = SystemTime::now(); + let not_before = now.duration_since(UNIX_EPOCH)?.as_secs(); + let not_after = not_before + duration.as_secs(); + + let mut builder = Builder::new_with_random_nonce( + &mut OsRng, pubkey, not_before, not_after, + )?; + builder.cert_type(CertType::Host)?; + builder.valid_principal(hostname)?; + for a in alias { + builder.valid_principal(*a)?; + } + + Ok(builder.sign(privkey)?) } /// Create a signed SSH certificate for a user public key @@ -158,17 +171,7 @@ pub fn sign_user_cert( duration: Duration, privkey: &PrivateKey, alias: &[&str], -) -> Result { - sign_cert(username, pubkey, duration, privkey, alias, CertType::User) -} - -fn sign_cert( - principal: &str, - pubkey: &PublicKey, - duration: Duration, - privkey: &PrivateKey, - alias: &[&str], - cert_type: CertType, + extensions: &[impl AsRef], ) -> Result { let now = SystemTime::now(); let not_before = now.duration_since(UNIX_EPOCH)?.as_secs(); @@ -177,11 +180,14 @@ fn sign_cert( let mut builder = Builder::new_with_random_nonce( &mut OsRng, pubkey, not_before, not_after, )?; - builder.cert_type(cert_type)?; - builder.valid_principal(principal)?; + builder.cert_type(CertType::User)?; + builder.valid_principal(username)?; for a in alias { builder.valid_principal(*a)?; } + for e in extensions { + builder.extension(e.as_ref(), "")?; + } Ok(builder.sign(privkey)?) } @@ -201,9 +207,9 @@ mod test { let host_pub_key = host_key.public_key(); let duration = Duration::from_secs(86400 * 30); let hostname = "cloud0.example.org"; - let cert = sign_cert( + let cert = sign_host_cert( hostname, - &host_pub_key, + host_pub_key, duration, &ca_key, &["nextcloud.example.org"], diff --git a/src/config.rs b/src/config.rs index e3ed190..c69b868 100644 --- a/src/config.rs +++ b/src/config.rs @@ -75,6 +75,10 @@ pub struct UserCaConfig { /// Duration of issued user certificates #[serde(default = "default_user_cert_duration")] pub cert_duration: u64, + + /// Certificate extensions + #[serde(default = "default_user_cert_extensions")] + pub extensions: Vec, } impl Default for UserCaConfig { @@ -83,6 +87,7 @@ impl Default for UserCaConfig { private_key_file: default_user_ca_key(), private_key_passphrase_file: None, cert_duration: default_user_cert_duration(), + extensions: default_user_cert_extensions(), } } } @@ -171,6 +176,16 @@ fn default_user_cert_duration() -> u64 { 3600 } +fn default_user_cert_extensions() -> Vec { + vec![ + "permit-X11-forwarding".into(), + "permit-agent-forwarding".into(), + "permit-port-forwarding".into(), + "permit-pty".into(), + "permit-user-rc".into(), + ] +} + /// Load configuration from a TOML file /// /// If `path` is provided, the configuration will be loaded from the diff --git a/src/server/user.rs b/src/server/user.rs index 68a093e..92df14f 100644 --- a/src/server/user.rs +++ b/src/server/user.rs @@ -168,6 +168,7 @@ pub(super) async fn sign_user_cert( let config = &ctx.config; let duration = Duration::from_secs(config.ca.user.cert_duration); + let extensions = &config.ca.user.extensions; let privkey = ca::load_private_key( &config.ca.user.private_key_file, config.ca.user.private_key_passphrase_file.as_ref(), @@ -192,7 +193,14 @@ pub(super) async fn sign_user_cert( pubkey.algorithm().as_str(), username ); - let cert = ca::sign_user_cert(username, &pubkey, duration, &privkey, &alias)?; + let cert = ca::sign_user_cert( + username, + &pubkey, + duration, + &privkey, + &alias, + &extensions[..], + )?; info!( "Signed {} key for {}", pubkey.algorithm().as_str(),