/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 | } |