Coverage Report

Created: 2026-08-14 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/strongswan/src/libcharon/encoding/payloads/certreq_payload.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2005-2010 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 <stddef.h>
19
20
#include <daemon.h>
21
#include <crypto/hashers/hasher.h>
22
#include <encoding/payloads/cert_payload.h>
23
24
#include "certreq_payload.h"
25
26
typedef struct private_certreq_payload_t private_certreq_payload_t;
27
28
/**
29
 * Private data of an certreq_payload_t object.
30
 */
31
struct private_certreq_payload_t {
32
33
  /**
34
   * Public certreq_payload_t interface.
35
   */
36
  certreq_payload_t public;
37
38
  /**
39
   * Next payload type.
40
   */
41
  uint8_t  next_payload;
42
43
  /**
44
   * Critical flag.
45
   */
46
  bool critical;
47
48
  /**
49
   * Reserved bits
50
   */
51
  bool reserved[7];
52
53
  /**
54
   * Length of this payload.
55
   */
56
  uint16_t payload_length;
57
58
  /**
59
   * Encoding of the CERT Data.
60
   */
61
  uint8_t encoding;
62
63
  /**
64
   * The contained certreq data value.
65
   */
66
  chunk_t data;
67
68
  /**
69
   * Payload type PLV2_CERTREQ or PLV1_CERTREQ
70
   */
71
  payload_type_t type;
72
};
73
74
/**
75
 * Encoding rules for CERTREQ payload.
76
 */
77
static encoding_rule_t encodings[] = {
78
  /* 1 Byte next payload type, stored in the field next_payload */
79
  { U_INT_8,      offsetof(private_certreq_payload_t, next_payload) },
80
  /* the critical bit */
81
  { FLAG,       offsetof(private_certreq_payload_t, critical)   },
82
  /* 7 Bit reserved bits */
83
  { RESERVED_BIT,   offsetof(private_certreq_payload_t, reserved[0])  },
84
  { RESERVED_BIT,   offsetof(private_certreq_payload_t, reserved[1])  },
85
  { RESERVED_BIT,   offsetof(private_certreq_payload_t, reserved[2])  },
86
  { RESERVED_BIT,   offsetof(private_certreq_payload_t, reserved[3])  },
87
  { RESERVED_BIT,   offsetof(private_certreq_payload_t, reserved[4])  },
88
  { RESERVED_BIT,   offsetof(private_certreq_payload_t, reserved[5])  },
89
  { RESERVED_BIT,   offsetof(private_certreq_payload_t, reserved[6])  },
90
  /* Length of the whole payload*/
91
  { PAYLOAD_LENGTH, offsetof(private_certreq_payload_t, payload_length) },
92
  /* 1 Byte CERTREQ type*/
93
  { U_INT_8,      offsetof(private_certreq_payload_t, encoding)   },
94
  /* some certreq data bytes, length is defined in PAYLOAD_LENGTH */
95
  { CHUNK_DATA,   offsetof(private_certreq_payload_t, data)     }
96
};
97
98
/*
99
                           1                   2                   3
100
       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
101
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
102
      ! Next Payload  !C!  RESERVED   !         Payload Length        !
103
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104
      ! Cert Encoding !                                               !
105
      +-+-+-+-+-+-+-+-+                                               !
106
      ~                    Certification Authority                    ~
107
      !                                                               !
108
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
109
*/
110
111
METHOD(payload_t, verify, status_t,
112
  private_certreq_payload_t *this)
113
2.11k
{
114
2.11k
  if (this->type == PLV2_CERTREQ &&
115
1.86k
    (this->encoding == ENC_X509_SIGNATURE ||
116
1.03k
     this->encoding == ENC_OCSP_CONTENT))
117
1.15k
  {
118
1.15k
    if (this->data.len % HASH_SIZE_SHA1)
119
2
    {
120
2
      DBG1(DBG_ENC, "invalid hash length (%d) in %N cert request",
121
2
         this->data.len, cert_encoding_names, this->encoding);
122
2
      return FAILED;
123
2
    }
124
1.15k
  }
125
2.11k
  return SUCCESS;
126
2.11k
}
127
128
METHOD(payload_t, get_encoding_rules, int,
129
  private_certreq_payload_t *this, encoding_rule_t **rules)
130
2.17k
{
131
2.17k
  *rules = encodings;
132
2.17k
  return countof(encodings);
133
2.17k
}
134
135
METHOD(payload_t, get_header_length, int,
136
  private_certreq_payload_t *this)
137
27.7k
{
138
27.7k
  return 5;
139
27.7k
}
140
141
METHOD(payload_t, get_type, payload_type_t,
142
  private_certreq_payload_t *this)
143
3.90k
{
144
3.90k
  return this->type;
145
3.90k
}
146
147
METHOD(payload_t, get_next_type, payload_type_t,
148
  private_certreq_payload_t *this)
149
2.11k
{
150
2.11k
  return this->next_payload;
151
2.11k
}
152
153
METHOD(payload_t, set_next_type, void,
154
  private_certreq_payload_t *this, payload_type_t type)
155
0
{
156
0
  this->next_payload = type;
157
0
}
158
159
METHOD(payload_t, get_length, size_t,
160
  private_certreq_payload_t *this)
161
0
{
162
0
  return this->payload_length;
163
0
}
164
165
METHOD(certreq_payload_t, get_dn, identification_t*,
166
  private_certreq_payload_t *this)
167
0
{
168
0
  if (this->data.len)
169
0
  {
170
0
    return identification_create_from_encoding(ID_DER_ASN1_DN, this->data);
171
0
  }
172
0
  return NULL;
173
0
}
174
175
METHOD(certreq_payload_t, add_keyid, void,
176
  private_certreq_payload_t *this, chunk_t keyid)
