Create certificates using a rolling state

A new key pair is now computed using the previous secret key as a seed.

This still provides forward secrecy, and allows multiple instances
to compute the same ephemeral keys without having to share a state.

Fixes #57
Fixes #27
pull/59/head
Frank Denis 3 years ago
parent 631ebd4776
commit dbed0a0867

@ -112,10 +112,8 @@ pub struct State {
impl State {
pub fn with_key_pair(provider_kp: SignKeyPair, key_cache_capacity: usize) -> Self {
let dnscrypt_encryption_params_set = vec![DNSCryptEncryptionParams::new(
&provider_kp,
key_cache_capacity,
)];
let dnscrypt_encryption_params_set =
DNSCryptEncryptionParams::new(&provider_kp, key_cache_capacity, None);
State {
provider_kp,
dnscrypt_encryption_params_set,

@ -132,12 +132,15 @@ pub struct CryptKeyPair {
}
impl CryptKeyPair {
pub fn new() -> Self {
pub fn from_seed(
seed: [u8; crypto_box_curve25519xchacha20poly1305_SEEDBYTES as usize],
) -> Self {
let mut kp = CryptKeyPair::default();
unsafe {
crypto_box_curve25519xchacha20poly1305_keypair(
crypto_box_curve25519xchacha20poly1305_seed_keypair(
kp.pk.0.as_mut_ptr(),
kp.sk.0.as_mut_ptr(),
seed.as_ptr(),
)
};
kp

@ -7,6 +7,7 @@ use crate::globals::*;
use byteorder::{BigEndian, ByteOrder};
use clockpro_cache::ClockProCache;
use parking_lot::Mutex;
use rand::prelude::*;
use std::mem;
use std::slice;
use std::sync::Arc;
@ -54,8 +55,7 @@ pub struct DNSCryptCert {
}
impl DNSCryptCert {
pub fn new(provider_kp: &SignKeyPair, resolver_kp: &CryptKeyPair) -> Self {
let ts_start = now();
pub fn new(provider_kp: &SignKeyPair, resolver_kp: &CryptKeyPair, ts_start: u32) -> Self {
let ts_end = ts_start + DNSCRYPT_CERTS_TTL;
let mut dnscrypt_cert = DNSCryptCert::default();
@ -92,6 +92,10 @@ impl DNSCryptCert {
&self.inner.client_magic
}
pub fn ts_start(&self) -> u32 {
BigEndian::read_u32(&self.inner.ts_start)
}
pub fn ts_end(&self) -> u32 {
BigEndian::read_u32(&self.inner.ts_end)
}
@ -108,20 +112,56 @@ pub struct DNSCryptEncryptionParams {
}
impl DNSCryptEncryptionParams {
pub fn new(provider_kp: &SignKeyPair, cache_capacity: usize) -> Self {
let mut resolver_kp;
while {
resolver_kp = CryptKeyPair::new();
resolver_kp.pk.as_bytes()
pub fn new(
provider_kp: &SignKeyPair,
cache_capacity: usize,
previous_params: Option<Arc<DNSCryptEncryptionParams>>,
) -> Vec<Self> {
let now = now();
let (mut ts_start, mut seed) = match &previous_params {
None => (now, rand::thread_rng().gen()),
Some(p) => (
p.dnscrypt_cert().ts_start() + DNSCRYPT_CERTS_RENEWAL,
*p.resolver_kp().sk.as_bytes(),
),
};
let mut active_params = vec![];
loop {
if ts_start > now + DNSCRYPT_CERTS_RENEWAL {
break;
}
let resolver_kp = CryptKeyPair::from_seed(seed);
seed = *resolver_kp.sk.as_bytes();
if resolver_kp.pk.as_bytes()
== &ANONYMIZED_DNSCRYPT_QUERY_MAGIC[..DNSCRYPT_QUERY_MAGIC_SIZE]
} {}
let dnscrypt_cert = DNSCryptCert::new(&provider_kp, &resolver_kp);
let cache = ClockProCache::new(cache_capacity).unwrap();
DNSCryptEncryptionParams {
dnscrypt_cert,
resolver_kp,
cache: Some(Arc::new(Mutex::new(cache))),
{
ts_start += DNSCRYPT_CERTS_RENEWAL;
continue;
}
if now >= ts_start {
let dnscrypt_cert = DNSCryptCert::new(&provider_kp, &resolver_kp, ts_start);
let cache = ClockProCache::new(cache_capacity).unwrap();
active_params.push(DNSCryptEncryptionParams {
dnscrypt_cert,
resolver_kp,
cache: Some(Arc::new(Mutex::new(cache))),
});
}
ts_start += DNSCRYPT_CERTS_RENEWAL;
}
if active_params.is_empty() && previous_params.is_none() {
warn!("Unable to recover a seed; creating an emergency certificate");
let ts_start = now - (now % DNSCRYPT_CERTS_RENEWAL);
let resolver_kp = CryptKeyPair::from_seed(seed);
let dnscrypt_cert = DNSCryptCert::new(&provider_kp, &resolver_kp, ts_start);
let cache = ClockProCache::new(cache_capacity).unwrap();
active_params.push(DNSCryptEncryptionParams {
dnscrypt_cert,
resolver_kp,
cache: Some(Arc::new(Mutex::new(cache))),
});
}
active_params
}
pub fn add_key_cache(&mut self, cache_capacity: usize) {
@ -154,19 +194,23 @@ impl DNSCryptEncryptionParamsUpdater {
pub fn update(&self) {
let now = now();
let mut new_params_set = vec![];
{
let previous_params = {
let params_set = self.globals.dnscrypt_encryption_params_set.read();
for params in &**params_set {
if params.dnscrypt_cert().ts_end() >= now {
new_params_set.push(params.clone());
}
}
}
let new_params = DNSCryptEncryptionParams::new(
params_set.last().cloned()
};
let active_params = DNSCryptEncryptionParams::new(
&self.globals.provider_kp,
self.globals.key_cache_capacity,
previous_params,
);
new_params_set.push(Arc::new(new_params));
for params in active_params {
new_params_set.push(Arc::new(params));
}
let state = State {
provider_kp: self.globals.provider_kp.clone(),
dnscrypt_encryption_params_set: new_params_set.iter().map(|x| (**x).clone()).collect(),

Loading…
Cancel
Save