Coverage Report

Created: 2026-06-10 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/strongswan/fuzz/fuzz_tls.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2026 Arthur SC Chan
3
 *
4
 * Copyright (C) secunet Security Networks AG
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License as published by the
8
 * Free Software Foundation; either version 2 of the License, or (at your
9
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
10
 *
11
 * This program is distributed in the hope that it will be useful, but
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14
 * for more details.
15
 */
16
17
#include <library.h>
18
#include <tls.h>
19
#include <credentials/sets/mem_cred.h>
20
21
/**
22
 * ECDSA256 private key (same as used in test_socket.c)
23
 */
24
static chunk_t ecdsa256 = chunk_from_chars(
25
  0x30,0x77,0x02,0x01,0x01,0x04,0x20,0x2d,0x01,0x7e,0x5b,0x4a,0x7d,0x78,0xe9,0x23,
26
  0xeb,0xb2,0xac,0x4c,0xf1,0x28,0x3b,0xfa,0x1d,0xa9,0x08,0x5c,0xd0,0x60,0x2a,0xa6,
27
  0x54,0xd3,0x94,0xd4,0x05,0xa1,0x04,0xa0,0x0a,0x06,0x08,0x2a,0x86,0x48,0xce,0x3d,
28
  0x03,0x01,0x07,0xa1,0x44,0x03,0x42,0x00,0x04,0x15,0x9c,0xbe,0xdb,0x54,0xa6,0xe7,
29
  0x7f,0x76,0x05,0xa6,0x9d,0xf3,0x41,0x38,0x43,0x98,0xe9,0x0b,0x2b,0x8b,0x02,0xb4,
30
  0x04,0x9b,0x61,0x84,0x65,0x63,0x3b,0x08,0xb2,0x4b,0x1e,0xd0,0x32,0x20,0xe9,0xfc,
31
  0x62,0xa7,0xd0,0x71,0x9e,0xe9,0xf9,0x2d,0x91,0xb8,0xf2,0xa3,0x4d,0x8a,0x78,0xb2,
32
  0x0b,0xfb,0x59,0x7c,0x40,0xbd,0xaf,0xa2,0x07
33
);
34
35
/**
36
 * TLS certificate for ECDSA256 key
37
 * pki --self --in ecdsa256.key --dn "C=CH, O=strongSwan, CN=tls-fuzz-ecdsa" --san server.test
38
 */
39
static chunk_t ecdsa256_crt = chunk_from_chars(
40
  0x30,0x82,0x01,0x87,0x30,0x82,0x01,0x2C,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x3D,
41
  0x6D,0x48,0xA3,0x1F,0x8A,0x62,0x3E,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,
42
  0x04,0x03,0x02,0x30,0x3B,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,
43
  0x43,0x48,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x73,0x74,0x72,
44
  0x6F,0x6E,0x67,0x53,0x77,0x61,0x6E,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x03,
45
  0x13,0x0E,0x74,0x6C,0x73,0x2D,0x66,0x75,0x7A,0x7A,0x2D,0x65,0x63,0x64,0x73,0x61,
46
  0x30,0x1E,0x17,0x0D,0x32,0x36,0x30,0x35,0x32,0x39,0x30,0x38,0x33,0x38,0x33,0x36,
47
  0x5A,0x17,0x0D,0x32,0x39,0x30,0x35,0x32,0x38,0x30,0x38,0x33,0x38,0x33,0x36,0x5A,
48
  0x30,0x3B,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x43,0x48,0x31,
49
  0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x73,0x74,0x72,0x6F,0x6E,0x67,
50
  0x53,0x77,0x61,0x6E,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x03,0x13,0x0E,0x74,
51
  0x6C,0x73,0x2D,0x66,0x75,0x7A,0x7A,0x2D,0x65,0x63,0x64,0x73,0x61,0x30,0x59,0x30,
52
  0x13,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x08,0x2A,0x86,0x48,0xCE,
53
  0x3D,0x03,0x01,0x07,0x03,0x42,0x00,0x04,0x15,0x9C,0xBE,0xDB,0x54,0xA6,0xE7,0x7F,
54
  0x76,0x05,0xA6,0x9D,0xF3,0x41,0x38,0x43,0x98,0xE9,0x0B,0x2B,0x8B,0x02,0xB4,0x04,
55
  0x9B,0x61,0x84,0x65,0x63,0x3B,0x08,0xB2,0x4B,0x1E,0xD0,0x32,0x20,0xE9,0xFC,0x62,
56
  0xA7,0xD0,0x71,0x9E,0xE9,0xF9,0x2D,0x91,0xB8,0xF2,0xA3,0x4D,0x8A,0x78,0xB2,0x0B,
57
  0xFB,0x59,0x7C,0x40,0xBD,0xAF,0xA2,0x07,0xA3,0x1A,0x30,0x18,0x30,0x16,0x06,0x03,
58
  0x55,0x1D,0x11,0x04,0x0F,0x30,0x0D,0x82,0x0B,0x73,0x65,0x72,0x76,0x65,0x72,0x2E,
59
  0x74,0x65,0x73,0x74,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x02,
60
  0x03,0x49,0x00,0x30,0x46,0x02,0x21,0x00,0xCB,0xD9,0x0D,0xC9,0x5C,0x68,0xF8,0x9D,
61
  0x69,0x69,0xB3,0x73,0x33,0xE7,0x29,0x08,0x63,0x7D,0xDB,0x12,0x8E,0xB5,0x5F,0xBF,
62
  0xEC,0xE7,0x81,0x95,0xC4,0x3F,0x7E,0xFA,0x02,0x21,0x00,0xB7,0x79,0xDA,0x0F,0xD1,
63
  0x42,0x9C,0xC2,0xD1,0x32,0x03,0x2D,0xE5,0x55,0x22,0xD8,0x09,0xAC,0xA9,0x1B,0xA1,
64
  0x0D,0x31,0xB8,0x24,0xEE,0xE3,0xE0,0xBF,0xBD,0x18,0xA5,
65
);
66
67
/**
68
 * Credential set
69
 */
70
static mem_cred_t *creds;
71
72
/**
73
 * Load the test certificate
74
 */
75
static void setup_cert()
76
2
{
77
2
  private_key_t *key;
78
2
  certificate_t *cert;
79
80
2
  creds = mem_cred_create();
81
2
  lib->credmgr->add_set(lib->credmgr, &creds->set);
82
83
2
  key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
84
2
               BUILD_BLOB, ecdsa256, BUILD_END);
85
2
  if (key)
86
2
  {
87
2
    creds->add_key(creds, key);
88
2
  }
89
90
2
  cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
91
2
                BUILD_BLOB, ecdsa256_crt, BUILD_END);
