mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 20:43:44 +02:00
Rekeying is now tested and works.
This commit is contained in:
parent
652f7360f0
commit
8b6c9051fb
4 changed files with 158 additions and 107 deletions
|
@ -31,7 +31,7 @@ pub trait ApplicationLayer: Sized {
|
||||||
/// Attempting to encrypt more than this many messages with a key will cause a hard error
|
/// Attempting to encrypt more than this many messages with a key will cause a hard error
|
||||||
/// and the internal erasure of ephemeral key material. You'll only ever hit this if something
|
/// and the internal erasure of ephemeral key material. You'll only ever hit this if something
|
||||||
/// goes wrong and rekeying fails.
|
/// goes wrong and rekeying fails.
|
||||||
const EXPIRE_AFTER_USES: u64 = 2147483648;
|
const EXPIRE_AFTER_USES: u64 = 2147483647;
|
||||||
|
|
||||||
/// Start attempting to rekey after a key has been in use for this many milliseconds.
|
/// Start attempting to rekey after a key has been in use for this many milliseconds.
|
||||||
///
|
///
|
||||||
|
|
102
zssp/src/main.rs
102
zssp/src/main.rs
|
@ -14,7 +14,7 @@ struct TestApplication {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl zssp::ApplicationLayer for TestApplication {
|
impl zssp::ApplicationLayer for TestApplication {
|
||||||
const REKEY_AFTER_USES: u64 = 131072;
|
const REKEY_AFTER_USES: u64 = 100000;
|
||||||
const EXPIRE_AFTER_USES: u64 = 2147483648;
|
const EXPIRE_AFTER_USES: u64 = 2147483648;
|
||||||
const REKEY_AFTER_TIME_MS: i64 = 1000 * 60 * 60 * 2;
|
const REKEY_AFTER_TIME_MS: i64 = 1000 * 60 * 60 * 2;
|
||||||
const REKEY_AFTER_TIME_MS_MAX_JITTER: u32 = 1000 * 60 * 10;
|
const REKEY_AFTER_TIME_MS_MAX_JITTER: u32 = 1000 * 60 * 10;
|
||||||
|
@ -44,6 +44,9 @@ fn alice_main(
|
||||||
let context = zssp::Context::<TestApplication>::new(16);
|
let context = zssp::Context::<TestApplication>::new(16);
|
||||||
let mut data_buf = [0u8; 65536];
|
let mut data_buf = [0u8; 65536];
|
||||||
let mut next_service = ms_monotonic() + 500;
|
let mut next_service = ms_monotonic() + 500;
|
||||||
|
let mut last_ratchet_count = 0;
|
||||||
|
let test_data = [1u8; 10000];
|
||||||
|
let mut up = false;
|
||||||
|
|
||||||
let alice_session = context
|
let alice_session = context
|
||||||
.open(
|
.open(
|
||||||
|
@ -62,51 +65,57 @@ fn alice_main(
|
||||||
|
|
||||||
println!("[alice] opening session {}", alice_session.id.to_string());
|
println!("[alice] opening session {}", alice_session.id.to_string());
|
||||||
|
|
||||||
let test_data = [1u8; 10000];
|
|
||||||
let mut up = false;
|
|
||||||
|
|
||||||
while run.load(Ordering::Relaxed) {
|
while run.load(Ordering::Relaxed) {
|
||||||
let pkt = alice_in.try_recv();
|
|
||||||
let current_time = ms_monotonic();
|
let current_time = ms_monotonic();
|
||||||
|
loop {
|
||||||
if let Ok(pkt) = pkt {
|
let pkt = alice_in.try_recv();
|
||||||
//println!("bob >> alice {}", pkt.len());
|
if let Ok(pkt) = pkt {
|
||||||
match context.receive(
|
//println!("bob >> alice {}", pkt.len());
|
||||||
alice_app,
|
match context.receive(
|
||||||
|| true,
|
alice_app,
|
||||||
|s_public, _| Some((P384PublicKey::from_bytes(s_public).unwrap(), Secret::default(), ())),
|
|| true,
|
||||||
|_, b| {
|
|s_public, _| Some((P384PublicKey::from_bytes(s_public).unwrap(), Secret::default(), ())),
|
||||||
let _ = alice_out.send(b.to_vec());
|
|_, b| {
|
||||||
},
|
let _ = alice_out.send(b.to_vec());
|
||||||
&mut data_buf,
|
},
|
||||||
pkt,
|
&mut data_buf,
|
||||||
TEST_MTU,
|
pkt,
|
||||||
current_time,
|
TEST_MTU,
|
||||||
) {
|
current_time,
|
||||||
Ok(zssp::ReceiveResult::Ok) => {
|
) {
|
||||||
//println!("[alice] ok");
|
Ok(zssp::ReceiveResult::Ok) => {
|
||||||
}
|
//println!("[alice] ok");
|
||||||
Ok(zssp::ReceiveResult::OkData(_, _)) => {
|
}
|
||||||
//println!("[alice] received {}", data.len());
|
Ok(zssp::ReceiveResult::OkData(_, data)) => {
|
||||||
}
|
//println!("[alice] received {}", data.len());
|
||||||
Ok(zssp::ReceiveResult::OkNewSession(s)) => {
|
}
|
||||||
println!("[alice] new session {}", s.id.to_string());
|
Ok(zssp::ReceiveResult::OkNewSession(s)) => {
|
||||||
}
|
println!("[alice] new session {}", s.id.to_string());
|
||||||
Ok(zssp::ReceiveResult::Rejected) => {}
|
}
|
||||||
Err(e) => {
|
Ok(zssp::ReceiveResult::Rejected) => {}
|
||||||
println!("[alice] ERROR {}", e.to_string());
|
Err(e) => {
|
||||||
|
println!("[alice] ERROR {}", e.to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if up {
|
if up {
|
||||||
|
let ratchet_count = alice_session.key_info().unwrap().0;
|
||||||
|
if ratchet_count > last_ratchet_count {
|
||||||
|
last_ratchet_count = ratchet_count;
|
||||||
|
println!("[alice] new key! ratchet count {}", ratchet_count);
|
||||||
|
}
|
||||||
|
|
||||||
assert!(alice_session
|
assert!(alice_session
|
||||||
.send(
|
.send(
|
||||||
|b| {
|
|b| {
|
||||||
let _ = alice_out.send(b.to_vec());
|
let _ = alice_out.send(b.to_vec());
|
||||||
},
|
},
|
||||||
&mut data_buf[..TEST_MTU],
|
&mut data_buf[..TEST_MTU],
|
||||||
&test_data[..2048 + ((zerotier_crypto::random::xorshift64_random() as usize) % (test_data.len() - 2048))],
|
&test_data[..1000 + ((zerotier_crypto::random::xorshift64_random() as usize) % (test_data.len() - 1000))],
|
||||||
)
|
)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
} else {
|
} else {
|
||||||
|
@ -137,6 +146,8 @@ fn bob_main(
|
||||||
) {
|
) {
|
||||||
let context = zssp::Context::<TestApplication>::new(16);
|
let context = zssp::Context::<TestApplication>::new(16);
|
||||||
let mut data_buf = [0u8; 65536];
|
let mut data_buf = [0u8; 65536];
|
||||||
|
let mut data_buf_2 = [0u8; TEST_MTU];
|
||||||
|
let mut last_ratchet_count = 0;
|
||||||
let mut last_speed_metric = ms_monotonic();
|
let mut last_speed_metric = ms_monotonic();
|
||||||
let mut next_service = last_speed_metric + 500;
|
let mut next_service = last_speed_metric + 500;
|
||||||
let mut transferred = 0u64;
|
let mut transferred = 0u64;
|
||||||
|
@ -144,7 +155,7 @@ fn bob_main(
|
||||||
let mut bob_session = None;
|
let mut bob_session = None;
|
||||||
|
|
||||||
while run.load(Ordering::Relaxed) {
|
while run.load(Ordering::Relaxed) {
|
||||||
let pkt = bob_in.recv_timeout(Duration::from_millis(10));
|
let pkt = bob_in.recv_timeout(Duration::from_millis(100));
|
||||||
let current_time = ms_monotonic();
|
let current_time = ms_monotonic();
|
||||||
|
|
||||||
if let Ok(pkt) = pkt {
|
if let Ok(pkt) = pkt {
|
||||||
|
@ -164,9 +175,18 @@ fn bob_main(
|
||||||
Ok(zssp::ReceiveResult::Ok) => {
|
Ok(zssp::ReceiveResult::Ok) => {
|
||||||
//println!("[bob] ok");
|
//println!("[bob] ok");
|
||||||
}
|
}
|
||||||
Ok(zssp::ReceiveResult::OkData(_, data)) => {
|
Ok(zssp::ReceiveResult::OkData(s, data)) => {
|
||||||
//println!("[bob] received {}", data.len());
|
//println!("[bob] received {}", data.len());
|
||||||
transferred += data.len() as u64;
|
transferred += data.len() as u64;
|
||||||
|
assert!(s
|
||||||
|
.send(
|
||||||
|
|b| {
|
||||||
|
let _ = bob_out.send(b.to_vec());
|
||||||
|
},
|
||||||
|
&mut data_buf_2,
|
||||||
|
data.as_mut(),
|
||||||
|
)
|
||||||
|
.is_ok());
|
||||||
}
|
}
|
||||||
Ok(zssp::ReceiveResult::OkNewSession(s)) => {
|
Ok(zssp::ReceiveResult::OkNewSession(s)) => {
|
||||||
println!("[bob] new session {}", s.id.to_string());
|
println!("[bob] new session {}", s.id.to_string());
|
||||||
|
@ -179,6 +199,14 @@ fn bob_main(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(bob_session) = bob_session.as_ref() {
|
||||||
|
let ratchet_count = bob_session.key_info().unwrap().0;
|
||||||
|
if ratchet_count > last_ratchet_count {
|
||||||
|
last_ratchet_count = ratchet_count;
|
||||||
|
println!("[bob] new key! ratchet count {}", ratchet_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let speed_metric_elapsed = current_time - last_speed_metric;
|
let speed_metric_elapsed = current_time - last_speed_metric;
|
||||||
if speed_metric_elapsed >= 1000 {
|
if speed_metric_elapsed >= 1000 {
|
||||||
last_speed_metric = current_time;
|
last_speed_metric = current_time;
|
||||||
|
@ -208,8 +236,8 @@ fn main() {
|
||||||
let alice_app = TestApplication { identity_key: P384KeyPair::generate() };
|
let alice_app = TestApplication { identity_key: P384KeyPair::generate() };
|
||||||
let bob_app = TestApplication { identity_key: P384KeyPair::generate() };
|
let bob_app = TestApplication { identity_key: P384KeyPair::generate() };
|
||||||
|
|
||||||
let (alice_out, bob_in) = mpsc::sync_channel::<Vec<u8>>(128);
|
let (alice_out, bob_in) = mpsc::sync_channel::<Vec<u8>>(1024);
|
||||||
let (bob_out, alice_in) = mpsc::sync_channel::<Vec<u8>>(128);
|
let (bob_out, alice_in) = mpsc::sync_channel::<Vec<u8>>(1024);
|
||||||
|
|
||||||
thread::scope(|ts| {
|
thread::scope(|ts| {
|
||||||
let alice_thread = ts.spawn(|| alice_main(&run, &alice_app, &bob_app, alice_out, alice_in));
|
let alice_thread = ts.spawn(|| alice_main(&run, &alice_app, &bob_app, alice_out, alice_in));
|
||||||
|
|
|
@ -33,8 +33,8 @@ pub(crate) const PACKET_TYPE_DATA: u8 = 0;
|
||||||
pub(crate) const PACKET_TYPE_ALICE_NOISE_XK_INIT: u8 = 1;
|
pub(crate) const PACKET_TYPE_ALICE_NOISE_XK_INIT: u8 = 1;
|
||||||
pub(crate) const PACKET_TYPE_BOB_NOISE_XK_ACK: u8 = 2;
|
pub(crate) const PACKET_TYPE_BOB_NOISE_XK_ACK: u8 = 2;
|
||||||
pub(crate) const PACKET_TYPE_ALICE_NOISE_XK_ACK: u8 = 3;
|
pub(crate) const PACKET_TYPE_ALICE_NOISE_XK_ACK: u8 = 3;
|
||||||
pub(crate) const PACKET_TYPE_ALICE_REKEY_INIT: u8 = 4;
|
pub(crate) const PACKET_TYPE_REKEY_INIT: u8 = 4;
|
||||||
pub(crate) const PACKET_TYPE_BOB_REKEY_ACK: u8 = 5;
|
pub(crate) const PACKET_TYPE_REKEY_ACK: u8 = 5;
|
||||||
|
|
||||||
pub(crate) const HEADER_SIZE: usize = 16;
|
pub(crate) const HEADER_SIZE: usize = 16;
|
||||||
pub(crate) const HEADER_PROTECT_ENCRYPT_START: usize = 6;
|
pub(crate) const HEADER_PROTECT_ENCRYPT_START: usize = 6;
|
||||||
|
@ -123,24 +123,26 @@ pub(crate) const ALICE_NOISE_XK_ACK_MIN_SIZE: usize = ALICE_NOISE_XK_ACK_ENC_STA
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub(crate) struct AliceRekeyInit {
|
pub(crate) struct RekeyInit {
|
||||||
pub header: [u8; HEADER_SIZE],
|
pub header: [u8; HEADER_SIZE],
|
||||||
|
pub session_protocol_version: u8,
|
||||||
// -- start AES-GCM encrypted portion (using current key)
|
// -- start AES-GCM encrypted portion (using current key)
|
||||||
pub alice_e: [u8; P384_PUBLIC_KEY_SIZE],
|
pub alice_e: [u8; P384_PUBLIC_KEY_SIZE],
|
||||||
// -- end AES-GCM encrypted portion
|
// -- end AES-GCM encrypted portion
|
||||||
pub gcm_mac: [u8; AES_GCM_TAG_SIZE],
|
pub gcm_mac: [u8; AES_GCM_TAG_SIZE],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AliceRekeyInit {
|
impl RekeyInit {
|
||||||
pub const ENC_START: usize = HEADER_SIZE;
|
pub const ENC_START: usize = HEADER_SIZE + 1;
|
||||||
pub const AUTH_START: usize = Self::ENC_START + P384_PUBLIC_KEY_SIZE;
|
pub const AUTH_START: usize = Self::ENC_START + P384_PUBLIC_KEY_SIZE;
|
||||||
pub const SIZE: usize = Self::AUTH_START + AES_GCM_TAG_SIZE;
|
pub const SIZE: usize = Self::AUTH_START + AES_GCM_TAG_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub(crate) struct BobRekeyAck {
|
pub(crate) struct RekeyAck {
|
||||||
pub header: [u8; HEADER_SIZE],
|
pub header: [u8; HEADER_SIZE],
|
||||||
|
pub session_protocol_version: u8,
|
||||||
// -- start AES-GCM encrypted portion (using current key)
|
// -- start AES-GCM encrypted portion (using current key)
|
||||||
pub bob_e: [u8; P384_PUBLIC_KEY_SIZE],
|
pub bob_e: [u8; P384_PUBLIC_KEY_SIZE],
|
||||||
pub next_key_fingerprint: [u8; SHA384_HASH_SIZE],
|
pub next_key_fingerprint: [u8; SHA384_HASH_SIZE],
|
||||||
|
@ -148,8 +150,8 @@ pub(crate) struct BobRekeyAck {
|
||||||
pub gcm_mac: [u8; AES_GCM_TAG_SIZE],
|
pub gcm_mac: [u8; AES_GCM_TAG_SIZE],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BobRekeyAck {
|
impl RekeyAck {
|
||||||
pub const ENC_START: usize = HEADER_SIZE;
|
pub const ENC_START: usize = HEADER_SIZE + 1;
|
||||||
pub const AUTH_START: usize = Self::ENC_START + P384_PUBLIC_KEY_SIZE + SHA384_HASH_SIZE;
|
pub const AUTH_START: usize = Self::ENC_START + P384_PUBLIC_KEY_SIZE + SHA384_HASH_SIZE;
|
||||||
pub const SIZE: usize = Self::AUTH_START + AES_GCM_TAG_SIZE;
|
pub const SIZE: usize = Self::AUTH_START + AES_GCM_TAG_SIZE;
|
||||||
}
|
}
|
||||||
|
@ -161,8 +163,8 @@ pub(crate) trait ProtocolFlatBuffer {}
|
||||||
impl ProtocolFlatBuffer for AliceNoiseXKInit {}
|
impl ProtocolFlatBuffer for AliceNoiseXKInit {}
|
||||||
impl ProtocolFlatBuffer for BobNoiseXKAck {}
|
impl ProtocolFlatBuffer for BobNoiseXKAck {}
|
||||||
//impl ProtocolFlatBuffer for NoiseXKAliceStaticAck {}
|
//impl ProtocolFlatBuffer for NoiseXKAliceStaticAck {}
|
||||||
impl ProtocolFlatBuffer for AliceRekeyInit {}
|
impl ProtocolFlatBuffer for RekeyInit {}
|
||||||
impl ProtocolFlatBuffer for BobRekeyAck {}
|
impl ProtocolFlatBuffer for RekeyAck {}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
|
|
139
zssp/src/zssp.rs
139
zssp/src/zssp.rs
|
@ -119,7 +119,7 @@ struct OutgoingSessionInit {
|
||||||
enum Offer {
|
enum Offer {
|
||||||
None,
|
None,
|
||||||
NoiseXKInit(Box<OutgoingSessionInit>),
|
NoiseXKInit(Box<OutgoingSessionInit>),
|
||||||
RekeyInit(P384KeyPair, [u8; AliceRekeyInit::SIZE], AtomicI64),
|
RekeyInit(P384KeyPair, [u8; RekeyInit::SIZE], AtomicI64),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An ephemeral session key with expiration info.
|
/// An ephemeral session key with expiration info.
|
||||||
|
@ -181,6 +181,7 @@ impl<Application: ApplicationLayer> Context<Application> {
|
||||||
&& (current_time >= key.rekey_at_time
|
&& (current_time >= key.rekey_at_time
|
||||||
|| session.send_counter.load(Ordering::Relaxed) >= key.rekey_at_counter)
|
|| session.send_counter.load(Ordering::Relaxed) >= key.rekey_at_counter)
|
||||||
{
|
{
|
||||||
|
drop(state);
|
||||||
session.initiate_rekey(|b| send(&session, b), current_time);
|
session.initiate_rekey(|b| send(&session, b), current_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1106,8 +1107,8 @@ impl<Application: ApplicationLayer> Context<Application> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PACKET_TYPE_ALICE_REKEY_INIT => {
|
PACKET_TYPE_REKEY_INIT => {
|
||||||
if pkt_assembled.len() != AliceRekeyInit::SIZE {
|
if pkt_assembled.len() != RekeyInit::SIZE {
|
||||||
return Err(Error::InvalidPacket);
|
return Err(Error::InvalidPacket);
|
||||||
}
|
}
|
||||||
if incoming.is_some() {
|
if incoming.is_some() {
|
||||||
|
@ -1116,58 +1117,74 @@ impl<Application: ApplicationLayer> Context<Application> {
|
||||||
|
|
||||||
if let Some(session) = session {
|
if let Some(session) = session {
|
||||||
let state = session.state.read().unwrap();
|
let state = session.state.read().unwrap();
|
||||||
if let Some(key) = state.keys[key_index].as_ref() {
|
if let Some(remote_session_id) = state.remote_session_id {
|
||||||
// Only the current "Alice" accepts rekeys initiated by the current "Bob." These roles
|
if let Some(key) = state.keys[key_index].as_ref() {
|
||||||
// flip with each rekey event.
|
// Only the current "Alice" accepts rekeys initiated by the current "Bob." These roles
|
||||||
if !key.bob {
|
// flip with each rekey event.
|
||||||
let mut c = key.get_receive_cipher();
|
if !key.bob {
|
||||||
c.reset_init_gcm(&incoming_message_nonce);
|
let mut c = key.get_receive_cipher();
|
||||||
c.crypt_in_place(&mut pkt_assembled[AliceRekeyInit::ENC_START..AliceRekeyInit::AUTH_START]);
|
c.reset_init_gcm(&incoming_message_nonce);
|
||||||
let aead_authentication_ok = c.finish_decrypt(&pkt_assembled[AliceRekeyInit::AUTH_START..]);
|
c.crypt_in_place(&mut pkt_assembled[RekeyInit::ENC_START..RekeyInit::AUTH_START]);
|
||||||
key.return_receive_cipher(c);
|
let aead_authentication_ok = c.finish_decrypt(&pkt_assembled[RekeyInit::AUTH_START..]);
|
||||||
|
key.return_receive_cipher(c);
|
||||||
|
|
||||||
if aead_authentication_ok {
|
if aead_authentication_ok {
|
||||||
let pkt: &AliceRekeyInit = byte_array_as_proto_buffer(&pkt_assembled).unwrap();
|
let pkt: &RekeyInit = byte_array_as_proto_buffer(&pkt_assembled).unwrap();
|
||||||
if let Some(alice_e) = P384PublicKey::from_bytes(&pkt.alice_e) {
|
if let Some(alice_e) = P384PublicKey::from_bytes(&pkt.alice_e) {
|
||||||
let bob_e_secret = P384KeyPair::generate();
|
let bob_e_secret = P384KeyPair::generate();
|
||||||
let next_session_key = Secret(hmac_sha512(
|
let next_session_key = Secret(hmac_sha512(
|
||||||
key.ratchet_key.as_bytes(),
|
key.ratchet_key.as_bytes(),
|
||||||
bob_e_secret.agree(&alice_e).ok_or(Error::FailedAuthentication)?.as_bytes(),
|
bob_e_secret.agree(&alice_e).ok_or(Error::FailedAuthentication)?.as_bytes(),
|
||||||
));
|
));
|
||||||
|
|
||||||
let mut reply_buf = [0u8; BobRekeyAck::SIZE];
|
let mut reply_buf = [0u8; RekeyAck::SIZE];
|
||||||
let reply: &mut BobRekeyAck = byte_array_as_proto_buffer_mut(&mut reply_buf).unwrap();
|
let reply: &mut RekeyAck = byte_array_as_proto_buffer_mut(&mut reply_buf).unwrap();
|
||||||
reply.bob_e = *bob_e_secret.public_key_bytes();
|
reply.session_protocol_version = SESSION_PROTOCOL_VERSION;
|
||||||
reply.next_key_fingerprint = SHA384::hash(next_session_key.as_bytes());
|
reply.bob_e = *bob_e_secret.public_key_bytes();
|
||||||
|
reply.next_key_fingerprint = SHA384::hash(next_session_key.as_bytes());
|
||||||
|
|
||||||
let counter = session.get_next_outgoing_counter().ok_or(Error::MaxKeyLifetimeExceeded)?;
|
let counter = session.get_next_outgoing_counter().ok_or(Error::MaxKeyLifetimeExceeded)?.get();
|
||||||
let mut c = key.get_send_cipher(counter.get())?;
|
set_packet_header(
|
||||||
c.reset_init_gcm(&create_message_nonce(PACKET_TYPE_BOB_REKEY_ACK, counter.get()));
|
&mut reply_buf,
|
||||||
c.crypt_in_place(&mut reply_buf[BobRekeyAck::ENC_START..BobRekeyAck::AUTH_START]);
|
1,
|
||||||
reply_buf[BobRekeyAck::AUTH_START..].copy_from_slice(&c.finish_encrypt());
|
0,
|
||||||
key.return_send_cipher(c);
|
PACKET_TYPE_REKEY_ACK,
|
||||||
|
u64::from(remote_session_id),
|
||||||
|
state.current_key,
|
||||||
|
counter,
|
||||||
|
);
|
||||||
|
|
||||||
send(Some(&session), &mut reply_buf);
|
let mut c = key.get_send_cipher(counter)?;
|
||||||
|
c.reset_init_gcm(&create_message_nonce(PACKET_TYPE_REKEY_ACK, counter));
|
||||||
|
c.crypt_in_place(&mut reply_buf[RekeyAck::ENC_START..RekeyAck::AUTH_START]);
|
||||||
|
reply_buf[RekeyAck::AUTH_START..].copy_from_slice(&c.finish_encrypt());
|
||||||
|
key.return_send_cipher(c);
|
||||||
|
|
||||||
// The new "Bob" doesn't know yet if Alice has received the new key, so the
|
session.header_protection_cipher.encrypt_block_in_place(
|
||||||
// new key is recorded as the "alt" (key_index ^ 1) but the current key is
|
&mut reply_buf[HEADER_PROTECT_ENCRYPT_START..HEADER_PROTECT_ENCRYPT_END],
|
||||||
// not advanced yet. This happens automatically the first time we receive a
|
);
|
||||||
// valid packet with the new key.
|
send(Some(&session), &mut reply_buf);
|
||||||
let next_ratchet_count = key.ratchet_count + 1;
|
|
||||||
drop(state);
|
|
||||||
let mut state = session.state.write().unwrap();
|
|
||||||
let _ = state.keys[key_index ^ 1].replace(SessionKey::new::<Application>(
|
|
||||||
next_session_key,
|
|
||||||
next_ratchet_count,
|
|
||||||
current_time,
|
|
||||||
counter.get(),
|
|
||||||
false,
|
|
||||||
));
|
|
||||||
|
|
||||||
return Ok(ReceiveResult::Ok);
|
// The new "Bob" doesn't know yet if Alice has received the new key, so the
|
||||||
|
// new key is recorded as the "alt" (key_index ^ 1) but the current key is
|
||||||
|
// not advanced yet. This happens automatically the first time we receive a
|
||||||
|
// valid packet with the new key.
|
||||||
|
let next_ratchet_count = key.ratchet_count + 1;
|
||||||
|
drop(state);
|
||||||
|
let mut state = session.state.write().unwrap();
|
||||||
|
let _ = state.keys[key_index ^ 1].replace(SessionKey::new::<Application>(
|
||||||
|
next_session_key,
|
||||||
|
next_ratchet_count,
|
||||||
|
current_time,
|
||||||
|
counter,
|
||||||
|
false,
|
||||||
|
));
|
||||||
|
|
||||||
|
return Ok(ReceiveResult::Ok);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return Err(Error::FailedAuthentication);
|
||||||
}
|
}
|
||||||
return Err(Error::FailedAuthentication);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Err(Error::OutOfSequence);
|
return Err(Error::OutOfSequence);
|
||||||
|
@ -1176,8 +1193,8 @@ impl<Application: ApplicationLayer> Context<Application> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PACKET_TYPE_BOB_REKEY_ACK => {
|
PACKET_TYPE_REKEY_ACK => {
|
||||||
if pkt_assembled.len() != BobRekeyAck::SIZE {
|
if pkt_assembled.len() != RekeyAck::SIZE {
|
||||||
return Err(Error::InvalidPacket);
|
return Err(Error::InvalidPacket);
|
||||||
}
|
}
|
||||||
if incoming.is_some() {
|
if incoming.is_some() {
|
||||||
|
@ -1192,12 +1209,12 @@ impl<Application: ApplicationLayer> Context<Application> {
|
||||||
if key.bob {
|
if key.bob {
|
||||||
let mut c = key.get_receive_cipher();
|
let mut c = key.get_receive_cipher();
|
||||||
c.reset_init_gcm(&incoming_message_nonce);
|
c.reset_init_gcm(&incoming_message_nonce);
|
||||||
c.crypt_in_place(&mut pkt_assembled[BobRekeyAck::ENC_START..BobRekeyAck::AUTH_START]);
|
c.crypt_in_place(&mut pkt_assembled[RekeyAck::ENC_START..RekeyAck::AUTH_START]);
|
||||||
let aead_authentication_ok = c.finish_decrypt(&pkt_assembled[BobRekeyAck::AUTH_START..]);
|
let aead_authentication_ok = c.finish_decrypt(&pkt_assembled[RekeyAck::AUTH_START..]);
|
||||||
key.return_receive_cipher(c);
|
key.return_receive_cipher(c);
|
||||||
|
|
||||||
if aead_authentication_ok {
|
if aead_authentication_ok {
|
||||||
let pkt: &BobRekeyAck = byte_array_as_proto_buffer(&pkt_assembled).unwrap();
|
let pkt: &RekeyAck = byte_array_as_proto_buffer(&pkt_assembled).unwrap();
|
||||||
if let Some(bob_e) = P384PublicKey::from_bytes(&pkt.bob_e) {
|
if let Some(bob_e) = P384PublicKey::from_bytes(&pkt.bob_e) {
|
||||||
let next_session_key = Secret(hmac_sha512(
|
let next_session_key = Secret(hmac_sha512(
|
||||||
key.ratchet_key.as_bytes(),
|
key.ratchet_key.as_bytes(),
|
||||||
|
@ -1333,8 +1350,9 @@ impl<Application: ApplicationLayer> Session<Application> {
|
||||||
fn initiate_rekey<SendFunction: FnMut(&mut [u8])>(&self, mut send: SendFunction, current_time: i64) {
|
fn initiate_rekey<SendFunction: FnMut(&mut [u8])>(&self, mut send: SendFunction, current_time: i64) {
|
||||||
let rekey_e = P384KeyPair::generate();
|
let rekey_e = P384KeyPair::generate();
|
||||||
|
|
||||||
let mut rekey_buf = [0u8; AliceRekeyInit::SIZE];
|
let mut rekey_buf = [0u8; RekeyInit::SIZE];
|
||||||
let pkt: &mut AliceRekeyInit = byte_array_as_proto_buffer_mut(&mut rekey_buf).unwrap();
|
let pkt: &mut RekeyInit = byte_array_as_proto_buffer_mut(&mut rekey_buf).unwrap();
|
||||||
|
pkt.session_protocol_version = SESSION_PROTOCOL_VERSION;
|
||||||
pkt.alice_e = *rekey_e.public_key_bytes();
|
pkt.alice_e = *rekey_e.public_key_bytes();
|
||||||
|
|
||||||
let state = self.state.read().unwrap();
|
let state = self.state.read().unwrap();
|
||||||
|
@ -1342,9 +1360,9 @@ impl<Application: ApplicationLayer> Session<Application> {
|
||||||
if let Some(key) = state.keys[state.current_key].as_ref() {
|
if let Some(key) = state.keys[state.current_key].as_ref() {
|
||||||
if let Some(counter) = self.get_next_outgoing_counter() {
|
if let Some(counter) = self.get_next_outgoing_counter() {
|
||||||
if let Ok(mut gcm) = key.get_send_cipher(counter.get()) {
|
if let Ok(mut gcm) = key.get_send_cipher(counter.get()) {
|
||||||
gcm.reset_init_gcm(&create_message_nonce(PACKET_TYPE_ALICE_REKEY_INIT, counter.get()));
|
gcm.reset_init_gcm(&create_message_nonce(PACKET_TYPE_REKEY_INIT, counter.get()));
|
||||||
gcm.crypt_in_place(&mut rekey_buf[AliceRekeyInit::ENC_START..AliceRekeyInit::AUTH_START]);
|
gcm.crypt_in_place(&mut rekey_buf[RekeyInit::ENC_START..RekeyInit::AUTH_START]);
|
||||||
rekey_buf[AliceRekeyInit::AUTH_START..].copy_from_slice(&gcm.finish_encrypt());
|
rekey_buf[RekeyInit::AUTH_START..].copy_from_slice(&gcm.finish_encrypt());
|
||||||
key.return_send_cipher(gcm);
|
key.return_send_cipher(gcm);
|
||||||
|
|
||||||
debug_assert!(rekey_buf.len() <= MIN_TRANSPORT_MTU);
|
debug_assert!(rekey_buf.len() <= MIN_TRANSPORT_MTU);
|
||||||
|
@ -1352,15 +1370,18 @@ impl<Application: ApplicationLayer> Session<Application> {
|
||||||
&mut rekey_buf,
|
&mut rekey_buf,
|
||||||
1,
|
1,
|
||||||
0,
|
0,
|
||||||
PACKET_TYPE_ALICE_REKEY_INIT,
|
PACKET_TYPE_REKEY_INIT,
|
||||||
u64::from(remote_session_id),
|
u64::from(remote_session_id),
|
||||||
state.current_key,
|
state.current_key,
|
||||||
counter.get(),
|
counter.get(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
drop(state);
|
||||||
|
|
||||||
|
self.header_protection_cipher
|
||||||
|
.encrypt_block_in_place(&mut rekey_buf[HEADER_PROTECT_ENCRYPT_START..HEADER_PROTECT_ENCRYPT_END]);
|
||||||
send(&mut rekey_buf);
|
send(&mut rekey_buf);
|
||||||
|
|
||||||
drop(state);
|
|
||||||
self.state.write().unwrap().current_offer = Offer::RekeyInit(rekey_e, rekey_buf, AtomicI64::new(current_time));
|
self.state.write().unwrap().current_offer = Offer::RekeyInit(rekey_e, rekey_buf, AtomicI64::new(current_time));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue