Skip to main content

tuwunel_service/oauth/server/
signing_key.rs

1use ring::{
2	rand::SystemRandom,
3	signature::{self, EcdsaKeyPair},
4};
5use serde::{Deserialize, Serialize};
6use tuwunel_core::{Result, at, err, info, utils};
7use tuwunel_database::{Cbor, Deserialized};
8
9use super::Data;
10
11#[derive(Deserialize, Serialize)]
12pub(super) struct SigningKey {
13	pub(super) key_id: String,
14	pub(super) key_der: Vec<u8>,
15}
16
17const SIGNING_KEY_DB_KEY: &str = "oidc_signing_key";
18
19pub(super) fn init_signing_key(db: &Data) -> Result<SigningKey> {
20	if let Ok(signing_key_data) = db
21		.oidc_signingkey
22		.get_blocking(SIGNING_KEY_DB_KEY)
23		.and_then(|val| val.deserialized::<Cbor<SigningKey>>())
24		.map(at!(0))
25	{
26		info!(
27			key_id = ?signing_key_data.key_id,
28			"Loaded existing OIDC signing key",
29		);
30
31		return Ok(signing_key_data);
32	}
33
34	let signing_key_data = generate_signing_key()?;
35
36	db.oidc_signingkey
37		.raw_put(SIGNING_KEY_DB_KEY, Cbor(&signing_key_data));
38
39	info!(
40		key_id = ?signing_key_data.key_id,
41		"Generated new OIDC signing key",
42	);
43
44	Ok(signing_key_data)
45}
46
47fn generate_signing_key() -> Result<SigningKey> {
48	let rng = SystemRandom::new();
49	let alg = &signature::ECDSA_P256_SHA256_FIXED_SIGNING;
50	let key_id = utils::random_string(16);
51	let pkcs8 = EcdsaKeyPair::generate_pkcs8(alg, &rng)
52		.map_err(|e| err!(error!("Failed to generate ECDSA key: {e}")))?;
53
54	Ok(SigningKey { key_der: pkcs8.as_ref().to_vec(), key_id })
55}