92
2
  if (cert)
93
2
  {
94
2
    creds->add_cert(creds, TRUE, cert);
95
2
  }
96
2
}
97
98
/**
99
 * Minimal TLS application stub for fuzzing
100
 */
101
typedef struct {
102
  tls_application_t public;
103
} fuzz_tls_application_t;
104
105
static status_t app_process(tls_application_t *this, bio_reader_t *reader)
106
0
{
107
  /* Consume application data without processing */
108
0
  return NEED_MORE;
109
0
}
110
111
static status_t app_build(tls_application_t *this, bio_writer_t *writer)
112
0
{
113
  /* No application data to send */
114
0
  return INVALID_STATE;
115
0
}
116
117
static void app_destroy(tls_application_t *this)
118
92
{
119
92
  free(this);
120
92
}
121
122
static tls_application_t *create_tls_application()
123
92
{
124
92
  fuzz_tls_application_t *app;
125
126
92
  INIT(app,
127
92
    .public = {
128
92
      .process = app_process,
129
92
      .build = app_build,
130
92
      .destroy = app_destroy,
131
92
    },
132
92
  );
133
92
  return &app->public;
134
92
}
135
136
int LLVMFuzzerInitialize(int *argc, char ***argv)
137
4
{
138
4
  dbg_default_set_level(-1);
139
4
  library_init(NULL, "fuzz_tls");
140
4
  if (!lib->plugins->load(lib->plugins, PLUGINS))
141
0
  {
142
0
    return 1;
143
0
  }
144
4
  setup_cert();
145
4
  return 0;
146
4
}
147
148
int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
149
96
{
150
96
  tls_t *tls;
151
96
  identification_t *server_id, *peer_id;
152
96
  tls_application_t *app;
153
96
  status_t status;
154
96
  char out[TLS_MAX_FRAGMENT_LEN + 2048];
155
96
  size_t outlen, msglen;
156
96
  bool is_server;
157
158
  /* Need one role byte plus minimum TLS record header (5 bytes) */
159
96
  if (len < 6)
160
4
  {
161
4
    return 0;
162
4
  }
163
164
  /* First byte selects role: input is then either a request (server) or
165
   * response (client) */
166
92
  is_server = buf[0] & 1;
167
92
  buf++;
168
92
  len--;
169
170
92
  server_id = identification_create_from_string("server.test");
171
92
  peer_id = identification_create_from_string("peer.test");
172
92
  app = create_tls_application();
173
174
92
  tls = tls_create(is_server, server_id, peer_id, TLS_PURPOSE_GENERIC,
175
92
           app, NULL, TLS_FLAG_ENCRYPTION_OPTIONAL);
176
92
  tls->set_version(tls, TLS_SUPPORTED_MIN, TLS_SUPPORTED_MAX);
177
178
  /* Client must emit ClientHello first so input is interpreted as the
179
   * server's reply */
180
92
  if (!is_server)
181
37
  {
182
37
    do
183
37
    {
184
37
      outlen = sizeof(out);
185
37
      status = tls->build(tls, out, &outlen, &msglen);
186
37
    }
187
37
    while (status == NEED_MORE);
188
37
  }
189
190
92
  status = tls->process(tls, (void*)buf, len);
191
192
  /* Drive build() naturally based on process() status */
193
92
  if (status == NEED_MORE)
194
90
  {
195
90
    do
196
90
    {
197
90
      outlen = sizeof(out);
198
90
      status = tls->build(tls, out, &outlen, &msglen);
199
90
    }
200
90
    while (status == NEED_MORE);
201
90
  }
202
203
92
  tls->destroy(tls);
204
92
  server_id->destroy(server_id);
205
92
  peer_id->destroy(peer_id);
206
92
  return 0;
207
96
}