aboutsummaryrefslogtreecommitdiffstats
path: root/src/wg_noise.h
blob: 198ddd1e55e16f1d75b37bfa8e451ac41a230656 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/* SPDX-License-Identifier: ISC
 *
 * Copyright (C) 2015-2021 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
 * Copyright (C) 2019-2021 Matt Dunwoodie <ncon@noconroy.net>
 */

#ifndef __NOISE_H__
#define __NOISE_H__

#include <sys/types.h>
#include <sys/time.h>
#include <sys/rwlock.h>

#include "crypto.h"

#define NOISE_PUBLIC_KEY_LEN	CURVE25519_KEY_SIZE
#define NOISE_SYMMETRIC_KEY_LEN	CHACHA20POLY1305_KEY_SIZE
#define NOISE_TIMESTAMP_LEN	(sizeof(uint64_t) + sizeof(uint32_t))
#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_lock_identity(struct noise_local *);
void	noise_local_unlock_identity(struct noise_local *);
int	noise_local_set_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 *,
	    const uint8_t[NOISE_PUBLIC_KEY_LEN], struct noise_local *);
int	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]);

/* Should be called anytime noise_local_set_private is called */
void	noise_remote_precompute(struct noise_remote *);

/* Cryptographic functions */
int	noise_create_initiation(
	    struct noise_remote *,
	    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]);

int	noise_consume_initiation(
	    struct noise_local *,
	    struct noise_remote **,
	    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]);

int	noise_create_response(
	    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_consume_response(
	    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);

#endif /* __NOISE_H__ */