Skip to content

Commit

Permalink
change how we handle ntp
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-bonez committed Oct 26, 2023
1 parent c15b5e7 commit 27c949d
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 41 deletions.
7 changes: 4 additions & 3 deletions backend/src/account.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use digest::Digest;
use std::time::SystemTime;

use ed25519_dalek::SecretKey;
use openssl::pkey::{PKey, Private};
use openssl::x509::X509;
Expand Down Expand Up @@ -29,11 +30,11 @@ pub struct AccountInfo {
pub root_ca_cert: X509,
}
impl AccountInfo {
pub fn new(password: &str) -> Result<Self, Error> {
pub fn new(password: &str, start_time: SystemTime) -> Result<Self, Error> {
let server_id = generate_id();
let hostname = generate_hostname();
let root_ca_key = generate_key()?;
let root_ca_cert = make_root_cert(&root_ca_key, &hostname)?;
let root_ca_cert = make_root_cert(&root_ca_key, &hostname, start_time)?;
Ok(Self {
server_id,
hostname,
Expand Down
7 changes: 5 additions & 2 deletions backend/src/context/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use serde::Deserialize;
use sqlx::postgres::PgConnectOptions;
use sqlx::PgPool;
use tokio::sync::{broadcast, oneshot, Mutex, RwLock};
use tokio::time::Instant;
use tracing::instrument;

use super::setup::CURRENT_SECRET;
Expand All @@ -29,7 +30,7 @@ use crate::install::cleanup::{cleanup_failed, uninstall};
use crate::manager::ManagerMap;
use crate::middleware::auth::HashSessionToken;
use crate::net::net_controller::NetController;
use crate::net::ssl::SslManager;
use crate::net::ssl::{root_ca_start_time, SslManager};
use crate::net::wifi::WpaCli;
use crate::notifications::NotificationManager;
use crate::shutdown::Shutdown;
Expand Down Expand Up @@ -123,6 +124,7 @@ pub struct RpcContextSeed {
pub current_secret: Arc<Jwk>,
pub client: Client,
pub hardware: Hardware,
pub start_time: Instant,
}

pub struct Hardware {
Expand Down Expand Up @@ -158,7 +160,7 @@ impl RpcContext {
base.dns_bind
.as_deref()
.unwrap_or(&[SocketAddr::from(([127, 0, 0, 1], 53))]),
SslManager::new(&account)?,
SslManager::new(&account, root_ca_start_time().await?)?,
&account.hostname,
&account.key,
)
Expand Down Expand Up @@ -214,6 +216,7 @@ impl RpcContext {
.build()
.with_kind(crate::ErrorKind::ParseUrl)?,
hardware: Hardware { devices, ram },
start_time: Instant::now(),
});

let res = Self(seed.clone());
Expand Down
5 changes: 3 additions & 2 deletions backend/src/db/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ impl Database {
.iter()
.map(|x| format!("{x:X}"))
.join(":"),
system_start_time: Utc::now().to_rfc3339(),
ntp_synced: false,
zram: true,
},
package_data: AllPackageData::default(),
Expand Down Expand Up @@ -125,7 +125,8 @@ pub struct ServerInfo {
pub password_hash: String,
pub pubkey: String,
pub ca_fingerprint: String,
pub system_start_time: String,
#[serde(default)]
pub ntp_synced: bool,
#[serde(default)]
pub zram: bool,
}
Expand Down
39 changes: 32 additions & 7 deletions backend/src/init.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fs::Permissions;
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
use std::time::Duration;
use std::time::{Duration, SystemTime};

use color_eyre::eyre::eyre;
use helpers::NonDetachingJoinHandle;
Expand All @@ -19,7 +19,6 @@ use crate::install::PKG_ARCHIVE_DIR;
use crate::middleware::auth::LOCAL_AUTH_COOKIE_PATH;
use crate::prelude::*;
use crate::sound::BEP;
use crate::system::time;
use crate::util::cpupower::{
current_governor, get_available_governors, set_governor, GOVERNOR_PERFORMANCE,
};
Expand Down Expand Up @@ -361,15 +360,28 @@ pub async fn init(cfg: &RpcContextConfig) -> Result<InitResult, Error> {
}
}

let mut warn_time_not_synced = true;
for _ in 0..60 {
let mut time_not_synced = true;
let mut not_made_progress = 0u32;
for _ in 0..1800 {
if check_time_is_synchronized().await? {
warn_time_not_synced = false;
time_not_synced = false;
break;
}
let t = SystemTime::now();
tokio::time::sleep(Duration::from_secs(1)).await;
if t.elapsed()
.map(|t| t > Duration::from_secs_f64(1.1))
.unwrap_or(true)
{
not_made_progress = 0;
} else {
not_made_progress += 1;
}
if not_made_progress > 30 {
break;
}
}
if warn_time_not_synced {
if time_not_synced {
tracing::warn!("Timed out waiting for system time to synchronize");
} else {
tracing::info!("Syncronized system clock");
Expand All @@ -385,7 +397,20 @@ pub async fn init(cfg: &RpcContextConfig) -> Result<InitResult, Error> {
backup_progress: None,
};

server_info.system_start_time = time().await?;
server_info.ntp_synced = if time_not_synced {
let db = db.clone();
tokio::spawn(async move {
while !check_time_is_synchronized().await.unwrap() {
tokio::time::sleep(Duration::from_secs(30)).await;
}
db.mutate(|v| v.as_server_info_mut().as_ntp_synced_mut().ser(&true))
.await
.unwrap()
});
false
} else {
true
};

db.mutate(|v| {
v.as_server_info_mut().ser(&server_info)?;
Expand Down
5 changes: 5 additions & 0 deletions backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ lazy_static::lazy_static! {
ARCH.to_string()
}
};
pub static ref SOURCE_DATE: SystemTime = {
std::fs::metadata(std::env::current_exe().unwrap()).unwrap().modified().unwrap()
};
}

pub mod account;
Expand Down Expand Up @@ -62,6 +65,8 @@ pub mod util;
pub mod version;
pub mod volume;

use std::time::SystemTime;

pub use config::Config;
pub use error::{Error, ErrorKind, ResultExt};
use rpc_toolkit::command;
Expand Down
69 changes: 47 additions & 22 deletions backend/src/net/ssl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use std::net::IpAddr;
use std::path::Path;
use std::time::{SystemTime, UNIX_EPOCH};


use futures::FutureExt;
use libc::time_t;
use openssl::asn1::{Asn1Integer, Asn1Time};
use openssl::bn::{BigNum, MsbOption};
use openssl::ec::{EcGroup, EcKey};
Expand All @@ -19,15 +19,22 @@ use tokio::sync::{Mutex, RwLock};
use tracing::instrument;

use crate::account::AccountInfo;
use crate::context::{RpcContext};
use crate::context::RpcContext;
use crate::hostname::Hostname;
use crate::init::check_time_is_synchronized;
use crate::net::dhcp::ips;
use crate::net::keys::{Key, KeyInfo};

use crate::{Error, ErrorKind, ResultExt};
use crate::{Error, ErrorKind, ResultExt, SOURCE_DATE};

static CERTIFICATE_VERSION: i32 = 2; // X509 version 3 is actually encoded as '2' in the cert because fuck you.

fn unix_time(time: SystemTime) -> time_t {
time.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs() as time_t)
.or_else(|_| UNIX_EPOCH.elapsed().map(|d| -(d.as_secs() as time_t)))
.unwrap_or_default()
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct CertPair {
pub ed25519: X509,
Expand Down Expand Up @@ -57,9 +64,13 @@ impl CertPair {
}),
);
if cert
.not_after()
.compare(Asn1Time::days_from_now(30)?.as_ref())?
== Ordering::Greater
.not_before()
.compare(Asn1Time::days_from_now(0)?.as_ref())?
== Ordering::Less
&& cert
.not_after()
.compare(Asn1Time::days_from_now(30)?.as_ref())?
== Ordering::Greater
&& ips.is_superset(&ip)
{
return Ok(cert.clone());
Expand All @@ -82,6 +93,14 @@ impl CertPair {
}
}

pub async fn root_ca_start_time() -> Result<SystemTime, Error> {
Ok(if check_time_is_synchronized().await? {
SystemTime::now()
} else {
*SOURCE_DATE
})
}

#[derive(Debug)]
pub struct SslManager {
hostname: Hostname,
Expand All @@ -91,9 +110,13 @@ pub struct SslManager {
cert_cache: RwLock<BTreeMap<Key, CertPair>>,
}
impl SslManager {
pub fn new(account: &AccountInfo) -> Result<Self, Error> {
pub fn new(account: &AccountInfo, start_time: SystemTime) -> Result<Self, Error> {
let int_key = generate_key()?;
let int_cert = make_int_cert((&account.root_ca_key, &account.root_ca_cert), &int_key)?;
let int_cert = make_int_cert(
(&account.root_ca_key, &account.root_ca_cert),
&int_key,
start_time,
)?;
Ok(Self {
hostname: account.hostname.clone(),
root_cert: account.root_ca_cert.clone(),
Expand Down Expand Up @@ -162,14 +185,20 @@ pub fn generate_key() -> Result<PKey<Private>, Error> {
}

#[instrument(skip_all)]
pub fn make_root_cert(root_key: &PKey<Private>, hostname: &Hostname) -> Result<X509, Error> {
pub fn make_root_cert(
root_key: &PKey<Private>,
hostname: &Hostname,
start_time: SystemTime,
) -> Result<X509, Error> {
let mut builder = X509Builder::new()?;
builder.set_version(CERTIFICATE_VERSION)?;

let embargo = Asn1Time::days_from_now(0)?;
let unix_start_time = unix_time(start_time);

let embargo = Asn1Time::from_unix(unix_start_time)?;
builder.set_not_before(&embargo)?;

let expiration = Asn1Time::days_from_now(3650)?;
let expiration = Asn1Time::from_unix(unix_start_time + (10 * 365 * 86400))?;
builder.set_not_after(&expiration)?;

builder.set_serial_number(&*rand_serial()?)?;
Expand Down Expand Up @@ -216,14 +245,17 @@ pub fn make_root_cert(root_key: &PKey<Private>, hostname: &Hostname) -> Result<X
pub fn make_int_cert(
signer: (&PKey<Private>, &X509),
applicant: &PKey<Private>,
start_time: SystemTime,
) -> Result<X509, Error> {
let mut builder = X509Builder::new()?;
builder.set_version(CERTIFICATE_VERSION)?;

let embargo = Asn1Time::days_from_now(0)?;
let unix_start_time = unix_time(start_time);

let embargo = Asn1Time::from_unix(unix_start_time)?;
builder.set_not_before(&embargo)?;

let expiration = Asn1Time::days_from_now(3650)?;
let expiration = Asn1Time::from_unix(unix_start_time + (10 * 365 * 86400))?;
builder.set_not_after(&expiration)?;

builder.set_serial_number(&*rand_serial()?)?;
Expand Down Expand Up @@ -346,14 +378,7 @@ pub fn make_leaf_cert(
let mut builder = X509Builder::new()?;
builder.set_version(CERTIFICATE_VERSION)?;

let embargo = Asn1Time::from_unix(
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs() as i64)
.or_else(|_| UNIX_EPOCH.elapsed().map(|d| -(d.as_secs() as i64)))
.unwrap_or_default()
- 86400,
)?;
let embargo = Asn1Time::from_unix(unix_time(SystemTime::now()) - 86400)?;
builder.set_not_before(&embargo)?;

// Google Apple and Mozilla reject certificate horizons longer than 397 days
Expand Down
3 changes: 2 additions & 1 deletion backend/src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use crate::disk::REPAIR_DISK_PATH;
use crate::hostname::Hostname;
use crate::init::{init, InitResult};
use crate::middleware::encrypt::EncryptedWire;
use crate::net::ssl::root_ca_start_time;
use crate::prelude::*;
use crate::util::io::{dir_copy, dir_size, Counter};
use crate::{Error, ErrorKind, ResultExt};
Expand Down Expand Up @@ -378,7 +379,7 @@ async fn fresh_setup(
ctx: &SetupContext,
embassy_password: &str,
) -> Result<(Hostname, OnionAddressV3, X509), Error> {
let account = AccountInfo::new(embassy_password)?;
let account = AccountInfo::new(embassy_password, root_ca_start_time().await?)?;
let sqlite_pool = ctx.secret_store().await?;
account.save(&sqlite_pool).await?;
sqlite_pool.close().await;
Expand Down
Loading

0 comments on commit 27c949d

Please sign in to comment.