summaryrefslogtreecommitdiffstats
path: root/sys/net/wg_noise.h
diff options
context:
space:
mode:
authorMatt Dunwoodie <ncon@noconroy.net>2021-04-03 04:05:08 +1100
committerMatt Dunwoodie <ncon@noconroy.net>2021-04-13 15:47:30 +1000
commitacce302ce645ccc1a3f7f46fb2c399c611e623d8 (patch)
tree0598e731f3bd5b52f6c00b98353346f1f58594c1 /sys/net/wg_noise.h
parentAdd refcnt_take_if_gt() (diff)
downloadwireguard-openbsd-acce302ce645ccc1a3f7f46fb2c399c611e623d8.tar.xz
wireguard-openbsd-acce302ce645ccc1a3f7f46fb2c399c611e623d8.zip
Use SMR for wg_noise
While the largest change here is to use SMR for wg_noise, this was motivated by other deficiencies in the module. Primarily, the nonce operations should be performed in serial (wg_queue_out, wg_deliver_in) and not parallel (wg_encap, wg_decap). This also brings in a lock-free encrypt and decrypt path, which is nice. I suppose other improvements are that local, remote and keypair structs are opaque, so no more reaching in and fiddling with things. Unfortunately, these changes make abuse of the API easier (such as calling noise_keypair_encrypt on a keypair retrieved with noise_keypair_lookup (instead of noise_keypair_current) as they have different checks). Additionally, we have to trust that the nonce passed to noise_keypair_encrypt is non repeating (retrieved with noise_keypair_nonce_next), and noise_keypair_nonce_check is valid on received nonces. One area that could use a little bit more adjustment is the *_free functions. They are used to call a function once it is safe to free a parent datastructure (one holding struct noise_{local,remote} *). This is currently used for lifetimes in the system and allows a consumer of wg_noise to opaquely manage lifetimes based on the reference counting of noise, remote and keypair. It is fine for now, but maybe revisit later.
Diffstat (limited to 'sys/net/wg_noise.h')
-rw-r--r--sys/net/wg_noise.h200
1 files changed, 76 insertions, 124 deletions
diff --git a/sys/net/wg_noise.h b/sys/net/wg_noise.h
index a90ed617ba1..ccee48c19a4 100644
--- a/sys/net/wg_noise.h
+++ b/sys/net/wg_noise.h
@@ -33,115 +33,85 @@
#define NOISE_AUTHTAG_LEN CHACHA20POLY1305_AUTHTAG_SIZE
#define NOISE_HASH_LEN BLAKE2S_HASH_SIZE
-/* Protocol string constants */
-#define NOISE_HANDSHAKE_NAME "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"
-#define NOISE_IDENTIFIER_NAME "WireGuard v1 zx2c4 Jason@zx2c4.com"
-
-/* Constants for the counter */
-#define COUNTER_BITS_TOTAL 8192
-#define COUNTER_BITS (sizeof(unsigned long) * 8)
-#define COUNTER_NUM (COUNTER_BITS_TOTAL / COUNTER_BITS)
-#define COUNTER_WINDOW_SIZE (COUNTER_BITS_TOTAL - COUNTER_BITS)
-
-/* Constants for the keypair */
-#define REKEY_AFTER_MESSAGES (1ull << 60)
-#define REJECT_AFTER_MESSAGES (UINT64_MAX - COUNTER_WINDOW_SIZE - 1)
-#define REKEY_AFTER_TIME 120
-#define REKEY_AFTER_TIME_RECV 165
#define REJECT_AFTER_TIME 180
-#define REJECT_INTERVAL (1000000000 / 50) /* fifty times per sec */
-/* 24 = floor(log2(REJECT_INTERVAL)) */
-#define REJECT_INTERVAL_MASK (~((1ull<<24)-1))
-
-enum noise_state_hs {
- HS_ZEROED = 0,
- CREATED_INITIATION,
- CONSUMED_INITIATION,
- CREATED_RESPONSE,
- CONSUMED_RESPONSE,
-};
-
-struct noise_handshake {
- enum noise_state_hs hs_state;
- uint32_t hs_local_index;
- uint32_t hs_remote_index;
- uint8_t hs_e[NOISE_PUBLIC_KEY_LEN];
- uint8_t hs_hash[NOISE_HASH_LEN];
- uint8_t hs_ck[NOISE_HASH_LEN];
-};
-
-struct noise_counter {
- struct rwlock c_lock;
- uint64_t c_send;
- uint64_t c_recv;
- unsigned long c_backtrack[COUNTER_NUM];
-};
-
-struct noise_keypair {
- SLIST_ENTRY(noise_keypair) kp_entry;
- int kp_valid;
- int kp_is_initiator;
- uint32_t kp_local_index;
- uint32_t kp_remote_index;
- uint8_t kp_send[NOISE_SYMMETRIC_KEY_LEN];
- uint8_t kp_recv[NOISE_SYMMETRIC_KEY_LEN];
- struct timespec kp_birthdate; /* nanouptime */
- struct noise_counter kp_ctr;
-};
-
-struct noise_remote {
- uint8_t r_public[NOISE_PUBLIC_KEY_LEN];
- struct noise_local *r_local;
- uint8_t r_ss[NOISE_PUBLIC_KEY_LEN];
-
- struct rwlock r_handshake_lock;
- struct noise_handshake r_handshake;
- uint8_t r_psk[NOISE_SYMMETRIC_KEY_LEN];
- uint8_t r_timestamp[NOISE_TIMESTAMP_LEN];
- struct timespec r_last_init; /* nanouptime */
-
- struct rwlock r_keypair_lock;
- SLIST_HEAD(,noise_keypair) r_unused_keypairs;
- struct noise_keypair *r_next, *r_current, *r_previous;
- struct noise_keypair r_keypair[3]; /* 3: next, current, previous. */
-
-};
-
-struct noise_local {
- struct rwlock l_identity_lock;
- int l_has_identity;
- uint8_t l_public[NOISE_PUBLIC_KEY_LEN];
- uint8_t l_private[NOISE_PUBLIC_KEY_LEN];
-
- struct noise_upcall {
- void *u_arg;
- struct noise_remote *
- (*u_remote_get)(void *, uint8_t[NOISE_PUBLIC_KEY_LEN]);
- uint32_t
- (*u_index_set)(void *, struct noise_remote *);
- void (*u_index_drop)(void *, uint32_t);
- } l_upcall;
-};
-
-/* Set/Get noise parameters */
-void noise_local_init(struct noise_local *, struct noise_upcall *);
-void noise_local_deinit(struct noise_local *);
-void noise_local_lock_identity(struct noise_local *);
-void noise_local_unlock_identity(struct noise_local *);
-int noise_local_set_private(struct noise_local *, uint8_t[NOISE_PUBLIC_KEY_LEN]);
-int noise_local_keys(struct noise_local *, uint8_t[NOISE_PUBLIC_KEY_LEN],
+#define REKEY_TIMEOUT 5
+#define KEEPALIVE_TIMEOUT 10
+
+struct noise_local;
+struct noise_remote;
+struct noise_keypair;
+
+/* Local configuration */
+struct noise_local *
+ noise_local_alloc(void *);
+struct noise_local *
+ noise_local_ref(struct noise_local *);
+void noise_local_put(struct noise_local *);
+void noise_local_free(struct noise_local *, void (*)(struct noise_local *));
+void * noise_local_arg(struct noise_local *);
+
+void noise_local_private(struct noise_local *,
+ const uint8_t[NOISE_PUBLIC_KEY_LEN]);
+int noise_local_keys(struct noise_local *,
+ uint8_t[NOISE_PUBLIC_KEY_LEN],
uint8_t[NOISE_PUBLIC_KEY_LEN]);
-void noise_remote_init(struct noise_remote *, uint8_t[NOISE_PUBLIC_KEY_LEN],
- struct noise_local *);
-void noise_remote_set_psk(struct noise_remote *, uint8_t[NOISE_SYMMETRIC_KEY_LEN]);
-int noise_remote_keys(struct noise_remote *, uint8_t[NOISE_PUBLIC_KEY_LEN],
+/* Remote configuration */
+struct noise_remote *
+ noise_remote_alloc(struct noise_local *, void *,
+ const uint8_t[NOISE_PUBLIC_KEY_LEN],
+ const uint8_t[NOISE_SYMMETRIC_KEY_LEN]);
+struct noise_remote *
+ noise_remote_lookup(struct noise_local *, const uint8_t[NOISE_PUBLIC_KEY_LEN]);
+struct noise_remote *
+ noise_remote_index_lookup(struct noise_local *, uint32_t);
+struct noise_remote *
+ noise_remote_ref(struct noise_remote *);
+void noise_remote_put(struct noise_remote *);
+void noise_remote_free(struct noise_remote *, void (*)(struct noise_remote *));
+struct noise_local *
+ noise_remote_local(struct noise_remote *);
+void * noise_remote_arg(struct noise_remote *);
+
+void noise_remote_set_psk(struct noise_remote *,
+ const uint8_t[NOISE_SYMMETRIC_KEY_LEN]);
+int noise_remote_keys(struct noise_remote *,
+ uint8_t[NOISE_PUBLIC_KEY_LEN],
uint8_t[NOISE_SYMMETRIC_KEY_LEN]);
+int noise_remote_initiation_expired(struct noise_remote *);
+void noise_remote_handshake_clear(struct noise_remote *);
+void noise_remote_keypairs_clear(struct noise_remote *);
+
+/* Keypair functions */
+struct noise_keypair *
+ noise_keypair_lookup(struct noise_local *, uint32_t);
+struct noise_keypair *
+ noise_keypair_current(struct noise_remote *);
+struct noise_keypair *
+ noise_keypair_ref(struct noise_keypair *);
+void noise_keypair_put(struct noise_keypair *);
+
+struct noise_remote *
+ noise_keypair_remote(struct noise_keypair *);
+
+int noise_keypair_nonce_next(struct noise_keypair *, uint64_t *);
+int noise_keypair_nonce_check(struct noise_keypair *, uint64_t);
+
+int noise_keep_key_fresh_send(struct noise_remote *);
+int noise_keep_key_fresh_recv(struct noise_remote *);
+void noise_keypair_encrypt(
+ struct noise_keypair *,
+ uint32_t *r_idx,
+ uint64_t nonce,
+ uint8_t *buf,
+ size_t buflen);
+int noise_keypair_decrypt(
+ struct noise_keypair *,
+ uint64_t nonce,
+ uint8_t *buf,
+ size_t buflen);
-/* Should be called anytime noise_local_set_private is called */
-void noise_remote_precompute(struct noise_remote *);
-
-/* Cryptographic functions */
+/* Handshake functions */
int noise_create_initiation(
struct noise_remote *,
uint32_t *s_idx,
@@ -165,31 +135,13 @@ int noise_create_response(
uint8_t en[0 + NOISE_AUTHTAG_LEN]);
int noise_consume_response(
- struct noise_remote *,
+ struct noise_local *,
+ struct noise_remote **,
uint32_t s_idx,
uint32_t r_idx,
uint8_t ue[NOISE_PUBLIC_KEY_LEN],
uint8_t en[0 + NOISE_AUTHTAG_LEN]);
-int noise_remote_begin_session(struct noise_remote *);
-void noise_remote_clear(struct noise_remote *);
-void noise_remote_expire_current(struct noise_remote *);
-
-int noise_remote_ready(struct noise_remote *);
-
-int noise_remote_encrypt(
- struct noise_remote *,
- uint32_t *r_idx,
- uint64_t *nonce,
- uint8_t *buf,
- size_t buflen);
-int noise_remote_decrypt(
- struct noise_remote *,
- uint32_t r_idx,
- uint64_t nonce,
- uint8_t *buf,
- size_t buflen);
-
#ifdef WGTEST
void noise_test();
#endif /* WGTEST */