177
0
{
178
0
  this->data = chunk_cat("mc", this->data, keyid);
179
0
  this->payload_length += keyid.len;
180
0
}
181
182
typedef struct keyid_enumerator_t keyid_enumerator_t;
183
184
/**
185
 * enumerator to enumerate keyids
186
 */
187
struct keyid_enumerator_t  {
188
  enumerator_t public;
189
  chunk_t full;
190
  u_char *pos;
191
};
192
193
METHOD(enumerator_t, keyid_enumerate, bool,
194
  keyid_enumerator_t *this, va_list args)
195
0
{
196
0
  chunk_t *chunk;
197
198
0
  VA_ARGS_VGET(args, chunk);
199
200
0
  if (this->pos == NULL)
201
0
  {
202
0
    this->pos = this->full.ptr;
203
0
  }
204
0
  else
205
0
  {
206
0
    this->pos += HASH_SIZE_SHA1;
207
0
    if (this->pos > (this->full.ptr + this->full.len - HASH_SIZE_SHA1))
208
0
    {
209
0
      this->pos = NULL;
210
0
    }
211
0
  }
212
0
  if (this->pos)
213
0
  {
214
0
    chunk->ptr = this->pos;
215
0
    chunk->len = HASH_SIZE_SHA1;
216
0
    return TRUE;
217
0
  }
218
0
  return FALSE;
219
0
}
220
221
METHOD(certreq_payload_t, create_keyid_enumerator, enumerator_t*,
222
  private_certreq_payload_t *this)
223
0
{
224
0
  keyid_enumerator_t *enumerator;
225
226
0
  if (this->type == PLV1_CERTREQ)
227
0
  {
228
0
    return enumerator_create_empty();
229
0
  }
230
0
  INIT(enumerator,
231
0
    .public = {
232
0
      .enumerate = enumerator_enumerate_default,
233
0
      .venumerate = _keyid_enumerate,
234
0
      .destroy = (void*)free,
235
0
    },
236
0
    .full = this->data,
237
0
  );
238
0
  return &enumerator->public;
239
0
}
240
241
METHOD(certreq_payload_t, get_cert_type, certificate_type_t,
242
  private_certreq_payload_t *this)
243
0
{
244
0
  switch (this->encoding)
245
0
  {
246
0
    case ENC_X509_SIGNATURE:
247
0
      return CERT_X509;
248
0
    case ENC_OCSP_CONTENT:
249
0
      return CERT_X509_OCSP_REQUEST;
250
0
    default:
251
0
      return CERT_ANY;
252
0
  }
253
0
}
254
255
METHOD2(payload_t, certreq_payload_t, destroy, void,
256
  private_certreq_payload_t *this)
257
2.17k
{
258
2.17k
  chunk_free(&this->data);
259
2.17k
  free(this);
260
2.17k
}
261
262
/*
263
 * Described in header
264
 */
265
certreq_payload_t *certreq_payload_create(payload_type_t type)
266
2.17k
{
267
2.17k
  private_certreq_payload_t *this;
268
269
2.17k
  INIT(this,
270
2.17k
    .public = {
271
2.17k
      .payload_interface = {
272
2.17k
        .verify = _verify,
273
2.17k
        .get_encoding_rules = _get_encoding_rules,
274
2.17k
        .get_header_length = _get_header_length,
275
2.17k
        .get_length = _get_length,
276
2.17k
        .get_next_type = _get_next_type,
277
2.17k
        .set_next_type = _set_next_type,
278
2.17k
        .get_type = _get_type,
279
2.17k
        .destroy = _destroy,
280
2.17k
      },
281
2.17k
      .create_keyid_enumerator = _create_keyid_enumerator,
282
2.17k
      .get_cert_type = _get_cert_type,
283
2.17k
      .add_keyid = _add_keyid,
284
2.17k
      .destroy = _destroy,
285
2.17k
      .get_dn = _get_dn,
286
2.17k
    },
287
2.17k
    .next_payload = PL_NONE,
288
2.17k
    .payload_length = get_header_length(this),
289
2.17k
    .type = type,
290
2.17k
  );
291
2.17k
  return &this->public;
292
2.17k
}
293
294
/*
295
 * Described in header
296
 */
297
certreq_payload_t *certreq_payload_create_type(certificate_type_t type)
298
0
{
299
0
  private_certreq_payload_t *this;
300
301
0
  this = (private_certreq_payload_t*)
302
0
          certreq_payload_create(PLV2_CERTREQ);
303
0
  switch (type)
304
0
  {
305
0
    case CERT_X509:
306
0
      this->encoding = ENC_X509_SIGNATURE;
307
0
      break;
308
0
    case CERT_X509_OCSP_REQUEST:
309
0
      this->encoding = ENC_OCSP_CONTENT;
310
0
      break;
311
0
    default:
312
0
      DBG1(DBG_ENC, "certificate type %N not supported in requests",
313
0
         certificate_type_names, type);
314
0
      free(this);
315
0
      return NULL;
316
0
  }
317
0
  return &this->public;
318
0
}
319
320
/*
321
 * Described in header
322
 */
323
certreq_payload_t *certreq_payload_create_dn(identification_t *id)
324
0
{
325
0
  private_certreq_payload_t *this;
326
327
0
  this = (private_certreq_payload_t*)
328
0
          certreq_payload_create(PLV1_CERTREQ);
329
330
0
  this->encoding = ENC_X509_SIGNATURE;
331
0
  this->data = chunk_clone(id->get_encoding(id));
332
0
  this->payload_length = get_header_length(this) + this->data.len;
333
334
0
  return &this->public;
335
0
}