summaryrefslogtreecommitdiffstats
path: root/src/wireguard.h
blob: 0be4645345d2760b58333b7bcb91e7e61e7f6810 (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
184
#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_COOKIE_VALID_TIME 120
#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_keypair {
	uint8_t pub[WG_KEY_SIZE];
	uint8_t priv[WG_KEY_SIZE];
};

struct wg_cookie {
	uint8_t		cookie[WG_COOKIE_SIZE];
	struct timespec	time;
};

struct wg_handshake {
	struct rwlock	hs_lock;

	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_timestamp[WG_TIMESTAMP_SIZE];

	uint8_t 	hs_epub[WG_KEY_SIZE];
	struct wg_keypair	hs_ekey;
	struct wg_cookie	hs_cookie;

	uint8_t		hs_shared[WG_KEY_SIZE];
	uint8_t		hs_spub[WG_KEY_SIZE];
	struct wg_keypair	*hs_skey;
};

struct wg_session {
	struct rwlock	s_lock;
	enum wg_role 	s_role;
	uint64_t 	s_txcounter;
	uint64_t 	s_rxcounter;
	uint32_t 	s_local_id;
	uint32_t 	s_remote_id;
	struct timespec s_created;

	uint8_t 	s_txkey[WG_KEY_SIZE];
	uint8_t 	s_rxkey[WG_KEY_SIZE];

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

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;

enum wg_error {
	WG_OK = 0,
	WG_DECRYPT,
	WG_REPLAY,
	WG_REJECT,
	WG_STATE,
	WG_MAC,
};

void wg_handshake_init(struct wg_handshake *);
void wg_session_init(struct wg_session *);
uint32_t wg_handshake_clean(struct wg_handshake *);
uint32_t wg_session_clean(struct wg_session *);

enum wg_error wg_handshake_make_initiation(struct wg_handshake *, uint32_t, struct wg_msg_initiation *);
enum wg_error wg_handshake_make_response(struct wg_handshake *, uint32_t, struct wg_msg_response *);
enum wg_error wg_handshake_make_cookie(struct wg_keypair *kp, struct wg_cookie *, uint32_t, uint8_t *, uint8_t, uint8_t mac[WG_MAC_SIZE], struct wg_msg_cookie *);
enum wg_error wg_session_encrypt(struct wg_session *, struct wg_msg_transport *, size_t);

enum wg_error wg_handshake_valid_mac2(struct wg_cookie *, uint8_t *, uint8_t);

enum wg_error wg_handshake_recv_initiation(struct wg_handshake *, struct wg_msg_initiation *);
enum wg_error wg_handshake_recv_response(struct wg_handshake *, struct wg_msg_response *);
enum wg_error wg_handshake_recv_cookie(struct wg_handshake *, struct wg_msg_cookie *);
enum wg_error wg_session_decrypt(struct wg_session *, struct wg_msg_transport *, size_t);

void wg_handshake_clone(struct wg_handshake *, struct wg_handshake *);
void wg_session_from_handshake(struct wg_session *, struct wg_handshake *);

int wg_session_reject_tx(struct wg_session *);
int wg_session_reject_rx(struct wg_session *);
int wg_session_rekey_tx(struct wg_session *);
int wg_session_rekey_rx(struct wg_session *);

void wg_keypair_from_bytes(struct wg_keypair *, const uint8_t [WG_KEY_SIZE]);
void wg_keypair_generate(struct wg_keypair *);
/* TODO make better */
int wg_timespec_timedout(struct timespec *, time_t);
enum wg_pkt_type wg_pkt_type(uint8_t *, size_t);


#endif /* _LIBWG_H_ */