Coverage Report

Created: 2026-10-17 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/WireGuardLayer.cpp
Line
Count
Source
1
0
#define LOG_MODULE PacketLogModuleWireGuardLayer
2
3
#include "Logger.h"
4
#include "UdpLayer.h"
5
#include "WireGuardLayer.h"
6
#include "EndianPortable.h"
7
#include <iomanip>
8
9
namespace pcpp
10
{
11
  WireGuardLayer* WireGuardLayer::parseWireGuardLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
12
3.94k
  {
13
3.94k
    if (dataLen < sizeof(WireGuardLayer::wg_common_header))
14
0
      return nullptr;
15
3.94k
    wg_common_header* wgHeader = reinterpret_cast<wg_common_header*>(data);
16
17
3.94k
    switch (wgHeader->messageType)
18
3.94k
    {
19
651
    case static_cast<uint8_t>(WireGuardMessageType::HandshakeInitiation):
20
651
      if (!WireGuardHandshakeInitiationLayer::isDataValid(data, dataLen))
21
0
        return nullptr;
22
651
      return new WireGuardHandshakeInitiationLayer(data, dataLen, prevLayer, packet);
23
1.06k
    case static_cast<uint8_t>(WireGuardMessageType::HandshakeResponse):
24
1.06k
      if (!WireGuardHandshakeResponseLayer::isDataValid(data, dataLen))
25
12
        return nullptr;
26
1.05k
      return new WireGuardHandshakeResponseLayer(data, dataLen, prevLayer, packet);
27
140
    case static_cast<uint8_t>(WireGuardMessageType::CookieReply):
28
140
      if (!WireGuardCookieReplyLayer::isDataValid(data, dataLen))
29
0
        return nullptr;
30
140
      return new WireGuardCookieReplyLayer(data, dataLen, prevLayer, packet);
31
2.08k
    case static_cast<uint8_t>(WireGuardMessageType::TransportData):
32
2.08k
      if (!WireGuardTransportDataLayer::isDataValid(data, dataLen))
33
6
        return nullptr;
34
2.07k
      return new WireGuardTransportDataLayer(data, dataLen, prevLayer, packet);
35
0
    default:
36
0
      return nullptr;
37
3.94k
    }
38
3.94k
  }
39
40
  std::string WireGuardLayer::getMessageTypeAsString() const
41
1.56k
  {
42
1.56k
    uint32_t messageType = getMessageType();
43
1.56k
    switch (messageType)
44
1.56k
    {
45
260
    case static_cast<uint8_t>(WireGuardMessageType::HandshakeInitiation):
46
260
      return "Handshake Initiation";
47
422
    case static_cast<uint8_t>(WireGuardMessageType::HandshakeResponse):
48
422
      return "Handshake Response";
49
56
    case static_cast<uint8_t>(WireGuardMessageType::CookieReply):
50
56
      return "Cookie Reply";
51
830
    case static_cast<uint8_t>(WireGuardMessageType::TransportData):
52
830
      return "Transport Data";
53
0
    default:
54
0
      return "Unknown";
55
1.56k
    }
56
1.56k
  }
57
58
  std::string WireGuardLayer::toString() const
59
1.56k
  {
60
1.56k
    return "WireGuard Layer, " + getMessageTypeAsString() + " message";
61
1.56k
  }
62
63
  size_t WireGuardLayer::getHeaderLen() const
64
784
  {
65
784
    return m_DataLen;
66
784
  }
67
68
  uint8_t WireGuardLayer::getMessageType() const
69
1.56k
  {
70
1.56k
    return getBasicHeader()->messageType;
71
1.56k
  }
72
73
  uint32_t WireGuardLayer::getReserved() const
74
0
  {
75
0
    uint32_t reservedValue = 0;
76
0
    memcpy(&reservedValue, getBasicHeader()->reserved, 3);
77
0
    return be32toh(reservedValue);
78
0
  }
79
80
  void WireGuardLayer::setReserved(const std::array<uint8_t, 3>& reserved)
81
0
  {
82
0
    wg_common_header* msg = reinterpret_cast<wg_common_header*>(m_Data);
83
0
    memcpy(msg->reserved, reserved.data(), 3);
84
0
  }
85
86
  bool WireGuardLayer::isDataValid(const uint8_t* data, size_t dataLen)
87
3.99k
  {
88
3.99k
    if (dataLen < sizeof(WireGuardLayer::wg_common_header))
89
0
      return false;
90
91
3.99k
    uint8_t messageType = data[0];
92
3.99k
    return messageType >= static_cast<uint8_t>(WireGuardLayer::WireGuardMessageType::HandshakeInitiation) &&
93
3.95k
           messageType <= static_cast<uint8_t>(WireGuardLayer::WireGuardMessageType::TransportData);
94
3.99k
  }
95
96
  // ~~~~~~~~~~~~~~~~~~~~
97
  // WireGuardHandshakeInitiationLayer
98
  // ~~~~~~~~~~~~~~~~~~~~
99
100
  WireGuardHandshakeInitiationLayer::WireGuardHandshakeInitiationLayer(uint32_t senderIndex,
101
                                                                       const uint8_t initiatorEphemeral[32],
102
                                                                       const uint8_t encryptedInitiatorStatic[48],
103
                                                                       const uint8_t encryptedTimestamp[28],
104
                                                                       const uint8_t mac1[16], const uint8_t mac2[16])
105
0
  {
106
0
    allocData(sizeof(wg_handshake_initiation));
107
108
0
    wg_handshake_initiation* msg = reinterpret_cast<wg_handshake_initiation*>(m_Data);
109
110
0
    msg->messageType = static_cast<uint8_t>(WireGuardMessageType::HandshakeInitiation);
111
0
    memset(msg->reserved, 0, 3);
112
0
    msg->senderIndex = htobe32(senderIndex);
113
114
0
    memcpy(msg->initiatorEphemeral, initiatorEphemeral, 32);
115
0
    memcpy(msg->encryptedInitiatorStatic, encryptedInitiatorStatic, 48);
116
0
    memcpy(msg->encryptedTimestamp, encryptedTimestamp, 28);
117
0
    memcpy(msg->mac1, mac1, 16);
118
0
    memcpy(msg->mac2, mac2, 16);
119
120
0
    m_Protocol = WireGuard;
121
0
  }
122
123
  uint32_t WireGuardHandshakeInitiationLayer::getSenderIndex() const
124
0
  {
125
0
    return be32toh(getHandshakeInitiationHeader()->senderIndex);
126
0
  }
127
128
  std::array<uint8_t, 32> WireGuardHandshakeInitiationLayer::getInitiatorEphemeral() const
129
0
  {
130
0
    std::array<uint8_t, 32> ephemeralArray;
131
0
    memcpy(ephemeralArray.data(), getHandshakeInitiationHeader()->initiatorEphemeral, 32);
132
0
    return ephemeralArray;
133
0
  }
134
135
  std::array<uint8_t, 48> WireGuardHandshakeInitiationLayer::getEncryptedInitiatorStatic() const
136
0
  {
137
0
    std::array<uint8_t, 48> initArray;
138
0
    memcpy(initArray.data(), getHandshakeInitiationHeader()->encryptedInitiatorStatic, 48);
139
0
    return initArray;
140
0
  }
141
142
  std::array<uint8_t, 28> WireGuardHandshakeInitiationLayer::getEncryptedTimestamp() const
143
0
  {
144
0
    std::array<uint8_t, 28> tsArray;
145
0
    memcpy(tsArray.data(), getHandshakeInitiationHeader()->encryptedTimestamp, 28);
146
0
    return tsArray;
147
0
  }
148
149
  std::array<uint8_t, 16> WireGuardHandshakeInitiationLayer::getMac1() const
150
0
  {
151
0
    std::array<uint8_t, 16> mac1Array;
152
0
    memcpy(mac1Array.data(), getHandshakeInitiationHeader()->mac1, 16);
153
0
    return mac1Array;
154
0
  }
155
156
  std::array<uint8_t, 16> WireGuardHandshakeInitiationLayer::getMac2() const
157
0
  {
158
0
    std::array<uint8_t, 16> mac2Array;
159
0
    memcpy(mac2Array.data(), getHandshakeInitiationHeader()->mac2, 16);
160
0
    return mac2Array;
161
0
  }
162
163
  void WireGuardHandshakeInitiationLayer::setSenderIndex(uint32_t senderIndex)
164
0
  {
165
0
    wg_handshake_initiation* msg = reinterpret_cast<wg_handshake_initiation*>(m_Data);
166
0
    msg->senderIndex = htobe32(senderIndex);
167
0
  }
168
169
  void WireGuardHandshakeInitiationLayer::setInitiatorEphemeral(const std::array<uint8_t, 32>& initiatorEphemeral)
170
0
  {
171
0
    wg_handshake_initiation* msg = reinterpret_cast<wg_handshake_initiation*>(m_Data);
172
0
    memcpy(msg->initiatorEphemeral, initiatorEphemeral.data(), 32);
173
0
  }
174
175
  void WireGuardHandshakeInitiationLayer::setEncryptedInitiatorStatic(
176
      const std::array<uint8_t, 48>& encryptedInitiatorStatic)
177
0
  {
178
0
    wg_handshake_initiation* msg = reinterpret_cast<wg_handshake_initiation*>(m_Data);
179
0
    memcpy(msg->encryptedInitiatorStatic, encryptedInitiatorStatic.data(), 48);
180
0
  }
181
182
  void WireGuardHandshakeInitiationLayer::setEncryptedTimestamp(const std::array<uint8_t, 28>& encryptedTimestamp)
183
0
  {
184
0
    wg_handshake_initiation* msg = reinterpret_cast<wg_handshake_initiation*>(m_Data);
185
0
    memcpy(msg->encryptedTimestamp, encryptedTimestamp.data(), 28);
186
0
  }
187
188
  void WireGuardHandshakeInitiationLayer::setMac1(const std::array<uint8_t, 16>& mac1)
189
0
  {
190
0
    wg_handshake_initiation* msg = reinterpret_cast<wg_handshake_initiation*>(m_Data);
191
0
    memcpy(msg->mac1, mac1.data(), 16);
192
0
  }
193
194
  void WireGuardHandshakeInitiationLayer::setMac2(const std::array<uint8_t, 16>& mac2)
195
0
  {
196
0
    wg_handshake_initiation* msg = reinterpret_cast<wg_handshake_initiation*>(m_Data);
197
0
    memcpy(msg->mac2, mac2.data(), 16);
198
0
  }
199
200
  // ~~~~~~~~~~~~~~~~~~~~
201
  // WireGuardHandshakeResponseLayer
202
  // ~~~~~~~~~~~~~~~~~~~~
203
204
  WireGuardHandshakeResponseLayer::WireGuardHandshakeResponseLayer(uint32_t senderIndex, uint32_t receiverIndex,
205
                                                                   const uint8_t responderEphemeral[32],
206
                                                                   const uint8_t encryptedEmpty[16],
207
                                                                   const uint8_t mac1[16], const uint8_t mac2[16])
208
0
  {
209
0
    allocData(sizeof(wg_handshake_response), false);
210
211
0
    wg_handshake_response* msg = reinterpret_cast<wg_handshake_response*>(m_Data);
212
213
0
    msg->messageType = static_cast<uint8_t>(WireGuardMessageType::HandshakeResponse);
214
0
    memset(msg->reserved, 0, 3);
215
0
    msg->senderIndex = htobe32(senderIndex);
216
0
    msg->receiverIndex = htobe32(receiverIndex);
217
0
    memcpy(msg->responderEphemeral, responderEphemeral, 32);
218
0
    memcpy(msg->encryptedEmpty, encryptedEmpty, 16);
219
0
    memcpy(msg->mac1, mac1, 16);
220
0
    memcpy(msg->mac2, mac2, 16);
221
222
0
    m_Protocol = WireGuard;
223
0
  }
224
225
  uint32_t WireGuardHandshakeResponseLayer::getSenderIndex() const
226
0
  {
227
0
    return be32toh(getHandshakeResponseHeader()->senderIndex);
228
0
  }
229
230
  uint32_t WireGuardHandshakeResponseLayer::getReceiverIndex() const
231
0
  {
232
0
    return be32toh(getHandshakeResponseHeader()->receiverIndex);
233
0
  }
234
235
  std::array<uint8_t, 32> WireGuardHandshakeResponseLayer::getResponderEphemeral() const
236
0
  {
237
0
    std::array<uint8_t, 32> responderEphemeralArray;
238
0
    memcpy(responderEphemeralArray.data(), getHandshakeResponseHeader()->responderEphemeral, 32);
239
0
    return responderEphemeralArray;
240
0
  }
241
242
  std::array<uint8_t, 16> WireGuardHandshakeResponseLayer::getEncryptedEmpty() const
243
0
  {
244
0
    std::array<uint8_t, 16> encryptedEmptyArray;
245
0
    memcpy(encryptedEmptyArray.data(), getHandshakeResponseHeader()->encryptedEmpty, 16);
246
0
    return encryptedEmptyArray;
247
0
  }
248
249
  std::array<uint8_t, 16> WireGuardHandshakeResponseLayer::getMac1() const
250
0
  {
251
0
    std::array<uint8_t, 16> mac1Array;
252
0
    memcpy(mac1Array.data(), getHandshakeResponseHeader()->mac1, 16);
253
0
    return mac1Array;
254
0
  }
255
256
  std::array<uint8_t, 16> WireGuardHandshakeResponseLayer::getMac2() const
257
0
  {
258
0
    std::array<uint8_t, 16> mac2Array;
259
0
    memcpy(mac2Array.data(), getHandshakeResponseHeader()->mac2, 16);
260
0
    return mac2Array;
261
0
  }
262
263
  void WireGuardHandshakeResponseLayer::setSenderIndex(uint32_t senderIndex)
264
0
  {
265
266
0
    wg_handshake_response* msg = reinterpret_cast<wg_handshake_response*>(m_Data);
267
0
    msg->senderIndex = htobe32(senderIndex);
268
0
  }
269
270
  void WireGuardHandshakeResponseLayer::setReceiverIndex(uint32_t receiverIndex)
271
0
  {
272
0
    wg_handshake_response* msg = reinterpret_cast<wg_handshake_response*>(m_Data);
273
0
    msg->receiverIndex = htobe32(receiverIndex);
274
0
  }
275
276
  void WireGuardHandshakeResponseLayer::setResponderEphemeral(const std::array<uint8_t, 32>& responderEphemeral)
277
0
  {
278
0
    wg_handshake_response* msg = reinterpret_cast<wg_handshake_response*>(m_Data);
279
0
    memcpy(msg->responderEphemeral, responderEphemeral.data(), 32);
280
0
  }
281
282
  void WireGuardHandshakeResponseLayer::setEncryptedEmpty(const std::array<uint8_t, 16>& encryptedEmpty)
283
0
  {
284
0
    wg_handshake_response* msg = reinterpret_cast<wg_handshake_response*>(m_Data);
285
0
    memcpy(msg->encryptedEmpty, encryptedEmpty.data(), 16);
286
0
  }
287
288
  void WireGuardHandshakeResponseLayer::setMac1(const std::array<uint8_t, 16>& mac1)
289
0
  {
290
0
    wg_handshake_response* msg = reinterpret_cast<wg_handshake_response*>(m_Data);
291
0
    memcpy(msg->mac1, mac1.data(), 16);
292
0
  }
293
294
  void WireGuardHandshakeResponseLayer::setMac2(const std::array<uint8_t, 16>& mac2)
295
0
  {
296
0
    wg_handshake_response* msg = reinterpret_cast<wg_handshake_response*>(m_Data);
297
0
    memcpy(msg->mac2, mac2.data(), 16);
298
0
  }
299
300
  // ~~~~~~~~~~~~~~~~~~~~
301
  // WireGuardCookieReplyLayer
302
  // ~~~~~~~~~~~~~~~~~~~~
303
304
  WireGuardCookieReplyLayer::WireGuardCookieReplyLayer(uint32_t receiverIndex, const uint8_t nonce[24],
305
                                                       const uint8_t encryptedCookie[32])
306
0
  {
307
0
    allocData(sizeof(wg_cookie_reply));
308
309
0
    wg_cookie_reply* msg = reinterpret_cast<wg_cookie_reply*>(m_Data);
310
311
0
    msg->messageType = static_cast<uint8_t>(WireGuardMessageType::CookieReply);
312
0
    memset(msg->reserved, 0, 3);
313
0
    msg->receiverIndex = htobe32(receiverIndex);
314
0
    memcpy(msg->nonce, nonce, 24);
315
0
    memcpy(msg->encryptedCookie, encryptedCookie, 32);
316
317
0
    m_Protocol = WireGuard;
318
0
  }
319
320
  uint32_t WireGuardCookieReplyLayer::getReceiverIndex() const
321
0
  {
322
0
    return be32toh(getCookieReplyHeader()->receiverIndex);
323
0
  }
324
325
  std::array<uint8_t, 24> WireGuardCookieReplyLayer::getNonce() const
326
0
  {
327
0
    std::array<uint8_t, 24> nonceArray;
328
0
    memcpy(nonceArray.data(), getCookieReplyHeader()->nonce, 24);
329
0
    return nonceArray;
330
0
  }
331
332
  std::array<uint8_t, 32> WireGuardCookieReplyLayer::getEncryptedCookie() const
333
0
  {
334
0
    std::array<uint8_t, 32> encryptedCookieArray;
335
0
    memcpy(encryptedCookieArray.data(), getCookieReplyHeader()->encryptedCookie, 32);
336
0
    return encryptedCookieArray;
337
0
  }
338
339
  void WireGuardCookieReplyLayer::setReceiverIndex(uint32_t receiverIndex)
340
0
  {
341
0
    wg_cookie_reply* msg = reinterpret_cast<wg_cookie_reply*>(m_Data);
342
0
    msg->receiverIndex = htobe32(receiverIndex);
343
0
  }
344
345
  void WireGuardCookieReplyLayer::setNonce(const std::array<uint8_t, 24>& nonce)
346
0
  {
347
0
    wg_cookie_reply* msg = reinterpret_cast<wg_cookie_reply*>(m_Data);
348
0
    memcpy(msg->nonce, nonce.data(), 24);
349
0
  }
350
351
  void WireGuardCookieReplyLayer::setEncryptedCookie(const std::array<uint8_t, 32>& encryptedCookie)
352
0
  {
353
0
    wg_cookie_reply* msg = reinterpret_cast<wg_cookie_reply*>(m_Data);
354
0
    memcpy(msg->encryptedCookie, encryptedCookie.data(), 32);
355
0
  }
356
357
  // ~~~~~~~~~~~~~~~~~~~~
358
  // WireGuardTransportDataLayer
359
  // ~~~~~~~~~~~~~~~~~~~~
360
361
  WireGuardTransportDataLayer::WireGuardTransportDataLayer(uint32_t receiverIndex, uint64_t counter,
362
                                                           const uint8_t* encryptedData, size_t encryptedDataLen)
363
0
  {
364
0
    const size_t messageLen = sizeof(wg_transport_data) + encryptedDataLen;
365
0
    allocData(messageLen);
366
367
0
    wg_transport_data* msg = reinterpret_cast<wg_transport_data*>(m_Data);
368
369
0
    msg->messageType = static_cast<uint8_t>(WireGuardMessageType::TransportData);
370
0
    memset(msg->reserved, 0, 3);
371
0
    msg->receiverIndex = htobe32(receiverIndex);
372
0
    msg->counter = htobe64(counter);
373
0
    memcpy(m_Data + sizeof(wg_transport_data), encryptedData, encryptedDataLen);
374
375
0
    m_Protocol = WireGuard;
376
0
  }
377
378
  uint32_t WireGuardTransportDataLayer::getReceiverIndex() const
379
0
  {
380
0
    return be32toh(getTransportHeader()->receiverIndex);
381
0
  }
382
383
  uint64_t WireGuardTransportDataLayer::getCounter() const
384
0
  {
385
0
    return be64toh(getTransportHeader()->counter);
386
0
  }
387
388
  const uint8_t* WireGuardTransportDataLayer::getEncryptedData() const
389
0
  {
390
0
    return getTransportHeader()->encryptedData;
391
0
  }
392
393
  void WireGuardTransportDataLayer::setReceiverIndex(uint32_t receiverIndex)
394
0
  {
395
0
    wg_transport_data* msg = reinterpret_cast<wg_transport_data*>(m_Data);
396
0
    msg->receiverIndex = htobe32(receiverIndex);
397
0
  }
398
399
  void WireGuardTransportDataLayer::setCounter(uint64_t counter)
400
0
  {
401
0
    wg_transport_data* msg = reinterpret_cast<wg_transport_data*>(m_Data);
402
0
    msg->counter = htobe64(counter);
403
0
  }
404
405
  void WireGuardTransportDataLayer::setEncryptedData(const uint8_t* encryptedData, size_t encryptedDataLen)
406
0
  {
407
0
    const size_t headerLen = sizeof(wg_transport_data);
408
0
    const size_t currentLen = m_DataLen - headerLen;
409
410
0
    if (encryptedDataLen < currentLen)
411
0
    {
412
0
      if (!shortenLayer(static_cast<int>(headerLen + encryptedDataLen), currentLen - encryptedDataLen))
413
0
      {
414
0
        PCPP_LOG_ERROR("Couldn't shorten the layer to fit the new encrypted data");
415
0
        return;
416
0
      }
417
0
    }
418
0
    else if (encryptedDataLen > currentLen)
419
0
    {
420
0
      if (!extendLayer(static_cast<int>(m_DataLen), encryptedDataLen - currentLen))
421
0
      {
422
0
        PCPP_LOG_ERROR("Couldn't extend the layer to fit the new encrypted data");
423
0
        return;
424
0
      }
425
0
    }
426
427
0
    memcpy(m_Data + headerLen, encryptedData, encryptedDataLen);
428
0
  }
429
430
}  // namespace pcpp