Skip to main content

tuwunel_service/server_keys/
keypair.rs

1use std::sync::Arc;
2
3use ruma::{api::federation::discovery::VerifyKey, serde::Base64, signatures::Ed25519KeyPair};
4use tuwunel_core::{Result, debug, debug_info, err, error, utils, utils::string_from_bytes};
5use tuwunel_database::Database;
6
7use super::VerifyKeys;
8
9pub(super) fn init(db: &Arc<Database>) -> Result<(Box<Ed25519KeyPair>, VerifyKeys)> {
10	let keypair = load(db).inspect_err(|_e| {
11		error!("Keypair invalid. Deleting...");
12		remove(db);
13	})?;
14
15	let verify_key = VerifyKey {
16		key: Base64::new(keypair.public_key().to_vec()),
17	};
18
19	let id = format!("ed25519:{}", keypair.version());
20	let verify_keys: VerifyKeys = [(id.try_into()?, verify_key)].into();
21
22	Ok((keypair, verify_keys))
23}
24
25fn load(db: &Arc<Database>) -> Result<Box<Ed25519KeyPair>> {
26	let (version, key) = db["global"]
27		.get_blocking(b"keypair")
28		.map(|ref val| {
29			// database deserializer is having trouble with this so it's manual for now
30			let mut elems = val.split(|&b| b == b'\xFF');
31			let vlen = elems.next().expect("invalid keypair entry").len();
32			let ver = string_from_bytes(&val[..vlen]).expect("invalid keypair version");
33			let der = val[vlen.saturating_add(1)..].to_vec();
34			debug!("Found existing Ed25519 keypair: {ver:?}");
35			(ver, der)
36		})
37		.or_else(|e| {
38			assert!(e.is_not_found(), "unexpected error fetching keypair");
39			create(db)
40		})?;
41
42	let key = Ed25519KeyPair::from_der(&key, version)
43		.map_err(|e| err!("Failed to load ed25519 keypair from der: {e:?}"))?;
44
45	Ok(Box::new(key))
46}
47
48fn create(db: &Arc<Database>) -> Result<(String, Vec<u8>)> {
49	let keypair = Ed25519KeyPair::generate();
50
51	let id = utils::rand::string(8);
52	debug_info!("Generated new Ed25519 keypair: {id:?}");
53
54	let value: (String, Vec<u8>) = (id, keypair.to_vec());
55	db["global"].raw_put(b"keypair", &value);
56
57	Ok(value)
58}
59
60#[inline]
61fn remove(db: &Arc<Database>) {
62	let global = &db["global"];
63	global.remove(b"keypair");
64}