Coverage Report

Created: 2026-10-10 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/strongswan/src/libcharon/encoding/parser.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2005-2009 Martin Willi
3
 * Copyright (C) 2005 Jan Hutter
4
 *
5
 * Copyright (C) secunet Security Networks AG
6
 *
7
 * This program is free software; you can redistribute it and/or modify it
8
 * under the terms of the GNU General Public License as published by the
9
 * Free Software Foundation; either version 2 of the License, or (at your
10
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
11
 *
12
 * This program is distributed in the hope that it will be useful, but
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15
 * for more details.
16
 */
17
18
#include <stdlib.h>
19
#include <string.h>
20
21
#include "parser.h"
22
23
#include <library.h>
24
#include <daemon.h>
25
#include <collections/linked_list.h>
26
#include <encoding/payloads/encodings.h>
27
#include <encoding/payloads/payload.h>
28
#include <encoding/payloads/sa_payload.h>
29
#include <encoding/payloads/proposal_substructure.h>
30
#include <encoding/payloads/transform_substructure.h>
31
#include <encoding/payloads/transform_attribute.h>
32
#include <encoding/payloads/ke_payload.h>
33
#include <encoding/payloads/nonce_payload.h>
34
#include <encoding/payloads/id_payload.h>
35
#include <encoding/payloads/notify_payload.h>
36
#include <encoding/payloads/encrypted_payload.h>
37
#include <encoding/payloads/auth_payload.h>
38
#include <encoding/payloads/cert_payload.h>
39
#include <encoding/payloads/certreq_payload.h>
40
#include <encoding/payloads/ts_payload.h>
41
#include <encoding/payloads/delete_payload.h>
42
#include <encoding/payloads/vendor_id_payload.h>
43
#include <encoding/payloads/cp_payload.h>
44
#include <encoding/payloads/configuration_attribute.h>
45
#include <encoding/payloads/eap_payload.h>
46
#include <encoding/payloads/unknown_payload.h>
47
48
49
typedef struct private_parser_t private_parser_t;
50
51
/**
52
 * Private data stored in a context.
53
 *
54
 * Contains pointers and counters to store current state.
55
 */
56
struct private_parser_t {
57
  /**
58
   * Public members, see parser_t.
59
   */
60
  parser_t public;
61
62
  /**
63
   * major IKE version
64
   */
65
  uint8_t major_version;
66
67
  /**
68
   * Current bit for reading in input data.
69
   */
70
  uint8_t bit_pos;
71
72
  /**
73
   * Current byte for reading in input data.
74
   */
75
  uint8_t *byte_pos;
76
77
  /**
78
   * Input data to parse.
79
   */
80
  uint8_t *input;
81
82
  /**
83
   * Roof of input, used for length-checking.
84
   */
85
  uint8_t *input_roof;
86
87
  /**
88
   * Set of encoding rules for this parsing session.
89
   */
90
  encoding_rule_t *rules;
91
};
92
93
/**
94
 * Log invalid length error
95
 */
96
static bool short_input(private_parser_t *this, int number)
97
0
{
98
0
  DBG1(DBG_ENC, "  not enough input to parse rule %d %N",
99
0
     number, encoding_type_names, this->rules[number].type);
100
0
  return FALSE;
101
0
}
102
103
/**
104
 * Log unaligned rules
105
 */
106
static bool bad_bitpos(private_parser_t *this, int number)
107
0
{
108
0
  DBG1(DBG_ENC, "  found rule %d %N on bitpos %d",
109
0
     number, encoding_type_names, this->rules[number].type, this->bit_pos);
110
0
  return FALSE;
111
0
}
112
113
/**
114
 * Parse a 4-Bit unsigned integer from the current parsing position.
115
 */
116
static bool parse_uint4(private_parser_t *this, int rule_number,
117
            uint8_t *output_pos)
118
0
{
119
0
  if (this->byte_pos + sizeof(uint8_t) > this->input_roof)
120
0
  {
121
0
    return short_input(this, rule_number);
122
0
  }
123
0
  switch (this->bit_pos)
124
0
  {
125
0
    case 0:
126
0
      if (output_pos)
127
0
      {
128
0
        *output_pos = *(this->byte_pos) >> 4;
129
0
      }
130
0
      this->bit_pos = 4;
131
0
      break;
132
0
    case 4:
133
0
      if (output_pos)
134
0
      {
135
0
        *output_pos = *(this->byte_pos) & 0x0F;
136
0
      }
137
0
      this->bit_pos = 0;
138
0
      this->byte_pos++;
139
0
      break;
140
0
    default:
141
0
      return bad_bitpos(this, rule_number);
142
0
  }
143
0
  if (output_pos)
144
0
  {
145
0
    DBG3(DBG_ENC, "   => %hhu", *output_pos);
146
0
  }
147
0
  return TRUE;
148
0
}
149
150
/**
151
 * Parse a 8-Bit unsigned integer from the current parsing position.
152
 */
153
static bool parse_uint8(private_parser_t *this, int rule_number,
154
            uint8_t *output_pos)
155
0
{
156
0
  if (this->byte_pos + sizeof(uint8_t) > this->input_roof)
157
0
  {
158
0
    return short_input(this, rule_number);
159
0
  }
160
0
  if (this->bit_pos)
161
0
  {
162
0
    return bad_bitpos(this, rule_number);
163
0
  }
164
0
  if (output_pos)
165
0
  {
166
0
    *output_pos = *(this->byte_pos);
167
0
    DBG3(DBG_ENC, "   => %hhu", *output_pos);
168
0
  }
169
0
  this->byte_pos++;
170
0
  return TRUE;
171
0
}
172
173
/**
174
 * Parse a 15-Bit unsigned integer from the current parsing position.
175
 */
176
static bool parse_uint15(private_parser_t *this, int rule_number,
177
             uint16_t *output_pos)
178
0
{
179
0
  if (this->byte_pos + sizeof(uint16_t) > this->input_roof)
180
0
  {
181
0
    return short_input(this, rule_number);
182
0
  }
183
0
  if (this->bit_pos != 1)
184
0
  {
185
0
    return bad_bitpos(this, rule_number);
186
0
  }
187
0
  if (output_pos)
188
0
  {
189
0
    memcpy(output_pos, this->byte_pos, sizeof(uint16_t));
190
0
    *output_pos = ntohs(*output_pos) & ~0x8000;
191
0
    DBG3(DBG_ENC, "   => %hu", *output_pos);
192
0
  }
193
0
  this->byte_pos += sizeof(uint16_t);
194
0
  this->bit_pos = 0;
195
0
  return TRUE;
196
0
}
197
198
/**
199
 * Parse a 16-Bit unsigned integer from the current parsing position.
200
 */
201
static bool parse_uint16(private_parser_t *this, int rule_number,
202
             uint16_t *output_pos)
203
0
{
204
0
  if (this->byte_pos + sizeof(uint16_t) > this->input_roof)
205
0
  {
206
0
    return short_input(this, rule_number);
207
0
  }
208
0
  if (this->bit_pos)
209
0
  {
210
0
    return bad_bitpos(this, rule_number);
211
0
  }
212
0
  if (output_pos)
213
0
  {
214
0
    memcpy(output_pos, this->byte_pos, sizeof(uint16_t));
215
0
    *output_pos = ntohs(*output_pos);
216
0
    DBG3(DBG_ENC, "   => %hu", *output_pos);
217
0
  }
218
0
  this->byte_pos += sizeof(uint16_t);
219
0
  return TRUE;
220
0
}
221
/**
222
 * Parse a 32-Bit unsigned integer from the current parsing position.
223
 */
224
static bool parse_uint32(private_parser_t *this, int rule_number,
225
             uint32_t *output_pos)
226
0
{
227
0
  if (this->byte_pos + sizeof(uint32_t) > this->input_roof)
228
0
  {
229
0
    return short_input(this, rule_number);
230
0
  }
231
0
  if (this->bit_pos)
232
0
  {
233
0
    return bad_bitpos(this, rule_number);
234
0
  }
235
0
  if (output_pos)
236
0
  {
237
0
    memcpy(output_pos, this->byte_pos, sizeof(uint32_t));
238
0
    *output_pos = ntohl(*output_pos);
239
0
    DBG3(DBG_ENC, "   => %u", *output_pos);
240
0
  }
241
0
  this->byte_pos += sizeof(uint32_t);
242
0
  return TRUE;
243
0
}
244
245
/**
246
 * Parse a given amount of bytes and writes them to a specific location
247
 */
248
static bool parse_bytes(private_parser_t *this, int rule_number,
249
            uint8_t *output_pos, int bytes)
250
0
{
251
0
  if (this->byte_pos + bytes > this->input_roof)
252
0
  {
253
0
    return short_input(this, rule_number);
254
0
  }
255
0
  if (this->bit_pos)
256
0
  {
257
0
    return bad_bitpos(this, rule_number);
258
0
  }
259
0
  if (output_pos)
260
0
  {
261
0
    memcpy(output_pos, this->byte_pos, bytes);
262
0
    DBG3(DBG_ENC, "   %b", output_pos, bytes);
263
0
  }
264
0
  this->byte_pos += bytes;
265
0
  return TRUE;
266
0
}
267
268
/**
269
 * Parse a single Bit from the current parsing position
270
 */
271
static bool parse_bit(private_parser_t *this, int rule_number,
272
            bool *output_pos)
273
0
{
274
0
  if (this->byte_pos + sizeof(uint8_t) > this->input_roof)
275
0
  {
276
0
    return short_input(this, rule_number);
277
0
  }
278
0
  if (output_pos)
279
0
  {
280
0
    uint8_t mask;
281
0
    mask = 0x01 << (7 - this->bit_pos);
282
0
    *output_pos = *this->byte_pos & mask;
283
284
0
    if (*output_pos)
285
0
    { /* set to a "clean", comparable true */
286
0
      *output_pos = TRUE;
287
0
    }
288
0
    DBG3(DBG_ENC, "   => %d", *output_pos);
289
0
  }
290
0
  this->bit_pos = (this->bit_pos + 1) % 8;
291
0
  if (this->bit_pos == 0)
292
0
  {
293
0
    this->byte_pos++;
294
0
  }
295
0
  return TRUE;
296
0
}
297
298
/**
299
 * Parse substructures in a list.
300
 */
301
static bool parse_list(private_parser_t *this, int rule_number,
302
      linked_list_t **output_pos, payload_type_t payload_type, int length)
303
0
{
304
0
  linked_list_t *list = *output_pos;
305
306
0
  if (length < 0)
307
0
  {
308
0
    return short_input(this, rule_number);
309
0
  }
310
0
  if (this->bit_pos)
311
0
  {
312
0
    return bad_bitpos(this, rule_number);
313
0
  }
314
0
  while (length > 0)
315
0
  {
316
0
    uint8_t *pos_before = this->byte_pos;
317
0
    payload_t *payload;
318
319
0
    DBG2(DBG_ENC, "  %d bytes left, parsing recursively %N",
320
0
       length, payload_type_names, payload_type);
321
322
0
    if (this->public.parse_payload(&this->public, payload_type,
323
0
                     &payload) != SUCCESS)
324
0
    {
325
0
      DBG1(DBG_ENC, "  parsing of a %N substructure failed",
326
0
         payload_type_names, payload_type);
327
0
      return FALSE;
328
0
    }
329
0
    list->insert_last(list, payload);
330
0
    length -= this->byte_pos - pos_before;
331
0
  }
332
0
  if (length != 0)
333
0
  { /* must yield exactly to zero */
334
0
    DBG1(DBG_ENC, "  length of %N substructure list invalid",
335
0
       payload_type_names, payload_type);
336
0
    return FALSE;
337
0
  }
338
0
  *output_pos = list;
339
0
  return TRUE;
340
0
}
341
342
/**
343
 * Parse data from current parsing position in a chunk.
344
 */
345
static bool parse_chunk(private_parser_t *this, int rule_number,
346
            chunk_t *output_pos, int length)
347
0
{
348
0
  if (this->byte_pos + length > this->input_roof)
349
0
  {
350
0
    return short_input(this, rule_number);
351
0
  }
352
0
  if (this->bit_pos)
353
0
  {
354
0
    return bad_bitpos(this, rule_number);
355
0
  }
356
0
  if (output_pos)
357
0
  {
358
0
    *output_pos = chunk_alloc(length);
359
0
    memcpy(output_pos->ptr, this->byte_pos, length);
360
0
    DBG3(DBG_ENC, "   %b", output_pos->ptr, length);
361
0
  }
362
0
  this->byte_pos += length;
363
0
  return TRUE;
364
0
}
365
366
METHOD(parser_t, parse_payload, status_t,
367
  private_parser_t *this, payload_type_t payload_type, payload_t **payload)
368
0
{
369
0
  payload_t *pld;
370
0
  void *output;
371
0
  int payload_length = 0, spi_size = 0, attribute_length = 0, header_length;
372
0
  bool attribute_format = FALSE;
373
0
  int rule_number, rule_count;
374
0
  encoding_rule_t *rule;
375
376
  /* create instance of the payload to parse */
377
0
  if (payload_is_known(payload_type, this->major_version))
378
0
  {
379
0
    pld = payload_create(payload_type);
380
0
  }
381
0
  else
382
0
  {
383
0
    pld = (payload_t*)unknown_payload_create(payload_type);
384
0
  }
385
386
0
  DBG2(DBG_ENC, "parsing %N payload, %d bytes left",
387
0
     payload_type_names, payload_type, this->input_roof - this->byte_pos);
388
389
0
  DBG3(DBG_ENC, "parsing payload from %b",
390
0
     this->byte_pos, (u_int)(this->input_roof - this->byte_pos));
391
392
  /* base pointer for output, avoids casting in every rule */
393
0
  output = pld;
394
  /* parse the payload with its own rules */
395
0
  rule_count = pld->get_encoding_rules(pld, &this->rules);
396
0
  for (rule_number = 0; rule_number < rule_count; rule_number++)
397
0
  {
398
    /* update header length for each rule, as it is dynamic (SPIs) */
399
0
    header_length = pld->get_header_length(pld);
400
401
0
    rule = &(this->rules[rule_number]);
402
0
    if (rule->type < PAYLOAD_LIST)
403
0
    {
404
0
      DBG2(DBG_ENC, "  parsing rule %d %N",
405
0
         rule_number, encoding_type_names, rule->type);
406
0
    }
407
0
    else
408
0
    {
409
0
      DBG2(DBG_ENC, "  parsing rule %d LIST of %N",
410
0
         rule_number, payload_type_names, rule->type - PAYLOAD_LIST);
411
0
    }
412
0
    switch ((int)rule->type)
413
0
    {
414
0
      case U_INT_4:
415
0
      {
416
0
        if (!parse_uint4(this, rule_number, output + rule->offset))
417
0
        {
418
0
          pld->destroy(pld);
419
0
          return PARSE_ERROR;
420
0
        }
421
0
        break;
422
0
      }
423
0
      case U_INT_8:
424
0
      case RESERVED_BYTE:
425
0
      {
426
0
        if (!parse_uint8(this, rule_number, output + rule->offset))
427
0
        {
428
0
          pld->destroy(pld);
429
0
          return PARSE_ERROR;
430
0
        }
431
0
        break;
432
0
      }
433
0
      case U_INT_16:
434
0
      {
435
0
        if (!parse_uint16(this, rule_number, output + rule->offset))
436
0
        {
437
0
          pld->destroy(pld);
438
0
          return PARSE_ERROR;
439
0
        }
440
0
        break;
441
0
      }
442
0
      case U_INT_32:
443
0
      case HEADER_LENGTH:
444
0
      {
445
0
        if (!parse_uint32(this, rule_number, output + rule->offset))
446
0
        {
447
0
          pld->destroy(pld);
448
0
          return PARSE_ERROR;
449
0
        }
450
0
        break;
451
0
      }
452
0
      case IKE_SPI:
453
0
      {
454
0
        if (!parse_bytes(this, rule_number, output + rule->offset, 8))
455
0
        {
456
0
          pld->destroy(pld);
457
0
          return PARSE_ERROR;
458
0
        }
459
0
        break;
460
0
      }
461
0
      case RESERVED_BIT:
462
0
      case FLAG:
463
0
      {
464
0
        if (!parse_bit(this, rule_number, output + rule->offset))
465
0
        {
466
0
          pld->destroy(pld);
467
0
          return PARSE_ERROR;
468
0
        }
469
0
        break;
470
0
      }
471
0
      case PAYLOAD_LENGTH:
472
0
      {
473
0
        if (!parse_uint16(this, rule_number, output + rule->offset))
474
0
        {
475
0
          pld->destroy(pld);
476
0
          return PARSE_ERROR;
477
0
        }
478
        /* parsed u_int16 should be aligned */
479
0
        payload_length = *(uint16_t*)(output + rule->offset);
480
        /* all payloads must have at least 4 bytes header */
481
0
        if (payload_length < 4)
482
0
        {
483
0
          pld->destroy(pld);
484
0
          return PARSE_ERROR;
485
0
        }
486
0
        break;
487
0
      }
488
0
      case SPI_SIZE:
489
0
      {
490
0
        if (!parse_uint8(this, rule_number, output + rule->offset))
491
0
        {
492
0
          pld->destroy(pld);
493
0
          return PARSE_ERROR;
494
0
        }
495
0
        spi_size = *(uint8_t*)(output + rule->offset);
496
0
        break;
497
0
      }
498
0
      case SPI:
499
0
      {
500
0
        if (!parse_chunk(this, rule_number, output + rule->offset,
501
0
                 spi_size))
502
0
        {
503
0
          pld->destroy(pld);
504
0
          return PARSE_ERROR;
505
0
        }
506
0
        break;
507
0
      }
508
0
      case PAYLOAD_LIST + PLV2_PROPOSAL_SUBSTRUCTURE:
509
0
      case PAYLOAD_LIST + PLV1_PROPOSAL_SUBSTRUCTURE:
510
0
      case PAYLOAD_LIST + PLV2_TRANSFORM_SUBSTRUCTURE:
511
0
      case PAYLOAD_LIST + PLV1_TRANSFORM_SUBSTRUCTURE:
512
0
      case PAYLOAD_LIST + PLV2_TRANSFORM_ATTRIBUTE:
513
0
      case PAYLOAD_LIST + PLV1_TRANSFORM_ATTRIBUTE:
514
0
      case PAYLOAD_LIST + PLV2_CONFIGURATION_ATTRIBUTE:
515
0
      case PAYLOAD_LIST + PLV1_CONFIGURATION_ATTRIBUTE:
516
0
      case PAYLOAD_LIST + PLV2_TRAFFIC_SELECTOR_SUBSTRUCTURE:
517
0
      {
518
0
        if (payload_length < header_length ||
519
0
          !parse_list(this, rule_number, output + rule->offset,
520
0
                rule->type - PAYLOAD_LIST,
521
0
                payload_length - header_length))
522
0
        {
523
0
          pld->destroy(pld);
524
0
          return PARSE_ERROR;
525
0
        }
526
0
        break;
527
0
      }
528
0
      case CHUNK_DATA:
529
0
      {
530
0
        if (payload_length < header_length ||
531
0
          !parse_chunk(this, rule_number, output + rule->offset,
532
0
                 payload_length - header_length))
533
0
        {
534
0
          pld->destroy(pld);
535
0
          return PARSE_ERROR;
536
0
        }
537
0
        break;
538
0
      }
539
0
      case ENCRYPTED_DATA:
540
0
      {
541
0
        if (!parse_chunk(this, rule_number, output + rule->offset,
542
0
                 this->input_roof - this->byte_pos))
543
0
        {
544
0
          pld->destroy(pld);
545
0
          return PARSE_ERROR;
546
0
        }
547
0
        break;
548
0
      }
549
0
      case ATTRIBUTE_FORMAT:
550
0
      {
551
0
        if (!parse_bit(this, rule_number, output + rule->offset))
552
0
        {
553
0
          pld->destroy(pld);
554
0
          return PARSE_ERROR;
555
0
        }
556
0
        attribute_format = *(bool*)(output + rule->offset);
557
0
        break;
558
0
      }
559
0
      case ATTRIBUTE_TYPE:
560
0
      {
561
0
        if (!parse_uint15(this, rule_number, output + rule->offset))
562
0
        {
563
0
          pld->destroy(pld);
564
0
          return PARSE_ERROR;
565
0
        }
566
0
        break;
567
0
      }
568
0
      case ATTRIBUTE_LENGTH:
569
0
      {
570
0
        if (!parse_uint16(this, rule_number, output + rule->offset))
571
0
        {
572
0
          pld->destroy(pld);
573
0
          return PARSE_ERROR;
574
0
        }
575
0
        attribute_length = *(uint16_t*)(output + rule->offset);
576
0
        break;
577
0
      }
578
0
      case ATTRIBUTE_LENGTH_OR_VALUE:
579
0
      {
580
0
        if (!parse_uint16(this, rule_number, output + rule->offset))
581
0
        {
582
0
          pld->destroy(pld);
583
0
          return PARSE_ERROR;
584
0
        }
585
0
        attribute_length = *(uint16_t*)(output + rule->offset);
586
0
        break;
587
0
      }
588
0
      case ATTRIBUTE_VALUE:
589
0
      {
590
0
        if (attribute_format == FALSE &&
591
0
          !parse_chunk(this, rule_number, output + rule->offset,
592
0
                 attribute_length))
593
0
        {
594
0
          pld->destroy(pld);
595
0
          return PARSE_ERROR;
596
0
        }
597
0
        break;
598
0
      }
599
0
      default:
600
0
      {
601
0
        DBG1(DBG_ENC, "  no rule to parse rule %d %N",
602
0
           rule_number, encoding_type_names, rule->type);
603
0
        pld->destroy(pld);
604
0
        return PARSE_ERROR;
605
0
      }
606
0
    }
607
    /* process next rule */
608
0
    rule++;
609
0
  }
610
611
0
  *payload = pld;
612
0
  DBG2(DBG_ENC, "parsing %N payload finished",
613
0
     payload_type_names, payload_type);
614
0
  return SUCCESS;
615
0
}
616
617
METHOD(parser_t, get_remaining_byte_count, int,
618
  private_parser_t *this)
619
0
{
620
0
  return this->input_roof - this->byte_pos;
621
0
}
622
623
METHOD(parser_t, reset_context, void,
624
  private_parser_t *this)
625
0
{
626
0
  this->byte_pos = this->input;
627
0
  this->bit_pos = 0;
628
0
}
629
630
METHOD(parser_t, set_major_version, void,
631
  private_parser_t *this, uint8_t major_version)
632
0
{
633
0
  this->major_version = major_version;
634
0
}
635
636
METHOD(parser_t, destroy, void,
637
  private_parser_t *this)
638
0
{
639
0
  free(this);
640
0
}
641
642
/*
643
 * Described in header.
644
 */
645
parser_t *parser_create(chunk_t data)
646
0
{
647
0
  private_parser_t *this;
648
649
0
  INIT(this,
650
0
    .public = {
651
0
      .parse_payload = _parse_payload,
652
0
      .reset_context = _reset_context,
653
0
      .set_major_version = _set_major_version,
654
0
      .get_remaining_byte_count = _get_remaining_byte_count,
655
0
      .destroy = _destroy,
656
0
    },
657
0
    .input = data.ptr,
658
0
    .byte_pos = data.ptr,
659
0
    .input_roof = data.ptr + data.len,
660
0
  );
661
662
0
  return &this->public;
663
0
}
664