summaryrefslogtreecommitdiffstats
path: root/src/wireguard.h
blob: 1187eba959f63c89d54877496e4af8372aac5e50 (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
181
182
183
#ifndef _LIBWG_H_
#define _LIBWG_H_

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

#define WG_KEY_SIZE 32
#define WG_MAC_SIZE 16
#define WG_HASH_SIZE 32
#define WG_COOKIE_SIZE 16
#define WG_XNONCE_SIZE 24
#define WG_MSG_PADDING_SIZE  16
#define WG_COOKIE_RAND_VAL_SIZE 16
#define WG_COOKIE_ID_VAL_MAXSIZE 32
#define WG_TIMESTAMP_SIZE 12

#define WG_ARI_BITS (sizeof(uint64_t) * 8)
#define WG_ARB_BITS (1<<10) /* 1024 bitmap (960 usable) */

#define WG_ENCRYPTED_SIZE(n) ((n) + WG_MAC_SIZE)
#define WG_PADDING_SIZE(n) ((WG_MSG_PADDING_SIZE - (n)) % WG_MSG_PADDING_SIZE)
#define WG_ENCRYPTED_PADDED_SIZE(n) WG_ENCRYPTED_SIZE(WG_PADDED_SIZE(n)) //unused

/* Constant for session */
#define WG_REKEY_AFTER_MESSAGES (((uint64_t) 2<<48) - 1)
#define WG_REJECT_AFTER_MESSAGES (((uint64_t) 2<<60) - 1)
#define WG_REKEY_AFTER_TIME 120
#define WG_REJECT_AFTER_TIME 180
#define WG_REKEY_ATTEMPT_COUNT 20
#define WG_REKEY_TIMEOUT 5
#define WG_KEEPALIVE_TIMEOUT 10
#define WG_REKEY_AFTER_TIME_RECV (WG_REJECT_AFTER_TIME - WG_KEEPALIVE_TIMEOUT - WG_REKEY_TIMEOUT)

enum wg_role {
	WG_ROLE_UNKNOWN = 0,
	WG_ROLE_INITIATOR,
	WG_ROLE_RESPONDER,
};

enum wg_keytype {
	WG_KEY_PSK,
	WG_KEY_LOCAL,
	WG_KEY_REMOTE,
};

enum wg_pkt_type {
	WG_PKT_UNKNOWN = 0,
	WG_PKT_INITIATION,
	WG_PKT_RESPONSE,
	WG_PKT_COOKIE,
	WG_PKT_TRANSPORT,
};

struct wg_handshake {
	enum wg_role 	hs_role;
	uint32_t 	hs_local_id;
	uint32_t 	hs_remote_id;
	uint8_t 	hs_mac[WG_MAC_SIZE];
	uint8_t 	hs_hash  [WG_HASH_SIZE];
	uint8_t 	hs_ck    [WG_HASH_SIZE];
	uint8_t 	hs_k     [WG_HASH_SIZE];
	uint8_t 	hs_local_epub[WG_KEY_SIZE];
	uint8_t 	hs_local_epriv[WG_KEY_SIZE];
	uint8_t 	hs_remote_epub[WG_KEY_SIZE];
};

struct wg_antireplay {
	uint64_t 	ar_head;
	uint64_t 	ar_bitmap[WG_ARB_BITS / WG_ARI_BITS];
};

struct wg_session {
	enum wg_role 	s_role;
	struct timespec s_created;
	uint64_t 	s_txcounter;
	uint64_t 	s_rxcounter;
	struct wg_antireplay	s_ar;
	uint8_t 	s_txkey[WG_KEY_SIZE];
	uint8_t 	s_rxkey[WG_KEY_SIZE];
	uint32_t 	s_local_id;
	uint32_t 	s_remote_id;
};

struct wg_cookie {
	uint8_t	c_value[WG_COOKIE_SIZE];
	struct timespec	c_time;
};

struct wg_timestamp {
	uint8_t ts_bytes[WG_TIMESTAMP_SIZE];
};

struct wg_conn;
struct wg_upcall {
	void *u_arg;
	uint32_t (*u_getid)(void *, struct wg_conn *);
	void (*u_dropid)(void *, uint32_t);
	struct wg_conn *(*u_keylookup)(void *, uint8_t *);
	void (*u_connready)(void *, struct wg_conn *);
	uint8_t *u_pubkey, *u_privkey;
};

struct wg_keyset {
	uint8_t k_psk[WG_KEY_SIZE];
	uint8_t k_pubkey[WG_KEY_SIZE];
	uint8_t k_local_pubkey[WG_KEY_SIZE], k_local_privkey[WG_KEY_SIZE];
};

struct wg_conn {
	struct rwlock c_lock;

	struct wg_keyset c_ks;
	struct wg_handshake c_hs;
	struct wg_session c_sess, c_sess_old;
	struct wg_cookie c_cookie;
	struct wg_timestamp c_ts;
	struct wg_upcall *c_upcall;
};

struct wg_msg_unknown {
	uint32_t 	type;
} 		__packed;

struct wg_msg_initiation {
	uint32_t 	type;
	uint32_t 	sender;
	uint8_t 	ephemeral[WG_KEY_SIZE];
	uint8_t 	static_pub[WG_ENCRYPTED_SIZE(WG_KEY_SIZE)];
	uint8_t 	timestamp[WG_ENCRYPTED_SIZE(WG_TIMESTAMP_SIZE)];
	uint8_t 	mac1  [WG_MAC_SIZE];
	uint8_t 	mac2  [WG_MAC_SIZE];
} 		__packed;

struct wg_msg_response {
	uint32_t 	type;
	uint32_t 	sender;
	uint32_t 	receiver;
	uint8_t 	ephemeral[WG_KEY_SIZE];
	uint8_t 	empty [WG_ENCRYPTED_SIZE(0)];
	uint8_t 	mac1  [WG_MAC_SIZE];
	uint8_t 	mac2  [WG_MAC_SIZE];
} 		__packed;

struct wg_msg_cookie {
	uint32_t 	type;
	uint32_t 	receiver;
	uint8_t 	nonce [WG_XNONCE_SIZE];
	uint8_t 	cookie[WG_ENCRYPTED_SIZE(WG_COOKIE_SIZE)];
} 		__packed;

struct wg_msg_transport {
	uint32_t 	type;
	uint32_t 	receiver;
	uint64_t 	counter;
	uint8_t 	data  [];
} 		__packed;

void wg_conn_init(struct wg_conn *, struct wg_upcall *);
void wg_conn_reset(struct wg_conn *);
void wg_conn_setkey(struct wg_conn *, enum wg_keytype, uint8_t *);

void wg_conn_make_initiation(struct wg_conn *, struct wg_msg_initiation *);
int wg_conn_make_response(struct wg_conn *, struct wg_msg_response *);
int wg_conn_make_cookie(struct wg_conn *, struct wg_msg_cookie *);
int wg_conn_encrypt(struct wg_conn *, struct wg_msg_transport *, size_t);

struct wg_conn *wg_conn_recv_initiation(struct wg_upcall *, struct wg_msg_initiation *);
int wg_conn_recv_response(struct wg_conn *, struct wg_msg_response *);
int wg_conn_recv_cookie(struct wg_conn *, struct wg_msg_cookie *);
int wg_conn_decrypt(struct wg_conn *, struct wg_msg_transport *, size_t);

int wg_conn_handshake_finish(struct wg_conn *);

int wg_conn_reject_tx(struct wg_conn *);
int wg_conn_rekey_tx(struct wg_conn *);
int wg_conn_rekey_rx(struct wg_conn *);

void wg_util_key_privtopub(uint8_t [WG_KEY_SIZE], const uint8_t [WG_KEY_SIZE]);
enum wg_pkt_type wg_util_pkt_type(uint8_t *, size_t);
int wg_timespec_timedout(struct timespec *, time_t);

#endif /* _LIBWG_H_ */