Coverage Report

Created: 2026-05-16 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/strongswan/src/libcharon/encoding/generator.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2011 Tobias Brunner
3
 * Copyright (C) 2005-2009 Martin Willi
4
 * Copyright (C) 2005 Jan Hutter
5
 *
6
 * Copyright (C) secunet Security Networks AG
7
 *
8
 * This program is free software; you can redistribute it and/or modify it
9
 * under the terms of the GNU General Public License as published by the
10
 * Free Software Foundation; either version 2 of the License, or (at your
11
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
12
 *
13
 * This program is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16
 * for more details.
17
 */
18
19
#include <stdlib.h>
20
#include <string.h>
21
#include <stdio.h>
22
23
#include "generator.h"
24
25
#include <library.h>
26
#include <daemon.h>
27
#include <collections/linked_list.h>
28
#include <encoding/payloads/payload.h>
29
#include <encoding/payloads/proposal_substructure.h>
30
#include <encoding/payloads/transform_substructure.h>
31
#include <encoding/payloads/sa_payload.h>
32
#include <encoding/payloads/ke_payload.h>
33
#include <encoding/payloads/notify_payload.h>
34
#include <encoding/payloads/nonce_payload.h>
35
#include <encoding/payloads/id_payload.h>
36
#include <encoding/payloads/auth_payload.h>
37
#include <encoding/payloads/cert_payload.h>
38
#include <encoding/payloads/certreq_payload.h>
39
#include <encoding/payloads/ts_payload.h>
40
#include <encoding/payloads/delete_payload.h>
41
#include <encoding/payloads/vendor_id_payload.h>
42
#include <encoding/payloads/cp_payload.h>
43
#include <encoding/payloads/configuration_attribute.h>
44
#include <encoding/payloads/eap_payload.h>
45
#include <encoding/payloads/unknown_payload.h>
46
47
/**
48
 * Generating is done in a data buffer.
49
 * This is the start size of this buffer in bytes.
50
 */
51
0
#define GENERATOR_DATA_BUFFER_SIZE 500
52
53
/**
54
 * Number of bytes to increase the buffer, if it is too small.
55
 */
56
0
#define GENERATOR_DATA_BUFFER_INCREASE_VALUE 500
57
58
typedef struct private_generator_t private_generator_t;
59
60
/**
61
 * Private part of a generator_t object.
62
 */
63
struct private_generator_t {
64
  /**
65
   * Public part of a generator_t object.
66
   */
67
   generator_t public;
68
69
  /**
70
   * Buffer used to generate the data into.
71
   */
72
  uint8_t *buffer;
73
74
  /**
75
   * Current write position in buffer (one byte aligned).
76
   */
77
  uint8_t *out_position;
78
79
  /**
80
   * Position of last byte in buffer.
81
   */
82
  uint8_t *roof_position;
83
84
  /**
85
   * Current bit writing to in current byte (between 0 and 7).
86
   */
87
  uint8_t current_bit;
88
89
  /**
90
   * Associated data struct to read information from.
91
   */
92
  void *data_struct;
93
94
  /**
95
   * Offset of the header length field in the buffer.
96
   */
97
  uint32_t header_length_offset;
98
99
  /**
100
   * Attribute format of the last generated transform attribute.
101
   *
102
   * Used to check if a variable value field is used or not for
103
   * the transform attribute value.
104
   */
105
  bool attribute_format;
106
107
  /**
108
   * Depending on the value of attribute_format this field is used
109
   * to hold the length of the transform attribute in bytes.
110
   */
111
  uint16_t attribute_length;
112
113
  /**
114
   * TRUE, if debug messages should be logged during generation.
115
   */
116
  bool debug;
117
};
118
119
/**
120
 * Get size of current buffer in bytes.
121
 */
122
static int get_size(private_generator_t *this)
123
0
{
124
0
  return this->roof_position - this->buffer;
125
0
}
126
127
/**
128
 * Get free space of current buffer in bytes.
129
 */
130
static int get_space(private_generator_t *this)
131
0
{
132
0
  return this->roof_position - this->out_position;
133
0
}
134
135
/**
136
 * Get length of data in buffer (in bytes).
137
 */
138
static int get_length(private_generator_t *this)
139
0
{
140
0
  return this->out_position - this->buffer;
141
0
}
142
143
/**
144
 * Get current offset in buffer (in bytes).
145
 */
146
static uint32_t get_offset(private_generator_t *this)
147
0
{
148
0
  return this->out_position - this->buffer;
149
0
}
150
151
/**
152
 * Makes sure enough space is available in buffer to store amount of bits.
153
 */
154
static void make_space_available(private_generator_t *this, int bits)
155
0
{
156
0
  while ((get_space(this) * 8 - this->current_bit) < bits)
157
0
  {
158
0
    int old_buffer_size, new_buffer_size, out_position_offset;
159
160
0
    old_buffer_size = get_size(this);
161
0
    new_buffer_size = old_buffer_size + GENERATOR_DATA_BUFFER_INCREASE_VALUE;
162
0
    out_position_offset = this->out_position - this->buffer;
163
164
0
    if (this->debug)
165
0
    {
166
0
      DBG2(DBG_ENC, "increasing gen buffer from %d to %d byte",
167
0
         old_buffer_size, new_buffer_size);
168
0
    }
169
170
0
    this->buffer = realloc(this->buffer,new_buffer_size);
171
0
    this->out_position = (this->buffer + out_position_offset);
172
0
    this->roof_position = (this->buffer + new_buffer_size);
173
0
  }
174
0
}
175
176
/**
177
 * Writes a specific amount of byte into the buffer.
178
 */
179
static void write_bytes_to_buffer(private_generator_t *this, void *bytes,
180
                  int number_of_bytes)
181
0
{
182
0
  int i;
183
0
  uint8_t *read_position = (uint8_t *)bytes;
184
185
0
  make_space_available(this, number_of_bytes * 8);
186
187
0
  for (i = 0; i < number_of_bytes; i++)
188
0
  {
189
0
    *(this->out_position) = *(read_position);
190
0
    read_position++;
191
0
    this->out_position++;
192
0
  }
193
0
}
194
195
/**
196
 * Generates a U_INT-Field type and writes it to buffer.
197
 */
198
static void generate_u_int_type(private_generator_t *this,
199
                encoding_type_t int_type,uint32_t offset)
200
0
{
201
0
  int number_of_bits = 0;
202
203
  /* find out number of bits of each U_INT type to check for enough space */
204
0
  switch (int_type)
205
0
  {
206
0
    case U_INT_4:
207
0
      number_of_bits = 4;
208
0
      break;
209
0
    case RESERVED_BYTE:
210
0
    case SPI_SIZE:
211
0
    case U_INT_8:
212
0
      number_of_bits = 8;
213
0
      break;
214
0
    case U_INT_16:
215
0
    case PAYLOAD_LENGTH:
216
0
    case ATTRIBUTE_LENGTH:
217
0
      number_of_bits = 16;
218
0
      break;
219
0
    case U_INT_32:
220
0
      number_of_bits = 32;
221
0
      break;
222
0
    case ATTRIBUTE_TYPE:
223
0
      number_of_bits = 15;
224
0
      break;
225
0
    case IKE_SPI:
226
0
      number_of_bits = 64;
227
0
      break;
228
0
    default:
229
0
      DBG1(DBG_ENC, "U_INT Type %N is not supported",
230
0
         encoding_type_names, int_type);
231
0
      return;
232
0
  }
233
0
  if ((number_of_bits % 8) == 0 && this->current_bit != 0)
234
0
  {
235
0
    DBG1(DBG_ENC, "U_INT Type %N is not 8 Bit aligned",
236
0
       encoding_type_names, int_type);
237
0
    return;
238
0
  }
239
240
0
  make_space_available(this, number_of_bits);
241
0
  switch (int_type)
242
0
  {
243
0
    case U_INT_4:
244
0
    {
245
0
      uint8_t high, low;
246
247
0
      if (this->current_bit == 0)
248
0
      {
249
        /* high of current byte in buffer has to be set to the new value*/
250
0
        high = *((uint8_t *)(this->data_struct + offset)) << 4;
251
        /* low in buffer is not changed */
252
0
        low = *(this->out_position) & 0x0F;
253
        /* high is set, low_val is not changed */
254
0
        *(this->out_position) = high | low;
255
0
        if (this->debug)
256
0
        {
257
0
          DBG3(DBG_ENC, "   => %hhu", *(this->out_position) >> 4);
258
0
        }
259
        /* write position is not changed, just bit position is moved */
260
0
        this->current_bit = 4;
261
0
      }
262
0
      else if (this->current_bit == 4)
263
0
      {
264
        /* high in buffer is not changed */
265
0
        high = *(this->out_position) & 0xF0;
266
        /* low of current byte in buffer has to be set to the new value*/
267
0
        low = *((uint8_t *)(this->data_struct + offset)) & 0x0F;
268
0
        *(this->out_position) = high | low;
269
0
        if (this->debug)
270
0
        {
271
0
          DBG3(DBG_ENC, "   => %hhu", *(this->out_position) & 0x0F);
272
0
        }
273
0
        this->out_position++;
274
0
        this->current_bit = 0;
275
0
      }
276
0
      else
277
0
      {
278
0
        DBG1(DBG_ENC, "U_INT_4 Type is not 4 Bit aligned");
279
        /* 4 Bit integers must have a 4 bit alignment */
280
0
        return;
281
0
      }
282
0
      break;
283
0
    }
284
0
    case RESERVED_BYTE:
285
0
    case SPI_SIZE:
286
0
    case U_INT_8:
287
0
    {
288
      /* 8 bit values are written as they are */
289
0
      *this->out_position = *((uint8_t *)(this->data_struct + offset));
290
0
      if (this->debug)
291
0
      {
292
0
        DBG3(DBG_ENC, "   => %hhu", *(this->out_position));
293
0
      }
294
0
      this->out_position++;
295
0
      break;
296
0
    }
297
0
    case ATTRIBUTE_TYPE:
298
0
    {
299
0
      uint8_t attribute_format_flag;
300
0
      uint16_t val;
301
302
      /* attribute type must not change first bit of current byte */
303
0
      if (this->current_bit != 1)
304
0
      {
305
0
        DBG1(DBG_ENC, "ATTRIBUTE FORMAT flag is not set");
306
0
        return;
307
0
      }
308
0
      attribute_format_flag = *(this->out_position) & 0x80;
309
      /* get attribute type value as 16 bit integer*/
310
0
      val = *((uint16_t*)(this->data_struct + offset));
311
      /* unset most significant bit */
312
0
      val &= 0x7FFF;
313
0
      if (attribute_format_flag)
314
0
      {
315
0
        val |= 0x8000;
316
0
      }
317
0
      val = htons(val);
318
0
      if (this->debug)
319
0
      {
320
0
        DBG3(DBG_ENC, "   => %hu", val);
321
0
      }
322
      /* write bytes to buffer (set bit is overwritten) */
323
0
      write_bytes_to_buffer(this, &val, sizeof(uint16_t));
324
0
      this->current_bit = 0;
325
0
      break;
326
327
0
    }
328
0
    case U_INT_16:
329
0
    case PAYLOAD_LENGTH:
330
0
    case ATTRIBUTE_LENGTH:
331
0
    {
332
0
      uint16_t val = htons(*((uint16_t*)(this->data_struct + offset)));
333
0
      if (this->debug)
334
0
      {
335
0
        DBG3(DBG_ENC, "   %b", &val, sizeof(uint16_t));
336
0
      }
337
0
      write_bytes_to_buffer(this, &val, sizeof(uint16_t));
338
0
      break;
339
0
    }
340
0
    case U_INT_32:
341
0
    {
342
0
      uint32_t val = htonl(*((uint32_t*)(this->data_struct + offset)));
343
0
      if (this->debug)
344
0
      {
345
0
        DBG3(DBG_ENC, "   %b", &val, sizeof(uint32_t));
346
0
      }
347
0
      write_bytes_to_buffer(this, &val, sizeof(uint32_t));
348
0
      break;
349
0
    }
350
0
    case IKE_SPI:
351
0
    {
352
      /* 64 bit are written as-is, no host order conversion */
353
0
      write_bytes_to_buffer(this, this->data_struct + offset,
354
0
                  sizeof(uint64_t));
355
0
      if (this->debug)
356
0
      {
357
0
        DBG3(DBG_ENC, "   %b", this->data_struct + offset,
358
0
           sizeof(uint64_t));
359
0
      }
360
0
      break;
361
0
    }
362
0
    default:
363
0
    {
364
0
      DBG1(DBG_ENC, "U_INT Type %N is not supported",
365
0
         encoding_type_names, int_type);
366
0
      return;
367
0
    }
368
0
  }
369
0
}
370
371
/**
372
 * Generate a FLAG filed
373
 */
374
static void generate_flag(private_generator_t *this, uint32_t offset)
375
0
{
376
0
  uint8_t flag_value;
377
0
  uint8_t flag;
378
379
0
  flag_value = (*((bool *) (this->data_struct + offset))) ? 1 : 0;
380
  /* get flag position */
381
0
  flag = (flag_value << (7 - this->current_bit));
382
383
  /* make sure one bit is available in buffer */
384
0
  make_space_available(this, 1);
385
0
  if (this->current_bit == 0)
386
0
  {
387
    /* memory must be zero */
388
0
    *(this->out_position) = 0x00;
389
0
  }
390
391
0
  *(this->out_position) = *(this->out_position) | flag;
392
0
  if (this->debug)
393
0
  {
394
0
    DBG3(DBG_ENC, "   => %hhu", *this->out_position);
395
0
  }
396
397
0
  this->current_bit++;
398
0
  if (this->current_bit >= 8)
399
0
  {
400
0
    this->current_bit = this->current_bit % 8;
401
0
    this->out_position++;
402
0
  }
403
0
}
404
405
/**
406
 * Generates a bytestream from a chunk_t.
407
 */
408
static void generate_from_chunk(private_generator_t *this, uint32_t offset)
409
0
{
410
0
  chunk_t *value;
411
412
0
  if (this->current_bit != 0)
413
0
  {
414
0
    DBG1(DBG_ENC, "can not generate a chunk at bitpos %hhu",
415
0
       this->current_bit);
416
0
    return ;
417
0
  }
418
419
0
  value = (chunk_t *)(this->data_struct + offset);
420
0
  if (this->debug)
421
0
  {
422
0
    DBG3(DBG_ENC, "   %B", value);
423
0
  }
424
425
0
  write_bytes_to_buffer(this, value->ptr, value->len);
426
0
}
427
428
METHOD(generator_t, get_chunk, chunk_t,
429
  private_generator_t *this, uint32_t **lenpos)
430
0
{
431
0
  chunk_t data;
432
433
0
  if (lenpos)
434
0
  {
435
0
    *lenpos = (uint32_t*)(this->buffer + this->header_length_offset);
436
0
  }
437
0
  data = chunk_create(this->buffer, get_length(this));
438
0
  if (this->debug)
439
0
  {
440
0
    DBG3(DBG_ENC, "generated data of this generator %B", &data);
441
0
  }
442
0
  return data;
443
0
}
444
445
METHOD(generator_t, generate_payload, void,
446
  private_generator_t *this, payload_t *payload)
447
0
{
448
0
  int i, rule_count;
449
0
  encoding_rule_t *rules;
450
#if DEBUG_LEVEL >= 2
451
  int offset_start = this->out_position - this->buffer;
452
#endif
453
454
0
  if (this->debug)
455
0
  {
456
0
    DBG2(DBG_ENC, "generating payload of type %N",
457
0
       payload_type_names, payload->get_type(payload));
458
0
  }
459
460
0
  this->data_struct = payload;
461
462
  /* each payload has its own encoding rules */
463
0
  rule_count = payload->get_encoding_rules(payload, &rules);
464
465
0
  for (i = 0; i < rule_count;i++)
466
0
  {
467
0
    if (this->debug)
468
0
    {
469
0
      if (rules[i].type < PAYLOAD_LIST)
470
0
      {
471
0
        DBG2(DBG_ENC, "  generating rule %d %N",
472
0
           i, encoding_type_names, rules[i].type);
473
0
      }
474
0
      else
475
0
      {
476
0
        DBG2(DBG_ENC, "  generating rule %d LIST of %N",
477
0
           i, payload_type_names, rules[i].type - PAYLOAD_LIST);
478
0
      }
479
0
    }
480
0
    switch ((int)rules[i].type)
481
0
    {
482
0
      case U_INT_4:
483
0
      case U_INT_8:
484
0
      case U_INT_16:
485
0
      case U_INT_32:
486
0
      case PAYLOAD_LENGTH:
487
0
      case IKE_SPI:
488
0
      case RESERVED_BYTE:
489
0
      case SPI_SIZE:
490
0
      case ATTRIBUTE_TYPE:
491
0
      case ATTRIBUTE_LENGTH:
492
0
        generate_u_int_type(this, rules[i].type, rules[i].offset);
493
0
        break;
494
0
      case RESERVED_BIT:
495
0
      case FLAG:
496
0
        generate_flag(this, rules[i].offset);
497
0
        break;
498
0
      case HEADER_LENGTH:
499
0
        this->header_length_offset = get_offset(this);
500
0
        generate_u_int_type(this, U_INT_32, rules[i].offset);
501
0
        break;
502
0
      case SPI:
503
0
      case CHUNK_DATA:
504
0
      case ENCRYPTED_DATA:
505
0
        generate_from_chunk(this, rules[i].offset);
506
0
        break;
507
0
      case PAYLOAD_LIST + PLV2_PROPOSAL_SUBSTRUCTURE:
508
0
      case PAYLOAD_LIST + PLV1_PROPOSAL_SUBSTRUCTURE:
509
0
      case PAYLOAD_LIST + PLV2_TRANSFORM_SUBSTRUCTURE:
510
0
      case PAYLOAD_LIST + PLV1_TRANSFORM_SUBSTRUCTURE:
511
0
      case PAYLOAD_LIST + PLV2_TRANSFORM_ATTRIBUTE:
512
0
      case PAYLOAD_LIST + PLV1_TRANSFORM_ATTRIBUTE:
513
0
      case PAYLOAD_LIST + PLV2_CONFIGURATION_ATTRIBUTE:
514
0
      case PAYLOAD_LIST + PLV1_CONFIGURATION_ATTRIBUTE:
515
0
      case PAYLOAD_LIST + PLV2_TRAFFIC_SELECTOR_SUBSTRUCTURE:
516
0
      {
517
0
        linked_list_t *proposals;
518
0
        enumerator_t *enumerator;
519
0
        payload_t *proposal;
520
521
0
        proposals = *((linked_list_t **)
522
0
                    (this->data_struct + rules[i].offset));
523
0
        enumerator = proposals->create_enumerator(proposals);
524
0
        while (enumerator->enumerate(enumerator, &proposal))
525
0
        {
526
0
          generate_payload(this, proposal);
527
0
        }
528
0
        enumerator->destroy(enumerator);
529
0
        break;
530
0
      }
531
0
      case ATTRIBUTE_FORMAT:
532
0
        generate_flag(this, rules[i].offset);
533
        /* Attribute format is a flag which is stored in context*/
534
0
        this->attribute_format =
535
0
              *((bool *)(this->data_struct + rules[i].offset));
536
0
        break;
537
0
      case ATTRIBUTE_LENGTH_OR_VALUE:
538
0
        if (this->attribute_format)
539
0
        {
540
0
          generate_u_int_type(this, U_INT_16, rules[i].offset);
541
0
        }
542
0
        else
543
0
        {
544
0
          generate_u_int_type(this, U_INT_16, rules[i].offset);
545
          /* this field hold the length of the attribute */
546
0
          this->attribute_length =
547
0
            *((uint16_t *)(this->data_struct + rules[i].offset));
548
0
        }
549
0
        break;
550
0
      case ATTRIBUTE_VALUE:
551
0
      {
552
0
        if (!this->attribute_format)
553
0
        {
554
0
          if (this->debug)
555
0
          {
556
0
            DBG2(DBG_ENC, "attribute value has not fixed size");
557
0
          }
558
          /* the attribute value is generated */
559
0
          generate_from_chunk(this, rules[i].offset);
560
0
        }
561
0
        break;
562
0
      }
563
0
      default:
564
0
        DBG1(DBG_ENC, "field type %N is not supported",
565
0
           encoding_type_names, rules[i].type);
566
0
        return;
567
0
    }
568
0
  }
569
0
  if (this->debug)
570
0
  {
571
0
    DBG2(DBG_ENC, "generating %N payload finished",
572
0
       payload_type_names, payload->get_type(payload));
573
0
    DBG3(DBG_ENC, "generated data for this payload %b",
574
0
       this->buffer + offset_start,
575
0
       (u_int)(this->out_position - this->buffer - offset_start));
576
0
  }
577
0
}
578
579
METHOD(generator_t, destroy, void,
580
  private_generator_t *this)
581
0
{
582
0
  free(this->buffer);
583
0
  free(this);
584
0
}
585
586
/*
587
 * Described in header
588
 */
589
generator_t *generator_create()
590
0
{
591
0
  private_generator_t *this;
592
593
0
  INIT(this,
594
0
    .public = {
595
0
      .get_chunk = _get_chunk,
596
0
      .generate_payload = _generate_payload,
597
0
      .destroy = _destroy,
598
0
    },
599
0
    .buffer = malloc(GENERATOR_DATA_BUFFER_SIZE),
600
0
    .debug = TRUE,
601
0
  );
602
603
0
  this->out_position = this->buffer;
604
0
  this->roof_position = this->buffer + GENERATOR_DATA_BUFFER_SIZE;
605
606
0
  return &this->public;
607
0
}
608
609
/*
610
 * Described in header
611
 */
612
generator_t *generator_create_no_dbg()
613
0
{
614
0
  private_generator_t *this = (private_generator_t*)generator_create();
615
616
0
  this->debug = FALSE;
617
618
0
  return &this->public;
619
0
}