diff --git a/src/net/tls.rs b/src/net/tls.rs index 972da0ac1..037e622c4 100644 --- a/src/net/tls.rs +++ b/src/net/tls.rs @@ -7,6 +7,7 @@ use anyhow::Result; use crate::net::session::SessionStream; use crate::sql::Sql; +use crate::tools::time; use tokio_rustls::rustls; use tokio_rustls::rustls::client::ClientSessionStore; @@ -164,9 +165,10 @@ pub async fn wrap_rustls<'a>( .peer_certificates() .and_then(|certs| certs.first()) { + let now = time(); let parsed_certificate = ParsedCertificate::try_from(end_entity)?; let spki = parsed_certificate.subject_public_key_info(); - spki_hash_store.save_spki(hostname, &spki, sql).await?; + spki_hash_store.save_spki(hostname, &spki, sql, now).await?; } Ok(tls_stream) diff --git a/src/net/tls/spki.rs b/src/net/tls/spki.rs index 140a24580..0ac9c3b0c 100644 --- a/src/net/tls/spki.rs +++ b/src/net/tls/spki.rs @@ -77,14 +77,15 @@ impl SpkiHashStore { hostname: &str, spki: &SubjectPublicKeyInfoDer<'_>, sql: &Sql, + timestamp: i64, ) -> Result<()> { let hash = spki_hash(spki); self.hash_store .write() .insert(hostname.to_string(), hash.clone()); sql.execute( - "INSERT OR REPLACE INTO tls_spki (host, spki_hash) VALUES (?, ?)", - (hostname, hash), + "INSERT OR REPLACE INTO tls_spki (host, spki_hash, timestamp) VALUES (?, ?, ?)", + (hostname, hash, timestamp), ) .await?; Ok(()) diff --git a/src/sql.rs b/src/sql.rs index a59d56550..5717bc661 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -874,6 +874,17 @@ pub async fn housekeeping(context: &Context) -> Result<()> { .log_err(context) .ok(); + context + .sql + .execute( + "DELETE FROM tls_spki WHERE ? > timestamp + ?", + (time(), 30 * 24 * 60 * 60), + ) + .await + .context("Failed to prune SPKI store") + .log_err(context) + .ok(); + // Cleanup `imap` and `imap_sync` entries for deleted transports. // // Transports may be deleted directly or via sync messages, diff --git a/src/sql/migrations.rs b/src/sql/migrations.rs index 193d0d3cd..b836d7d1e 100644 --- a/src/sql/migrations.rs +++ b/src/sql/migrations.rs @@ -2365,7 +2365,8 @@ ALTER TABLE contacts ADD COLUMN name_normalized TEXT; sql.execute_migration( "CREATE TABLE tls_spki ( host TEXT NOT NULL UNIQUE, - spki_hash TEXT NOT NULL -- base64 of SPKI SHA-256 hash + spki_hash TEXT NOT NULL, -- base64 of SPKI SHA-256 hash + timestamp INTEGER NOT NULL -- timestamp of the last time we have seen this key ) STRICT", migration_version, )