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
185
186
187
188
189
190
191
192
193
194
195
196
|
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2015-2021 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
#pragma once
#include "interlocked.h"
#include "messages.h"
#include "peerlookup.h"
#include "timers.h"
#include "rcu.h"
typedef struct _NOISE_REPLAY_COUNTER
{
UINT64 Counter;
KSPIN_LOCK Lock;
ULONG_PTR Backtrack[COUNTER_BITS_TOTAL / BITS_PER_POINTER];
} NOISE_REPLAY_COUNTER;
typedef struct _NOISE_SYMMETRIC_KEY
{
UINT8 Key[NOISE_SYMMETRIC_KEY_LEN];
UINT64 Birthdate;
BOOLEAN IsValid;
} NOISE_SYMMETRIC_KEY;
typedef struct _NOISE_KEYPAIR
{
INDEX_HASHTABLE_ENTRY Entry;
NOISE_SYMMETRIC_KEY Sending;
LONG64 SendingCounter;
NOISE_SYMMETRIC_KEY Receiving;
NOISE_REPLAY_COUNTER ReceivingCounter;
UINT32_LE RemoteIndex;
BOOLEAN IAmTheInitiator;
KREF Refcount;
RCU_CALLBACK Rcu;
UINT64 InternalId;
} NOISE_KEYPAIR;
typedef struct _NOISE_KEYPAIRS
{
NOISE_KEYPAIR __rcu *CurrentKeypair;
NOISE_KEYPAIR __rcu *PreviousKeypair;
NOISE_KEYPAIR __rcu *NextKeypair;
KSPIN_LOCK KeypairUpdateLock;
} NOISE_KEYPAIRS;
typedef struct _NOISE_STATIC_IDENTITY
{
UINT8 StaticPublic[NOISE_PUBLIC_KEY_LEN];
UINT8 StaticPrivate[NOISE_PUBLIC_KEY_LEN];
EX_PUSH_LOCK Lock;
BOOLEAN HasIdentity;
} NOISE_STATIC_IDENTITY;
typedef enum _NOISE_HANDSHAKE_STATE
{
HANDSHAKE_ZEROED,
HANDSHAKE_CREATED_INITIATION,
HANDSHAKE_CONSUMED_INITIATION,
HANDSHAKE_CREATED_RESPONSE,
HANDSHAKE_CONSUMED_RESPONSE
} NOISE_HANDSHAKE_STATE;
typedef struct _NOISE_HANDSHAKE
{
INDEX_HASHTABLE_ENTRY Entry;
NOISE_HANDSHAKE_STATE State;
UINT64 LastInitiationConsumption;
NOISE_STATIC_IDENTITY *StaticIdentity;
UINT8 EphemeralPrivate[NOISE_PUBLIC_KEY_LEN];
UINT8 RemoteStatic[NOISE_PUBLIC_KEY_LEN];
UINT8 RemoteEphemeral[NOISE_PUBLIC_KEY_LEN];
UINT8 PrecomputedStaticStatic[NOISE_PUBLIC_KEY_LEN];
UINT8 PresharedKey[NOISE_SYMMETRIC_KEY_LEN];
UINT8 Hash[NOISE_HASH_LEN];
UINT8 ChainingKey[NOISE_HASH_LEN];
UINT8 LatestTimestamp[NOISE_TIMESTAMP_LEN];
UINT32_LE RemoteIndex;
/* Protects all members except the immutable (after noise_handshake_
* init): remote_static, precomputed_static_static, static_identity.
*/
EX_PUSH_LOCK Lock;
} NOISE_HANDSHAKE;
typedef struct _WG_DEVICE WG_DEVICE;
VOID NoiseDriverEntry(VOID);
_IRQL_requires_max_(APC_LEVEL)
_Requires_lock_held_(Peer->Device->DeviceUpdateLock)
VOID
NoiseHandshakeInit(
_Out_ NOISE_HANDSHAKE *Handshake,
_In_ NOISE_STATIC_IDENTITY *StaticIdentity,
_In_ CONST UINT8 PeerPublicKey[NOISE_PUBLIC_KEY_LEN],
_In_ CONST UINT8 PeerPresharedKey[NOISE_SYMMETRIC_KEY_LEN],
_In_ WG_PEER *Peer);
_IRQL_requires_max_(APC_LEVEL)
_Requires_lock_not_held_(Handshake->Lock)
VOID
NoiseHandshakeClear(_Inout_ NOISE_HANDSHAKE *Handshake);
static inline VOID
NoiseResetLastSentHandshake(_Out_ _Interlocked_operand_ LONG64 *HandshakeSysTimeUnits)
{
WriteNoFence64(
HandshakeSysTimeUnits, KeQueryInterruptTime() - (UINT64)(REKEY_TIMEOUT + 1) * SYS_TIME_UNITS_PER_SEC);
}
VOID
NoiseKeypairPut(_In_opt_ NOISE_KEYPAIR *Keypair, _In_ BOOLEAN UnreferenceNow);
_Must_inspect_result_
_Post_maybenull_
NOISE_KEYPAIR *
NoiseKeypairGet(_Inout_opt_ NOISE_KEYPAIR *Keypair);
_IRQL_requires_max_(DISPATCH_LEVEL)
_Requires_lock_not_held_(Keypairs->KeypairUpdateLock)
VOID
NoiseKeypairsClear(_Inout_ NOISE_KEYPAIRS *Keypairs);
_IRQL_requires_max_(DISPATCH_LEVEL)
_Requires_lock_not_held_(Keypairs->KeypairUpdateLock)
BOOLEAN
NoiseReceivedWithKeypair(_Inout_ NOISE_KEYPAIRS *Keypairs, _In_ NOISE_KEYPAIR *ReceivedKeypair);
_IRQL_requires_max_(APC_LEVEL)
_Requires_lock_not_held_(Peer->Keypairs.KeypairUpdateLock)
VOID
NoiseExpireCurrentPeerKeypairs(_Inout_ WG_PEER *Peer);
_Requires_exclusive_lock_held_(StaticIdentity->Lock)
VOID
NoiseSetStaticIdentityPrivateKey(
_Inout_ NOISE_STATIC_IDENTITY *StaticIdentity,
_In_ CONST UINT8 PrivateKey[NOISE_PUBLIC_KEY_LEN]);
_IRQL_requires_max_(APC_LEVEL)
_Requires_lock_not_held_(StaticIdentity->Lock)
VOID
NoiseStaticIdentityClear(_Inout_ NOISE_STATIC_IDENTITY *StaticIdentity);
_IRQL_requires_max_(APC_LEVEL)
_Requires_lock_held_(Peer->Device->DeviceUpdateLock)
_Requires_lock_not_held_(Peer->Handshake.Lock)
VOID
NoisePrecomputeStaticStatic(_Inout_ WG_PEER *Peer);
_IRQL_requires_max_(APC_LEVEL)
_Requires_lock_not_held_(Handshake->StaticIdentity->Lock)
_Requires_lock_not_held_(Handshake->Lock)
_Must_inspect_result_
_Return_type_success_(return != FALSE)
BOOLEAN
NoiseHandshakeCreateInitiation(_Out_ MESSAGE_HANDSHAKE_INITIATION *Dst, _Inout_ NOISE_HANDSHAKE *Handshake);
_IRQL_requires_max_(APC_LEVEL)
_Requires_lock_not_held_(Wg->StaticIdentity.Lock)
_Must_inspect_result_
_Return_type_success_(return != NULL)
WG_PEER *
NoiseHandshakeConsumeInitiation(_In_ CONST MESSAGE_HANDSHAKE_INITIATION *Src, _Inout_ WG_DEVICE *Wg);
_IRQL_requires_max_(APC_LEVEL)
_Requires_lock_not_held_(Handshake->StaticIdentity->Lock)
_Requires_lock_not_held_(Handshake->Lock)
_Must_inspect_result_
_Return_type_success_(return != FALSE)
BOOLEAN
NoiseHandshakeCreateResponse(_Out_ MESSAGE_HANDSHAKE_RESPONSE *Dst, _Inout_ NOISE_HANDSHAKE *Handshake);
_IRQL_requires_max_(APC_LEVEL)
_Requires_lock_not_held_(Wg->StaticIdentity.Lock)
_Must_inspect_result_
_Return_type_success_(return != NULL)
WG_PEER *
NoiseHandshakeConsumeResponse(_In_ CONST MESSAGE_HANDSHAKE_RESPONSE *Src, _Inout_ WG_DEVICE *Wg);
_IRQL_requires_max_(APC_LEVEL)
_Requires_lock_not_held_(Handshake->Lock)
_Must_inspect_result_
_Return_type_success_(return != FALSE)
BOOLEAN
NoiseHandshakeBeginSession(_Inout_ NOISE_HANDSHAKE *Handshake, _Inout_ NOISE_KEYPAIRS *Keypairs);
|