node-ikev2 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +86 -0
- package/lib/src/attribute.d.ts +67 -0
- package/lib/src/attribute.js +161 -0
- package/lib/src/header.d.ts +102 -0
- package/lib/src/header.js +307 -0
- package/lib/src/index.d.ts +9 -0
- package/lib/src/index.js +38 -0
- package/lib/src/message.d.ts +88 -0
- package/lib/src/message.js +264 -0
- package/lib/src/payload.d.ts +1013 -0
- package/lib/src/payload.js +1840 -0
- package/lib/src/proposal.d.ts +90 -0
- package/lib/src/proposal.js +200 -0
- package/lib/src/selector.d.ts +80 -0
- package/lib/src/selector.js +132 -0
- package/lib/src/transform.d.ts +316 -0
- package/lib/src/transform.js +470 -0
- package/package.json +56 -0
|
@@ -0,0 +1,1840 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.payloadTypeMapping = exports.PayloadEAP = exports.PayloadCP = exports.cfgType = exports.PayloadSK = exports.PayloadTSr = exports.PayloadTSi = exports.PayloadTS = exports.PayloadVENDOR = exports.PayloadDELETE = exports.PayloadNOTIFY = exports.notifyMessageType = exports.securityProtocolId = exports.PayloadNONCE = exports.PayloadAUTH = exports.PayloadCERTREQ = exports.PayloadCERT = exports.CertificateType = exports.PayloadIDr = exports.PayloadIDi = exports.PayloadID = exports.IDType = exports.PayloadKE = exports.PayloadSA = exports.Payload = exports.payloadType = void 0;
|
|
4
|
+
const proposal_1 = require("./proposal");
|
|
5
|
+
const attribute_1 = require("./attribute");
|
|
6
|
+
const selector_1 = require("./selector");
|
|
7
|
+
/*
|
|
8
|
+
IKEv2 Generic Payload Header
|
|
9
|
+
|
|
10
|
+
0 1 2 3
|
|
11
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
12
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
13
|
+
! Next Payload !C! RESERVED ! Payload Length !
|
|
14
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
15
|
+
|
|
16
|
+
Generic Payload Header
|
|
17
|
+
|
|
18
|
+
Critical bit: specifies the processing by the recipient in case the type
|
|
19
|
+
of this payload is not understood:
|
|
20
|
+
- 0 payload skipped
|
|
21
|
+
- 1 message rejected
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* IKEv2 Payload Types: \
|
|
25
|
+
Next Payload Type Notation Value
|
|
26
|
+
--------------------------------------------------
|
|
27
|
+
No Next Payload 0 \
|
|
28
|
+
Security Association SA 33 \
|
|
29
|
+
Key Exchange KE 34 \
|
|
30
|
+
Identification - Initiator IDi 35 \
|
|
31
|
+
Identification - Responder IDr 36 \
|
|
32
|
+
Certificate CERT 37 \
|
|
33
|
+
Certificate Request CERTREQ 38 \
|
|
34
|
+
Authentication AUTH 39 \
|
|
35
|
+
Nonce Ni, Nr 40 \
|
|
36
|
+
Notify N 41 \
|
|
37
|
+
Delete D 42 \
|
|
38
|
+
Vendor ID V 43 \
|
|
39
|
+
Traffic Selector - Initiator TSi 44 \
|
|
40
|
+
Traffic Selector - Responder TSr 45 \
|
|
41
|
+
Encrypted and Authenticated SK 46 \
|
|
42
|
+
Configuration CP 47 \
|
|
43
|
+
Extensible Authentication EAP 48
|
|
44
|
+
*/
|
|
45
|
+
var payloadType;
|
|
46
|
+
(function (payloadType) {
|
|
47
|
+
payloadType[payloadType["NONE"] = 0] = "NONE";
|
|
48
|
+
payloadType[payloadType["SA"] = 33] = "SA";
|
|
49
|
+
payloadType[payloadType["KE"] = 34] = "KE";
|
|
50
|
+
payloadType[payloadType["IDi"] = 35] = "IDi";
|
|
51
|
+
payloadType[payloadType["IDr"] = 36] = "IDr";
|
|
52
|
+
payloadType[payloadType["CERT"] = 37] = "CERT";
|
|
53
|
+
payloadType[payloadType["CERTREQ"] = 38] = "CERTREQ";
|
|
54
|
+
payloadType[payloadType["AUTH"] = 39] = "AUTH";
|
|
55
|
+
payloadType[payloadType["NONCE"] = 40] = "NONCE";
|
|
56
|
+
payloadType[payloadType["NOTIFY"] = 41] = "NOTIFY";
|
|
57
|
+
payloadType[payloadType["DELETE"] = 42] = "DELETE";
|
|
58
|
+
payloadType[payloadType["VENDOR"] = 43] = "VENDOR";
|
|
59
|
+
payloadType[payloadType["TSi"] = 44] = "TSi";
|
|
60
|
+
payloadType[payloadType["TSr"] = 45] = "TSr";
|
|
61
|
+
payloadType[payloadType["SK"] = 46] = "SK";
|
|
62
|
+
payloadType[payloadType["CP"] = 47] = "CP";
|
|
63
|
+
payloadType[payloadType["EAP"] = 48] = "EAP";
|
|
64
|
+
})(payloadType || (exports.payloadType = payloadType = {}));
|
|
65
|
+
/**
|
|
66
|
+
* IKEv2 Generic Payload Header
|
|
67
|
+
* @class
|
|
68
|
+
* @property {payloadType}
|
|
69
|
+
* @property {payloadType} nextPayload - 1 byte
|
|
70
|
+
* @property {boolean} critical - 1 bit
|
|
71
|
+
* @property {number} length - 2 bytes
|
|
72
|
+
*/
|
|
73
|
+
class Payload {
|
|
74
|
+
constructor(type, nextPayload, critical = false, // default to false for all defined payloads in IKEv2
|
|
75
|
+
length) {
|
|
76
|
+
this.type = type;
|
|
77
|
+
this.nextPayload = nextPayload;
|
|
78
|
+
this.critical = critical;
|
|
79
|
+
this.length = length;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Parses a payload generic header from a buffer
|
|
83
|
+
* @param buffer
|
|
84
|
+
* @static
|
|
85
|
+
* @public
|
|
86
|
+
* @returns
|
|
87
|
+
*/
|
|
88
|
+
static parse(buffer) {
|
|
89
|
+
try {
|
|
90
|
+
// Input validation
|
|
91
|
+
if (!Buffer.isBuffer(buffer)) {
|
|
92
|
+
throw new Error("Input must be a Buffer");
|
|
93
|
+
}
|
|
94
|
+
// Check minimum buffer length for payload header (4 bytes)
|
|
95
|
+
if (buffer.length < 4) {
|
|
96
|
+
throw new Error(`Buffer too short for payload header. Expected at least 4 bytes, got ${buffer.length}`);
|
|
97
|
+
}
|
|
98
|
+
const nextPayload = buffer.readUInt8(0);
|
|
99
|
+
const critical = (buffer.readUInt8(1) & 0x80) === 0x80;
|
|
100
|
+
const length = buffer.readUInt16BE(2);
|
|
101
|
+
// Validate payload length
|
|
102
|
+
if (length < 4) {
|
|
103
|
+
throw new Error(`Invalid payload length. Must be at least 4 bytes, got ${length}`);
|
|
104
|
+
}
|
|
105
|
+
// Check if buffer contains the full payload
|
|
106
|
+
if (buffer.length < length) {
|
|
107
|
+
throw new Error(`Buffer too short for declared payload length. Expected ${length} bytes, got ${buffer.length}`);
|
|
108
|
+
}
|
|
109
|
+
return new Payload(payloadType.NONE, nextPayload, critical, length);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
if (error instanceof Error) {
|
|
113
|
+
throw new Error(`Failed to parse generic payload header: ${error.message}`);
|
|
114
|
+
}
|
|
115
|
+
throw new Error("Failed to parse generic payload header");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Serialize a JSON payload to a buffer
|
|
120
|
+
* @param json
|
|
121
|
+
* @static
|
|
122
|
+
* @public
|
|
123
|
+
* @returns {Buffer}
|
|
124
|
+
*/
|
|
125
|
+
static serializeJSON(json) {
|
|
126
|
+
try {
|
|
127
|
+
// Input validation
|
|
128
|
+
if (!json || typeof json !== "object") {
|
|
129
|
+
throw new Error("JSON input must be a valid object");
|
|
130
|
+
}
|
|
131
|
+
// Validate required fields
|
|
132
|
+
if (typeof json.nextPayload === "undefined") {
|
|
133
|
+
throw new Error("nextPayload is required");
|
|
134
|
+
}
|
|
135
|
+
if (typeof json.length === "undefined") {
|
|
136
|
+
throw new Error("length is required");
|
|
137
|
+
}
|
|
138
|
+
// Validate data types
|
|
139
|
+
if (!Number.isInteger(json.nextPayload) ||
|
|
140
|
+
json.nextPayload < 0 ||
|
|
141
|
+
json.nextPayload > 255) {
|
|
142
|
+
throw new Error(`nextPayload must be a valid 8-bit unsigned integer (0-255), got ${json.nextPayload}`);
|
|
143
|
+
}
|
|
144
|
+
if (!Number.isInteger(json.length) ||
|
|
145
|
+
json.length < 4 ||
|
|
146
|
+
json.length > 65535) {
|
|
147
|
+
throw new Error(`length must be a valid 16-bit unsigned integer (4-65535), got ${json.length}`);
|
|
148
|
+
}
|
|
149
|
+
// Validate critical flag
|
|
150
|
+
if (typeof json.critical !== "boolean") {
|
|
151
|
+
throw new Error(`critical must be a boolean, got ${typeof json.critical}`);
|
|
152
|
+
}
|
|
153
|
+
const buffer = Buffer.alloc(4);
|
|
154
|
+
buffer.writeUInt8(json.nextPayload, 0);
|
|
155
|
+
buffer.writeUInt8(json.critical ? 0x80 : 0, 1);
|
|
156
|
+
buffer.writeUInt16BE(json.length, 2);
|
|
157
|
+
return buffer;
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
if (error instanceof Error) {
|
|
161
|
+
throw new Error(`Failed to serialize payload JSON: ${error.message}`);
|
|
162
|
+
}
|
|
163
|
+
throw new Error("Failed to serialize payload JSON");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Serializes the payload to a buffer
|
|
168
|
+
* @public
|
|
169
|
+
* @returns {Buffer}
|
|
170
|
+
*/
|
|
171
|
+
serialize() {
|
|
172
|
+
// The length should be set by the child class before calling this method
|
|
173
|
+
if (this.length < 4) {
|
|
174
|
+
throw new Error(`Invalid payload length: ${this.length}`);
|
|
175
|
+
}
|
|
176
|
+
const buffer = Buffer.alloc(4);
|
|
177
|
+
buffer.writeUInt8(this.nextPayload, 0);
|
|
178
|
+
buffer.writeUInt8(this.critical ? 0x80 : 0, 1);
|
|
179
|
+
buffer.writeUInt16BE(this.length, 2);
|
|
180
|
+
return buffer;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Returns a JSON representation of the payload
|
|
184
|
+
* @public
|
|
185
|
+
* @returns {Record<string, any>}
|
|
186
|
+
*/
|
|
187
|
+
toJSON() {
|
|
188
|
+
return {};
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Returns a string representation of the payload
|
|
192
|
+
* @public
|
|
193
|
+
* @returns {string}
|
|
194
|
+
*/
|
|
195
|
+
genToJSON() {
|
|
196
|
+
return {
|
|
197
|
+
type: this.type,
|
|
198
|
+
nextPayload: this.nextPayload,
|
|
199
|
+
critical: this.critical,
|
|
200
|
+
length: this.length,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Returns a string representation of the payload
|
|
205
|
+
* @public
|
|
206
|
+
* @returns {string}
|
|
207
|
+
*/
|
|
208
|
+
genToString() {
|
|
209
|
+
const prettyJson = this.genToJSON();
|
|
210
|
+
prettyJson.type = `${payloadType[prettyJson.type]} (${prettyJson.type})`;
|
|
211
|
+
prettyJson.nextPayload = `${payloadType[prettyJson.nextPayload]} (${prettyJson.nextPayload})`;
|
|
212
|
+
prettyJson.critical = prettyJson.critical ? "Critical" : "Non-critical";
|
|
213
|
+
return JSON.stringify(prettyJson, null, 2);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
exports.Payload = Payload;
|
|
217
|
+
/**
|
|
218
|
+
* IKEv2 Security Association Payload
|
|
219
|
+
* @class
|
|
220
|
+
* @extends Payload
|
|
221
|
+
*/
|
|
222
|
+
class PayloadSA extends Payload {
|
|
223
|
+
constructor(nextPayload, proposals, critical = false, length = 0) {
|
|
224
|
+
super(payloadType.SA, nextPayload, critical, length > 0
|
|
225
|
+
? length
|
|
226
|
+
: 4 + proposals.reduce((acc, prop) => acc + prop.length, 0));
|
|
227
|
+
this.nextPayload = nextPayload;
|
|
228
|
+
this.proposals = proposals;
|
|
229
|
+
this.critical = critical;
|
|
230
|
+
this.length = length;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Parses a Security Association Payload from a buffer
|
|
234
|
+
* @param buffer
|
|
235
|
+
* @static
|
|
236
|
+
* @public
|
|
237
|
+
* @returns {PayloadSA}
|
|
238
|
+
*/
|
|
239
|
+
static parse(buffer) {
|
|
240
|
+
const genericPayload = Payload.parse(buffer);
|
|
241
|
+
// Validate that buffer is at least as long as the declared payload length
|
|
242
|
+
if (buffer.length < genericPayload.length) {
|
|
243
|
+
throw new Error(`Buffer too short for declared payload length. Expected at least ${genericPayload.length} bytes, got ${buffer.length}`);
|
|
244
|
+
}
|
|
245
|
+
const proposals = [];
|
|
246
|
+
let offset = 4;
|
|
247
|
+
while (offset < genericPayload.length) {
|
|
248
|
+
// Check if we have enough data for the next proposal header (8 bytes minimum)
|
|
249
|
+
if (offset + 8 > genericPayload.length) {
|
|
250
|
+
throw new Error(`Insufficient data for proposal header at offset ${offset}. Need at least 8 bytes, have ${genericPayload.length - offset}`);
|
|
251
|
+
}
|
|
252
|
+
// Read proposal length from the buffer to determine exact slice size
|
|
253
|
+
const proposalLength = buffer.readUInt16BE(offset + 2);
|
|
254
|
+
// Validate proposal length
|
|
255
|
+
if (proposalLength < 8) {
|
|
256
|
+
throw new Error(`Invalid proposal length. Must be at least 8 bytes, got ${proposalLength}`);
|
|
257
|
+
}
|
|
258
|
+
// Check if we have enough data for the complete proposal
|
|
259
|
+
if (offset + proposalLength > genericPayload.length) {
|
|
260
|
+
throw new Error(`Insufficient data for complete proposal at offset ${offset}. Need ${proposalLength} bytes, have ${genericPayload.length - offset}`);
|
|
261
|
+
}
|
|
262
|
+
// Pass only the exact buffer slice for this proposal
|
|
263
|
+
const proposalBuffer = buffer.subarray(offset, offset + proposalLength);
|
|
264
|
+
const proposal = proposal_1.Proposal.parse(proposalBuffer);
|
|
265
|
+
proposals.push(proposal);
|
|
266
|
+
offset += proposalLength;
|
|
267
|
+
// Safety check to prevent infinite loops
|
|
268
|
+
if (offset > genericPayload.length) {
|
|
269
|
+
throw new Error(`Proposal parsing exceeded payload length. Offset: ${offset}, Payload length: ${genericPayload.length}`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return new PayloadSA(genericPayload.nextPayload, proposals, genericPayload.critical, genericPayload.length);
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Serializes a JSON representation of the SA payload to a buffer
|
|
276
|
+
* @param json
|
|
277
|
+
* @static
|
|
278
|
+
* @public
|
|
279
|
+
* @returns {Buffer}
|
|
280
|
+
*/
|
|
281
|
+
static serializeJSON(json) {
|
|
282
|
+
const proposalsBuffer = json.proposals.map((proposal) => proposal_1.Proposal.serializeJSON(proposal));
|
|
283
|
+
const buffer = Buffer.alloc(json.length);
|
|
284
|
+
const genericPayload = Payload.serializeJSON(json);
|
|
285
|
+
genericPayload.copy(buffer);
|
|
286
|
+
let offset = 4;
|
|
287
|
+
for (const proposalBuffer of proposalsBuffer) {
|
|
288
|
+
proposalBuffer.copy(buffer, offset);
|
|
289
|
+
offset += proposalBuffer.length;
|
|
290
|
+
}
|
|
291
|
+
return buffer;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Serializes the SA payload to a buffer
|
|
295
|
+
* @public
|
|
296
|
+
* @returns {Buffer}
|
|
297
|
+
*/
|
|
298
|
+
serialize() {
|
|
299
|
+
// Encode deep first, to calculate the total length
|
|
300
|
+
const proposalsBuffer = this.proposals.map((proposal) => proposal.serialize());
|
|
301
|
+
const proposals = Buffer.concat(proposalsBuffer);
|
|
302
|
+
// Fix the length
|
|
303
|
+
this.length = 4 + proposals.length;
|
|
304
|
+
const buffer = Buffer.alloc(this.length);
|
|
305
|
+
super.serialize().copy(buffer);
|
|
306
|
+
proposals.copy(buffer, 4);
|
|
307
|
+
return buffer;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Returns a JSON representation of the SA payload
|
|
311
|
+
* @public
|
|
312
|
+
* @returns {Record<string, any>}
|
|
313
|
+
*/
|
|
314
|
+
toJSON() {
|
|
315
|
+
const json = super.genToJSON();
|
|
316
|
+
json.proposals = this.proposals.map((proposal) => proposal.toJSON());
|
|
317
|
+
return json;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Returns a string representation of the SA payload
|
|
321
|
+
* @public
|
|
322
|
+
* @returns {string}
|
|
323
|
+
*/
|
|
324
|
+
toString() {
|
|
325
|
+
const genericString = super.genToString();
|
|
326
|
+
const proposalsString = this.proposals.map((proposal) => proposal.toString());
|
|
327
|
+
return `${genericString}\nProposals:\n${proposalsString.join("\n")}`;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
exports.PayloadSA = PayloadSA;
|
|
331
|
+
/**
|
|
332
|
+
* IKEv2 Key Exchange Payload
|
|
333
|
+
* @class
|
|
334
|
+
* @extends Payload
|
|
335
|
+
*/
|
|
336
|
+
class PayloadKE extends Payload {
|
|
337
|
+
constructor(nextPayload, dhGroup, keyData, critical = false, length = 0) {
|
|
338
|
+
super(payloadType.KE, nextPayload, critical, length > 0 ? length : 8 + keyData.length);
|
|
339
|
+
this.nextPayload = nextPayload;
|
|
340
|
+
this.dhGroup = dhGroup;
|
|
341
|
+
this.keyData = keyData;
|
|
342
|
+
this.critical = critical;
|
|
343
|
+
this.length = length;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Parses a Key Exchange Payload from a buffer
|
|
347
|
+
* @param buffer
|
|
348
|
+
* @static
|
|
349
|
+
* @public
|
|
350
|
+
* @returns {PayloadKE}
|
|
351
|
+
*/
|
|
352
|
+
static parse(buffer) {
|
|
353
|
+
const genericPayload = Payload.parse(buffer);
|
|
354
|
+
// Validate that buffer is at least as long as the declared payload length
|
|
355
|
+
if (buffer.length < genericPayload.length) {
|
|
356
|
+
throw new Error(`Buffer too short for declared payload length. Expected at least ${genericPayload.length} bytes, got ${buffer.length}`);
|
|
357
|
+
}
|
|
358
|
+
// Check if we have enough data for dhGroup (2 bytes) and reserved field (2 bytes)
|
|
359
|
+
if (genericPayload.length < 8) {
|
|
360
|
+
throw new Error(`Payload too short for KE payload. Expected at least 8 bytes, got ${genericPayload.length}`);
|
|
361
|
+
}
|
|
362
|
+
const dhGroup = buffer.readUInt16BE(4);
|
|
363
|
+
const keyData = buffer.subarray(8, genericPayload.length);
|
|
364
|
+
return new PayloadKE(genericPayload.nextPayload, dhGroup, keyData, genericPayload.critical, genericPayload.length);
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Serializes a JSON representation of the KE payload to a buffer
|
|
368
|
+
* @param json
|
|
369
|
+
* @static
|
|
370
|
+
* @public
|
|
371
|
+
* @returns {Buffer}
|
|
372
|
+
*/
|
|
373
|
+
static serializeJSON(json) {
|
|
374
|
+
try {
|
|
375
|
+
// Input validation
|
|
376
|
+
if (!json || typeof json !== "object") {
|
|
377
|
+
throw new Error("JSON input must be a valid object");
|
|
378
|
+
}
|
|
379
|
+
// Validate required fields
|
|
380
|
+
if (typeof json.dhGroup === "undefined") {
|
|
381
|
+
throw new Error("dhGroup is required");
|
|
382
|
+
}
|
|
383
|
+
if (typeof json.keyData === "undefined") {
|
|
384
|
+
throw new Error("keyData is required");
|
|
385
|
+
}
|
|
386
|
+
// Validate dhGroup
|
|
387
|
+
if (!Number.isInteger(json.dhGroup) ||
|
|
388
|
+
json.dhGroup < 0 ||
|
|
389
|
+
json.dhGroup > 65535) {
|
|
390
|
+
throw new Error(`dhGroup must be a valid 16-bit unsigned integer (0-65535), got ${json.dhGroup}`);
|
|
391
|
+
}
|
|
392
|
+
// Validate keyData
|
|
393
|
+
if (typeof json.keyData !== "string") {
|
|
394
|
+
throw new Error(`keyData must be a hex string, got ${typeof json.keyData}`);
|
|
395
|
+
}
|
|
396
|
+
// Validate hex string format
|
|
397
|
+
if (!/^[0-9a-fA-F]*$/.test(json.keyData)) {
|
|
398
|
+
throw new Error("keyData must be a valid hex string");
|
|
399
|
+
}
|
|
400
|
+
const buffer = Buffer.alloc(json.length);
|
|
401
|
+
const genericPayload = Payload.serializeJSON(json);
|
|
402
|
+
genericPayload.copy(buffer);
|
|
403
|
+
buffer.writeUInt16BE(json.dhGroup, 4);
|
|
404
|
+
buffer.writeUInt16BE(0, 6); // Reserved - use big-endian for consistency
|
|
405
|
+
Buffer.from(json.keyData, "hex").copy(buffer, 8);
|
|
406
|
+
return buffer;
|
|
407
|
+
}
|
|
408
|
+
catch (error) {
|
|
409
|
+
if (error instanceof Error) {
|
|
410
|
+
throw new Error(`Failed to serialize KE payload JSON: ${error.message}`);
|
|
411
|
+
}
|
|
412
|
+
throw new Error("Failed to serialize KE payload JSON");
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Serializes the KE payload to a buffer
|
|
417
|
+
* @public
|
|
418
|
+
* @returns {Buffer}
|
|
419
|
+
*/
|
|
420
|
+
serialize() {
|
|
421
|
+
// Fix the length
|
|
422
|
+
this.length = 8 + this.keyData.length;
|
|
423
|
+
const buffer = Buffer.alloc(this.length);
|
|
424
|
+
super.serialize().copy(buffer);
|
|
425
|
+
buffer.writeUInt16BE(this.dhGroup, 4);
|
|
426
|
+
// No need to blank 2 reserved bytes, Buffer.alloc does that
|
|
427
|
+
this.keyData.copy(buffer, 8);
|
|
428
|
+
return buffer;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Returns a JSON representation of the KE payload
|
|
432
|
+
* @public
|
|
433
|
+
* @returns {Record<string, any>}
|
|
434
|
+
*/
|
|
435
|
+
toJSON() {
|
|
436
|
+
const json = super.genToJSON();
|
|
437
|
+
json.dhGroup = this.dhGroup;
|
|
438
|
+
json.keyData = this.keyData.toString("hex");
|
|
439
|
+
return json;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Returns a string representation of the KE payload
|
|
443
|
+
* @public
|
|
444
|
+
* @returns {string}
|
|
445
|
+
*/
|
|
446
|
+
toString() {
|
|
447
|
+
const genericString = super.genToString();
|
|
448
|
+
return `${genericString}\ndhGroup: ${this.dhGroup}\nkeyData: "${this.keyData.toString("hex")}"`;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
exports.PayloadKE = PayloadKE;
|
|
452
|
+
/**
|
|
453
|
+
* IKEv2 Identification Payload
|
|
454
|
+
* @enum
|
|
455
|
+
*/
|
|
456
|
+
var IDType;
|
|
457
|
+
(function (IDType) {
|
|
458
|
+
IDType[IDType["ID_IPV4_ADDR"] = 1] = "ID_IPV4_ADDR";
|
|
459
|
+
IDType[IDType["ID_FQDN"] = 2] = "ID_FQDN";
|
|
460
|
+
IDType[IDType["ID_RFC822_ADDR"] = 3] = "ID_RFC822_ADDR";
|
|
461
|
+
IDType[IDType["ID_IPV6_ADDR"] = 5] = "ID_IPV6_ADDR";
|
|
462
|
+
IDType[IDType["ID_DER_ASN1_DN"] = 9] = "ID_DER_ASN1_DN";
|
|
463
|
+
IDType[IDType["ID_DER_ASN1_GN"] = 10] = "ID_DER_ASN1_GN";
|
|
464
|
+
IDType[IDType["ID_KEY_ID"] = 11] = "ID_KEY_ID";
|
|
465
|
+
})(IDType || (exports.IDType = IDType = {}));
|
|
466
|
+
/**
|
|
467
|
+
* IKEv2 Identification Payload
|
|
468
|
+
* @class
|
|
469
|
+
* @extends Payload
|
|
470
|
+
*/
|
|
471
|
+
class PayloadID extends Payload {
|
|
472
|
+
constructor(nextPayload, idType, idData, critical = false, length = 0) {
|
|
473
|
+
super(payloadType.NONE, nextPayload, critical, length > 0 ? length : 5 + idData.length);
|
|
474
|
+
this.nextPayload = nextPayload;
|
|
475
|
+
this.idType = idType;
|
|
476
|
+
this.idData = idData;
|
|
477
|
+
this.critical = critical;
|
|
478
|
+
this.length = length;
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Parses an Identification Payload from a buffer
|
|
482
|
+
* @param buffer
|
|
483
|
+
* @static
|
|
484
|
+
* @public
|
|
485
|
+
* @returns {PayloadID}
|
|
486
|
+
*/
|
|
487
|
+
static parse(buffer) {
|
|
488
|
+
const genericPayload = Payload.parse(buffer);
|
|
489
|
+
// Validate that buffer is at least as long as the declared payload length
|
|
490
|
+
if (buffer.length < genericPayload.length) {
|
|
491
|
+
throw new Error(`Buffer too short for declared payload length. Expected at least ${genericPayload.length} bytes, got ${buffer.length}`);
|
|
492
|
+
}
|
|
493
|
+
// Check if we have enough data for idType (1 byte) and reserved field (3 bytes)
|
|
494
|
+
if (genericPayload.length < 8) {
|
|
495
|
+
throw new Error(`Payload too short for ID payload. Expected at least 8 bytes, got ${genericPayload.length}`);
|
|
496
|
+
}
|
|
497
|
+
const idType = buffer.readUInt8(4);
|
|
498
|
+
const idData = buffer.subarray(8, genericPayload.length);
|
|
499
|
+
return new PayloadID(genericPayload.nextPayload, idType, idData, genericPayload.critical, genericPayload.length);
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Serializes a JSON representation of the ID payload to a buffer
|
|
503
|
+
* @param json
|
|
504
|
+
* @static
|
|
505
|
+
* @public
|
|
506
|
+
* @returns {Buffer}
|
|
507
|
+
*/
|
|
508
|
+
static serializeJSON(json) {
|
|
509
|
+
try {
|
|
510
|
+
// Input validation
|
|
511
|
+
if (!json || typeof json !== "object") {
|
|
512
|
+
throw new Error("JSON input must be a valid object");
|
|
513
|
+
}
|
|
514
|
+
// Validate required fields
|
|
515
|
+
if (typeof json.idType === "undefined") {
|
|
516
|
+
throw new Error("idType is required");
|
|
517
|
+
}
|
|
518
|
+
if (typeof json.idData === "undefined") {
|
|
519
|
+
throw new Error("idData is required");
|
|
520
|
+
}
|
|
521
|
+
// Validate idType
|
|
522
|
+
if (!Number.isInteger(json.idType) ||
|
|
523
|
+
json.idType < 0 ||
|
|
524
|
+
json.idType > 255) {
|
|
525
|
+
throw new Error(`idType must be a valid 8-bit unsigned integer (0-255), got ${json.idType}`);
|
|
526
|
+
}
|
|
527
|
+
// Validate idData
|
|
528
|
+
if (typeof json.idData !== "string") {
|
|
529
|
+
throw new Error(`idData must be a hex string, got ${typeof json.idData}`);
|
|
530
|
+
}
|
|
531
|
+
// Validate hex string format
|
|
532
|
+
if (!/^[0-9a-fA-F]*$/.test(json.idData)) {
|
|
533
|
+
throw new Error("idData must be a valid hex string");
|
|
534
|
+
}
|
|
535
|
+
const buffer = Buffer.alloc(json.length);
|
|
536
|
+
const genericPayload = Payload.serializeJSON(json);
|
|
537
|
+
genericPayload.copy(buffer);
|
|
538
|
+
buffer.writeUInt8(json.idType, 4);
|
|
539
|
+
// Write 3-byte reserved field as zeros in big-endian order
|
|
540
|
+
buffer.writeUInt8(0, 5);
|
|
541
|
+
buffer.writeUInt8(0, 6);
|
|
542
|
+
buffer.writeUInt8(0, 7);
|
|
543
|
+
Buffer.from(json.idData, "hex").copy(buffer, 8);
|
|
544
|
+
return buffer;
|
|
545
|
+
}
|
|
546
|
+
catch (error) {
|
|
547
|
+
if (error instanceof Error) {
|
|
548
|
+
throw new Error(`Failed to serialize ID payload JSON: ${error.message}`);
|
|
549
|
+
}
|
|
550
|
+
throw new Error("Failed to serialize ID payload JSON");
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Serializes the ID payload to a buffer
|
|
555
|
+
* @public
|
|
556
|
+
* @returns {Buffer}
|
|
557
|
+
*/
|
|
558
|
+
serialize() {
|
|
559
|
+
// Fix the length
|
|
560
|
+
this.length = 8 + this.idData.length;
|
|
561
|
+
const buffer = Buffer.alloc(this.length);
|
|
562
|
+
super.serialize().copy(buffer);
|
|
563
|
+
buffer.writeUInt8(this.idType, 4);
|
|
564
|
+
// No need to blank 3 reserved bytes, Buffer.alloc does that
|
|
565
|
+
this.idData.copy(buffer, 8);
|
|
566
|
+
return buffer;
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Returns a JSON representation of the ID payload
|
|
570
|
+
* @public
|
|
571
|
+
* @returns {Record<string, any>}
|
|
572
|
+
*/
|
|
573
|
+
toJSON() {
|
|
574
|
+
const json = super.genToJSON();
|
|
575
|
+
json.idType = this.idType;
|
|
576
|
+
json.idData = this.idData.toString("hex");
|
|
577
|
+
return json;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Returns a string representation of the ID payload
|
|
581
|
+
* @public
|
|
582
|
+
* @returns {string}
|
|
583
|
+
*/
|
|
584
|
+
toString() {
|
|
585
|
+
const genericString = super.genToString();
|
|
586
|
+
return `${genericString}\nidType: ${IDType[this.idType]}\nidData: "${this.idData.toString("hex")}"`;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
exports.PayloadID = PayloadID;
|
|
590
|
+
/**
|
|
591
|
+
* IKEv2 Identification - Initiator Payload
|
|
592
|
+
* @class
|
|
593
|
+
* @extends PayloadID
|
|
594
|
+
*/
|
|
595
|
+
class PayloadIDi extends PayloadID {
|
|
596
|
+
constructor(nextPayload, idType, idData, critical = false, length = 0) {
|
|
597
|
+
super(nextPayload, idType, idData, critical, length > 0 ? length : 5 + idData.length);
|
|
598
|
+
this.nextPayload = nextPayload;
|
|
599
|
+
this.idType = idType;
|
|
600
|
+
this.idData = idData;
|
|
601
|
+
this.critical = critical;
|
|
602
|
+
this.length = length;
|
|
603
|
+
this.type = payloadType.IDi;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
exports.PayloadIDi = PayloadIDi;
|
|
607
|
+
/**
|
|
608
|
+
* IKEv2 Identification - Responder Payload
|
|
609
|
+
* @class
|
|
610
|
+
* @extends PayloadID
|
|
611
|
+
*/
|
|
612
|
+
class PayloadIDr extends PayloadID {
|
|
613
|
+
constructor(nextPayload, idType, idData, critical, length) {
|
|
614
|
+
super(nextPayload, idType, idData, critical, length > 0 ? length : 5 + idData.length);
|
|
615
|
+
this.nextPayload = nextPayload;
|
|
616
|
+
this.idType = idType;
|
|
617
|
+
this.idData = idData;
|
|
618
|
+
this.critical = critical;
|
|
619
|
+
this.length = length;
|
|
620
|
+
this.type = payloadType.IDr;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
exports.PayloadIDr = PayloadIDr;
|
|
624
|
+
/**
|
|
625
|
+
* IKEv2 Notify Message Types
|
|
626
|
+
* @enum
|
|
627
|
+
*/
|
|
628
|
+
var CertificateType;
|
|
629
|
+
(function (CertificateType) {
|
|
630
|
+
CertificateType[CertificateType["RESERVED"] = 0] = "RESERVED";
|
|
631
|
+
CertificateType[CertificateType["PKCS7_X509_CERTIFICATE"] = 1] = "PKCS7_X509_CERTIFICATE";
|
|
632
|
+
CertificateType[CertificateType["PGP_CERTIFICATE"] = 2] = "PGP_CERTIFICATE";
|
|
633
|
+
CertificateType[CertificateType["DNS_SIGNED_KEY"] = 3] = "DNS_SIGNED_KEY";
|
|
634
|
+
CertificateType[CertificateType["X509_CERTIFICATE_SIGNATURE"] = 4] = "X509_CERTIFICATE_SIGNATURE";
|
|
635
|
+
CertificateType[CertificateType["UNDEFINED"] = 5] = "UNDEFINED";
|
|
636
|
+
CertificateType[CertificateType["KERBEROS_TOKENS"] = 6] = "KERBEROS_TOKENS";
|
|
637
|
+
CertificateType[CertificateType["CRL"] = 7] = "CRL";
|
|
638
|
+
CertificateType[CertificateType["ARL"] = 8] = "ARL";
|
|
639
|
+
CertificateType[CertificateType["SPKI_CERTIFICATE"] = 9] = "SPKI_CERTIFICATE";
|
|
640
|
+
CertificateType[CertificateType["X509_CERTIFICATE_ATTRIBUTE"] = 10] = "X509_CERTIFICATE_ATTRIBUTE";
|
|
641
|
+
CertificateType[CertificateType["RAW_RSA_KEY"] = 11] = "RAW_RSA_KEY";
|
|
642
|
+
CertificateType[CertificateType["HASH_AND_URL_X509_CERTIFICATE"] = 12] = "HASH_AND_URL_X509_CERTIFICATE";
|
|
643
|
+
CertificateType[CertificateType["HASH_AND_URL_X509_BUNDLE"] = 13] = "HASH_AND_URL_X509_BUNDLE";
|
|
644
|
+
CertificateType[CertificateType["OCSP_CONTENT"] = 14] = "OCSP_CONTENT";
|
|
645
|
+
})(CertificateType || (exports.CertificateType = CertificateType = {}));
|
|
646
|
+
/**
|
|
647
|
+
* IKEv2 Certificate Payload
|
|
648
|
+
* @class
|
|
649
|
+
* @extends Payload
|
|
650
|
+
*/
|
|
651
|
+
class PayloadCERT extends Payload {
|
|
652
|
+
constructor(nextPayload, certEncoding, certData, critical = false, length = 0) {
|
|
653
|
+
super(payloadType.CERT, nextPayload, critical, length > 0 ? length : 5 + certData.length);
|
|
654
|
+
this.nextPayload = nextPayload;
|
|
655
|
+
this.certEncoding = certEncoding;
|
|
656
|
+
this.certData = certData;
|
|
657
|
+
this.critical = critical;
|
|
658
|
+
this.length = length;
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Parses a Certificate Payload from a buffer
|
|
662
|
+
* @param buffer
|
|
663
|
+
* @static
|
|
664
|
+
* @public
|
|
665
|
+
* @returns {PayloadCERT}
|
|
666
|
+
*/
|
|
667
|
+
static parse(buffer) {
|
|
668
|
+
const genericPayload = Payload.parse(buffer);
|
|
669
|
+
// Validate that buffer is at least as long as the declared payload length
|
|
670
|
+
if (buffer.length < genericPayload.length) {
|
|
671
|
+
throw new Error(`Buffer too short for declared payload length. Expected at least ${genericPayload.length} bytes, got ${buffer.length}`);
|
|
672
|
+
}
|
|
673
|
+
// Check if we have enough data for certEncoding (1 byte)
|
|
674
|
+
if (genericPayload.length < 5) {
|
|
675
|
+
throw new Error(`Payload too short for CERT payload. Expected at least 5 bytes, got ${genericPayload.length}`);
|
|
676
|
+
}
|
|
677
|
+
const certEncoding = buffer.readUInt8(4);
|
|
678
|
+
const certData = buffer.subarray(5, genericPayload.length);
|
|
679
|
+
return new PayloadCERT(genericPayload.nextPayload, certEncoding, certData, genericPayload.critical, genericPayload.length);
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Serializes a JSON representation of the CERT payload to a buffer
|
|
683
|
+
* @param json
|
|
684
|
+
* @static
|
|
685
|
+
* @public
|
|
686
|
+
* @returns {Buffer}
|
|
687
|
+
*/
|
|
688
|
+
static serializeJSON(json) {
|
|
689
|
+
const buffer = Buffer.alloc(json.length);
|
|
690
|
+
const genericPayload = Payload.serializeJSON(json);
|
|
691
|
+
genericPayload.copy(buffer);
|
|
692
|
+
buffer.writeUInt8(json.certEncoding, 4);
|
|
693
|
+
Buffer.from(json.certData, "hex").copy(buffer, 5);
|
|
694
|
+
return buffer;
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* Serializes the CERT payload to a buffer
|
|
698
|
+
* @public
|
|
699
|
+
* @returns {Buffer}
|
|
700
|
+
*/
|
|
701
|
+
serialize() {
|
|
702
|
+
// Fix the length
|
|
703
|
+
this.length = 5 + this.certData.length;
|
|
704
|
+
const buffer = Buffer.alloc(this.length);
|
|
705
|
+
super.serialize().copy(buffer);
|
|
706
|
+
buffer.writeUInt8(this.certEncoding, 4);
|
|
707
|
+
this.certData.copy(buffer, 5);
|
|
708
|
+
return buffer;
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Returns a JSON representation of the CERT payload
|
|
712
|
+
* @public
|
|
713
|
+
* @returns {Record<string, any>}
|
|
714
|
+
*/
|
|
715
|
+
toJSON() {
|
|
716
|
+
const json = super.genToJSON();
|
|
717
|
+
json.certEncoding = this.certEncoding;
|
|
718
|
+
json.certData = this.certData.toString("hex");
|
|
719
|
+
return json;
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Returns a string representation of the CERT payload
|
|
723
|
+
* @public
|
|
724
|
+
* @returns {string}
|
|
725
|
+
*/
|
|
726
|
+
toString() {
|
|
727
|
+
const genericString = super.genToString();
|
|
728
|
+
return `${genericString}\ncertEncoding: ${CertificateType[this.certEncoding]} (${this.certEncoding})\ncertData: "${this.certData.toString("hex")}"`;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
exports.PayloadCERT = PayloadCERT;
|
|
732
|
+
/**
|
|
733
|
+
* IKEv2 Certificate Request Payload
|
|
734
|
+
* @class
|
|
735
|
+
* @extends Payload
|
|
736
|
+
*/
|
|
737
|
+
class PayloadCERTREQ extends Payload {
|
|
738
|
+
constructor(nextPayload, certEncoding, certAuthority, critical = false, length = 0) {
|
|
739
|
+
super(payloadType.CERTREQ, nextPayload, critical, length > 0 ? length : 5 + certAuthority.length);
|
|
740
|
+
this.nextPayload = nextPayload;
|
|
741
|
+
this.certEncoding = certEncoding;
|
|
742
|
+
this.certAuthority = certAuthority;
|
|
743
|
+
this.critical = critical;
|
|
744
|
+
this.length = length;
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* Parses a Certificate Request Payload from a buffer
|
|
748
|
+
* @param buffer
|
|
749
|
+
* @static
|
|
750
|
+
* @public
|
|
751
|
+
* @returns {PayloadCERTREQ}
|
|
752
|
+
*/
|
|
753
|
+
static parse(buffer) {
|
|
754
|
+
const genericPayload = Payload.parse(buffer);
|
|
755
|
+
const certEncoding = buffer.readUInt8(4);
|
|
756
|
+
const certAuthority = buffer.subarray(5, genericPayload.length);
|
|
757
|
+
return new PayloadCERTREQ(genericPayload.nextPayload, certEncoding, certAuthority, genericPayload.critical, genericPayload.length);
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Serializes a JSON representation of the CERTREQ payload to a buffer
|
|
761
|
+
* @param json
|
|
762
|
+
* @static
|
|
763
|
+
* @public
|
|
764
|
+
* @returns {Buffer}
|
|
765
|
+
*/
|
|
766
|
+
static serializeJSON(json) {
|
|
767
|
+
const buffer = Buffer.alloc(json.length);
|
|
768
|
+
const genericPayload = Payload.serializeJSON(json);
|
|
769
|
+
genericPayload.copy(buffer);
|
|
770
|
+
buffer.writeUInt8(json.certEncoding, 4);
|
|
771
|
+
Buffer.from(json.certAuthority, "hex").copy(buffer, 5);
|
|
772
|
+
return buffer;
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Serializes the CERTREQ payload to a buffer
|
|
776
|
+
* @public
|
|
777
|
+
* @returns {Buffer}
|
|
778
|
+
*/
|
|
779
|
+
serialize() {
|
|
780
|
+
// Fix the length
|
|
781
|
+
this.length = 5 + this.certAuthority.length;
|
|
782
|
+
const buffer = Buffer.alloc(this.length);
|
|
783
|
+
super.serialize().copy(buffer);
|
|
784
|
+
buffer.writeUInt8(this.certEncoding, 4);
|
|
785
|
+
this.certAuthority.copy(buffer, 5);
|
|
786
|
+
return buffer;
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Returns a JSON representation of the CERTREQ payload
|
|
790
|
+
* @public
|
|
791
|
+
* @returns {Record<string, any>}
|
|
792
|
+
*/
|
|
793
|
+
toJSON() {
|
|
794
|
+
const json = super.genToJSON();
|
|
795
|
+
json.certEncoding = this.certEncoding;
|
|
796
|
+
json.certAuthority = this.certAuthority.toString("hex");
|
|
797
|
+
return json;
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Returns a string representation of the CERTREQ payload
|
|
801
|
+
* @public
|
|
802
|
+
* @returns {string}
|
|
803
|
+
*/
|
|
804
|
+
toString() {
|
|
805
|
+
const genericString = super.genToString();
|
|
806
|
+
return `${genericString}\ncertEncoding: ${CertificateType[this.certEncoding]} (${this.certEncoding})\ncertAuthority: "${this.certAuthority.toString("hex")}"`;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
exports.PayloadCERTREQ = PayloadCERTREQ;
|
|
810
|
+
/**
|
|
811
|
+
* IKEv2 Authentication Payload
|
|
812
|
+
* @class
|
|
813
|
+
* @extends Payload
|
|
814
|
+
*/
|
|
815
|
+
class PayloadAUTH extends Payload {
|
|
816
|
+
constructor(nextPayload, authMethod, authData, critical = false, length = 0) {
|
|
817
|
+
super(payloadType.AUTH, nextPayload, critical, length > 0 ? length : 5 + authData.length);
|
|
818
|
+
this.nextPayload = nextPayload;
|
|
819
|
+
this.authMethod = authMethod;
|
|
820
|
+
this.authData = authData;
|
|
821
|
+
this.critical = critical;
|
|
822
|
+
this.length = length;
|
|
823
|
+
}
|
|
824
|
+
/**
|
|
825
|
+
* Parses an Authentication Payload from a buffer
|
|
826
|
+
* @param buffer
|
|
827
|
+
* @static
|
|
828
|
+
* @public
|
|
829
|
+
* @returns {PayloadAUTH}
|
|
830
|
+
*/
|
|
831
|
+
static parse(buffer) {
|
|
832
|
+
const genericPayload = Payload.parse(buffer);
|
|
833
|
+
const authMethod = buffer.readUInt8(4);
|
|
834
|
+
const authData = buffer.subarray(5, genericPayload.length);
|
|
835
|
+
return new PayloadAUTH(genericPayload.nextPayload, authMethod, authData, genericPayload.critical, genericPayload.length);
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Serializes a JSON representation of the AUTH payload to a buffer
|
|
839
|
+
* @param json
|
|
840
|
+
* @static
|
|
841
|
+
* @public
|
|
842
|
+
* @returns {Buffer}
|
|
843
|
+
*/
|
|
844
|
+
static serializeJSON(json) {
|
|
845
|
+
const buffer = Buffer.alloc(json.length);
|
|
846
|
+
const genericPayload = Payload.serializeJSON(json);
|
|
847
|
+
genericPayload.copy(buffer);
|
|
848
|
+
buffer.writeUInt8(json.authMethod, 4);
|
|
849
|
+
// Write 3-byte reserved field as zeros in big-endian order
|
|
850
|
+
buffer.writeUInt8(0, 5);
|
|
851
|
+
buffer.writeUInt8(0, 6);
|
|
852
|
+
buffer.writeUInt8(0, 7);
|
|
853
|
+
Buffer.from(json.authData, "hex").copy(buffer, 8);
|
|
854
|
+
return buffer;
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Serializes the AUTH payload to a buffer
|
|
858
|
+
* @public
|
|
859
|
+
* @returns {Buffer}
|
|
860
|
+
*/
|
|
861
|
+
serialize() {
|
|
862
|
+
// Fix the length
|
|
863
|
+
this.length = 8 + this.authData.length;
|
|
864
|
+
const buffer = Buffer.alloc(this.length);
|
|
865
|
+
super.serialize().copy(buffer);
|
|
866
|
+
buffer.writeUInt8(this.authMethod, 4);
|
|
867
|
+
// No need to blank 3 reserved bytes, Buffer.alloc does that
|
|
868
|
+
this.authData.copy(buffer, 8);
|
|
869
|
+
return buffer;
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* Returns a JSON representation of the AUTH payload
|
|
873
|
+
* @public
|
|
874
|
+
* @returns {Record<string, any>}
|
|
875
|
+
*/
|
|
876
|
+
toJSON() {
|
|
877
|
+
const json = super.genToJSON();
|
|
878
|
+
json.authMethod = this.authMethod;
|
|
879
|
+
json.authData = this.authData.toString("hex");
|
|
880
|
+
return json;
|
|
881
|
+
}
|
|
882
|
+
/**
|
|
883
|
+
* Returns a string representation of the AUTH payload
|
|
884
|
+
* @public
|
|
885
|
+
* @returns {string}
|
|
886
|
+
*/
|
|
887
|
+
toString() {
|
|
888
|
+
const genericString = super.genToString();
|
|
889
|
+
return `${genericString}\nauthMethod: ${this.authMethod}\nauthData: "${this.authData.toString("hex")}"`;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
exports.PayloadAUTH = PayloadAUTH;
|
|
893
|
+
/**
|
|
894
|
+
* IKEv2 Nonce Payload
|
|
895
|
+
* @class
|
|
896
|
+
* @extends Payload
|
|
897
|
+
*/
|
|
898
|
+
class PayloadNONCE extends Payload {
|
|
899
|
+
constructor(nextPayload, nonceData, critical = false, length = 0) {
|
|
900
|
+
super(payloadType.NONCE, nextPayload, critical, length > 0 ? length : 4 + nonceData.length);
|
|
901
|
+
this.nextPayload = nextPayload;
|
|
902
|
+
this.nonceData = nonceData;
|
|
903
|
+
this.critical = critical;
|
|
904
|
+
this.length = length;
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Parses a Nonce Payload from a buffer
|
|
908
|
+
* @param buffer
|
|
909
|
+
* @static
|
|
910
|
+
* @public
|
|
911
|
+
* @returns {PayloadNONCE}
|
|
912
|
+
*/
|
|
913
|
+
static parse(buffer) {
|
|
914
|
+
const genericPayload = Payload.parse(buffer);
|
|
915
|
+
const nonceData = buffer.subarray(4, genericPayload.length);
|
|
916
|
+
return new PayloadNONCE(genericPayload.nextPayload, nonceData, genericPayload.critical, genericPayload.length);
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* Serializes a JSON representation of the NONCE payload to a buffer
|
|
920
|
+
* @param json
|
|
921
|
+
* @static
|
|
922
|
+
* @public
|
|
923
|
+
* @returns {Buffer}
|
|
924
|
+
*/
|
|
925
|
+
static serializeJSON(json) {
|
|
926
|
+
const buffer = Buffer.alloc(json.length);
|
|
927
|
+
const genericPayload = Payload.serializeJSON(json);
|
|
928
|
+
genericPayload.copy(buffer);
|
|
929
|
+
Buffer.from(json.nonceData, "hex").copy(buffer, 4);
|
|
930
|
+
return buffer;
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* Serializes the NONCE payload to a buffer
|
|
934
|
+
* @public
|
|
935
|
+
* @returns {Buffer}
|
|
936
|
+
*/
|
|
937
|
+
serialize() {
|
|
938
|
+
// Fix the length
|
|
939
|
+
this.length = 4 + this.nonceData.length;
|
|
940
|
+
const buffer = Buffer.alloc(this.length);
|
|
941
|
+
super.serialize().copy(buffer);
|
|
942
|
+
this.nonceData.copy(buffer, 4);
|
|
943
|
+
return buffer;
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* Returns a JSON representation of the NONCE payload
|
|
947
|
+
* @public
|
|
948
|
+
* @returns {Record<string, any>}
|
|
949
|
+
*/
|
|
950
|
+
toJSON() {
|
|
951
|
+
const json = super.genToJSON();
|
|
952
|
+
json.nonceData = this.nonceData.toString("hex");
|
|
953
|
+
return json;
|
|
954
|
+
}
|
|
955
|
+
/**
|
|
956
|
+
* Returns a string representation of the NONCE payload
|
|
957
|
+
* @public
|
|
958
|
+
* @returns {string}
|
|
959
|
+
*/
|
|
960
|
+
toString() {
|
|
961
|
+
const genericString = super.genToString();
|
|
962
|
+
return `${genericString}\nnonceData: "${this.nonceData.toString("hex")}"`;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
exports.PayloadNONCE = PayloadNONCE;
|
|
966
|
+
/**
|
|
967
|
+
* IKEv2 Protocol Id
|
|
968
|
+
* @enum
|
|
969
|
+
*/
|
|
970
|
+
var securityProtocolId;
|
|
971
|
+
(function (securityProtocolId) {
|
|
972
|
+
// 0 - Reserved
|
|
973
|
+
securityProtocolId[securityProtocolId["NONE"] = 0] = "NONE";
|
|
974
|
+
securityProtocolId[securityProtocolId["IKE"] = 1] = "IKE";
|
|
975
|
+
securityProtocolId[securityProtocolId["AH"] = 2] = "AH";
|
|
976
|
+
securityProtocolId[securityProtocolId["ESP"] = 3] = "ESP";
|
|
977
|
+
securityProtocolId[securityProtocolId["FC_ESP_HEADER"] = 4] = "FC_ESP_HEADER";
|
|
978
|
+
securityProtocolId[securityProtocolId["FC_CT_AUTHENTICATION"] = 5] = "FC_CT_AUTHENTICATION";
|
|
979
|
+
securityProtocolId[securityProtocolId["GIKE_UPDATE"] = 6] = "GIKE_UPDATE";
|
|
980
|
+
// 7-200 Unassigned
|
|
981
|
+
// 201-255 - Reserved for Private Use
|
|
982
|
+
})(securityProtocolId || (exports.securityProtocolId = securityProtocolId = {}));
|
|
983
|
+
/**
|
|
984
|
+
* IKEv2 Notify Message Types
|
|
985
|
+
* @enum
|
|
986
|
+
*/
|
|
987
|
+
var notifyMessageType;
|
|
988
|
+
(function (notifyMessageType) {
|
|
989
|
+
notifyMessageType[notifyMessageType["UNSUPPORTED_CRITICAL_PAYLOAD"] = 1] = "UNSUPPORTED_CRITICAL_PAYLOAD";
|
|
990
|
+
notifyMessageType[notifyMessageType["INVALID_IKE_SPI"] = 4] = "INVALID_IKE_SPI";
|
|
991
|
+
notifyMessageType[notifyMessageType["INVALID_MAJOR_VERSION"] = 5] = "INVALID_MAJOR_VERSION";
|
|
992
|
+
notifyMessageType[notifyMessageType["INVALID_SYNTAX"] = 7] = "INVALID_SYNTAX";
|
|
993
|
+
notifyMessageType[notifyMessageType["INVALID_MESSAGE_ID"] = 9] = "INVALID_MESSAGE_ID";
|
|
994
|
+
notifyMessageType[notifyMessageType["INVALID_SPI"] = 11] = "INVALID_SPI";
|
|
995
|
+
notifyMessageType[notifyMessageType["NO_PROPOSAL_CHOSEN"] = 14] = "NO_PROPOSAL_CHOSEN";
|
|
996
|
+
notifyMessageType[notifyMessageType["INVALID_KE_PAYLOAD"] = 17] = "INVALID_KE_PAYLOAD";
|
|
997
|
+
notifyMessageType[notifyMessageType["AUTHENTICATION_FAILED"] = 24] = "AUTHENTICATION_FAILED";
|
|
998
|
+
notifyMessageType[notifyMessageType["SINGLE_PAIR_REQUIRED"] = 34] = "SINGLE_PAIR_REQUIRED";
|
|
999
|
+
notifyMessageType[notifyMessageType["NO_ADDITIONAL_SAS"] = 35] = "NO_ADDITIONAL_SAS";
|
|
1000
|
+
notifyMessageType[notifyMessageType["INTERNAL_ADDRESS_FAILURE"] = 36] = "INTERNAL_ADDRESS_FAILURE";
|
|
1001
|
+
notifyMessageType[notifyMessageType["FAILED_CP_REQUIRED"] = 37] = "FAILED_CP_REQUIRED";
|
|
1002
|
+
notifyMessageType[notifyMessageType["TS_UNACCEPTABLE"] = 38] = "TS_UNACCEPTABLE";
|
|
1003
|
+
notifyMessageType[notifyMessageType["INVALID_SELECTORS"] = 39] = "INVALID_SELECTORS";
|
|
1004
|
+
notifyMessageType[notifyMessageType["TEMPORARY_FAILURE"] = 43] = "TEMPORARY_FAILURE";
|
|
1005
|
+
notifyMessageType[notifyMessageType["CHILD_SA_NOT_FOUND"] = 44] = "CHILD_SA_NOT_FOUND";
|
|
1006
|
+
notifyMessageType[notifyMessageType["INITIAL_CONTACT"] = 16384] = "INITIAL_CONTACT";
|
|
1007
|
+
notifyMessageType[notifyMessageType["SET_WINDOW_SIZE"] = 16385] = "SET_WINDOW_SIZE";
|
|
1008
|
+
notifyMessageType[notifyMessageType["ADDITIONAL_TS_POSSIBLE"] = 16386] = "ADDITIONAL_TS_POSSIBLE";
|
|
1009
|
+
notifyMessageType[notifyMessageType["IPCOMP_SUPPORTED"] = 16387] = "IPCOMP_SUPPORTED";
|
|
1010
|
+
notifyMessageType[notifyMessageType["NAT_DETECTION_SOURCE_IP"] = 16388] = "NAT_DETECTION_SOURCE_IP";
|
|
1011
|
+
notifyMessageType[notifyMessageType["NAT_DETECTION_DESTINATION_IP"] = 16389] = "NAT_DETECTION_DESTINATION_IP";
|
|
1012
|
+
notifyMessageType[notifyMessageType["COOKIE"] = 16390] = "COOKIE";
|
|
1013
|
+
notifyMessageType[notifyMessageType["USE_TRANSPORT_MODE"] = 16391] = "USE_TRANSPORT_MODE";
|
|
1014
|
+
notifyMessageType[notifyMessageType["HTTP_CERT_LOOKUP_SUPPORTED"] = 16392] = "HTTP_CERT_LOOKUP_SUPPORTED";
|
|
1015
|
+
notifyMessageType[notifyMessageType["REKEY_SA"] = 16393] = "REKEY_SA";
|
|
1016
|
+
notifyMessageType[notifyMessageType["ESP_TFC_PADDING_NOT_SUPPORTED"] = 16394] = "ESP_TFC_PADDING_NOT_SUPPORTED";
|
|
1017
|
+
notifyMessageType[notifyMessageType["NON_FIRST_FRAGMENTS_ALSO"] = 16395] = "NON_FIRST_FRAGMENTS_ALSO";
|
|
1018
|
+
notifyMessageType[notifyMessageType["MOBIKE_SUPPORTED"] = 16396] = "MOBIKE_SUPPORTED";
|
|
1019
|
+
notifyMessageType[notifyMessageType["ADDITIONAL_IP4_ADDRESS"] = 16397] = "ADDITIONAL_IP4_ADDRESS";
|
|
1020
|
+
notifyMessageType[notifyMessageType["ADDITIONAL_IP6_ADDRESS"] = 16398] = "ADDITIONAL_IP6_ADDRESS";
|
|
1021
|
+
notifyMessageType[notifyMessageType["NO_ADDITIONAL_ADDRESSES"] = 16399] = "NO_ADDITIONAL_ADDRESSES";
|
|
1022
|
+
notifyMessageType[notifyMessageType["UPDATE_SA_ADDRESSES"] = 16400] = "UPDATE_SA_ADDRESSES";
|
|
1023
|
+
notifyMessageType[notifyMessageType["COOKIE2"] = 16401] = "COOKIE2";
|
|
1024
|
+
notifyMessageType[notifyMessageType["NO_NATS_ALLOWED"] = 16402] = "NO_NATS_ALLOWED";
|
|
1025
|
+
notifyMessageType[notifyMessageType["AUTH_LIFETIME"] = 16403] = "AUTH_LIFETIME";
|
|
1026
|
+
notifyMessageType[notifyMessageType["MULTIPLE_AUTH_SUPPORTED"] = 16404] = "MULTIPLE_AUTH_SUPPORTED";
|
|
1027
|
+
notifyMessageType[notifyMessageType["ANOTHER_AUTH_FOLLOWS"] = 16405] = "ANOTHER_AUTH_FOLLOWS";
|
|
1028
|
+
notifyMessageType[notifyMessageType["REDIRECT_SUPPORTED"] = 16406] = "REDIRECT_SUPPORTED";
|
|
1029
|
+
notifyMessageType[notifyMessageType["REDIRECT"] = 16407] = "REDIRECT";
|
|
1030
|
+
notifyMessageType[notifyMessageType["REDIRECTED_FROM"] = 16408] = "REDIRECTED_FROM";
|
|
1031
|
+
notifyMessageType[notifyMessageType["TICKET_LT_OPAQUE"] = 16409] = "TICKET_LT_OPAQUE";
|
|
1032
|
+
notifyMessageType[notifyMessageType["TICKET_REQUEST"] = 16410] = "TICKET_REQUEST";
|
|
1033
|
+
notifyMessageType[notifyMessageType["TICKET_ACK"] = 16411] = "TICKET_ACK";
|
|
1034
|
+
notifyMessageType[notifyMessageType["TICKET_NACK"] = 16412] = "TICKET_NACK";
|
|
1035
|
+
notifyMessageType[notifyMessageType["TICKET_OPAQUE"] = 16413] = "TICKET_OPAQUE";
|
|
1036
|
+
notifyMessageType[notifyMessageType["LINK_ID"] = 16414] = "LINK_ID";
|
|
1037
|
+
notifyMessageType[notifyMessageType["USE_WESP_MODE"] = 16415] = "USE_WESP_MODE";
|
|
1038
|
+
notifyMessageType[notifyMessageType["ROHC_SUPPORTED"] = 16416] = "ROHC_SUPPORTED";
|
|
1039
|
+
notifyMessageType[notifyMessageType["EAP_ONLY_AUTHENTICATION"] = 16417] = "EAP_ONLY_AUTHENTICATION";
|
|
1040
|
+
notifyMessageType[notifyMessageType["CHILDLESS_IKEV2_SUPPORTED"] = 16418] = "CHILDLESS_IKEV2_SUPPORTED";
|
|
1041
|
+
notifyMessageType[notifyMessageType["QUICK_CRASH_DETECTION"] = 16419] = "QUICK_CRASH_DETECTION";
|
|
1042
|
+
notifyMessageType[notifyMessageType["IKEV2_MESSAGE_ID_SYNC_SUPPORTED"] = 16420] = "IKEV2_MESSAGE_ID_SYNC_SUPPORTED";
|
|
1043
|
+
notifyMessageType[notifyMessageType["IPSEC_REPLAY_COUNTER_SYNC_SUPPORTED"] = 16421] = "IPSEC_REPLAY_COUNTER_SYNC_SUPPORTED";
|
|
1044
|
+
notifyMessageType[notifyMessageType["IKEV2_MESSAGE_ID_SYNC"] = 16422] = "IKEV2_MESSAGE_ID_SYNC";
|
|
1045
|
+
notifyMessageType[notifyMessageType["IPSEC_REPLAY_COUNTER_SYNC"] = 16423] = "IPSEC_REPLAY_COUNTER_SYNC";
|
|
1046
|
+
notifyMessageType[notifyMessageType["SECURE_PASSWORD_METHODS"] = 16424] = "SECURE_PASSWORD_METHODS";
|
|
1047
|
+
notifyMessageType[notifyMessageType["PSK_PERSIST"] = 16425] = "PSK_PERSIST";
|
|
1048
|
+
notifyMessageType[notifyMessageType["PSK_CONFIRM"] = 16426] = "PSK_CONFIRM";
|
|
1049
|
+
notifyMessageType[notifyMessageType["ERX_SUPPORTED"] = 16427] = "ERX_SUPPORTED";
|
|
1050
|
+
notifyMessageType[notifyMessageType["IFOM_CAPABILITY"] = 16428] = "IFOM_CAPABILITY";
|
|
1051
|
+
notifyMessageType[notifyMessageType["SENDER_REQUEST_ID"] = 16429] = "SENDER_REQUEST_ID";
|
|
1052
|
+
notifyMessageType[notifyMessageType["IKEV2_FRAGMENTATION_SUPPORTED"] = 16430] = "IKEV2_FRAGMENTATION_SUPPORTED";
|
|
1053
|
+
notifyMessageType[notifyMessageType["SIGNATURE_HASH_ALGORITHMS"] = 16431] = "SIGNATURE_HASH_ALGORITHMS";
|
|
1054
|
+
notifyMessageType[notifyMessageType["CLONE_IKE_SA_SUPPORTED"] = 16432] = "CLONE_IKE_SA_SUPPORTED";
|
|
1055
|
+
notifyMessageType[notifyMessageType["CLONE_IKE_SA"] = 16433] = "CLONE_IKE_SA";
|
|
1056
|
+
notifyMessageType[notifyMessageType["PUZZLE"] = 16434] = "PUZZLE";
|
|
1057
|
+
notifyMessageType[notifyMessageType["USE_PPK"] = 16435] = "USE_PPK";
|
|
1058
|
+
notifyMessageType[notifyMessageType["PPK_IDENTITY"] = 16436] = "PPK_IDENTITY";
|
|
1059
|
+
notifyMessageType[notifyMessageType["NO_PPK_AUTH"] = 16437] = "NO_PPK_AUTH";
|
|
1060
|
+
notifyMessageType[notifyMessageType["INTERMEDIATE_EXCHANGE_SUPPORTED"] = 16438] = "INTERMEDIATE_EXCHANGE_SUPPORTED";
|
|
1061
|
+
notifyMessageType[notifyMessageType["IP4_ALLOWED_1"] = 16439] = "IP4_ALLOWED_1";
|
|
1062
|
+
notifyMessageType[notifyMessageType["IP4_ALLOWED_2"] = 16440] = "IP4_ALLOWED_2";
|
|
1063
|
+
notifyMessageType[notifyMessageType["ADDITIONAL_KEY_EXCHANGE"] = 16441] = "ADDITIONAL_KEY_EXCHANGE";
|
|
1064
|
+
notifyMessageType[notifyMessageType["USE_AGGFRAG"] = 16442] = "USE_AGGFRAG";
|
|
1065
|
+
notifyMessageType[notifyMessageType["RESERVED_TO_IANA_STATUS_TYPES"] = 16443] = "RESERVED_TO_IANA_STATUS_TYPES";
|
|
1066
|
+
})(notifyMessageType || (exports.notifyMessageType = notifyMessageType = {}));
|
|
1067
|
+
/**
|
|
1068
|
+
* IKEv2 Notify Payload
|
|
1069
|
+
* @class
|
|
1070
|
+
* @extends Payload
|
|
1071
|
+
*/
|
|
1072
|
+
class PayloadNOTIFY extends Payload {
|
|
1073
|
+
constructor(nextPayload, protocolId, spiSize, notifyType, spi, notifyData, critical = false, length = 0) {
|
|
1074
|
+
super(payloadType.NOTIFY, nextPayload, critical, length > 0 ? length : 8 + spi.length + notifyData.length);
|
|
1075
|
+
this.nextPayload = nextPayload;
|
|
1076
|
+
this.protocolId = protocolId;
|
|
1077
|
+
this.spiSize = spiSize;
|
|
1078
|
+
this.notifyType = notifyType;
|
|
1079
|
+
this.spi = spi;
|
|
1080
|
+
this.notifyData = notifyData;
|
|
1081
|
+
this.critical = critical;
|
|
1082
|
+
this.length = length;
|
|
1083
|
+
}
|
|
1084
|
+
/**
|
|
1085
|
+
* Parses a Notify Payload from a buffer
|
|
1086
|
+
* @param buffer
|
|
1087
|
+
* @static
|
|
1088
|
+
* @public
|
|
1089
|
+
* @returns {PayloadNOTIFY}
|
|
1090
|
+
*/
|
|
1091
|
+
static parse(buffer) {
|
|
1092
|
+
const genericPayload = Payload.parse(buffer);
|
|
1093
|
+
const protocolId = buffer.readUInt8(4);
|
|
1094
|
+
const spiSize = buffer.readUInt8(5);
|
|
1095
|
+
const notifyType = buffer.readUInt16BE(6);
|
|
1096
|
+
const spi = buffer.subarray(8, 8 + spiSize);
|
|
1097
|
+
const notifyData = buffer.subarray(8 + spiSize, genericPayload.length);
|
|
1098
|
+
return new PayloadNOTIFY(genericPayload.nextPayload, protocolId, spiSize, notifyType, spi, notifyData, genericPayload.critical, genericPayload.length);
|
|
1099
|
+
}
|
|
1100
|
+
/**
|
|
1101
|
+
* Serializes a JSON representation of the NOTIFY payload to a buffer
|
|
1102
|
+
* @param json
|
|
1103
|
+
* @static
|
|
1104
|
+
* @public
|
|
1105
|
+
* @returns {Buffer}
|
|
1106
|
+
*/
|
|
1107
|
+
static serializeJSON(json) {
|
|
1108
|
+
const buffer = Buffer.alloc(json.length);
|
|
1109
|
+
const genericPayload = Payload.serializeJSON(json);
|
|
1110
|
+
genericPayload.copy(buffer);
|
|
1111
|
+
buffer.writeUInt8(json.protocolId, 4);
|
|
1112
|
+
buffer.writeUInt8(json.spiSize, 5);
|
|
1113
|
+
buffer.writeUInt16BE(json.notifyType, 6);
|
|
1114
|
+
json.spi.length > 0
|
|
1115
|
+
? Buffer.from(json.spi, "hex").copy(buffer, 8)
|
|
1116
|
+
: Buffer.alloc(0).copy(buffer, 8);
|
|
1117
|
+
json.notifyData.length > 0
|
|
1118
|
+
? Buffer.from(json.notifyData, "hex").copy(buffer, 8 + json.spiSize)
|
|
1119
|
+
: Buffer.alloc(0).copy(buffer, 8 + json.spiSize);
|
|
1120
|
+
return buffer;
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* Serializes the NOTIFY payload to a buffer
|
|
1124
|
+
* @public
|
|
1125
|
+
* @returns {Buffer}
|
|
1126
|
+
*/
|
|
1127
|
+
serialize() {
|
|
1128
|
+
// Fix the length
|
|
1129
|
+
this.length = 8 + this.spi.length + this.notifyData.length;
|
|
1130
|
+
const buffer = Buffer.alloc(this.length);
|
|
1131
|
+
super.serialize().copy(buffer);
|
|
1132
|
+
buffer.writeUInt8(this.protocolId, 4);
|
|
1133
|
+
buffer.writeUInt8(this.spiSize, 5);
|
|
1134
|
+
buffer.writeUInt16BE(this.notifyType, 6);
|
|
1135
|
+
this.spi.copy(buffer, 8);
|
|
1136
|
+
this.notifyData.copy(buffer, 8 + this.spiSize);
|
|
1137
|
+
return buffer;
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Returns a JSON representation of the NOTIFY payload
|
|
1141
|
+
* @public
|
|
1142
|
+
* @returns {Record<string, any>}
|
|
1143
|
+
*/
|
|
1144
|
+
toJSON() {
|
|
1145
|
+
const json = super.genToJSON();
|
|
1146
|
+
json.protocolId = this.protocolId;
|
|
1147
|
+
json.spiSize = this.spiSize;
|
|
1148
|
+
json.notifyType = this.notifyType;
|
|
1149
|
+
json.spi = this.spi.toString("hex");
|
|
1150
|
+
json.notifyData = this.notifyData.toString("hex");
|
|
1151
|
+
return json;
|
|
1152
|
+
}
|
|
1153
|
+
/**
|
|
1154
|
+
* Returns a string representation of the NOTIFY payload
|
|
1155
|
+
* @public
|
|
1156
|
+
* @returns {string}
|
|
1157
|
+
*/
|
|
1158
|
+
toString() {
|
|
1159
|
+
var _a, _b;
|
|
1160
|
+
const genericString = super.genToString();
|
|
1161
|
+
return `${genericString}\nprotocolId: ${securityProtocolId[this.protocolId]}\nspiSize: ${this.spiSize}\nnotifyType: ${notifyMessageType[this.notifyType]} (${this.notifyType})\nspi: "${(_b = (_a = this.spi) === null || _a === void 0 ? void 0 : _a.toString("hex")) !== null && _b !== void 0 ? _b : "N/A"}"\nnotifyData: "${this.notifyData.toString("hex")}"`;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
exports.PayloadNOTIFY = PayloadNOTIFY;
|
|
1165
|
+
/**
|
|
1166
|
+
* IKEv2 Delete Payload
|
|
1167
|
+
* @class
|
|
1168
|
+
* @extends Payload
|
|
1169
|
+
*/
|
|
1170
|
+
class PayloadDELETE extends Payload {
|
|
1171
|
+
constructor(nextPayload, protocolId, spiSize, numSpi, spis, critical = false, length = 0) {
|
|
1172
|
+
super(payloadType.DELETE, nextPayload, critical, length > 0 ? length : 8 + spiSize * numSpi);
|
|
1173
|
+
this.nextPayload = nextPayload;
|
|
1174
|
+
this.protocolId = protocolId;
|
|
1175
|
+
this.spiSize = spiSize;
|
|
1176
|
+
this.numSpi = numSpi;
|
|
1177
|
+
this.spis = spis;
|
|
1178
|
+
this.critical = critical;
|
|
1179
|
+
this.length = length;
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* Parses a Delete Payload from a buffer
|
|
1183
|
+
* @param buffer
|
|
1184
|
+
* @static
|
|
1185
|
+
* @public
|
|
1186
|
+
* @returns {PayloadDELETE}
|
|
1187
|
+
*/
|
|
1188
|
+
static parse(buffer) {
|
|
1189
|
+
const genericPayload = Payload.parse(buffer);
|
|
1190
|
+
const protocolId = buffer.readUInt8(4);
|
|
1191
|
+
const spiSize = buffer.readUInt8(5);
|
|
1192
|
+
const numSpi = buffer.readUInt16BE(6);
|
|
1193
|
+
const spis = [];
|
|
1194
|
+
let offset = 8;
|
|
1195
|
+
for (let i = 0; i < numSpi; i++) {
|
|
1196
|
+
const spi = buffer.subarray(offset, offset + spiSize);
|
|
1197
|
+
spis.push(spi);
|
|
1198
|
+
offset += spiSize;
|
|
1199
|
+
}
|
|
1200
|
+
return new PayloadDELETE(genericPayload.nextPayload, protocolId, spiSize, numSpi, spis, genericPayload.critical, genericPayload.length);
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
* Serializes a JSON representation of the DELETE payload to a buffer
|
|
1204
|
+
* @param json
|
|
1205
|
+
* @static
|
|
1206
|
+
* @public
|
|
1207
|
+
* @returns {Buffer}
|
|
1208
|
+
*/
|
|
1209
|
+
static serializeJSON(json) {
|
|
1210
|
+
var _a;
|
|
1211
|
+
const buffer = Buffer.alloc(json.length);
|
|
1212
|
+
const genericPayload = Payload.serializeJSON(json);
|
|
1213
|
+
genericPayload.copy(buffer);
|
|
1214
|
+
buffer.writeUInt8(json.protocolId, 4);
|
|
1215
|
+
buffer.writeUInt8(json.spiSize, 5);
|
|
1216
|
+
buffer.writeUInt16BE(json.numSpi, 6);
|
|
1217
|
+
let offset = 8;
|
|
1218
|
+
const spisBuffer = ((_a = json.spis) === null || _a === void 0 ? void 0 : _a.length) > 0
|
|
1219
|
+
? json.spis.map((spi) => Buffer.from(spi, "hex"))
|
|
1220
|
+
: [Buffer.alloc(0)];
|
|
1221
|
+
for (const spiBuffer of spisBuffer) {
|
|
1222
|
+
spiBuffer.copy(buffer, offset);
|
|
1223
|
+
offset += json.spiSize;
|
|
1224
|
+
}
|
|
1225
|
+
return buffer;
|
|
1226
|
+
}
|
|
1227
|
+
/**
|
|
1228
|
+
* Serializes the DELETE payload to a buffer
|
|
1229
|
+
* @public
|
|
1230
|
+
* @returns {Buffer}
|
|
1231
|
+
*/
|
|
1232
|
+
serialize() {
|
|
1233
|
+
// Fix the length
|
|
1234
|
+
this.length = 8 + this.spiSize * this.numSpi;
|
|
1235
|
+
const buffer = Buffer.alloc(this.length);
|
|
1236
|
+
super.serialize().copy(buffer);
|
|
1237
|
+
buffer.writeUInt8(this.protocolId, 4);
|
|
1238
|
+
buffer.writeUInt8(this.spiSize, 5);
|
|
1239
|
+
buffer.writeUInt16BE(this.numSpi, 6);
|
|
1240
|
+
let offset = 8;
|
|
1241
|
+
for (const spi of this.spis) {
|
|
1242
|
+
spi.copy(buffer, offset);
|
|
1243
|
+
offset += this.spiSize;
|
|
1244
|
+
}
|
|
1245
|
+
return buffer;
|
|
1246
|
+
}
|
|
1247
|
+
/**
|
|
1248
|
+
* Returns a JSON representation of the DELETE payload
|
|
1249
|
+
* @public
|
|
1250
|
+
* @returns {Record<string, any>}
|
|
1251
|
+
*/
|
|
1252
|
+
toJSON() {
|
|
1253
|
+
const json = super.genToJSON();
|
|
1254
|
+
json.protocolId = this.protocolId;
|
|
1255
|
+
json.spiSize = this.spiSize;
|
|
1256
|
+
json.numSpi = this.numSpi;
|
|
1257
|
+
json.spis = this.spis.map((spi) => spi.toString("hex"));
|
|
1258
|
+
return json;
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Returns a string representation of the DELETE payload
|
|
1262
|
+
* @public
|
|
1263
|
+
* @returns {string}
|
|
1264
|
+
*/
|
|
1265
|
+
toString() {
|
|
1266
|
+
const genericString = super.genToString();
|
|
1267
|
+
return `${genericString}\nprotocolId: ${this.protocolId}\nspiSize: ${this.spiSize}\nnumSpi: ${this.numSpi}\nspis: ${this.spis.map((spi) => spi.toString("hex")).join(",")}`;
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
exports.PayloadDELETE = PayloadDELETE;
|
|
1271
|
+
/**
|
|
1272
|
+
* IKEv2 Vendor ID Payload
|
|
1273
|
+
* @class
|
|
1274
|
+
* @extends Payload
|
|
1275
|
+
*/
|
|
1276
|
+
class PayloadVENDOR extends Payload {
|
|
1277
|
+
constructor(nextPayload, vendorId, critical = false, length = 0) {
|
|
1278
|
+
super(payloadType.VENDOR, nextPayload, critical, length > 0 ? length : 4 + vendorId.length);
|
|
1279
|
+
this.nextPayload = nextPayload;
|
|
1280
|
+
this.vendorId = vendorId;
|
|
1281
|
+
this.critical = critical;
|
|
1282
|
+
this.length = length;
|
|
1283
|
+
}
|
|
1284
|
+
/**
|
|
1285
|
+
* Parses a Vendor ID Payload from a buffer
|
|
1286
|
+
* @param buffer
|
|
1287
|
+
* @static
|
|
1288
|
+
* @public
|
|
1289
|
+
* @returns {PayloadVENDOR}
|
|
1290
|
+
*/
|
|
1291
|
+
static parse(buffer) {
|
|
1292
|
+
const genericPayload = Payload.parse(buffer);
|
|
1293
|
+
const vendorId = buffer.subarray(4, genericPayload.length);
|
|
1294
|
+
return new PayloadVENDOR(genericPayload.nextPayload, vendorId, genericPayload.critical, genericPayload.length);
|
|
1295
|
+
}
|
|
1296
|
+
/**
|
|
1297
|
+
* Serializes a JSON representation of the VENDOR payload to a buffer
|
|
1298
|
+
* @param json
|
|
1299
|
+
* @static
|
|
1300
|
+
* @public
|
|
1301
|
+
* @returns {Buffer}
|
|
1302
|
+
*/
|
|
1303
|
+
static serializeJSON(json) {
|
|
1304
|
+
const buffer = Buffer.alloc(json.length);
|
|
1305
|
+
const genericPayload = Payload.serializeJSON(json);
|
|
1306
|
+
genericPayload.copy(buffer);
|
|
1307
|
+
Buffer.from(json.vendorId, "hex").copy(buffer, 4);
|
|
1308
|
+
return buffer;
|
|
1309
|
+
}
|
|
1310
|
+
/**
|
|
1311
|
+
* Serializes the VENDOR payload to a buffer
|
|
1312
|
+
* @public
|
|
1313
|
+
* @returns {Buffer}
|
|
1314
|
+
*/
|
|
1315
|
+
serialize() {
|
|
1316
|
+
// Fix the length
|
|
1317
|
+
this.length = 4 + this.vendorId.length;
|
|
1318
|
+
const buffer = Buffer.alloc(this.length);
|
|
1319
|
+
super.serialize().copy(buffer);
|
|
1320
|
+
this.vendorId.copy(buffer, 4);
|
|
1321
|
+
return buffer;
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Returns a JSON representation of the VENDOR payload
|
|
1325
|
+
* @public
|
|
1326
|
+
* @returns {Record<string, any>}
|
|
1327
|
+
*/
|
|
1328
|
+
toJSON() {
|
|
1329
|
+
const json = super.genToJSON();
|
|
1330
|
+
json.vendorId = this.vendorId.toString("hex");
|
|
1331
|
+
return json;
|
|
1332
|
+
}
|
|
1333
|
+
/**
|
|
1334
|
+
* Returns a string representation of the VENDOR payload
|
|
1335
|
+
* @public
|
|
1336
|
+
* @returns {string}
|
|
1337
|
+
*/
|
|
1338
|
+
toString() {
|
|
1339
|
+
const genericString = super.genToString();
|
|
1340
|
+
return `${genericString}\nvendorId: "${this.vendorId.toString("hex")}"`;
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
exports.PayloadVENDOR = PayloadVENDOR;
|
|
1344
|
+
/**
|
|
1345
|
+
* IKEv2 Traffic Selector
|
|
1346
|
+
* @class
|
|
1347
|
+
* @extends Payload
|
|
1348
|
+
*/
|
|
1349
|
+
class PayloadTS extends Payload {
|
|
1350
|
+
constructor(nextPayload, numTs, tsList, critical = false, length = 0) {
|
|
1351
|
+
super(payloadType.NONE, nextPayload, critical, length > 0 ? length : 5 + tsList.reduce((acc, ts) => acc + ts.length, 0));
|
|
1352
|
+
this.nextPayload = nextPayload;
|
|
1353
|
+
this.numTs = numTs;
|
|
1354
|
+
this.tsList = tsList;
|
|
1355
|
+
this.critical = critical;
|
|
1356
|
+
this.length = length;
|
|
1357
|
+
}
|
|
1358
|
+
/**
|
|
1359
|
+
* Parses a Traffic Selector Payload from a buffer
|
|
1360
|
+
* @param buffer
|
|
1361
|
+
* @static
|
|
1362
|
+
* @public
|
|
1363
|
+
* @returns {PayloadTS}
|
|
1364
|
+
*/
|
|
1365
|
+
static parse(buffer) {
|
|
1366
|
+
const genericPayload = Payload.parse(buffer);
|
|
1367
|
+
const numTs = buffer.readUInt8(4);
|
|
1368
|
+
const tsList = [];
|
|
1369
|
+
let offset = 8;
|
|
1370
|
+
for (let i = 0; i < numTs; i++) {
|
|
1371
|
+
const ts = selector_1.TrafficSelector.parse(buffer.subarray(offset, genericPayload.length));
|
|
1372
|
+
tsList.push(ts);
|
|
1373
|
+
offset += ts.length;
|
|
1374
|
+
}
|
|
1375
|
+
return new PayloadTS(genericPayload.nextPayload, numTs, tsList, genericPayload.critical, genericPayload.length);
|
|
1376
|
+
}
|
|
1377
|
+
/**
|
|
1378
|
+
* Serializes a JSON representation of the TS payload to a buffer
|
|
1379
|
+
* @param json
|
|
1380
|
+
* @static
|
|
1381
|
+
* @public
|
|
1382
|
+
* @returns {Buffer}
|
|
1383
|
+
*/
|
|
1384
|
+
static serializeJSON(json) {
|
|
1385
|
+
var _a;
|
|
1386
|
+
const buffer = Buffer.alloc(json.length);
|
|
1387
|
+
const genericPayload = Payload.serializeJSON(json);
|
|
1388
|
+
genericPayload.copy(buffer);
|
|
1389
|
+
buffer.writeUInt8(json.numTs, 4);
|
|
1390
|
+
const tsListBuffer = ((_a = json.tList) === null || _a === void 0 ? void 0 : _a.lenght) > 0
|
|
1391
|
+
? json.tsList.map((ts) => selector_1.TrafficSelector.serializeJSON(ts))
|
|
1392
|
+
: [Buffer.alloc(0)];
|
|
1393
|
+
let offset = 8;
|
|
1394
|
+
for (const tsBuffer of tsListBuffer) {
|
|
1395
|
+
tsBuffer.copy(buffer, offset);
|
|
1396
|
+
offset += tsBuffer.length;
|
|
1397
|
+
}
|
|
1398
|
+
return buffer;
|
|
1399
|
+
}
|
|
1400
|
+
/**
|
|
1401
|
+
* Serializes the TS payload to a buffer
|
|
1402
|
+
* @public
|
|
1403
|
+
* @returns {Buffer}
|
|
1404
|
+
*/
|
|
1405
|
+
serialize() {
|
|
1406
|
+
// Encode deep first to calculate length
|
|
1407
|
+
const tsListBuffer = this.tsList.map((ts) => ts.serialize());
|
|
1408
|
+
const tsBuffer = Buffer.concat(tsListBuffer);
|
|
1409
|
+
// Fix the length
|
|
1410
|
+
this.length = 5 + tsBuffer.length;
|
|
1411
|
+
const buffer = Buffer.alloc(this.length);
|
|
1412
|
+
super.serialize().copy(buffer);
|
|
1413
|
+
buffer.writeUInt8(this.numTs, 4);
|
|
1414
|
+
// No need to blank 3 reserved bytes, Buffer.alloc does that
|
|
1415
|
+
tsBuffer.copy(buffer, 8);
|
|
1416
|
+
return buffer;
|
|
1417
|
+
}
|
|
1418
|
+
/**
|
|
1419
|
+
* Returns a JSON representation of the TS payload
|
|
1420
|
+
* @public
|
|
1421
|
+
* @returns {Record<string, any>}
|
|
1422
|
+
*/
|
|
1423
|
+
toJSON() {
|
|
1424
|
+
const json = super.genToJSON();
|
|
1425
|
+
json.numTs = this.numTs;
|
|
1426
|
+
json.tsList = this.tsList.map((ts) => ts.toJSON());
|
|
1427
|
+
return json;
|
|
1428
|
+
}
|
|
1429
|
+
/**
|
|
1430
|
+
* Returns a string representation of the TS payload
|
|
1431
|
+
* @public
|
|
1432
|
+
* @returns {string}
|
|
1433
|
+
*/
|
|
1434
|
+
toString() {
|
|
1435
|
+
const genericString = super.genToString();
|
|
1436
|
+
return `${genericString}\nnumTs: ${this.numTs}\ntsList: ${this.tsList.map((ts) => ts.toString()).join(", ")}`;
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
exports.PayloadTS = PayloadTS;
|
|
1440
|
+
/**
|
|
1441
|
+
* IKEv2 Traffic Selector - Initiator Payload
|
|
1442
|
+
* @class
|
|
1443
|
+
* @extends Payload
|
|
1444
|
+
*/
|
|
1445
|
+
class PayloadTSi extends PayloadTS {
|
|
1446
|
+
constructor(nextPayload, numTs, tsList, critical = false, length = 0) {
|
|
1447
|
+
super(nextPayload, numTs, tsList, critical, length > 0 ? length : 5 + tsList.reduce((acc, ts) => acc + ts.length, 0));
|
|
1448
|
+
this.nextPayload = nextPayload;
|
|
1449
|
+
this.numTs = numTs;
|
|
1450
|
+
this.tsList = tsList;
|
|
1451
|
+
this.critical = critical;
|
|
1452
|
+
this.length = length;
|
|
1453
|
+
this.type = payloadType.TSi;
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
exports.PayloadTSi = PayloadTSi;
|
|
1457
|
+
/**
|
|
1458
|
+
* IKEv2 Traffic Selector - Responder Payload
|
|
1459
|
+
* @class
|
|
1460
|
+
* @extends Payload
|
|
1461
|
+
*/
|
|
1462
|
+
class PayloadTSr extends PayloadTS {
|
|
1463
|
+
constructor(nextPayload, numTs, tsList, critical = false, length = 0) {
|
|
1464
|
+
super(nextPayload, numTs, tsList, critical, length > 0 ? length : 5 + tsList.reduce((acc, ts) => acc + ts.length, 0));
|
|
1465
|
+
this.nextPayload = nextPayload;
|
|
1466
|
+
this.numTs = numTs;
|
|
1467
|
+
this.tsList = tsList;
|
|
1468
|
+
this.critical = critical;
|
|
1469
|
+
this.length = length;
|
|
1470
|
+
this.type = payloadType.TSr;
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
exports.PayloadTSr = PayloadTSr;
|
|
1474
|
+
/**
|
|
1475
|
+
* IKEv2 Encrypted and Authenticated Payload
|
|
1476
|
+
* @class
|
|
1477
|
+
* @extends Payload
|
|
1478
|
+
*/
|
|
1479
|
+
class PayloadSK extends Payload {
|
|
1480
|
+
constructor(nextPayload, encryptedData, critical = false, length = 0) {
|
|
1481
|
+
super(payloadType.SK, nextPayload, critical, length > 0 ? length : 4 + encryptedData.length);
|
|
1482
|
+
this.nextPayload = nextPayload;
|
|
1483
|
+
this.encryptedData = encryptedData;
|
|
1484
|
+
this.critical = critical;
|
|
1485
|
+
this.length = length;
|
|
1486
|
+
}
|
|
1487
|
+
/**
|
|
1488
|
+
* Parses an SK Payload from a buffer
|
|
1489
|
+
* @param buffer
|
|
1490
|
+
* @static
|
|
1491
|
+
* @public
|
|
1492
|
+
* @returns {PayloadSK}
|
|
1493
|
+
*/
|
|
1494
|
+
static parse(buffer) {
|
|
1495
|
+
const genericPayload = Payload.parse(buffer);
|
|
1496
|
+
const encryptedData = buffer.subarray(4, genericPayload.length);
|
|
1497
|
+
return new PayloadSK(genericPayload.nextPayload, encryptedData, genericPayload.critical, genericPayload.length);
|
|
1498
|
+
}
|
|
1499
|
+
/**
|
|
1500
|
+
* Serializes a JSON representation of the SK payload to a buffer
|
|
1501
|
+
* @param json
|
|
1502
|
+
* @static
|
|
1503
|
+
* @public
|
|
1504
|
+
* @returns {Buffer}
|
|
1505
|
+
*/
|
|
1506
|
+
static serializeJSON(json) {
|
|
1507
|
+
const buffer = Buffer.alloc(json.length);
|
|
1508
|
+
const genericPayload = Payload.serializeJSON(json);
|
|
1509
|
+
genericPayload.copy(buffer);
|
|
1510
|
+
Buffer.from(json.encryptedData, "hex").copy(buffer, 4);
|
|
1511
|
+
return buffer;
|
|
1512
|
+
}
|
|
1513
|
+
/**
|
|
1514
|
+
* Serializes the SK payload to a buffer
|
|
1515
|
+
* @public
|
|
1516
|
+
* @returns {Buffer}
|
|
1517
|
+
*/
|
|
1518
|
+
serialize() {
|
|
1519
|
+
// Fix the length
|
|
1520
|
+
this.length = 4 + this.encryptedData.length;
|
|
1521
|
+
const buffer = Buffer.alloc(this.length);
|
|
1522
|
+
super.serialize().copy(buffer);
|
|
1523
|
+
this.encryptedData.copy(buffer, 4);
|
|
1524
|
+
return buffer;
|
|
1525
|
+
}
|
|
1526
|
+
/**
|
|
1527
|
+
* Returns a JSON representation of the SK payload
|
|
1528
|
+
* @public
|
|
1529
|
+
* @returns {Record<string, any>}
|
|
1530
|
+
*/
|
|
1531
|
+
toJSON() {
|
|
1532
|
+
const json = super.genToJSON();
|
|
1533
|
+
json.encryptedData = this.encryptedData.toString("hex");
|
|
1534
|
+
return json;
|
|
1535
|
+
}
|
|
1536
|
+
/**
|
|
1537
|
+
* Returns a string representation of the SK payload
|
|
1538
|
+
* @public
|
|
1539
|
+
* @returns {string}
|
|
1540
|
+
*/
|
|
1541
|
+
toString() {
|
|
1542
|
+
const genericString = super.genToString();
|
|
1543
|
+
return `${genericString}\nencryptedData: "${this.encryptedData.toString("hex")}"`;
|
|
1544
|
+
}
|
|
1545
|
+
/**
|
|
1546
|
+
* Decrypts the encrypted data in the SK payload.
|
|
1547
|
+
*
|
|
1548
|
+
* The decryptFunction should handle removing the IV, Padding and Integrity Checksum Data.
|
|
1549
|
+
*
|
|
1550
|
+
* This should be called after checking the Integrity Checksum Data (except for AEAD algorithms, which are
|
|
1551
|
+
* self-checking).
|
|
1552
|
+
*
|
|
1553
|
+
* @param aad Additional Authenticated Data to include in the Integrity Checksum Data calculation - include here
|
|
1554
|
+
* the entire IKE header and the SK payload header (first 4 bytes of the SK payload), so everything before the IV
|
|
1555
|
+
* inside the SK payload. This is needed for AEAD algorithms, which include integrity protection in the encryption
|
|
1556
|
+
* process (they output inClearData is shorter than the encryptedData).
|
|
1557
|
+
* @param decryptFunction Function that takes a Buffer and returns a decrypted Buffer
|
|
1558
|
+
* @returns {Payload[]} Array of decrypted Payloads
|
|
1559
|
+
* @public
|
|
1560
|
+
*/
|
|
1561
|
+
decrypt(decryptFunction, aad) {
|
|
1562
|
+
if (this.encryptedData.length === 0) {
|
|
1563
|
+
throw new Error("No encrypted data to decrypt - must contain at least the IV and the Integrity Checksum Data");
|
|
1564
|
+
}
|
|
1565
|
+
let nextPayload = this.nextPayload;
|
|
1566
|
+
let offset = 0;
|
|
1567
|
+
const payloads = [];
|
|
1568
|
+
if (nextPayload === payloadType.NONE) {
|
|
1569
|
+
return {
|
|
1570
|
+
firstPayload: payloadType.NONE,
|
|
1571
|
+
inClearPayloads: [],
|
|
1572
|
+
iv: Buffer.alloc(0),
|
|
1573
|
+
};
|
|
1574
|
+
}
|
|
1575
|
+
// Decrypt data
|
|
1576
|
+
const { inClearData, iv } = decryptFunction(this.encryptedData, aad);
|
|
1577
|
+
if (inClearData.length === 0) {
|
|
1578
|
+
return {
|
|
1579
|
+
firstPayload: payloadType.NONE,
|
|
1580
|
+
inClearPayloads: [],
|
|
1581
|
+
iv: iv,
|
|
1582
|
+
};
|
|
1583
|
+
}
|
|
1584
|
+
let nextPayloadClass = exports.payloadTypeMapping[nextPayload];
|
|
1585
|
+
if (!nextPayloadClass) {
|
|
1586
|
+
throw new Error(`Unknown payload type: ${nextPayload}`);
|
|
1587
|
+
}
|
|
1588
|
+
while (offset < inClearData.length &&
|
|
1589
|
+
nextPayloadClass &&
|
|
1590
|
+
nextPayload !== payloadType.NONE) {
|
|
1591
|
+
// Validate we have enough data for the next payload
|
|
1592
|
+
if (offset + 4 > inClearData.length) {
|
|
1593
|
+
throw new Error(`Insufficient data for payload header at offset ${offset}`);
|
|
1594
|
+
}
|
|
1595
|
+
const payload = nextPayloadClass.parse(inClearData.subarray(offset, inClearData.length));
|
|
1596
|
+
payloads.push(payload);
|
|
1597
|
+
offset += payload.length;
|
|
1598
|
+
nextPayload = payload.nextPayload;
|
|
1599
|
+
nextPayloadClass = exports.payloadTypeMapping[nextPayload];
|
|
1600
|
+
// Validate payload length
|
|
1601
|
+
if (offset > inClearData.length) {
|
|
1602
|
+
throw new Error(`Payload length exceeds packet size. Offset: ${offset}, Packet size: ${inClearData.length}`);
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
return {
|
|
1606
|
+
firstPayload: this.nextPayload /* the original payload type */,
|
|
1607
|
+
inClearPayloads: payloads,
|
|
1608
|
+
iv: iv,
|
|
1609
|
+
};
|
|
1610
|
+
}
|
|
1611
|
+
/**
|
|
1612
|
+
* Encrypts data and sets it as the encrypted data in the SK payload. Should be called before serializing the IKE
|
|
1613
|
+
* message, when the SK payload is included and is the last one in the message.
|
|
1614
|
+
*
|
|
1615
|
+
* Also sets the nextPayload in the SK payload as the type of the first payload inside the encrypted data. This is
|
|
1616
|
+
* an exception to the rule, but the SK payload is always the last one in the message, to compensate.
|
|
1617
|
+
*
|
|
1618
|
+
* The encryptFunction should include pre-pending the IV, appending Padding and space for the Integrity Checksum Data.
|
|
1619
|
+
*
|
|
1620
|
+
* The Integrity Checksum Data bytes will have to be updated after the entire IKE message is serialized. The IV is
|
|
1621
|
+
* needed then, so it is returned by this function.
|
|
1622
|
+
*
|
|
1623
|
+
* @param inClearPayloads Array of Payloads to encrypt
|
|
1624
|
+
* @param aad Additional Authenticated Data to include in the Integrity Checksum Data calculation - include here
|
|
1625
|
+
* the entire IKE header and the SK payload header (first 4 bytes of the SK payload), so everything before the IV
|
|
1626
|
+
* inside the SK payload. This is needed for AEAD algorithms, which include integrity protection in the encryption
|
|
1627
|
+
* process (they would also produce more data than the plaintext payloads data).
|
|
1628
|
+
* @param encryptFunction Function that takes a Buffer and returns an encrypted Buffer
|
|
1629
|
+
* @returns The IV used for encryption, to be used in the message.updateIntegrityChecksumData function
|
|
1630
|
+
*/
|
|
1631
|
+
encrypt(inClearPayloads, encryptFunction, aad) {
|
|
1632
|
+
if (inClearPayloads.length === 0) {
|
|
1633
|
+
throw new Error("No in-clear payloads to encrypt - must contain at least one payload");
|
|
1634
|
+
}
|
|
1635
|
+
// Fix the nextPayload in the SK payload and the inner payloads
|
|
1636
|
+
this.nextPayload = inClearPayloads[0].type;
|
|
1637
|
+
for (let i = 0; i < inClearPayloads.length - 1; i++) {
|
|
1638
|
+
inClearPayloads[i].nextPayload = inClearPayloads[i + 1].type;
|
|
1639
|
+
}
|
|
1640
|
+
inClearPayloads[inClearPayloads.length - 1].nextPayload = payloadType.NONE;
|
|
1641
|
+
// Serialize all payloads to encrypt
|
|
1642
|
+
const inClearData = Buffer.concat(inClearPayloads.map((p) => p.serialize()));
|
|
1643
|
+
const { skPayloadData, iv } = encryptFunction(inClearData, aad);
|
|
1644
|
+
this.encryptedData = skPayloadData;
|
|
1645
|
+
return { iv: iv };
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
exports.PayloadSK = PayloadSK;
|
|
1649
|
+
/**
|
|
1650
|
+
* IKEv2 Configuration Payload - Types
|
|
1651
|
+
* @enum
|
|
1652
|
+
*/
|
|
1653
|
+
var cfgType;
|
|
1654
|
+
(function (cfgType) {
|
|
1655
|
+
cfgType[cfgType["CFG_REQUEST"] = 1] = "CFG_REQUEST";
|
|
1656
|
+
cfgType[cfgType["CFG_REPLY"] = 2] = "CFG_REPLY";
|
|
1657
|
+
cfgType[cfgType["CFG_SET"] = 3] = "CFG_SET";
|
|
1658
|
+
cfgType[cfgType["CFG_ACK"] = 4] = "CFG_ACK";
|
|
1659
|
+
})(cfgType || (exports.cfgType = cfgType = {}));
|
|
1660
|
+
/**
|
|
1661
|
+
* IKEv2 Configuration Payload
|
|
1662
|
+
* @class
|
|
1663
|
+
* @extends Payload
|
|
1664
|
+
*/
|
|
1665
|
+
class PayloadCP extends Payload {
|
|
1666
|
+
constructor(nextPayload, cfgType, cfgData, critical = false, length = 0) {
|
|
1667
|
+
super(payloadType.CP, nextPayload, critical, length > 0 ? length : 5 + cfgData.length);
|
|
1668
|
+
this.nextPayload = nextPayload;
|
|
1669
|
+
this.cfgType = cfgType;
|
|
1670
|
+
this.cfgData = cfgData;
|
|
1671
|
+
this.critical = critical;
|
|
1672
|
+
this.length = length;
|
|
1673
|
+
}
|
|
1674
|
+
/**
|
|
1675
|
+
* Parses a Configuration Payload from a buffer
|
|
1676
|
+
* @param buffer
|
|
1677
|
+
* @static
|
|
1678
|
+
* @public
|
|
1679
|
+
* @returns {PayloadCP}
|
|
1680
|
+
*/
|
|
1681
|
+
static parse(buffer) {
|
|
1682
|
+
const genericPayload = Payload.parse(buffer);
|
|
1683
|
+
const cfgType = buffer.readUInt8(4);
|
|
1684
|
+
const cfgData = buffer.subarray(5, genericPayload.length);
|
|
1685
|
+
return new PayloadCP(genericPayload.nextPayload, cfgType, cfgData, genericPayload.critical, genericPayload.length);
|
|
1686
|
+
}
|
|
1687
|
+
/**
|
|
1688
|
+
* Serializes a JSON representation of the CP payload to a buffer
|
|
1689
|
+
* @param json
|
|
1690
|
+
* @static
|
|
1691
|
+
* @public
|
|
1692
|
+
* @returns {Buffer}
|
|
1693
|
+
*/
|
|
1694
|
+
static serializeJSON(json) {
|
|
1695
|
+
const buffer = Buffer.alloc(json.length);
|
|
1696
|
+
const genericPayload = Payload.serializeJSON(json);
|
|
1697
|
+
genericPayload.copy(buffer);
|
|
1698
|
+
buffer.writeUInt8(json.cfgType, 4);
|
|
1699
|
+
// Write 3-byte reserved field as zeros in big-endian order
|
|
1700
|
+
buffer.writeUInt8(0, 5);
|
|
1701
|
+
buffer.writeUInt8(0, 6);
|
|
1702
|
+
buffer.writeUInt8(0, 7);
|
|
1703
|
+
Buffer.from(json.cfgData, "hex").copy(buffer, 8);
|
|
1704
|
+
return buffer;
|
|
1705
|
+
}
|
|
1706
|
+
/**
|
|
1707
|
+
* Serializes the CP payload to a buffer
|
|
1708
|
+
* @public
|
|
1709
|
+
* @returns {Buffer}
|
|
1710
|
+
*/
|
|
1711
|
+
serialize() {
|
|
1712
|
+
// Fix the length
|
|
1713
|
+
this.length = 8 + this.cfgData.length;
|
|
1714
|
+
const buffer = Buffer.alloc(this.length);
|
|
1715
|
+
super.serialize().copy(buffer);
|
|
1716
|
+
buffer.writeUInt8(this.cfgType, 4);
|
|
1717
|
+
// No need to blank 3 reserved bytes, Buffer.alloc does that
|
|
1718
|
+
this.cfgData.copy(buffer, 8);
|
|
1719
|
+
return buffer;
|
|
1720
|
+
}
|
|
1721
|
+
/**
|
|
1722
|
+
* Returns a JSON representation of the CP payload
|
|
1723
|
+
* @public
|
|
1724
|
+
* @returns {Record<string, any>}
|
|
1725
|
+
*/
|
|
1726
|
+
toJSON() {
|
|
1727
|
+
const json = super.genToJSON();
|
|
1728
|
+
json.cfgType = this.cfgType;
|
|
1729
|
+
json.cfgData = this.cfgData.toString("hex");
|
|
1730
|
+
return json;
|
|
1731
|
+
}
|
|
1732
|
+
/**
|
|
1733
|
+
* Returns a string representation of the CP payload
|
|
1734
|
+
* @public
|
|
1735
|
+
* @returns {string}
|
|
1736
|
+
*/
|
|
1737
|
+
toString() {
|
|
1738
|
+
const genericString = super.genToString();
|
|
1739
|
+
return `${genericString}\ncfgType: ${cfgType[this.cfgType]}\ncfgData: "${this.cfgData.toString("hex")}"`;
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
exports.PayloadCP = PayloadCP;
|
|
1743
|
+
/**
|
|
1744
|
+
* IKEv2 Extensible Authentication Payload
|
|
1745
|
+
* @class
|
|
1746
|
+
* @extends Payload
|
|
1747
|
+
*/
|
|
1748
|
+
class PayloadEAP extends Payload {
|
|
1749
|
+
constructor(nextPayload, tlvData, critical = false, length = 0) {
|
|
1750
|
+
super(payloadType.EAP, nextPayload, critical, length > 0 ? length : 4 + tlvData.length);
|
|
1751
|
+
this.nextPayload = nextPayload;
|
|
1752
|
+
this.tlvData = tlvData;
|
|
1753
|
+
this.critical = critical;
|
|
1754
|
+
this.length = length;
|
|
1755
|
+
}
|
|
1756
|
+
/**
|
|
1757
|
+
* Parses an EAP Payload from a buffer
|
|
1758
|
+
* @param buffer
|
|
1759
|
+
* @static
|
|
1760
|
+
* @public
|
|
1761
|
+
* @returns {PayloadEAP}
|
|
1762
|
+
*/
|
|
1763
|
+
static parse(buffer) {
|
|
1764
|
+
const genericPayload = Payload.parse(buffer);
|
|
1765
|
+
const tlvData = attribute_1.Attribute.parse(buffer.subarray(4, genericPayload.length));
|
|
1766
|
+
return new PayloadEAP(genericPayload.nextPayload, tlvData, genericPayload.critical, genericPayload.length);
|
|
1767
|
+
}
|
|
1768
|
+
/**
|
|
1769
|
+
* Serializes a JSON representation of the EAP payload to a buffer
|
|
1770
|
+
* @param json
|
|
1771
|
+
* @static
|
|
1772
|
+
* @public
|
|
1773
|
+
* @returns {Buffer}
|
|
1774
|
+
*/
|
|
1775
|
+
static serializeJSON(json) {
|
|
1776
|
+
const buffer = Buffer.alloc(json.length);
|
|
1777
|
+
const genericPayload = Payload.serializeJSON(json);
|
|
1778
|
+
genericPayload.copy(buffer);
|
|
1779
|
+
const tlvDataBuffer = attribute_1.Attribute.serializeJSON(json.tlvData);
|
|
1780
|
+
tlvDataBuffer.copy(buffer, 4);
|
|
1781
|
+
return buffer;
|
|
1782
|
+
}
|
|
1783
|
+
/**
|
|
1784
|
+
* Serializes the EAP payload to a buffer
|
|
1785
|
+
* @public
|
|
1786
|
+
* @returns {Buffer}
|
|
1787
|
+
*/
|
|
1788
|
+
serialize() {
|
|
1789
|
+
// Encode deep first to calculate length
|
|
1790
|
+
const tlvDataBuffer = this.tlvData.serialize();
|
|
1791
|
+
// Fix the length
|
|
1792
|
+
this.length = 4 + tlvDataBuffer.length;
|
|
1793
|
+
const buffer = Buffer.alloc(this.length);
|
|
1794
|
+
super.serialize().copy(buffer);
|
|
1795
|
+
tlvDataBuffer.copy(buffer, 4);
|
|
1796
|
+
return buffer;
|
|
1797
|
+
}
|
|
1798
|
+
/**
|
|
1799
|
+
* Returns a JSON representation of the EAP payload
|
|
1800
|
+
* @public
|
|
1801
|
+
* @returns {Record<string, any>}
|
|
1802
|
+
*/
|
|
1803
|
+
toJSON() {
|
|
1804
|
+
const json = super.genToJSON();
|
|
1805
|
+
json.tlvData = this.tlvData.toJSON();
|
|
1806
|
+
return json;
|
|
1807
|
+
}
|
|
1808
|
+
/**
|
|
1809
|
+
* Returns a string representation of the EAP payload
|
|
1810
|
+
* @public
|
|
1811
|
+
* @returns {string}
|
|
1812
|
+
*/
|
|
1813
|
+
toString() {
|
|
1814
|
+
const genericString = super.genToString();
|
|
1815
|
+
return `${genericString}\ntlvData: ${this.tlvData.toString()}`;
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
exports.PayloadEAP = PayloadEAP;
|
|
1819
|
+
/**
|
|
1820
|
+
* Payload Type to its class mapping for IKEv2 payloads
|
|
1821
|
+
*/
|
|
1822
|
+
exports.payloadTypeMapping = {
|
|
1823
|
+
[payloadType.NONE]: Payload,
|
|
1824
|
+
[payloadType.SA]: PayloadSA,
|
|
1825
|
+
[payloadType.KE]: PayloadKE,
|
|
1826
|
+
[payloadType.IDi]: PayloadIDi,
|
|
1827
|
+
[payloadType.IDr]: PayloadIDr,
|
|
1828
|
+
[payloadType.CERT]: PayloadCERT,
|
|
1829
|
+
[payloadType.CERTREQ]: PayloadCERTREQ,
|
|
1830
|
+
[payloadType.AUTH]: PayloadAUTH,
|
|
1831
|
+
[payloadType.NONCE]: PayloadNONCE,
|
|
1832
|
+
[payloadType.NOTIFY]: PayloadNOTIFY,
|
|
1833
|
+
[payloadType.DELETE]: PayloadDELETE,
|
|
1834
|
+
[payloadType.VENDOR]: PayloadVENDOR,
|
|
1835
|
+
[payloadType.TSi]: PayloadTSi,
|
|
1836
|
+
[payloadType.TSr]: PayloadTSr,
|
|
1837
|
+
[payloadType.SK]: PayloadSK,
|
|
1838
|
+
[payloadType.CP]: PayloadCP,
|
|
1839
|
+
[payloadType.EAP]: PayloadEAP,
|
|
1840
|
+
};
|