commit 46e0f3c43a81ce9411612c152e414162a9c220ac
parent 2cd17fe7afeaef2a29787999b1cb48a512811571
Author: Daniel GarcĂa <dani-garcia@users.noreply.github.com>
Date: Fri, 25 Jun 2021 20:49:44 +0200
Load RSA keys as pem format directly, and using openssl crate, backported from async branch
Diffstat:
7 files changed, 53 insertions(+), 61 deletions(-)
diff --git a/src/api/core/mod.rs b/src/api/core/mod.rs
@@ -27,7 +27,6 @@ pub fn routes() -> Vec<Route> {
//
// Move this somewhere else
//
-use rocket::response::Response;
use rocket::Route;
use rocket_contrib::json::Json;
use serde_json::Value;
@@ -41,7 +40,7 @@ use crate::{
};
#[put("/devices/identifier/<uuid>/clear-token")]
-fn clear_device_token<'a>(uuid: String) -> Response<'a> {
+fn clear_device_token<'a>(uuid: String) -> &'static str {
// This endpoint doesn't have auth header
let _ = uuid;
@@ -50,7 +49,7 @@ fn clear_device_token<'a>(uuid: String) -> Response<'a> {
// This only clears push token
// https://github.com/bitwarden/core/blob/master/src/Api/Controllers/DevicesController.cs#L109
// https://github.com/bitwarden/core/blob/master/src/Core/Services/Implementations/DeviceService.cs#L37
- Response::new()
+ ""
}
#[put("/devices/identifier/<uuid>/token", data = "<data>")]
diff --git a/src/api/core/two_factor/duo.rs b/src/api/core/two_factor/duo.rs
@@ -343,7 +343,7 @@ fn parse_duo_values(key: &str, val: &str, ikey: &str, prefix: &str, time: i64) -
err!("Invalid ikey")
}
- let expire = match expire.parse() {
+ let expire: i64 = match expire.parse() {
Ok(e) => e,
Err(_) => err!("Invalid expire time"),
};
diff --git a/src/auth.rs b/src/auth.rs
@@ -27,17 +27,26 @@ static JWT_VERIFYEMAIL_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|verifyema
static JWT_ADMIN_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|admin", CONFIG.domain_origin()));
static JWT_SEND_ISSUER: Lazy<String> = Lazy::new(|| format!("{}|send", CONFIG.domain_origin()));
-static PRIVATE_RSA_KEY: Lazy<Vec<u8>> = Lazy::new(|| match read_file(&CONFIG.private_rsa_key()) {
- Ok(key) => key,
- Err(e) => panic!("Error loading private RSA Key.\n Error: {}", e),
+static PRIVATE_RSA_KEY_VEC: Lazy<Vec<u8>> = Lazy::new(|| {
+ read_file(&CONFIG.private_rsa_key()).unwrap_or_else(|e| panic!("Error loading private RSA Key.\n{}", e))
});
-static PUBLIC_RSA_KEY: Lazy<Vec<u8>> = Lazy::new(|| match read_file(&CONFIG.public_rsa_key()) {
- Ok(key) => key,
- Err(e) => panic!("Error loading public RSA Key.\n Error: {}", e),
+static PRIVATE_RSA_KEY: Lazy<EncodingKey> = Lazy::new(|| {
+ EncodingKey::from_rsa_pem(&PRIVATE_RSA_KEY_VEC).unwrap_or_else(|e| panic!("Error decoding private RSA Key.\n{}", e))
+});
+static PUBLIC_RSA_KEY_VEC: Lazy<Vec<u8>> = Lazy::new(|| {
+ read_file(&CONFIG.public_rsa_key()).unwrap_or_else(|e| panic!("Error loading public RSA Key.\n{}", e))
+});
+static PUBLIC_RSA_KEY: Lazy<DecodingKey> = Lazy::new(|| {
+ DecodingKey::from_rsa_pem(&PUBLIC_RSA_KEY_VEC).unwrap_or_else(|e| panic!("Error decoding public RSA Key.\n{}", e))
});
+pub fn load_keys() {
+ Lazy::force(&PRIVATE_RSA_KEY);
+ Lazy::force(&PUBLIC_RSA_KEY);
+}
+
pub fn encode_jwt<T: Serialize>(claims: &T) -> String {
- match jsonwebtoken::encode(&JWT_HEADER, claims, &EncodingKey::from_rsa_der(&PRIVATE_RSA_KEY)) {
+ match jsonwebtoken::encode(&JWT_HEADER, claims, &PRIVATE_RSA_KEY) {
Ok(token) => token,
Err(e) => panic!("Error encoding jwt {}", e),
}
@@ -55,10 +64,7 @@ fn decode_jwt<T: DeserializeOwned>(token: &str, issuer: String) -> Result<T, Err
};
let token = token.replace(char::is_whitespace, "");
-
- jsonwebtoken::decode(&token, &DecodingKey::from_rsa_der(&PUBLIC_RSA_KEY), &validation)
- .map(|d| d.claims)
- .map_res("Error decoding JWT")
+ jsonwebtoken::decode(&token, &&PUBLIC_RSA_KEY, &validation).map(|d| d.claims).map_res("Error decoding JWT")
}
pub fn decode_login(token: &str) -> Result<LoginJwtClaims, Error> {
diff --git a/src/config.rs b/src/config.rs
@@ -770,13 +770,10 @@ impl Config {
}
pub fn private_rsa_key(&self) -> String {
- format!("{}.der", CONFIG.rsa_key_filename())
- }
- pub fn private_rsa_key_pem(&self) -> String {
format!("{}.pem", CONFIG.rsa_key_filename())
}
pub fn public_rsa_key(&self) -> String {
- format!("{}.pub.der", CONFIG.rsa_key_filename())
+ format!("{}.pub.pem", CONFIG.rsa_key_filename())
}
pub fn mail_enabled(&self) -> bool {
let inner = &self.inner.read().unwrap().config;
diff --git a/src/error.rs b/src/error.rs
@@ -50,6 +50,7 @@ use std::time::SystemTimeError as TimeErr;
use u2f::u2ferror::U2fError as U2fErr;
use webauthn_rs::error::WebauthnError as WebauthnErr;
use yubico::yubicoerror::YubicoError as YubiErr;
+use openssl::error::ErrorStack as SSLErr;
#[derive(Serialize)]
pub struct Empty {}
@@ -82,6 +83,7 @@ make_error! {
Lettre(LettreErr): _has_source, _api_error,
Address(AddrErr): _has_source, _api_error,
Smtp(SmtpErr): _has_source, _api_error,
+ OpenSSL(SSLErr): _has_source, _api_error,
DieselCon(DieselConErr): _has_source, _api_error,
DieselMig(DieselMigErr): _has_source, _api_error,
diff --git a/src/main.rs b/src/main.rs
@@ -21,7 +21,7 @@ use std::{
fs::create_dir_all,
panic,
path::Path,
- process::{exit, Command},
+ process::exit,
str::FromStr,
thread,
time::Duration,
@@ -53,7 +53,10 @@ fn main() {
let extra_debug = matches!(level, LF::Trace | LF::Debug);
check_data_folder();
- check_rsa_keys();
+ check_rsa_keys().unwrap_or_else(|_| {
+ error!("Error creating keys, exiting...");
+ exit(1);
+ });
check_web_vault();
create_icon_cache_folder();
@@ -249,52 +252,29 @@ fn check_data_folder() {
}
}
-fn check_rsa_keys() {
+fn check_rsa_keys()-> Result<(), crate::error::Error> {
// If the RSA keys don't exist, try to create them
- if !util::file_exists(&CONFIG.private_rsa_key()) || !util::file_exists(&CONFIG.public_rsa_key()) {
- info!("JWT keys don't exist, checking if OpenSSL is available...");
-
- Command::new("openssl").arg("version").status().unwrap_or_else(|_| {
- info!(
- "Can't create keys because OpenSSL is not available, make sure it's installed and available on the PATH"
- );
- exit(1);
- });
-
- info!("OpenSSL detected, creating keys...");
-
- let key = CONFIG.rsa_key_filename();
-
- let pem = format!("{}.pem", key);
- let priv_der = format!("{}.der", key);
- let pub_der = format!("{}.pub.der", key);
+ let priv_path = CONFIG.private_rsa_key();
+ let pub_path = CONFIG.public_rsa_key();
- let mut success = Command::new("openssl")
- .args(&["genrsa", "-out", &pem])
- .status()
- .expect("Failed to create private pem file")
- .success();
+ if !util::file_exists(&priv_path) {
+ let rsa_key = openssl::rsa::Rsa::generate(2048)?;
- success &= Command::new("openssl")
- .args(&["rsa", "-in", &pem, "-outform", "DER", "-out", &priv_der])
- .status()
- .expect("Failed to create private der file")
- .success();
+ let priv_key = rsa_key.private_key_to_pem()?;
+ crate::util::write_file(&priv_path, &priv_key)?;
+ info!("Private key created correctly.");
+ }
- success &= Command::new("openssl")
- .args(&["rsa", "-in", &priv_der, "-inform", "DER"])
- .args(&["-RSAPublicKey_out", "-outform", "DER", "-out", &pub_der])
- .status()
- .expect("Failed to create public der file")
- .success();
+ if !util::file_exists(&pub_path) {
+ let rsa_key = openssl::rsa::Rsa::private_key_from_pem(&util::read_file(&priv_path)?)?;
- if success {
- info!("Keys created correctly.");
- } else {
- error!("Error creating keys, exiting...");
- exit(1);
- }
+ let pub_key = rsa_key.public_key_to_pem()?;
+ crate::util::write_file(&pub_path, &pub_key)?;
+ info!("Public key created correctly.");
}
+
+ auth::load_keys();
+ Ok(())
}
fn check_web_vault() {
diff --git a/src/util.rs b/src/util.rs
@@ -219,6 +219,14 @@ pub fn read_file(path: &str) -> IOResult<Vec<u8>> {
Ok(contents)
}
+pub fn write_file(path: &str, content: &[u8]) -> Result<(), crate::error::Error> {
+ use std::io::Write;
+ let mut f = File::create(path)?;
+ f.write_all(content)?;
+ f.flush()?;
+ Ok(())
+}
+
pub fn read_file_string(path: &str) -> IOResult<String> {
let mut contents = String::new();