/* * Copyright (c) 2020 Doc.ai and/or its affiliates. * Copyright (c) 2015-2020 Jason A. Donenfeld . * Copyright (c) 2019-2020 Matt Dunwoodie . * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include /* This implements Noise_IKpsk2: * * <- s * ****** * -> e, es, s, ss, {t} * <- e, ee, se, psk, {} */ noise_local_t *noise_local_pool; /* Private functions */ static noise_keypair_t *noise_remote_keypair_allocate (noise_remote_t *); static void noise_remote_keypair_free (vlib_main_t * vm, noise_remote_t *, noise_keypair_t **); static uint32_t noise_remote_handshake_index_get (vlib_main_t *vm, noise_remote_t *); static void noise_remote_handshake_index_drop (vlib_main_t *vm, noise_remote_t *); static uint64_t noise_counter_send (noise_counter_t *); bool noise_counter_recv (noise_counter_t *, uint64_t); static void noise_kdf (uint8_t *, uint8_t *, uint8_t *, const uint8_t *, size_t, size_t, size_t, size_t, const uint8_t[NOISE_HASH_LEN]); static bool noise_mix_dh (uint8_t[NOISE_HASH_LEN], uint8_t[NOISE_SYMMETRIC_KEY_LEN], const uint8_t[NOISE_PUBLIC_KEY_LEN], const uint8_t[NOISE_PUBLIC_KEY_LEN]); static bool noise_mix_ss (uint8_t ck[NOISE_HASH_LEN], uint8_t key[NOISE_SYMMETRIC_KEY_LEN], const uint8_t ss[NOISE_PUBLIC_KEY_LEN]); static void noise_mix_hash (uint8_t[NOISE_HASH_LEN], const uint8_t *, size_t); static void noise_mix_psk (uint8_t[NOISE_HASH_LEN], uint8_t[NOISE_HASH_LEN], uint8_t[NOISE_SYMMETRIC_KEY_LEN], const uint8_t[NOISE_SYMMETRIC_KEY_LEN]); static void noise_param_init (uint8_t[NOISE_HASH_LEN], uint8_t[NOISE_HASH_LEN], const uint8_t[NOISE_PUBLIC_KEY_LEN]); static void noise_msg_encrypt (vlib_main_t * vm, uint8_t *, uint8_t *, size_t, uint32_t key_idx, uint8_t[NOISE_HASH_LEN]); static bool noise_msg_decrypt (vlib_main_t * vm, uint8_t *, uint8_t *, size_t, uint32_t key_idx, uint8_t[NOISE_HASH_LEN]); static void noise_msg_ephemeral (uint8_t[NOISE_HASH_LEN], uint8_t[NOISE_HASH_LEN], const uint8_t src[NOISE_PUBLIC_KEY_LEN]); static void noise_tai64n_now (uint8_t[NOISE_TIMESTAMP_LEN]); /* Set/Get noise parameters */ void noise_local_init (noise_local_t * l, struct noise_upcall *upcall) { clib_memset (l, 0, sizeof (*l)); l->l_upcall = *upcall; } bool noise_local_set_private (noise_local_t * l, const uint8_t private[NOISE_PUBLIC_KEY_LEN]) { clib_memcpy (l->l_private, private, NOISE_PUBLIC_KEY_LEN); return curve25519_gen_public (l->l_public, private); } void noise_remote_init (vlib_main_t *vm, noise_remote_t *r, uint32_t peer_pool_idx, const uint8_t public[NOISE_PUBLIC_KEY_LEN], u32 noise_local_idx) { clib_memset (r, 0, sizeof (*r)); clib_memcpy (r->r_public, public, NOISE_PUBLIC_KEY_LEN); clib_rwlock_init (&r->r_keypair_lock); r->r_peer_idx = peer_pool_idx; r->r_local_idx = noise_local_idx; r->r_handshake.hs_state = HS_ZEROED; noise_remote_precompute (vm, r); } void noise_remote_precompute (vlib_main_t *vm, noise_remote_t *r) { noise_local_t *l = noise_local_get (r->r_local_idx); if (!curve25519_gen_shared (r->r_ss, l->l_private, r->r_public)) clib_memset (r->r_ss, 0, NOISE_PUBLIC_KEY_LEN); noise_remote_handshake_index_drop (vm, r); wg_secure_zero_memory (&r->r_handshake, sizeof (r->r_handshake)); } /* Handshake functions */ bool noise_create_initiation (vlib_main_t * vm, noise_remote_t * r, uint32_t * s_idx, uint8_t ue[NOISE_PUBLIC_KEY_LEN], uint8_t es[NOISE_PUBLIC_KEY_LEN + NOISE_AUTHTAG_LEN], uint8_t ets[NOISE_TIMESTAMP_LEN + NOISE_AUTHTAG_LEN]) { noise_handshake_t *hs = &r->r_handshake; noise_local_t *l = noise_local_get (r->r_local_idx); uint8_t _key[NOISE_SYMMETRIC_KEY_LEN] = { 0 }; uint32_t key_idx; uint8_t *key; int ret = false; key_idx = vnet_crypto_key_add (vm, VNET_CRYPTO_ALG_CHACHA20_POLY1305, _key, NOISE_SYMMETRIC_KEY_LEN); key = vnet_crypto_get_key (key_idx)->data; noise_param_init (hs->hs_ck, hs->hs_hash, r->r_public); /* e */ curve25519_gen_secret (hs->hs_e); if (!curve25519_gen_public (ue, hs->hs_e)) goto error; noise_msg_ephemeral (hs->hs_ck, hs->hs_hash, ue); /* es */ if (!noise_mix_dh (hs->hs_ck, key, hs->hs_e, r->r_public)) goto error; vnet_crypto_key_update (vm, key_idx); /* s */ noise_msg_encrypt (vm, es, l->l_public, NOISE_PUBLIC_KEY_LEN, key_idx, hs->hs_hash); /* ss */ if (!noise_mix_ss (hs->hs_ck, key, r->r_ss)) goto error; vnet_crypto_key_update (vm, key_idx); /* {t} */ noise_tai64n_now (ets); noise_msg_encrypt (vm, ets, ets, NOISE_TIMESTAMP_LEN, key_idx, hs->hs_hash); noise_remote_handshake_index_drop (vm, r); hs->hs_state = CREATED_INITIATION; hs->hs_local_index = noise_remote_handshake_index_get (vm, r); *s_idx = hs->hs_local_index; ret = true; error: wg_secure_zero_memory (key, NOISE_SYMMETRIC_KEY_LEN); vnet_crypto_key_del (vm, key_idx); return ret; } bool noise_consume_initiation (vlib_main_t * vm, noise_local_t * l, noise_remote_t ** rp, uint32_t s_idx, uint8_t ue[NOISE_PUBLIC_KEY_LEN], uint8_t es[NOISE_PUBLIC_KEY_LEN + NOISE_AUTHTAG_LEN], uint8_t ets[NOISE_TIMESTAMP_LEN + NOISE_AUTHTAG_LEN]) { noise_remote_t *r; noise_handshake_t hs; uint8_t _key[NOISE_SYMMETRIC_KEY_LEN] = { 0 }; uint8_t r_public[NOISE_PUBLIC_KEY_LEN] = { 0 }; uint8_t timestamp[NOISE_TIMESTAMP_LEN] = { 0 }; u32 key_idx; uint8_t *key; int ret = false; key_idx = vnet_crypto_key_add (vm, VNET_CRYPTO_ALG_CHACHA20_POLY1305, _key, NOISE_SYMMETRIC_KEY_LEN); key = vnet_crypto_get_key (key_idx)->data; noise_param_init (hs.hs_ck, hs.hs_hash, l->l_public); /* e */ noise_msg_ephemeral (hs.hs_ck, hs.hs_hash, ue); /* es */ if (!noise_mix_dh (hs.hs_ck, key, l->l_private, ue)) goto error; vnet_crypto_key_update (vm, key_idx); /* s */ if (!noise_msg_decrypt (vm, r_public, es, NOISE_PUBLIC_KEY_LEN + NOISE_AUTHTAG_LEN, key_idx, hs.hs_hash)) goto error; /* Lookup the remote we received from */ if ((r = l->l_upcall.u_remote_get (r_public)) == NULL) goto error; /* ss */ if (!noise_mix_ss (hs.hs_ck, key, r->r_ss)) goto error; vnet_crypto_key_update (vm, key_idx); /* {t} */ if (!noise_msg_decrypt (vm, timestamp, ets, NOISE_TIMESTAMP_LEN + NOISE_AUTHTAG_LEN, key_idx, hs.hs_hash)) goto error; ; hs.hs_state = CONSUMED_INITIATION; hs.hs_local_index = 0; hs.hs_remote_index = s_idx; clib_memcpy (hs.hs_e, ue, NOISE_PUBLIC_KEY_LEN); /* Replay */ if (clib_memcmp (timestamp, r->r_timestamp, NOISE_TIMESTAMP_LEN) > 0) clib_memcpy (r->r_timestamp, timestamp, NOISE_TIMESTAMP_LEN); else goto error; /* Flood attack */ if (wg_birthdate_has_expired (r->r_last_init, REJECT_INTERVAL)) r->r_last_init = vlib_time_now (vm); else goto error; /* Ok, we're happy to accept this initiation now */ noise_remote_handshake_index_drop (vm, r); r->r_handshake = hs; *rp = r; ret = true; error: wg_secure_zero_memory (key, NOISE_SYMMETRIC_KEY_LEN); vnet_crypto_key_del (vm, key_idx); wg_secure_zero_memory (&hs, sizeof (hs)); return ret; } bool noise_create_response (vlib_main_t * vm, noise_remote_t * r, uint32_t * s_idx, uint32_t * r_idx, uint8_t ue[NOISE_PUBLIC_KEY_LEN], uint8_t en[0 + NOISE_AUTHTAG_LEN]) { noise_handshake_t *hs = &r->r_handshake; uint8_t _key[NOISE_SYMMETRIC_KEY_LEN] = { 0 }; uint8_t e[NOISE_PUBLIC_KEY_LEN] = { 0 }; uint32_t key_idx; uint8_t *key; int ret = false; key_idx = vnet_crypto_key_add (vm, VNET_CRYPTO_ALG_CHACHA20_POLY1305, _key, NOISE_SYMMETRIC_KEY_LEN); key = vnet_crypto_get_key (key_idx)->data; if (hs->hs_state != CONSUMED_INITIATION) goto error; /* e */ curve25519_gen_secret (e); if (!curve25519_gen_public (ue, e)) goto error; noise_msg_ephemeral (hs->hs_ck, hs->hs_hash, ue); /* ee */ if (!noise_mix_dh (hs->hs_ck, NULL, e, hs->hs_e)) goto error; /* se */ if (!noise_mix_dh (hs->hs_ck, NULL, e, r->r_public)) goto error; /* psk */ noise_mix_psk (hs->hs_ck, hs->hs_hash, key, r->r_psk); vnet_crypto_key_update (vm, key_idx); /* {} */ noise_msg_encrypt (vm, en, NULL, 0, key_idx, hs->hs_hash); hs->hs_state = CREATED_RESPONSE; hs->hs_local_index = noise_remote_handshake_index_get (vm, r); *r_idx = hs->hs_remote_index; *s_idx = hs->hs_local_index; ret = true; error: wg_secure_zero_memory (key, NOISE_SYMMETRIC_KEY_LEN); vnet_crypto_key_del (vm, key_idx); wg_secure_zero_memory (e, NOISE_PUBLIC_KEY_LEN); return ret; } bool noise_consume_response (vlib_main_t * vm, noise_remote_t * r, uint32_t s_idx, uint32_t r_idx, uint8_t ue[NOISE_PUBLIC_KEY_LEN], uint8_t en[0 + NOISE_AUTHTAG_LEN]) { noise_local_t *l = noise_local_get (r->r_local_idx); noise_handshake_t hs; uint8_t _key[NOISE_SYMMETRIC_KEY_LEN] = { 0 }; uint8_t preshared_key[NOISE_PUBLIC_KEY_LEN] = { 0 }; uint32_t key_idx; uint8_t *key; int ret = false; key_idx = vnet_crypto_key_add (vm, VNET_CRYPTO_ALG_CHACHA20_POLY1305, _key, NOISE_SYMMETRIC_KEY_LEN); key = vnet_crypto_get_key (key_idx)->data; hs = r->r_handshake; clib_memcpy (preshared_key, r->r_psk, NOISE_SYMMETRIC_KEY_LEN); if (hs.hs_state != CREATED_INITIATION || hs.hs_local_index != r_idx) goto error; /* e */ noise_msg_ephemeral (hs.hs_ck, hs.hs_hash, ue); /* ee */ if (!noise_mix_dh (hs.hs_ck, NULL, hs.hs_e, ue)) goto error; /* se */ if (!noise_mix_dh (hs.hs_ck, NULL, l->l_private, ue)) goto error; /* psk */ noise_mix_psk (hs.hs_ck, hs.hs_hash, key, preshared_key); vnet_crypto_key_update (vm, key_idx); /* {} */ if (!noise_msg_decrypt (vm, NULL, en, 0 + NOISE_AUTHTAG_LEN, key_idx, hs.hs_hash)) goto error; hs.hs_remote_index = s_idx; if (r->r_handshake.hs_state == hs.hs_state && r->r_handshake.hs_local_index == hs.hs_local_index) { r->r_handshake = hs; r->r_handshake.hs_state = CONSUMED_RESPONSE; ret = true; } error: wg_secure_zero_memory (&hs, sizeof (hs)); wg_secure_zero_memory (key, NOISE_SYMMETRIC_KEY_LEN); vnet_crypto_key_del (vm, key_idx); return ret; } bool noise_remote_begin_session (vlib_main_t * vm, noise_remote_t * r) { noise_handshake_t *hs = &r->r_handshake; noise_keypair_t kp, *next, *current, *previous; uint8_t key_send[NOISE_SYMMETRIC_KEY_LEN]; uint8_t key_recv[NOISE_SYMMETRIC_KEY_LEN]; /* We now derive the keypair from the handshake */ if (hs->hs_state == CONSUMED_RESPONSE) { kp.kp_is_initiator = 1; noise_kdf (key_send, key_recv, NULL, NULL, NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, 0, hs->hs_ck); } else if (hs->hs_state == CREATED_RESPONSE) { kp.kp_is_initiator = 0; noise_kdf (key_recv, key_send, NULL, NULL, NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, 0, hs->hs_ck); } else { return false; } kp.kp_valid = 1; kp.kp_send_index = vnet_crypto_key_add (vm, VNET_CRYPTO_ALG_CHACHA20_POLY1305, key_send, NOISE_SYMMETRIC_KEY_LEN); kp.kp_recv_index = vnet_crypto_key_add (vm, VNET_CRYPTO_ALG_CHACHA20_POLY1305, key_recv, NOISE_SYMMETRIC_KEY_LEN); kp.kp_local_index = hs->hs_local_index; kp.kp_remote_index = hs->hs_remote_index; kp.kp_birthdate = vlib_time_now (vm); clib_memset (&kp.kp_ctr, 0, sizeof (kp.kp_ctr)); /* Now we need to add_new_keypair */ clib_rwlock_writer_lock (&r->r_keypair_lock); /* Activate barrier to synchronization keys between threads */ vlib_worker_thread_barrier_sync (vm); next = r->r_next; current = r->r_current; previous = r->r_previous; if (kp.kp_is_initiator) { if (next != NULL) { r->r_next = NULL; r->r_previous = next; noise_remote_keypair_free (vm, r, ¤t); } else { r->r_previous = current; } noise_remote_keypair_free (vm, r, &previous); r->r_current = noise_remote_keypair_allocate (r); *r->r_current = kp; } else { noise_remote_keypair_free (vm, r, &next); r->r_previous = NULL; noise_remote_keypair_free (vm, r, &previous); r->r_next = noise_remote_keypair_allocate (r); *r->r_next = kp; } vlib_worker_thread_barrier_release (vm); clib_rwlock_writer_unlock (&r->r_keypair_lock); wg_secure_zero_memory (&r->r_handshake, sizeof (r->r_handshake)); wg_secure_zero_memory (&kp, sizeof (kp)); return true; } void noise_remote_clear (vlib_main_t * vm, noise_remote_t * r) { noise_remote_handshake_index_drop (vm, r); wg_secure_zero_memory (&r->r_handshake, sizeof (r->r_handshake)); clib_rwlock_writer_lock (&r->r_keypair_lock); noise_remote_keypair_free (vm, r, &r->r_next); noise_remote_keypair_free (vm, r, &r->r_current); noise_remote_keypair_free (vm, r, &r->r_previous); r->r_next = NULL; r->r_current = NULL; r->r_previous = NULL; clib_rwlock_writer_unlock (&r->r_keypair_lock); } void noise_remote_expire_current (noise_remote_t * r) { clib_rwlock_writer_lock (&r->r_keypair_lock); if (r->r_next != NULL) r->r_next->kp_valid = 0; if (r->r_current != NULL) r->r_current->kp_valid = 0; clib_rwlock_writer_unlock (&r->r_keypair_lock); } bool noise_remote_ready (noise_remote_t * r) { noise_keypair_t *kp; int ret; clib_rwlock_reader_lock (&r->r_keypair_lock); if ((kp = r->r_current) == NULL || !kp->kp_valid || wg_birthdate_has_expired (kp->kp_birthdate, REJECT_AFTER_TIME) || kp->kp_ctr.c_recv >= REJECT_AFTER_MESSAGES || kp->kp_ctr.c_send >= REJECT_AFTER_MESSAGES) ret = false; else ret = true; clib_rwlock_reader_unlock (&r->r_keypair_lock); return ret; } enum noise_state_crypt noise_remote_encrypt (vlib_main_t * vm, noise_remote_t * r, uint32_t * r_idx, uint64_t * nonce, uint8_t * src, size_t srclen, uint8_t * dst) { noise_keypair_t *kp; enum noise_state_crypt ret = SC_FAILED; if ((kp = r->r_current) == NULL) goto error; /* We confirm that our values are within our tolerances. We want: * - a valid keypair * - our keypair to be less than REJECT_AFTER_TIME seconds old * - our receive counter to be less than REJECT_AFTER_MESSAGES * - our send counter to be less than REJECT_AFTER_MESSAGES */ if (!kp->kp_valid || wg_birthdate_has_expired (kp->kp_birthdate, REJECT_AFTER_TIME) || kp->kp_ctr.c_recv >= REJECT_AFTER_MESSAGES || ((*nonce = noise_counter_send (&kp->kp_ctr)) > REJECT_AFTER_MESSAGES)) goto error; /* We encrypt into the same buffer, so the caller must ensure that buf * has NOISE_AUTHTAG_LEN bytes to store the MAC. The nonce and index * are passed back out to the caller through the provided data pointer. */ *r_idx = kp->kp_remote_index; wg_chacha20poly1305_calc (vm, src, srclen, dst, NULL, 0, *nonce, VNET_CRYPTO_OP_CHACHA20_POLY1305_ENC, kp->kp_send_index); /* If our values are still within tolerances, but we are approaching * the tolerances, we notify the caller with ESTALE that they should * establish a new keypair. The current keypair can continue to be used * until the tolerances are hit. We notify if: * - our send counter is valid and not less than REKEY_AFTER_MESSAGES * - we're the initiator and our keypair is older than * REKEY_AFTER_TIME seconds */ ret = SC_KEEP_KEY_FRESH; if ((kp->kp_valid && *nonce >= REKEY_AFTER_MESSAGES) || (kp->kp_is_initiator && wg_birthdate_has_expired (kp->kp_birthdate, REKEY_AFTER_TIME))) goto error; ret = SC_OK; error: return ret; } /* Private functions - these should not be called outside this file under any * circumstances. */ static noise_keypair_t * noise_remote_keypair_allocate (noise_remote_t * r) { noise_keypair_t *kp; kp = clib_mem_alloc (sizeof (*kp)); return kp; } static uint32_t noise_remote_handshake_index_get (vlib_main_t *vm, noise_remote_t *r) { noise_local_t *local = noise_local_get (r->r_local_idx); struct noise_upcall *u = &local->l_upcall; return u->u_index_set (vm, r); } static void noise_remote_handshake_index_drop (vlib_main_t *vm, noise_remote_t *r) { noise_handshake_t *hs = &r->r_handshake; noise_local_t *local = noise_local_get (r->r_local_idx); struct noise_upcall *u = &local->l_upcall; if (hs->hs_state != HS_ZEROED) u->u_index_drop (vm, hs->hs_local_index); } static void noise_kdf (uint8_t * a, uint8_t * b, uint8_t * c, const uint8_t * x, size_t a_len, size_t b_len, size_t c_len, size_t x_len, const uint8_t ck[NOISE_HASH_LEN]) { uint8_t out[BLAKE2S_HASH_SIZE + 1]; uint8_t sec[BLAKE2S_HASH_SIZE]; /* Extract entropy from "x" into sec */ u32 l = 0; HMAC (EVP_blake2s256 (), ck, NOISE_HASH_LEN, x, x_len, sec, &l); ASSERT (l == BLAKE2S_HASH_SIZE); if (a == NULL || a_len == 0) goto out; /* Expand first key: key = sec, data = 0x1 */ out[0] = 1; HMAC (EVP_blake2s256 (), sec, BLAKE2S_HASH_SIZE, out, 1, out, &l); ASSERT (l == BLAKE2S_HASH_SIZE); clib_memcpy (a, out, a_len); if (b == NULL || b_len == 0) goto out; /* Expand second key: key = sec, data = "a" || 0x2 */ out[BLAKE2S_HASH_SIZE] = 2; HMAC (EVP_blake2s256 (), sec, BLAKE2S_HASH_SIZE, out, BLAKE2S_HASH_SIZE + 1, out, &l); ASSERT (l == BLAKE2S_HASH_SIZE); clib_memcpy (b, out, b_len); if (c == NULL || c_len == 0) goto out; /* Expand third key: key = sec, data = "b" || 0x3 */ out[BLAKE2S_HASH_SIZE] = 3; HMAC (EVP_blake2s256 (), sec, BLAKE2S_HASH_SIZE, out, BLAKE2S_HASH_SIZE + 1, out, &l); ASSERT (l == BLAKE2S_HASH_SIZE); clib_memcpy (c, out, c_len); out: /* Clear sensitive data from stack */ wg_secure_zero_memory (sec, BLAKE2S_HASH_SIZE); wg_secure_zero_memory (out, BLAKE2S_HASH_SIZE + 1); } static bool noise_mix_dh (uint8_t ck[NOISE_HASH_LEN], uint8_t key[NOISE_SYMMETRIC_KEY_LEN], const uint8_t private[NOISE_PUBLIC_KEY_LEN], const uint8_t public[NOISE_PUBLIC_KEY_LEN]) { uint8_t dh[NOISE_PUBLIC_KEY_LEN]; if (!curve25519_gen_shared (dh, private, public)) return false; noise_kdf (ck, key, NULL, dh, NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN, ck); wg_secure_zero_memory (dh, NOISE_PUBLIC_KEY_LEN); return true; } static bool noise_mix_ss (uint8_t ck[NOISE_HASH_LEN], uint8_t key[NOISE_SYMMETRIC_KEY_LEN], const uint8_t ss[NOISE_PUBLIC_KEY_LEN]) { static uint8_t null_point[NOISE_PUBLIC_KEY_LEN]; if (clib_memcmp (ss, null_point, NOISE_PUBLIC_KEY_LEN) == 0) return false; noise_kdf (ck, key, NULL, ss, NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN, ck); return true; } static void noise_mix_hash (uint8_t hash[NOISE_HASH_LEN], const uint8_t * src, size_t src_len) { blake2s_state_t blake; blake2s_init (&blake, NOISE_HASH_LEN); blake2s_update (&blake, hash, NOISE_HASH_LEN); blake2s_update (&blake, src, src_len); blake2s_final (&blake, hash, NOISE_HASH_LEN); } static void noise_mix_psk (uint8_t ck[NOISE_HASH_LEN], uint8_t hash[NOISE_HASH_LEN], uint8_t key[NOISE_SYMMETRIC_KEY_LEN], const uint8_t psk[NOISE_SYMMETRIC_KEY_LEN]) { uint8_t tmp[NOISE_HASH_LEN]; noise_kdf (ck, tmp, key, psk, NOISE_HASH_LEN, NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, ck); noise_mix_hash (hash, tmp, NOISE_HASH_LEN); wg_secure_zero_memory (tmp, NOISE_HASH_LEN); } static void noise_param_init (uint8_t ck[NOISE_HASH_LEN], uint8_t hash[NOISE_HASH_LEN], const uint8_t s[NOISE_PUBLIC_KEY_LEN]) { blake2s_state_t blake; blake2s (ck, NOISE_HASH_LEN, (uint8_t *) NOISE_HANDSHAKE_NAME, strlen (NOISE_HANDSHAKE_NAME), NULL, 0); blake2s_init (&blake, NOISE_HASH_LEN); blake2s_update (&blake, ck, NOISE_HASH_LEN); blake2s_update (&blake, (uint8_t *) NOISE_IDENTIFIER_NAME, strlen (NOISE_IDENTIFIER_NAME)); blake2s_final (&blake, hash, NOISE_HASH_LEN); noise_mix_hash (hash, s, NOISE_PUBLIC_KEY_LEN); } static void noise_msg_encrypt (vlib_main_t * vm, uint8_t * dst, uint8_t * src, size_t src_len, uint32_t key_idx, uint8_t hash[NOISE_HASH_LEN]) { /* Nonce always zero for Noise_IK */ wg_chacha20poly1305_calc (vm, src, src_len, dst, hash, NOISE_HASH_LEN, 0, VNET_CRYPTO_OP_CHACHA20_POLY1305_ENC, key_idx); noise_mix_hash (hash, dst, src_len + NOISE_AUTHTAG_LEN); } static bool noise_msg_decrypt (vlib_main_t * vm, uint8_t * dst, uint8_t * src, size_t src_len, uint32_t key_idx, uint8_t hash[NOISE_HASH_LEN]) { /* Nonce always zero for Noise_IK */ if (!wg_chacha20poly1305_calc (vm, src, src_len, dst, hash, NOISE_HASH_LEN, 0, VNET_CRYPTO_OP_CHACHA20_POLY1305_DEC, key_idx)) return false; noise_mix_hash (hash, src, src_len); return true; } static void noise_msg_ephemeral (uint8_t ck[NOISE_HASH_LEN], uint8_t hash[NOISE_HASH_LEN], const uint8_t src[NOISE_PUBLIC_KEY_LEN]) { noise_mix_hash (hash, src, NOISE_PUBLIC_KEY_LEN); noise_kdf (ck, NULL, NULL, src, NOISE_HASH_LEN, 0, 0, NOISE_PUBLIC_KEY_LEN, ck); } static void noise_tai64n_now (uint8_t output[NOISE_TIMESTAMP_LEN]) { uint32_t unix_sec; uint32_t unix_nanosec; uint64_t sec; uint32_t nsec; unix_time_now_nsec_fraction (&unix_sec, &unix_nanosec); /* Round down the nsec counter to limit precise timing leak. */ unix_nanosec &= REJECT_INTERVAL_MASK; /* https://cr.yp.to/libtai/tai64.html */ sec = htobe64 (0x400000000000000aULL + unix_sec); nsec = htobe32 (unix_nanosec); /* memcpy to output buffer, assuming output could be unaligned. */ clib_memcpy (output, &sec, sizeof (sec)); clib_memcpy (output + sizeof (sec), &nsec, sizeof (nsec)); } /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */