mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-08 05:23:44 +02:00
Some more renaming to make code more readable.
This commit is contained in:
parent
45bf978dcd
commit
826f0d3ab5
2 changed files with 83 additions and 78 deletions
|
@ -52,10 +52,10 @@ pub(crate) const REKEY_AFTER_TIME_MS_MAX_JITTER: u32 = 1000 * 60 * 10; // 10 min
|
|||
pub(crate) const SESSION_PROTOCOL_VERSION: u8 = 0x00;
|
||||
|
||||
/// Secondary key type: none, use only P-384 for forward secrecy.
|
||||
pub(crate) const E1_TYPE_NONE: u8 = 0;
|
||||
pub(crate) const HYBRID_KEY_TYPE_NONE: u8 = 0;
|
||||
|
||||
/// Secondary key type: Kyber1024, PQ forward secrecy enabled.
|
||||
pub(crate) const E1_TYPE_KYBER1024: u8 = 1;
|
||||
pub(crate) const HYBRID_KEY_TYPE_KYBER1024: u8 = 1;
|
||||
|
||||
/// Size of packet header
|
||||
pub(crate) const HEADER_SIZE: usize = 16;
|
||||
|
|
157
zssp/src/zssp.rs
157
zssp/src/zssp.rs
|
@ -35,7 +35,7 @@ pub enum Error {
|
|||
/// Packet failed one or more authentication (MAC) checks
|
||||
FailedAuthentication,
|
||||
|
||||
/// New session was rejected via Host::check_new_session_attempt or Host::accept_new_session.
|
||||
/// New session was rejected by the application layer.
|
||||
NewSessionRejected,
|
||||
|
||||
/// Rekeying failed and session secret has reached its hard usage count limit
|
||||
|
@ -56,7 +56,10 @@ pub enum Error {
|
|||
/// Data object is too large to send, even with fragmentation
|
||||
DataTooLarge,
|
||||
|
||||
/// An unexpected buffer overrun occured while attempting to encode or decode a packet, this can only ever happen if exceptionally large key blobs or metadata are being used, or as the result of an internal encoding bug.
|
||||
/// An unexpected buffer overrun occured while attempting to encode or decode a packet.
|
||||
///
|
||||
/// This can only ever happen if exceptionally large key blobs or metadata are being used,
|
||||
/// or as the result of an internal encoding bug.
|
||||
UnexpectedBufferOverrun,
|
||||
}
|
||||
|
||||
|
@ -99,12 +102,12 @@ pub struct ReceiveContext<H: ApplicationLayer> {
|
|||
}
|
||||
|
||||
/// ZSSP bi-directional packet transport channel.
|
||||
pub struct Session<Layer: ApplicationLayer> {
|
||||
pub struct Session<Application: ApplicationLayer> {
|
||||
/// This side's session ID (unique on this side)
|
||||
pub id: SessionId,
|
||||
|
||||
/// An arbitrary object associated with session (type defined in Host trait)
|
||||
pub user_data: Layer::SessionUserData,
|
||||
pub user_data: Application::SessionUserData,
|
||||
|
||||
send_counter: Counter, // Outgoing packet counter and nonce state
|
||||
psk: Secret<64>, // Arbitrary PSK provided by external code
|
||||
|
@ -114,7 +117,7 @@ pub struct Session<Layer: ApplicationLayer> {
|
|||
remote_s_public_blob_hash: [u8; 48], // SHA384(remote static public key blob)
|
||||
remote_s_public_raw: [u8; P384_PUBLIC_KEY_SIZE], // Remote NIST P-384 static public key
|
||||
|
||||
defrag: Mutex<RingBufferMap<u32, GatherArray<Layer::IncomingPacketBuffer, MAX_FRAGMENTS>, 8, 8>>,
|
||||
defrag: Mutex<RingBufferMap<u32, GatherArray<Application::IncomingPacketBuffer, MAX_FRAGMENTS>, 8, 8>>,
|
||||
}
|
||||
|
||||
struct SessionMutableState {
|
||||
|
@ -208,7 +211,6 @@ fn safe_write_all(buffer: &mut [u8], idx: usize, src: &[u8]) -> Result<usize, Er
|
|||
}
|
||||
}
|
||||
/// Write a variable length integer, which can consume up to 10 bytes. Uses safe_write_all to do so.
|
||||
#[inline(always)]
|
||||
fn varint_safe_write(buffer: &mut [u8], idx: usize, v: u64) -> Result<usize, Error> {
|
||||
let mut b = [0_u8; varint::VARINT_MAX_SIZE_BYTES];
|
||||
let i = varint::encode(&mut b, v);
|
||||
|
@ -227,7 +229,6 @@ fn safe_read_exact<'a>(src: &mut &'a [u8], amt: usize) -> Result<&'a [u8], Error
|
|||
}
|
||||
}
|
||||
/// Read a variable length integer, which can consume up to 10 bytes. Uses varint_safe_read to do so.
|
||||
#[inline(always)]
|
||||
fn varint_safe_read(src: &mut &[u8]) -> Result<u64, Error> {
|
||||
let (v, amt) = varint::decode(*src).ok_or(Error::InvalidPacket)?;
|
||||
let (_, b) = src.split_at(amt);
|
||||
|
@ -235,7 +236,7 @@ fn varint_safe_read(src: &mut &[u8]) -> Result<u64, Error> {
|
|||
Ok(v)
|
||||
}
|
||||
|
||||
impl<Layer: ApplicationLayer> Session<Layer> {
|
||||
impl<Application: ApplicationLayer> Session<Application> {
|
||||
/// Create a new session and send an initial key offer message to the other end.
|
||||
///
|
||||
/// * `host` - Interface to application using ZSSP
|
||||
|
@ -247,19 +248,19 @@ impl<Layer: ApplicationLayer> Session<Layer> {
|
|||
/// * `mtu` - Physical wire maximum transmition unit
|
||||
/// * `current_time` - Current monotonic time in milliseconds
|
||||
pub fn start_new<SendFunction: FnMut(&mut [u8])>(
|
||||
host: &Layer,
|
||||
app: &Application,
|
||||
mut send: SendFunction,
|
||||
local_session_id: SessionId,
|
||||
remote_s_public_blob: &[u8],
|
||||
offer_metadata: &[u8],
|
||||
psk: &Secret<64>,
|
||||
user_data: Layer::SessionUserData,
|
||||
user_data: Application::SessionUserData,
|
||||
mtu: usize,
|
||||
current_time: i64,
|
||||
) -> Result<Self, Error> {
|
||||
let bob_s_public_blob = remote_s_public_blob;
|
||||
if let Some(bob_s_public) = Layer::extract_s_public_from_raw(bob_s_public_blob) {
|
||||
if let Some(noise_ss) = host.get_local_s_keypair().agree(&bob_s_public) {
|
||||
if let Some(bob_s_public) = Application::extract_s_public_from_raw(bob_s_public_blob) {
|
||||
if let Some(noise_ss) = app.get_local_s_keypair().agree(&bob_s_public) {
|
||||
let send_counter = Counter::new();
|
||||
let bob_s_public_blob_hash = SHA384::hash(bob_s_public_blob);
|
||||
let header_check_cipher =
|
||||
|
@ -270,7 +271,7 @@ impl<Layer: ApplicationLayer> Session<Layer> {
|
|||
send_counter.next(),
|
||||
local_session_id,
|
||||
None,
|
||||
host.get_local_s_public_blob(),
|
||||
app.get_local_s_public_blob(),
|
||||
offer_metadata,
|
||||
&bob_s_public,
|
||||
&bob_s_public_blob_hash,
|
||||
|
@ -310,16 +311,16 @@ impl<Layer: ApplicationLayer> Session<Layer> {
|
|||
/// Send data over the session.
|
||||
///
|
||||
/// * `send` - Function to call to send physical packet(s)
|
||||
/// * `mtu_buffer` - A writable work buffer whose size also specifies the physical MTU
|
||||
/// * `mtu_sized_buffer` - A writable work buffer whose size also specifies the physical MTU
|
||||
/// * `data` - Data to send
|
||||
#[inline]
|
||||
pub fn send<SendFunction: FnMut(&mut [u8])>(
|
||||
&self,
|
||||
mut send: SendFunction,
|
||||
mtu_buffer: &mut [u8],
|
||||
mtu_sized_buffer: &mut [u8],
|
||||
mut data: &[u8],
|
||||
) -> Result<(), Error> {
|
||||
debug_assert!(mtu_buffer.len() >= MIN_TRANSPORT_MTU);
|
||||
debug_assert!(mtu_sized_buffer.len() >= MIN_TRANSPORT_MTU);
|
||||
let state = self.state.read().unwrap();
|
||||
if let Some(remote_session_id) = state.remote_session_id {
|
||||
if let Some(session_key) = state.session_keys[state.cur_session_key_idx].as_ref() {
|
||||
|
@ -335,9 +336,9 @@ impl<Layer: ApplicationLayer> Session<Layer> {
|
|||
|
||||
// Create initial header for first fragment of packet and place in first HEADER_SIZE bytes of buffer.
|
||||
create_packet_header(
|
||||
mtu_buffer,
|
||||
mtu_sized_buffer,
|
||||
packet_len,
|
||||
mtu_buffer.len(),
|
||||
mtu_sized_buffer.len(),
|
||||
PACKET_TYPE_DATA,
|
||||
remote_session_id.into(),
|
||||
counter,
|
||||
|
@ -350,21 +351,21 @@ impl<Layer: ApplicationLayer> Session<Layer> {
|
|||
|
||||
// Send first N-1 fragments of N total fragments.
|
||||
let last_fragment_size;
|
||||
if packet_len > mtu_buffer.len() {
|
||||
let mut header: [u8; 16] = mtu_buffer[..HEADER_SIZE].try_into().unwrap();
|
||||
let fragment_data_mtu = mtu_buffer.len() - HEADER_SIZE;
|
||||
let last_fragment_data_mtu = mtu_buffer.len() - (HEADER_SIZE + AES_GCM_TAG_SIZE);
|
||||
if packet_len > mtu_sized_buffer.len() {
|
||||
let mut header: [u8; 16] = mtu_sized_buffer[..HEADER_SIZE].try_into().unwrap();
|
||||
let fragment_data_mtu = mtu_sized_buffer.len() - HEADER_SIZE;
|
||||
let last_fragment_data_mtu = mtu_sized_buffer.len() - (HEADER_SIZE + AES_GCM_TAG_SIZE);
|
||||
loop {
|
||||
let fragment_data_size = fragment_data_mtu.min(data.len());
|
||||
let fragment_size = fragment_data_size + HEADER_SIZE;
|
||||
c.crypt(&data[..fragment_data_size], &mut mtu_buffer[HEADER_SIZE..fragment_size]);
|
||||
c.crypt(&data[..fragment_data_size], &mut mtu_sized_buffer[HEADER_SIZE..fragment_size]);
|
||||
data = &data[fragment_data_size..];
|
||||
set_header_check_code(mtu_buffer, &self.header_check_cipher);
|
||||
send(&mut mtu_buffer[..fragment_size]);
|
||||
set_header_check_code(mtu_sized_buffer, &self.header_check_cipher);
|
||||
send(&mut mtu_sized_buffer[..fragment_size]);
|
||||
|
||||
debug_assert!(header[15].wrapping_shr(2) < 63);
|
||||
header[15] += 0x04; // increment fragment number
|
||||
mtu_buffer[..HEADER_SIZE].copy_from_slice(&header);
|
||||
mtu_sized_buffer[..HEADER_SIZE].copy_from_slice(&header);
|
||||
|
||||
if data.len() <= last_fragment_data_mtu {
|
||||
break;
|
||||
|
@ -377,11 +378,11 @@ impl<Layer: ApplicationLayer> Session<Layer> {
|
|||
|
||||
// Send final fragment (or only fragment if no fragmentation was needed)
|
||||
let payload_end = data.len() + HEADER_SIZE;
|
||||
c.crypt(data, &mut mtu_buffer[HEADER_SIZE..payload_end]);
|
||||
c.crypt(data, &mut mtu_sized_buffer[HEADER_SIZE..payload_end]);
|
||||
let gcm_tag = c.finish_encrypt();
|
||||
mtu_buffer[payload_end..last_fragment_size].copy_from_slice(&gcm_tag);
|
||||
set_header_check_code(mtu_buffer, &self.header_check_cipher);
|
||||
send(&mut mtu_buffer[..last_fragment_size]);
|
||||
mtu_sized_buffer[payload_end..last_fragment_size].copy_from_slice(&gcm_tag);
|
||||
set_header_check_code(mtu_sized_buffer, &self.header_check_cipher);
|
||||
send(&mut mtu_sized_buffer[..last_fragment_size]);
|
||||
|
||||
// Check reusable AES-GCM instance back into pool.
|
||||
session_key.return_send_cipher(c);
|
||||
|
@ -425,7 +426,7 @@ impl<Layer: ApplicationLayer> Session<Layer> {
|
|||
/// * `force_rekey` - Re-key the session now regardless of key aging (still subject to rate limiting)
|
||||
pub fn service<SendFunction: FnMut(&mut [u8])>(
|
||||
&self,
|
||||
host: &Layer,
|
||||
host: &Application,
|
||||
mut send: SendFunction,
|
||||
offer_metadata: &[u8],
|
||||
mtu: usize,
|
||||
|
@ -440,7 +441,7 @@ impl<Layer: ApplicationLayer> Session<Layer> {
|
|||
&& state
|
||||
.offer
|
||||
.as_ref()
|
||||
.map_or(true, |o| (current_time - o.creation_time) > Layer::REKEY_RATE_LIMIT_MS)
|
||||
.map_or(true, |o| (current_time - o.creation_time) > Application::REKEY_RATE_LIMIT_MS)
|
||||
{
|
||||
if let Some(remote_s_public) = P384PublicKey::from_bytes(&self.remote_s_public_raw) {
|
||||
let mut offer = None;
|
||||
|
@ -474,8 +475,8 @@ impl<Layer: ApplicationLayer> Session<Layer> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Layer: ApplicationLayer> ReceiveContext<Layer> {
|
||||
pub fn new(host: &Layer) -> Self {
|
||||
impl<Application: ApplicationLayer> ReceiveContext<Application> {
|
||||
pub fn new(host: &Application) -> Self {
|
||||
Self {
|
||||
initial_offer_defrag: Mutex::new(RingBufferMap::new(random::xorshift64_random() as u32)),
|
||||
incoming_init_header_check_cipher: Aes::new(
|
||||
|
@ -495,14 +496,14 @@ impl<Layer: ApplicationLayer> ReceiveContext<Layer> {
|
|||
#[inline]
|
||||
pub fn receive<'a, SendFunction: FnMut(&mut [u8])>(
|
||||
&self,
|
||||
host: &Layer,
|
||||
remote_address: &Layer::RemoteAddress,
|
||||
app: &Application,
|
||||
remote_address: &Application::RemoteAddress,
|
||||
mut send: SendFunction,
|
||||
data_buf: &'a mut [u8],
|
||||
incoming_packet_buf: Layer::IncomingPacketBuffer,
|
||||
incoming_packet_buf: Application::IncomingPacketBuffer,
|
||||
mtu: usize,
|
||||
current_time: i64,
|
||||
) -> Result<ReceiveResult<'a, Layer>, Error> {
|
||||
) -> Result<ReceiveResult<'a, Application>, Error> {
|
||||
let incoming_packet = incoming_packet_buf.as_ref();
|
||||
if incoming_packet.len() < MIN_PACKET_SIZE {
|
||||
unlikely_branch();
|
||||
|
@ -517,7 +518,7 @@ impl<Layer: ApplicationLayer> ReceiveContext<Layer> {
|
|||
|
||||
if let Some(local_session_id) = SessionId::new_from_u64(u64::from_le(memory::load_raw(&incoming_packet[8..16])) & 0xffffffffffffu64)
|
||||
{
|
||||
if let Some(session) = host.lookup_session(local_session_id) {
|
||||
if let Some(session) = app.lookup_session(local_session_id) {
|
||||
if verify_header_check_code(incoming_packet, &session.header_check_cipher) {
|
||||
let canonical_header = CanonicalHeader::make(local_session_id, packet_type, counter);
|
||||
if fragment_count > 1 {
|
||||
|
@ -527,7 +528,7 @@ impl<Layer: ApplicationLayer> ReceiveContext<Layer> {
|
|||
if let Some(assembled_packet) = fragment_gather_array.add(fragment_no, incoming_packet_buf) {
|
||||
drop(defrag); // release lock
|
||||
return self.receive_complete(
|
||||
host,
|
||||
app,
|
||||
remote_address,
|
||||
&mut send,
|
||||
data_buf,
|
||||
|
@ -545,7 +546,7 @@ impl<Layer: ApplicationLayer> ReceiveContext<Layer> {
|
|||
}
|
||||
} else {
|
||||
return self.receive_complete(
|
||||
host,
|
||||
app,
|
||||
remote_address,
|
||||
&mut send,
|
||||
data_buf,
|
||||
|
@ -576,7 +577,7 @@ impl<Layer: ApplicationLayer> ReceiveContext<Layer> {
|
|||
if let Some(assembled_packet) = fragment_gather_array.add(fragment_no, incoming_packet_buf) {
|
||||
drop(defrag); // release lock
|
||||
return self.receive_complete(
|
||||
host,
|
||||
app,
|
||||
remote_address,
|
||||
&mut send,
|
||||
data_buf,
|
||||
|
@ -590,7 +591,7 @@ impl<Layer: ApplicationLayer> ReceiveContext<Layer> {
|
|||
}
|
||||
} else {
|
||||
return self.receive_complete(
|
||||
host,
|
||||
app,
|
||||
remote_address,
|
||||
&mut send,
|
||||
data_buf,
|
||||
|
@ -618,17 +619,17 @@ impl<Layer: ApplicationLayer> ReceiveContext<Layer> {
|
|||
#[inline]
|
||||
fn receive_complete<'a, SendFunction: FnMut(&mut [u8])>(
|
||||
&self,
|
||||
host: &Layer,
|
||||
remote_address: &Layer::RemoteAddress,
|
||||
app: &Application,
|
||||
remote_address: &Application::RemoteAddress,
|
||||
send: &mut SendFunction,
|
||||
data_buf: &'a mut [u8],
|
||||
canonical_header_bytes: &[u8; 12],
|
||||
fragments: &[Layer::IncomingPacketBuffer],
|
||||
canonical_header_bytes: &[u8; AES_GCM_TAG_SIZE],
|
||||
fragments: &[Application::IncomingPacketBuffer],
|
||||
packet_type: u8,
|
||||
session: Option<Layer::SessionRef>,
|
||||
session: Option<Application::SessionRef>,
|
||||
mtu: usize,
|
||||
current_time: i64,
|
||||
) -> Result<ReceiveResult<'a, Layer>, Error> {
|
||||
) -> Result<ReceiveResult<'a, Application>, Error> {
|
||||
debug_assert!(fragments.len() >= 1);
|
||||
|
||||
// The first 'if' below should capture both DATA and NOP but not other types. Sanity check this.
|
||||
|
@ -769,7 +770,7 @@ impl<Layer: ApplicationLayer> ReceiveContext<Layer> {
|
|||
// Check the second HMAC first, which proves that the sender knows the recipient's full static identity.
|
||||
let hmac2 = &kex_packet[hmac1_end..kex_packet_len];
|
||||
if !hmac_sha384_2(
|
||||
host.get_local_s_public_blob_hash(),
|
||||
app.get_local_s_public_blob_hash(),
|
||||
canonical_header_bytes,
|
||||
&kex_packet[HEADER_SIZE..hmac1_end],
|
||||
)
|
||||
|
@ -780,11 +781,11 @@ impl<Layer: ApplicationLayer> ReceiveContext<Layer> {
|
|||
|
||||
// Check rate limits.
|
||||
if let Some(session) = session.as_ref() {
|
||||
if (current_time - session.state.read().unwrap().last_remote_offer) < Layer::REKEY_RATE_LIMIT_MS {
|
||||
if (current_time - session.state.read().unwrap().last_remote_offer) < Application::REKEY_RATE_LIMIT_MS {
|
||||
return Err(Error::RateLimited);
|
||||
}
|
||||
} else {
|
||||
if !host.check_new_session(self, remote_address) {
|
||||
if !app.check_new_session(self, remote_address) {
|
||||
return Err(Error::RateLimited);
|
||||
}
|
||||
}
|
||||
|
@ -792,7 +793,7 @@ impl<Layer: ApplicationLayer> ReceiveContext<Layer> {
|
|||
// Key agreement: alice (remote) ephemeral NIST P-384 <> local static NIST P-384
|
||||
let alice_e_public =
|
||||
P384PublicKey::from_bytes(&kex_packet[(HEADER_SIZE + 1)..plaintext_end]).ok_or(Error::FailedAuthentication)?;
|
||||
let noise_es = host
|
||||
let noise_es = app
|
||||
.get_local_s_keypair()
|
||||
.agree(&alice_e_public)
|
||||
.ok_or(Error::FailedAuthentication)?;
|
||||
|
@ -832,10 +833,10 @@ impl<Layer: ApplicationLayer> ReceiveContext<Layer> {
|
|||
}
|
||||
|
||||
// Extract alice's static NIST P-384 public key from her public blob.
|
||||
let alice_s_public = Layer::extract_s_public_from_raw(alice_s_public_blob).ok_or(Error::InvalidPacket)?;
|
||||
let alice_s_public = Application::extract_s_public_from_raw(alice_s_public_blob).ok_or(Error::InvalidPacket)?;
|
||||
|
||||
// Key agreement: both sides' static P-384 keys.
|
||||
let noise_ss = host
|
||||
let noise_ss = app
|
||||
.get_local_s_keypair()
|
||||
.agree(&alice_s_public)
|
||||
.ok_or(Error::FailedAuthentication)?;
|
||||
|
@ -874,7 +875,7 @@ impl<Layer: ApplicationLayer> ReceiveContext<Layer> {
|
|||
let state = session.state.read().unwrap();
|
||||
for k in state.session_keys.iter() {
|
||||
if let Some(k) = k.as_ref() {
|
||||
if secret_fingerprint(k.ratchet_key.as_bytes())[..16].eq(alice_ratchet_key_fingerprint) {
|
||||
if public_fingerprint_of_secret(k.ratchet_key.as_bytes())[..16].eq(alice_ratchet_key_fingerprint) {
|
||||
ratchet_key = Some(k.ratchet_key.clone());
|
||||
ratchet_count = k.ratchet_count;
|
||||
break;
|
||||
|
@ -888,13 +889,13 @@ impl<Layer: ApplicationLayer> ReceiveContext<Layer> {
|
|||
(None, ratchet_key, ratchet_count)
|
||||
} else {
|
||||
if let Some((new_session_id, psk, associated_object)) =
|
||||
host.accept_new_session(self, remote_address, alice_s_public_blob, alice_metadata)
|
||||
app.accept_new_session(self, remote_address, alice_s_public_blob, alice_metadata)
|
||||
{
|
||||
let header_check_cipher = Aes::new(
|
||||
kbkdf512(noise_ss.as_bytes(), KBKDF_KEY_USAGE_LABEL_HEADER_CHECK).first_n::<HEADER_CHECK_AES_KEY_SIZE>(),
|
||||
);
|
||||
(
|
||||
Some(Session::<Layer> {
|
||||
Some(Session::<Application> {
|
||||
id: new_session_id,
|
||||
user_data: associated_object,
|
||||
send_counter: Counter::new(),
|
||||
|
@ -983,10 +984,10 @@ impl<Layer: ApplicationLayer> ReceiveContext<Layer> {
|
|||
idx = varint_safe_write(&mut reply_buf, idx, 0)?; // they don't need our static public; they have it
|
||||
idx = varint_safe_write(&mut reply_buf, idx, 0)?; // no meta-data in counter-offers (could be used in the future)
|
||||
if let Some(bob_hk_public) = bob_hk_public.as_ref() {
|
||||
idx = safe_write_all(&mut reply_buf, idx, &[E1_TYPE_KYBER1024])?;
|
||||
idx = safe_write_all(&mut reply_buf, idx, &[HYBRID_KEY_TYPE_KYBER1024])?;
|
||||
idx = safe_write_all(&mut reply_buf, idx, bob_hk_public)?;
|
||||
} else {
|
||||
idx = safe_write_all(&mut reply_buf, idx, &[E1_TYPE_NONE])?;
|
||||
idx = safe_write_all(&mut reply_buf, idx, &[HYBRID_KEY_TYPE_NONE])?;
|
||||
}
|
||||
if ratchet_key.is_some() {
|
||||
idx = safe_write_all(&mut reply_buf, idx, &[0x01])?;
|
||||
|
@ -1086,7 +1087,7 @@ impl<Layer: ApplicationLayer> ReceiveContext<Layer> {
|
|||
let bob_e_public = P384PublicKey::from_bytes(&kex_packet[(HEADER_SIZE + 1)..plaintext_end])
|
||||
.ok_or(Error::FailedAuthentication)?;
|
||||
let noise_ee = offer.alice_e_keypair.agree(&bob_e_public).ok_or(Error::FailedAuthentication)?;
|
||||
let noise_se = host.get_local_s_keypair().agree(&bob_e_public).ok_or(Error::FailedAuthentication)?;
|
||||
let noise_se = app.get_local_s_keypair().agree(&bob_e_public).ok_or(Error::FailedAuthentication)?;
|
||||
|
||||
let noise_ik_key = Secret(hmac_sha512(
|
||||
session.psk.as_bytes(),
|
||||
|
@ -1229,7 +1230,7 @@ fn send_ephemeral_offer<SendFunction: FnMut(&mut [u8])>(
|
|||
// Perform key agreement with the other side's static P-384 public key.
|
||||
let noise_es = alice_e_keypair.agree(bob_s_public).ok_or(Error::InvalidPacket)?;
|
||||
|
||||
// Generate a Kyber1024 pair if enabled.
|
||||
// Generate a Kyber1024 (hybrid PQ crypto) pair if enabled.
|
||||
let alice_hk_keypair = if JEDI {
|
||||
Some(pqc_kyber::keypair(&mut random::SecureRandom::get()))
|
||||
} else {
|
||||
|
@ -1268,14 +1269,14 @@ fn send_ephemeral_offer<SendFunction: FnMut(&mut [u8])>(
|
|||
idx = varint_safe_write(&mut packet_buf, idx, alice_metadata.len() as u64)?;
|
||||
idx = safe_write_all(&mut packet_buf, idx, alice_metadata)?;
|
||||
if let Some(hkp) = alice_hk_keypair {
|
||||
idx = safe_write_all(&mut packet_buf, idx, &[E1_TYPE_KYBER1024])?;
|
||||
idx = safe_write_all(&mut packet_buf, idx, &[HYBRID_KEY_TYPE_KYBER1024])?;
|
||||
idx = safe_write_all(&mut packet_buf, idx, &hkp.public)?;
|
||||
} else {
|
||||
idx = safe_write_all(&mut packet_buf, idx, &[E1_TYPE_NONE])?;
|
||||
idx = safe_write_all(&mut packet_buf, idx, &[HYBRID_KEY_TYPE_NONE])?;
|
||||
}
|
||||
if let Some(ratchet_key) = ratchet_key.as_ref() {
|
||||
idx = safe_write_all(&mut packet_buf, idx, &[0x01])?;
|
||||
idx = safe_write_all(&mut packet_buf, idx, &secret_fingerprint(ratchet_key.as_bytes())[..16])?;
|
||||
idx = safe_write_all(&mut packet_buf, idx, &public_fingerprint_of_secret(ratchet_key.as_bytes())[..16])?;
|
||||
} else {
|
||||
idx = safe_write_all(&mut packet_buf, idx, &[0x00])?;
|
||||
}
|
||||
|
@ -1362,7 +1363,7 @@ fn send_ephemeral_offer<SendFunction: FnMut(&mut [u8])>(
|
|||
/// Populate all but the header check code in the first 16 bytes of a packet or fragment.
|
||||
#[inline(always)]
|
||||
fn create_packet_header(
|
||||
header: &mut [u8],
|
||||
header_destination_buffer: &mut [u8],
|
||||
packet_len: usize,
|
||||
mtu: usize,
|
||||
packet_type: u8,
|
||||
|
@ -1371,7 +1372,7 @@ fn create_packet_header(
|
|||
) -> Result<(), Error> {
|
||||
let fragment_count = ((packet_len as f32) / (mtu - HEADER_SIZE) as f32).ceil() as usize;
|
||||
|
||||
debug_assert!(header.len() >= HEADER_SIZE);
|
||||
debug_assert!(header_destination_buffer.len() >= HEADER_SIZE);
|
||||
debug_assert!(mtu >= MIN_TRANSPORT_MTU);
|
||||
debug_assert!(packet_len >= MIN_PACKET_SIZE);
|
||||
debug_assert!(fragment_count > 0);
|
||||
|
@ -1386,11 +1387,11 @@ fn create_packet_header(
|
|||
// [112-115] packet type (0-15)
|
||||
// [116-121] number of fragments (0..63 for 1..64 fragments total)
|
||||
// [122-127] fragment number (0, 1, 2, ...)
|
||||
memory::store_raw((counter.to_u32() as u64).to_le(), header);
|
||||
memory::store_raw((counter.to_u32() as u64).to_le(), header_destination_buffer);
|
||||
memory::store_raw(
|
||||
(u64::from(recipient_session_id) | (packet_type as u64).wrapping_shl(48) | ((fragment_count - 1) as u64).wrapping_shl(52))
|
||||
.to_le(),
|
||||
&mut header[8..],
|
||||
&mut header_destination_buffer[8..],
|
||||
);
|
||||
Ok(())
|
||||
} else {
|
||||
|
@ -1464,7 +1465,7 @@ fn parse_dec_key_offer_after_header(
|
|||
let alice_metadata = safe_read_exact(&mut p, alice_metadata_len as usize)?;
|
||||
|
||||
let alice_hk_public_raw = match safe_read_exact(&mut p, 1)?[0] {
|
||||
E1_TYPE_KYBER1024 => {
|
||||
HYBRID_KEY_TYPE_KYBER1024 => {
|
||||
if packet_type == PACKET_TYPE_INITIAL_KEY_OFFER {
|
||||
safe_read_exact(&mut p, pqc_kyber::KYBER_PUBLICKEYBYTES)?
|
||||
} else {
|
||||
|
@ -1473,6 +1474,7 @@ fn parse_dec_key_offer_after_header(
|
|||
}
|
||||
_ => &[],
|
||||
};
|
||||
|
||||
if p.is_empty() {
|
||||
return Err(Error::InvalidPacket);
|
||||
}
|
||||
|
@ -1481,6 +1483,7 @@ fn parse_dec_key_offer_after_header(
|
|||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok((
|
||||
offer_id, //always 16 bytes
|
||||
alice_session_id,
|
||||
|
@ -1501,7 +1504,7 @@ impl SessionKey {
|
|||
Role::Bob => (a2b, b2a),
|
||||
};
|
||||
Self {
|
||||
secret_fingerprint: secret_fingerprint(key.as_bytes())[..16].try_into().unwrap(),
|
||||
secret_fingerprint: public_fingerprint_of_secret(key.as_bytes())[..16].try_into().unwrap(),
|
||||
establish_time: current_time,
|
||||
establish_counter: current_counter,
|
||||
lifetime: KeyLifetime::new(current_counter, current_time),
|
||||
|
@ -1599,16 +1602,18 @@ fn hmac_sha384_2(key: &[u8], a: &[u8], b: &[u8]) -> [u8; 48] {
|
|||
hmac.finish()
|
||||
}
|
||||
|
||||
/// HMAC-SHA512 key derivation function modeled on: https://csrc.nist.gov/publications/detail/sp/800-108/final (page 12)
|
||||
/// Cryptographically this isn't really different from HMAC(key, [label]) with just one byte.
|
||||
/// HMAC-SHA512 key derivation based on: https://csrc.nist.gov/publications/detail/sp/800-108/final (page 12)
|
||||
///
|
||||
/// Cryptographically this isn't meaningfully different from HMAC(key, [label]),
|
||||
/// but NIST seems to like it this way.
|
||||
fn kbkdf512(key: &[u8], label: u8) -> Secret<64> {
|
||||
Secret(hmac_sha512(key, &[0, 0, 0, 0, b'Z', b'T', label, 0, 0, 0, 0, 0x02, 0x00]))
|
||||
}
|
||||
|
||||
/// Get a hash of a secret key that can be used as a public fingerprint.
|
||||
fn secret_fingerprint(key: &[u8]) -> [u8; 48] {
|
||||
/// Get a hash of a secret that can be used as a public key fingerprint to check ratcheting during key exchange.
|
||||
fn public_fingerprint_of_secret(key: &[u8]) -> [u8; 48] {
|
||||
let mut tmp = SHA384::new();
|
||||
tmp.update("fp".as_bytes());
|
||||
tmp.update(&[0xf0, 0x0d]); // arbitrary salt
|
||||
tmp.update(key);
|
||||
tmp.finish()
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue