GNU libmicrohttpd 1.0.9
Loading...
Searching...
No Matches
fuzz_tls.c
Go to the documentation of this file.
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2026 Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library.
17 If not, see <http://www.gnu.org/licenses/>.
18*/
19
178#define FUZZ_HARNESS_NAME "fuzz_tls"
179#include "fuzz_common.h"
180
181/* Pulls in MHD_config.h, which is where HTTPS_SUPPORT is defined. It
182 must come before <microhttpd.h>: it also settles FD_SETSIZE. */
183#include "mhd_options.h"
184
185#ifdef HTTPS_SUPPORT
186
187#include <microhttpd.h>
188#include <gnutls/gnutls.h>
189#include <gnutls/abstract.h>
190#include <sys/socket.h>
191#include <netinet/in.h>
192#include <sys/select.h>
193#include <arpa/inet.h>
194
221const char *
222__lsan_default_suppressions (void);
223
224const char *
225__lsan_default_suppressions (void)
226{
227 return "leak:gnutls_x509_crt_init\n";
228}
229
230
231#define MAX_SEGMENTS 48
232#define MAX_CONNECTIONS 3
233#define RESP_BUF_SIZE 16384
234#define GEN_BUF_SIZE 4096
235#define MAX_SNI_LEN 255
236#define FUZZ_PEM_BODY_MAX 1024
237
239#define CLIENT_PRIO_COUNT 4
240
246#define HANDSHAKE_ROUNDS 64
247
248
249/* ------------------------------------------------------------------ */
250/* Test credentials */
251/* ------------------------------------------------------------------ */
252
253/*
254 * Taken verbatim from src/testcurl/https/tls_test_keys.h (the CA
255 * certificate, the CA-signed server certificate and its key, and the
256 * self-signed server certificate and its key), so that this harness
257 * stays a single translation unit. dh_params_pem is RFC 3526 group 14,
258 * as emitted by "certtool --get-dh-params --sec-param medium".
259 */
260
261static const char ca_cert_pem[] =
262 "-----BEGIN CERTIFICATE-----\n"
263 "MIIGITCCBAmgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCUlUx\n"
264 "DzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MRswGQYDVQQKDBJ0ZXN0\n"
265 "LWxpYm1pY3JvaHR0cGQxITAfBgkqhkiG9w0BCQEWEm5vYm9keUBleGFtcGxlLm9y\n"
266 "ZzEQMA4GA1UEAwwHdGVzdC1DQTAgFw0yMTA0MDcxNzM2MThaGA8yMTIxMDMxNDE3\n"
267 "MzYxOFowgYExCzAJBgNVBAYTAlJVMQ8wDQYDVQQIDAZNb3Njb3cxDzANBgNVBAcM\n"
268 "Bk1vc2NvdzEbMBkGA1UECgwSdGVzdC1saWJtaWNyb2h0dHBkMSEwHwYJKoZIhvcN\n"
269 "AQkBFhJub2JvZHlAZXhhbXBsZS5vcmcxEDAOBgNVBAMMB3Rlc3QtQ0EwggIiMA0G\n"
270 "CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDdaWupA4qZjCBNkJoJOm5xnCaizl36\n"
271 "ZLUwp4xBL/YfXPWE3LkmAREiVI/YnAb8l6G7CJnz8dTsOJWkNXG6T1KVP5/2RvBI\n"
272 "IaaaufRIAl7hEnj1j9E2hQlV2fxF2ZNhz+nqi0LqKV4LJSpclkXADf2FA9HsVRP/\n"
273 "B7zYh+DP0fSU8V6bsu8XCeRGshroAPrc8rH8lFEEXpNLNIqQr8yKx6SmdB6hfja6\n"
274 "6SQ0++qBhl0aJtn4LHWZohgjBmkIaGFPYIJLgxQ/xyp2Grz2q7lGKJ+zBkBF8iOP\n"
275 "t3x+F1hSCBnr/DGYWmjEm5tYm+7pyuriPddXdCc8+qa2LxMZo3EXxLo5YISpPCyw\n"
276 "Z7V3YAOZTr3m1C24LiYvPehCq1CTIkhhmqtlVJXU7ISD48cx9y+5Pi34wtbTI/gN\n"
277 "x4voyTLAfyavKMmIpxxIRsWldiF2n06HdvCRVdihDQUad10ygTmWf1J/s2ZETAtH\n"
278 "QaSd7MD389t6nQFtTIXigsNKnnDPlrtxt7rOLvLQeR0K04Gzrf/scheOanRAfOXH\n"
279 "KNBFU7YkDFG8rqizlC65rx9qeXFYXQcHZTuqxK7tgZnSgJat3E70VbTSCsEEG7eR\n"
280 "bNX/fChUKAIIpWaiW6HDlKLl6m2y+BzM91umBsKOqTvntMVFBSF9pVYlXK854aIR\n"
281 "q8A2Xujd012seQIDAQABo4GfMIGcMAsGA1UdDwQEAwICpDASBgNVHRMBAf8ECDAG\n"
282 "AQH/AgEBMB0GA1UdDgQWBBRYdUPApWoxw4U13Rqsjf9AHdbpLDATBgNVHSUEDDAK\n"
283 "BggrBgEFBQcDATAkBglghkgBhvhCAQ0EFxYVVGVzdCBsaWJtaWNyb2h0dHBkIENB\n"
284 "MB8GA1UdIwQYMBaAFFh1Q8ClajHDhTXdGqyN/0Ad1uksMA0GCSqGSIb3DQEBCwUA\n"
285 "A4ICAQBvrrcTKVeI1EYnXo4BQD4oCvf9z1fYQmL21EbHwgjg1nmaPkvStgWAc5p1\n"
286 "kKwySrpEMKXfu68X76RccXZyWWIamEjz2OCWYZgjX6d6FpjhLphL8WxXDy5C9eay\n"
287 "ixN7+URz2XQoi22wqR+tCPDhrIzcMPyMkx/6gRgcYeDnaFrkdSeSsKsID4plfcIj\n"
288 "ISWJDvv+IAgrtsG1NVHnGwpAv0od3A8/4/fR6PPyewaU3aydvjZ7Au8O9DGDjlU9\n"
289 "9HdlOkkY6GVJ1pfGZib7cV7lhy0D2kj1g9xZh97YjpoUfppPl9r+6A8gDm0hXlAD\n"
290 "TlzNYlwTb681ZEoSd9PiLEY8HETssHlays2dYXdcNwAEp69iIHz8q1Q98Be9LScl\n"
291 "WEzgaOT9U7lpIw/MWbELoMsC+Ecs1cVWBIuiIq8aSG2kRr1x3S8yVXbAohAXif2s\n"
292 "E6puieM/VJ25iaNhkbLmDkk58QVVmn9NZNv6ETxuSQMp9e0EwbVlj68vzClQ91Y/\n"
293 "nmAiGcLFUEwB9G0szv9+vR+oDW4IkvdFZSUbcICd2cnynnwAD395onqS4hEZO1xM\n"
294 "Gy5ZldbTMTjgn7fChNopz15ChPBnwFIjhm+S0CyiLRQAowfknRVq2IBkj7/5kOWg\n"
295 "4mcxcq76HoQWK/8X/8RFL1eFVAvY7TNHYJ0RS51DMuwCNQictA==\n"
296 "-----END CERTIFICATE-----\n";
297
298
299static const char srv_signed_key_pem[] =
300 "-----BEGIN PRIVATE KEY-----\n"
301 "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCff7amw9zNSE+h\n"
302 "rOMhBrzbbsJluUP3gmd8nOKY5MUimoPkxmAXfp2L0il+MPZT/ZEmo11q0k6J2jfG\n"
303 "UBQ+oZW9ahNZ9gCDjbYlBblo/mqTai+LdeLO3qk53d0zrZKXvCO6sA3uKpG2WR+g\n"
304 "+sNKxfYpIHCpanqBU6O+degIV/+WKy3nQ2Fwp7K5HUNj1u0pg0QQ18yf68LTnKFU\n"
305 "HFjZmmaaopWki5wKSBieHivzQy6w+04HSTogHHRK/y/UcoJNSG7xnHmoPPo1vLT8\n"
306 "CMRIYnSSgU3wJ43XBJ80WxrC2dcoZjV2XZz+XdQwCD4ZrC1ihykcAmiQA+sauNm7\n"
307 "dztOMkGzAgMBAAECggEAIbKDzlvXDG/YkxnJqrKXt+yAmak4mNQuNP+YSCEdHSBz\n"
308 "+SOILa6MbnvqVETX5grOXdFp7SWdfjZiTj2g6VKOJkSA7iKxHRoVf2DkOTB3J8np\n"
309 "XZd8YaRdMGKVV1O2guQ20Dxd1RGdU18k9YfFNsj4Jtw5sTFTzHr1P0n9ybV9xCXp\n"
310 "znSxVfRg8U6TcMHoRDJR9EMKQMO4W3OQEmreEPoGt2/+kMuiHjclxLtbwDxKXTLP\n"
311 "pD0gdg3ibvlufk/ccKl/yAglDmd0dfW22oS7NgvRKUve7tzDxY1Q6O5v8BCnLFSW\n"
312 "D+z4hS1PzooYRXRkM0xYudvPkryPyu+1kEpw3fNsoQKBgQDRfXJo82XQvlX8WPdZ\n"
313 "Ts3PfBKKMVu3Wf8J3SYpuvYT816qR3ot6e4Ivv5ZCQkdDwzzBKe2jAv6JddMJIhx\n"
314 "pkGHc0KKOodd9HoBewOd8Td++hapJAGaGblhL5beIidLKjXDjLqtgoHRGlv5Cojo\n"
315 "zHa7Viel1eOPPcBumhp83oJ+mQKBgQDC6PmdETZdrW3QPm7ZXxRzF1vvpC55wmPg\n"
316 "pRfTRM059jzRzAk0QiBgVp3yk2a6Ob3mB2MLfQVDgzGf37h2oO07s5nspSFZTFnM\n"
317 "KgSjFy0xVOAVDLe+0VpbmLp1YUTYvdCNowaoTE7++5rpePUDu3BjAifx07/yaSB+\n"
318 "W+YPOfOuKwKBgQCGK6g5G5qcJSuBIaHZ6yTZvIdLRu2M8vDral5k3793a6m3uWvB\n"
319 "OFAh/eF9ONJDcD5E7zhTLEMHhXDs7YEN+QODMwjs6yuDu27gv97DK5j1lEsrLUpx\n"
320 "XgRjAE3KG2m7NF+WzO1K74khWZaKXHrvTvTEaxudlO3X8h7rN3u7ee9uEQKBgQC2\n"
321 "wI1zeTUZhsiFTlTPWfgppchdHPs6zUqq0wFQ5Zzr8Pa72+zxY+NJkU2NqinTCNsG\n"
322 "ePykQ/gQgk2gUrt595AYv2De40IuoYk9BlTMuql0LNniwsbykwd/BOgnsSlFdEy8\n"
323 "0RQn70zOhgmNSg2qDzDklJvxghLi7zE5aV9//V1/ewKBgFRHHZN1a8q/v8AAOeoB\n"
324 "ROuXfgDDpxNNUKbzLL5MO5odgZGi61PBZlxffrSOqyZoJkzawXycNtoBP47tcVzT\n"
325 "QPq5ZOB3kjHTcN7dRLmPWjji9h4O3eHCX67XaPVMSWiMuNtOZIg2an06+jxGFhLE\n"
326 "qdJNJ1DkyUc9dN2cliX4R+rG\n"
327 "-----END PRIVATE KEY-----\n";
328
329
330static const char srv_signed_cert_pem[] =
331 "-----BEGIN CERTIFICATE-----\n"
332 "MIIFSzCCAzOgAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCUlUx\n"
333 "DzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MRswGQYDVQQKDBJ0ZXN0\n"
334 "LWxpYm1pY3JvaHR0cGQxITAfBgkqhkiG9w0BCQEWEm5vYm9keUBleGFtcGxlLm9y\n"
335 "ZzEQMA4GA1UEAwwHdGVzdC1DQTAgFw0yMjA0MjAxODQzMDJaGA8yMTIyMDMyNjE4\n"
336 "NDMwMlowZTELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwG\n"
337 "TW9zY293MRswGQYDVQQKDBJ0ZXN0LWxpYm1pY3JvaHR0cGQxFzAVBgNVBAMMDnRl\n"
338 "c3QtbWhkc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn3+2\n"
339 "psPczUhPoazjIQa8227CZblD94JnfJzimOTFIpqD5MZgF36di9IpfjD2U/2RJqNd\n"
340 "atJOido3xlAUPqGVvWoTWfYAg422JQW5aP5qk2ovi3Xizt6pOd3dM62Sl7wjurAN\n"
341 "7iqRtlkfoPrDSsX2KSBwqWp6gVOjvnXoCFf/list50NhcKeyuR1DY9btKYNEENfM\n"
342 "n+vC05yhVBxY2ZpmmqKVpIucCkgYnh4r80MusPtOB0k6IBx0Sv8v1HKCTUhu8Zx5\n"
343 "qDz6Nby0/AjESGJ0koFN8CeN1wSfNFsawtnXKGY1dl2c/l3UMAg+GawtYocpHAJo\n"
344 "kAPrGrjZu3c7TjJBswIDAQABo4HmMIHjMAsGA1UdDwQEAwIFoDAMBgNVHRMBAf8E\n"
345 "AjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMBMDEGA1UdEQQqMCiCDnRlc3QtbWhk\n"
346 "c2VydmVyhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMB0GA1UdDgQWBBQ57Z06WJae\n"
347 "8fJIHId4QGx/HsRgDDAoBglghkgBhvhCAQ0EGxYZVGVzdCBsaWJtaWNyb2h0dHBk\n"
348 "IHNlcnZlcjARBglghkgBhvhCAQEEBAMCBkAwHwYDVR0jBBgwFoAUWHVDwKVqMcOF\n"
349 "Nd0arI3/QB3W6SwwDQYJKoZIhvcNAQELBQADggIBAI7Lggm/XzpugV93H5+KV48x\n"
350 "X+Ct8unNmPCSzCaI5hAHGeBBJpvD0KME5oiJ5p2wfCtK5Dt9zzf0S0xYdRKqU8+N\n"
351 "aKIvPoU1hFixXLwTte1qOp6TviGvA9Xn2Fc4n36dLt6e9aiqDnqPbJgBwcVO82ll\n"
352 "HJxVr3WbrAcQTB3irFUMqgAke/Cva9Bw79VZgX4ghb5EnejDzuyup4pHGzV10Myv\n"
353 "hdg+VWZbAxpCe0S4eKmstZC7mWsFCLeoRTf/9Pk1kQ6+azbTuV/9QOBNfFi8QNyb\n"
354 "18jUjmm8sc2HKo8miCGqb2sFqaGD918hfkWmR+fFkzQ3DZQrT+eYbKq2un3k0pMy\n"
355 "UySy8SRn1eadfab+GwBVb68I9TrPRMrJsIzysNXMX4iKYl2fFE/RSNnaHtPw0C8y\n"
356 "B7memyxPRl+H2xg6UjpoKYh3+8e44/XKm0rNIzXjrwA8f8gnw2TbqmMDkj1YqGnC\n"
357 "SCj5A27zUzaf2pT/YsnQXIWOJjVvbEI+YKj34wKWyTrXA093y8YI8T3mal7Kr9YM\n"
358 "WiIyPts0/aVeziM0Gunglz+8Rj1VesL52FTurobqusPgM/AME82+qb/qnxuPaCKj\n"
359 "OT1qAbIblaRuWqCsid8BzP7ZQiAnAWgMRSUg1gzDwSwRhrYQRRWAyn/Qipzec+27\n"
360 "/w0gW9EVWzFhsFeGEssi\n"
361 "-----END CERTIFICATE-----\n";
362
363
364static const char srv_self_signed_cert_pem[] =
365 "-----BEGIN CERTIFICATE-----\n"
366 "MIIDJzCCAg+gAwIBAgIUOKf6e6Heee2XA+yF5St3t+fVM40wDQYJKoZIhvcNAQEF\n"
367 "BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTIyMTAxMDA4MzQ0N1oYDzIxMjIw\n"
368 "OTE2MDgzNDQ3WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB\n"
369 "AQUAA4IBDwAwggEKAoIBAQClivgF8Xq0ekQli++0l7Q5JFwJCuLf04Cb1UKIS80U\n"
370 "CfphFd1ILJepNw4bWR3OV1sRI1vFiw6LnCz53vOwVNyiZ+sMGi4bDX4AV9Xd+F83\n"
371 "xhG8AjOmKTayW0TxSIvt47Qd5S/4fgraxMtvqrRRBen30iKOwX7uNF/4dYb9vdin\n"
372 "OldV/e8uzbqSurMGkNDznOeSaNBmdO/7x0VMFZM2hwmHyiiw75/j4BhUlLCcMEvK\n"
373 "oN+YHNCNcTt3Qm1vVuiGXmh9QreOV09Gc1SzAltxF2gmI0jzw8r/duz18QXMNsMw\n"
374 "El/Ah4+02gR70L7qlgttN1NPU3RJpK/L34J7yg649wHTAgMBAAGjbzBtMB0GA1Ud\n"
375 "DgQWBBROVferD+YYcV1YEnFgC0jYm5X9BjAfBgNVHSMEGDAWgBROVferD+YYcV1Y\n"
376 "EnFgC0jYm5X9BjAPBgNVHRMBAf8EBTADAQH/MBoGA1UdEQQTMBGCCWxvY2FsaG9z\n"
377 "dIcEfwAAATANBgkqhkiG9w0BAQUFAAOCAQEAoRbozsm5xXdNX3VO++s2LMzw5KM9\n"
378 "RpIInHNkMJbnyLJFKJ8DF7nTxSGCA38YMkX3tphPNKZXbg+V64Dqr/XpzOVyiinU\n"
379 "7hIwyUdSSKKyErZxIWR97lY6Q3SOyPAg8ZElbtvSsSzmd772VE23VTXGDi7AW0PQ\n"
380 "hag9N2EEnHURMvID15O+UXyFpDdyUyQIbx3HuswsGDH9xBTm4irLyrZwO0KwKg5a\n"
381 "JBeUiPs0SYRRfn9/MoE6VwAnmOCg3LLR6ZPU3hQtTPLHj2Op1g5fey3X3X6lC+JC\n"
382 "K6dNZc1zBFPz8KANGUsFYbmoP2bvAAA+6KwCnZZEflUgE7/HFEmQhVOezw==\n"
383 "-----END CERTIFICATE-----\n";
384
385
386static const char srv_self_signed_key_pem[] =
387 "-----BEGIN PRIVATE KEY-----\n"
388 "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQClivgF8Xq0ekQl\n"
389 "i++0l7Q5JFwJCuLf04Cb1UKIS80UCfphFd1ILJepNw4bWR3OV1sRI1vFiw6LnCz5\n"
390 "3vOwVNyiZ+sMGi4bDX4AV9Xd+F83xhG8AjOmKTayW0TxSIvt47Qd5S/4fgraxMtv\n"
391 "qrRRBen30iKOwX7uNF/4dYb9vdinOldV/e8uzbqSurMGkNDznOeSaNBmdO/7x0VM\n"
392 "FZM2hwmHyiiw75/j4BhUlLCcMEvKoN+YHNCNcTt3Qm1vVuiGXmh9QreOV09Gc1Sz\n"
393 "AltxF2gmI0jzw8r/duz18QXMNsMwEl/Ah4+02gR70L7qlgttN1NPU3RJpK/L34J7\n"
394 "yg649wHTAgMBAAECggEAERbbCtYGakoy7cNX8Ac3Kiz4OVC/4gZWAQBPeX2FwrtS\n"
395 "9yHIMbK0x1mxIZ6eBpabBpZlW2vDCSOKuxLKiloAWt2qdJnhR5apesSWhe8leT7/\n"
396 "xq5dgZpAlMH6SIRKObknd2yY+qicW0A0licDrVeUcypkueL8xP9wJtiPInOuQXkI\n"
397 "QROhB13eStRuRKYwOn5gtwAHJ+J1DFKKiqpBOkrSYf4625StGegJO9+bjK0ei+0W\n"
398 "tp6unpiwA/lXTgz6Xim1Z3fzWs4XjFgVKzK5s/6yBJjr8spHX6lv7QsahP4w6HZ/\n"
399 "VcRxP6cJNd/otiTEtJXpbxiiyccwXm/AOcOn22P1cQKBgQDAnY/0G/ap/G98pneE\n"
400 "suzNXhWOQ8JoL8d66Io8vwTvfiJggfgUcwblI7pPCrSlaZMR7/q6JImE53lZtPk8\n"
401 "eI3c9lN0ocr8E7+huDpYdk7cMYj9SuxySsXoMLiMqzHFi+NcIhKMF56kk6a5CFCt\n"
402 "yP1Ofy76LVweGE3XvTwpwE7wUQKBgQDcBLyH1cC71s0I0Gz28AyELV9hPhasjAKO\n"
403 "12CVbeBVTPd+28uk/3o80wSrTksc6H5ehAA2aTvrb4OhwssWNL+D0fS8YK2cJ3V0\n"
404 "FJxGAM266+vC4d/8jRTHJnc+6PP3ix5t6vAt+K2Y0fePtefLqf4ebgXx/ODAj3J2\n"
405 "aZKBldjK4wKBgGIRFpTLk/eR/dUyEBHw4x3gdAsdtqJDCUYrlQ4+ly20Q55tLbiD\n"
406 "pBQP77CEm9rH+MgeLcKODbIsBB3HRUojet7wTydHpMhY6a1V1ebqPVZgpgWIGwBJ\n"
407 "z59bBusf0lRo15Y2Bslq0SurvSvh7um8NjO8D1fytj7gUumvgC0lq0sxAoGBAI1+\n"
408 "kkx9IBTtIDER8XGhkTsT/uoHxwcyh5abVmbjIclZ1TUFX2L+Vft17ePJVy8BKfvY\n"
409 "wlY7uShBMBNAteDTDXNV/CGFv0DUc4myk4nFjIkwng9XufeuN3WX/Eo+AF/rXSdt\n"
410 "VwcJjYLhTWdjoe1tppqlQTeN3HCaEA+s92ZVGvXnAoGAMCXGS6WZl1e5wsHRq0Yy\n"
411 "8Ef2Wrk620bBjKHolkTfvgfhlvxeZM1sv1ioZGsOeQ0z7O7wdJhvL0M/WAG+3yQj\n"
412 "HSXp81T1vOICPwNYZf8xcvbLKmvj7rHFt6ZAZF2o4EK8ReZTRyA3DUpBCDY+s3FN\n"
413 "GmBv0D7N3QP0CT3SzfQrPkc=\n"
414 "-----END PRIVATE KEY-----\n";
415
416
417static const char dh_params_pem[] =
418 "-----BEGIN DH PARAMETERS-----\n"
419 "MIIBDAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n"
420 "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n"
421 "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\n"
422 "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n"
423 "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\n"
424 "ssbzSibBsu/6iGtCOGEoXJf//////////wIBAgICAQA=\n"
425 "-----END DH PARAMETERS-----\n";
426
428static const char garbage_cert_pem[] =
429 "-----BEGIN CERTIFICATE-----\n"
430 "this is not base64 at all, not even close !!!! ????\n"
431 "-----END CERTIFICATE-----\n";
432
433static const char garbage_key_pem[] =
434 "-----BEGIN PRIVATE KEY-----\n"
435 "@@@@ neither is this @@@@\n"
436 "-----END PRIVATE KEY-----\n";
437
439static const char truncated_cert_pem[] =
440 "-----BEGIN CERTIFICATE-----\n"
441 "MIIFSzCCAzOgAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCUlUx\n"
442 "DzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MRswGQYDVQQKDBJ0ZXN0\n";
443
444static const char truncated_key_pem[] =
445 "-----BEGIN PRIVATE KEY-----\n"
446 "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCff7amw9zNSE+h\n";
447
449static const char no_armour_pem[] =
450 "MIIFSzCCAzOgAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCUlUx\n"
451 "DzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MRswGQYDVQQKDBJ0ZXN0\n";
452
453static const char garbage_dh_pem[] =
454 "-----BEGIN DH PARAMETERS-----\n"
455 "not-dh-parameters\n"
456 "-----END DH PARAMETERS-----\n";
457
463static char fuzz_cert_pem[FUZZ_PEM_BODY_MAX + 128];
464static char fuzz_key_pem[FUZZ_PEM_BODY_MAX + 128];
465
466
472struct cred_pair
473{
474 const char *cert;
475 const char *key;
476};
477
478static const struct cred_pair cred_tbl[] = {
479 { srv_signed_cert_pem, srv_signed_key_pem }, /* 0 valid, CA signed */
480 { srv_self_signed_cert_pem, srv_self_signed_key_pem }, /* 1 valid, self signed */
481 { srv_signed_cert_pem, srv_self_signed_key_pem }, /* 2 key does not match */
482 { srv_self_signed_cert_pem, srv_signed_key_pem }, /* 3 key does not match */
483 { srv_signed_cert_pem, NULL }, /* 4 certificate only */
484 { NULL, srv_signed_key_pem }, /* 5 key only */
485 { NULL, NULL }, /* 6 neither */
486 { "", "" }, /* 7 empty strings */
487 { truncated_cert_pem, srv_signed_key_pem }, /* 8 truncated armour */
488 { srv_signed_cert_pem, truncated_key_pem }, /* 9 truncated armour */
489 { garbage_cert_pem, garbage_key_pem }, /* 10 armour, no base64 */
490 { no_armour_pem, srv_signed_key_pem }, /* 11 base64, no armour */
491 { fuzz_cert_pem, srv_signed_key_pem }, /* 12 PEM from the input */
492 { srv_signed_cert_pem, fuzz_key_pem }, /* 13 PEM from the input */
493 { fuzz_cert_pem, fuzz_key_pem }, /* 14 PEM from the input */
494 { srv_signed_cert_pem, srv_signed_key_pem } /* 15 valid (bias) */
495};
496
497#define CRED_COUNT (sizeof (cred_tbl) / sizeof (cred_tbl[0]))
498
505static const char *const prio_tbl[] = {
506 "NORMAL",
507 "NORMAL:-VERS-ALL:+VERS-TLS1.3",
508 "NORMAL:-VERS-ALL:+VERS-TLS1.2",
509 "SECURE128",
510 "PERFORMANCE",
511 "@LIBMICROHTTPD",
512 "@SYSTEM",
513 "NONE",
514 "",
515 "BOGUS-PRIORITY-STRING",
516 "NORMAL:!!!",
517 "NORMAL:-VERS-ALL",
518 "NORMAL:+ANON-ECDH",
519 "NORMAL:%SERVER_PRECEDENCE",
520 "SECURE256:-CIPHER-ALL",
521 ":::::"
522};
523
524#define PRIO_COUNT (sizeof (prio_tbl) / sizeof (prio_tbl[0]))
525
527static const char *const client_prio_tbl[CLIENT_PRIO_COUNT] = {
528 "NORMAL",
529 "NORMAL:-VERS-ALL:+VERS-TLS1.3",
530 "NORMAL:-VERS-ALL:+VERS-TLS1.2",
531 "PERFORMANCE"
532};
533
549static const char *const psk_prio_tbl[CLIENT_PRIO_COUNT] = {
550 "NORMAL:+ECDHE-PSK:+DHE-PSK:+PSK",
551 "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-PSK:+DHE-PSK:+PSK",
552 "NORMAL:-VERS-ALL:+VERS-TLS1.3:+ECDHE-PSK:+DHE-PSK:+PSK",
553 "NORMAL:-KX-ALL:+ECDHE-PSK:+DHE-PSK:+PSK"
554};
555
561static const int cred_type_tbl[] = {
562 (int) GNUTLS_CRD_CERTIFICATE,
563 (int) GNUTLS_CRD_PSK,
564 (int) GNUTLS_CRD_ANON,
565 (int) GNUTLS_CRD_SRP,
566 (int) GNUTLS_CRD_IA,
567 (int) GNUTLS_CRD_CERTIFICATE,
568 99,
569 -1
570};
571
572#define CRED_TYPE_COUNT (sizeof (cred_type_tbl) / sizeof (cred_type_tbl[0]))
573
575#define PSK_CRED_TYPE_IDX 1u
576
590static const unsigned char psk_key_bytes[16] = {
591 0x9e, 0x1d, 0x4c, 0x7b, 0x30, 0xa5, 0xf2, 0x68,
592 0x11, 0xc3, 0x54, 0xd9, 0x87, 0x2a, 0x6f, 0xb0
593};
594
595static const size_t mem_limit_tbl[] = {
596 0 /* MHD default */, 256, 512, 1024, 1400, 1500, 2048, 4096, 8192, 32768,
597 0, 1024, 2048, 4096, 16384, 0
598};
599
600#define MEM_LIMIT_COUNT (sizeof (mem_limit_tbl) / sizeof (mem_limit_tbl[0]))
601
602static const char https_key_password[] = "not-the-password";
603
604
605/* ------------------------------------------------------------------ */
606/* Per-iteration configuration */
607/* ------------------------------------------------------------------ */
608
610enum sni_behaviour
611{
612 SNI_ALWAYS_OK = 0,
613 SNI_FAIL,
614 SNI_EMPTY,
615 SNI_BY_NAME,
616 SNI_MISMATCH,
617 SNI_NO_KEY,
618 SNI_SELF_SIGNED,
619 SNI_BEHAVIOUR_COUNT
620};
621
626enum psk_behaviour
627{
628 PSK_OK = 0,
629 PSK_FAIL,
630 PSK_EMPTY,
631 PSK_LONG,
632 PSK_FROM_ID,
635 PSK_HUGE,
636 PSK_NO_HANDLER,
637 /* Appended rather than grouped with PSK_EMPTY on purpose: the seeds
638 below encode the behaviour as a literal index, so inserting in the
639 middle would silently re-point every one of them. */
640 PSK_ONE_SHORT,
641 PSK_BEHAVIOUR_COUNT
642};
643
645enum client_mode
646{
647 CLIENT_RAW = 0,
648 CLIENT_TLS,
649 CLIENT_TLS_ABANDON,
650 CLIENT_RECORDS
651};
652
653struct fuzz_cfg
654{
655 /* ---- daemon ---- */
656 const char *cert;
657 const char *key;
658 int use_tls;
659 int use_trust;
660 int trust_garbage;
661 int use_dhparams;
662 int dh_garbage;
663 int use_sni;
664 int use_prio;
665 int prio_append;
666 unsigned int prio_idx;
667 const char *prio_str;
668 int use_cred_type;
669 unsigned int cred_type_idx;
670 int no_alpn;
671 int key_password;
672 int allow_upgrade;
673 size_t mem_limit;
674 unsigned int loop_mode;
675
676 /* ---- SNI callback ---- */
677 enum sni_behaviour sni_mode;
678
679 /* ---- TLS-PSK ---- */
680 int psk_scenario;
681 enum psk_behaviour psk_mode;
682
683 /* ---- client ---- */
684 enum client_mode mode;
685 int client_sni;
686 int client_cert;
687 int client_psk;
688 unsigned int client_prio_idx;
689 int client_bye;
690 int client_shut_wr;
691 unsigned int hs_budget;
692 unsigned int extra_pump;
693
694 /* ---- handler ---- */
695 unsigned int resp_kind;
696 int conn_info;
697 int daemon_info;
698 int conn_option;
699 int error_reply;
700 int resp_header;
701 int quiesce;
702 int stop_with_queued;
703};
704
705static struct fuzz_cfg cfg;
706
713static const char *const sni_name_tbl[] = {
714 "test-mhdserver",
715 "localhost",
716 "mhdhost1",
717 "nobody.example.org",
718 "",
719 "example.org",
720 "TEST-MHDSERVER",
721 "a.very.long.name.that.nobody.has.a.certificate.for.example.org"
722};
723
724#define SNI_NAME_COUNT (sizeof (sni_name_tbl) / sizeof (sni_name_tbl[0]))
725
727static char sni_name[MAX_SNI_LEN + 1];
728static size_t sni_name_len;
729
731static char resp_buf[RESP_BUF_SIZE];
732static size_t resp_len;
733
735static unsigned long stat_daemons;
736static unsigned long stat_daemons_failed;
737static unsigned long stat_connections;
738static unsigned long stat_handshakes_ok;
739static unsigned long stat_handshakes_failed;
740static unsigned long stat_handler_calls;
741static unsigned long stat_sni_calls;
742static unsigned long stat_psk_calls;
743static int stats_registered;
744
745
746static void
747print_stats (void)
748{
749 if (! fuzz_verbose)
750 return;
751 fprintf (stderr,
752 "%s: daemons=%lu (start failed=%lu) connections=%lu "
753 "handshakes ok=%lu failed=%lu handler calls=%lu SNI calls=%lu "
754 "PSK calls=%lu\n",
756 stat_daemons, stat_daemons_failed, stat_connections,
757 stat_handshakes_ok, stat_handshakes_failed, stat_handler_calls,
758 stat_sni_calls, stat_psk_calls);
759}
760
761
762/* ------------------------------------------------------------------ */
763/* The SNI (certificate retrieve) callback */
764/* ------------------------------------------------------------------ */
765
773struct sni_host
774{
775 const char *name;
776 const char *cert_pem;
777 const char *key_pem;
778 gnutls_pcert_st pcrt;
779 gnutls_privkey_t key;
780 int loaded;
781};
782
783static struct sni_host sni_hosts[2] = {
784 { "test-mhdserver", NULL, NULL, { 0, { NULL, 0 }, 0 }, NULL, 0 },
785 { "localhost", NULL, NULL, { 0, { NULL, 0 }, 0 }, NULL, 0 }
786};
787
788static int sni_hosts_ready;
789
790
794static int
795sni_hosts_init (void)
796{
797 unsigned int i;
798
799 if (0 != sni_hosts_ready)
800 return (1 == sni_hosts_ready) ? 0 : -1;
801 sni_hosts[0].cert_pem = srv_signed_cert_pem;
802 sni_hosts[0].key_pem = srv_signed_key_pem;
803 sni_hosts[1].cert_pem = srv_self_signed_cert_pem;
804 sni_hosts[1].key_pem = srv_self_signed_key_pem;
805 sni_hosts_ready = 1;
806 for (i = 0; i < sizeof (sni_hosts) / sizeof (sni_hosts[0]); i++)
807 {
808 struct sni_host *h = &sni_hosts[i];
809 gnutls_datum_t d;
810
811 d.data = (unsigned char *) (intptr_t) h->cert_pem;
812 d.size = (unsigned int) strlen (h->cert_pem);
813 if (GNUTLS_E_SUCCESS !=
814 gnutls_pcert_import_x509_raw (&h->pcrt, &d, GNUTLS_X509_FMT_PEM, 0))
815 {
816 sni_hosts_ready = -1;
817 continue;
818 }
819 if (GNUTLS_E_SUCCESS != gnutls_privkey_init (&h->key))
820 {
821 gnutls_pcert_deinit (&h->pcrt);
822 sni_hosts_ready = -1;
823 continue;
824 }
825 d.data = (unsigned char *) (intptr_t) h->key_pem;
826 d.size = (unsigned int) strlen (h->key_pem);
827 if (GNUTLS_E_SUCCESS !=
828 gnutls_privkey_import_x509_raw (h->key, &d, GNUTLS_X509_FMT_PEM,
829 NULL, 0))
830 {
831 gnutls_privkey_deinit (h->key);
832 h->key = NULL;
833 gnutls_pcert_deinit (&h->pcrt);
834 sni_hosts_ready = -1;
835 continue;
836 }
837 h->loaded = 1;
838 }
839 return (1 == sni_hosts_ready) ? 0 : -1;
840}
841
842
848static int
849sni_callback (gnutls_session_t session,
850 const gnutls_datum_t *req_ca_dn,
851 int nreqs,
852 const gnutls_pk_algorithm_t *pk_algos,
853 int pk_algos_length,
854 gnutls_pcert_st **pcert,
855 unsigned int *pcert_length,
856 gnutls_privkey_t *pkey)
857{
858 char name[MAX_SNI_LEN + 1];
859 size_t name_len = sizeof (name);
860 unsigned int type;
861 unsigned int i;
862
863 (void) req_ca_dn;
864 (void) nreqs;
865 (void) pk_algos;
866 (void) pk_algos_length;
867 stat_sni_calls++;
868 if (! sni_hosts[0].loaded)
869 return -1;
870 switch (cfg.sni_mode)
871 {
872 case SNI_FAIL:
873 return -1;
874 case SNI_EMPTY:
875 *pcert = NULL;
876 *pcert_length = 0;
877 *pkey = NULL;
878 return 0;
879 case SNI_NO_KEY:
880 *pcert = &sni_hosts[0].pcrt;
881 *pcert_length = 1;
882 *pkey = NULL;
883 return 0;
884 case SNI_MISMATCH:
885 if (! sni_hosts[1].loaded)
886 return -1;
887 *pcert = &sni_hosts[0].pcrt;
888 *pcert_length = 1;
889 *pkey = sni_hosts[1].key;
890 return 0;
891 case SNI_SELF_SIGNED:
892 if (! sni_hosts[1].loaded)
893 return -1;
894 *pcert = &sni_hosts[1].pcrt;
895 *pcert_length = 1;
896 *pkey = sni_hosts[1].key;
897 return 0;
898 case SNI_BY_NAME:
899 if (GNUTLS_E_SUCCESS !=
900 gnutls_server_name_get (session, name, &name_len, &type, 0))
901 return -1;
902 for (i = 0; i < sizeof (sni_hosts) / sizeof (sni_hosts[0]); i++)
903 if ( (sni_hosts[i].loaded) &&
904 (0 == strncmp (name, sni_hosts[i].name, name_len)) )
905 {
906 *pcert = &sni_hosts[i].pcrt;
907 *pcert_length = 1;
908 *pkey = sni_hosts[i].key;
909 return 0;
910 }
911 return -1;
912 case SNI_ALWAYS_OK:
913 case SNI_BEHAVIOUR_COUNT:
914 default:
915 break;
916 }
917 *pcert = &sni_hosts[0].pcrt;
918 *pcert_length = 1;
919 *pkey = sni_hosts[0].key;
920 return 0;
921}
922
923
924/* ------------------------------------------------------------------ */
925/* The application */
926/* ------------------------------------------------------------------ */
927
928static const char resp_body[] = "hello world over TLS";
929
930
931static enum MHD_Result
932ahc (void *cls,
933 struct MHD_Connection *connection,
934 const char *url,
935 const char *method,
936 const char *version,
937 const char *upload_data,
938 size_t *upload_data_size,
939 void **req_cls)
940{
941 static int marker;
942 struct MHD_Response *r;
943 enum MHD_Result ret;
944
945 (void) cls;
946 (void) url;
947 (void) method;
948 (void) version;
949 (void) upload_data;
951 if (NULL == *req_cls)
952 {
953 /* first call: MHD only wants to know that we are interested */
954 *req_cls = &marker;
955 return MHD_YES;
956 }
957 if (0 != *upload_data_size)
958 {
959 /* discard the request body */
960 *upload_data_size = 0;
961 return MHD_YES;
962 }
963 if (cfg.conn_info)
964 {
965 /* The TLS-specific members of MHD_ConnectionInfo; all three answer
966 NULL on a connection without a session, which is a state this
967 harness can produce. */
968 (void) MHD_get_connection_info (connection,
970 (void) MHD_get_connection_info (connection,
972 (void) MHD_get_connection_info (connection,
974 (void) MHD_get_connection_info (connection,
976 (void) MHD_get_connection_info (connection,
978 (void) MHD_get_connection_info (connection,
980 }
981 if (cfg.conn_option)
982 (void) MHD_set_connection_option (connection,
984 (unsigned int) 0);
985 switch (cfg.resp_kind)
986 {
987 case 1:
989 resp_body);
990 break;
991 case 2:
993 break;
994 case 3:
996 break;
997 case 0:
998 default:
1000 resp_body);
1001 break;
1002 }
1003 if (NULL == r)
1004 return MHD_NO;
1005 if (cfg.resp_header)
1006 (void) MHD_add_response_header (r, "X-Fuzz", "tls");
1007 ret = MHD_queue_response (connection,
1008 cfg.error_reply
1010 : MHD_HTTP_OK,
1011 r);
1013 return ret;
1014}
1015
1016
1017static void
1018panic_cb (void *cls,
1019 const char *file,
1020 unsigned int line,
1021 const char *reason)
1022{
1023 char msg[512];
1024
1025 (void) cls;
1026 (void) snprintf (msg, sizeof (msg),
1027 "MHD_PANIC() reached at %s:%u: %s",
1028 (NULL != file) ? file : "?",
1029 line,
1030 (NULL != reason) ? reason : "?");
1031 fuzz_report_finding (msg);
1032}
1033
1034
1035/* ------------------------------------------------------------------ */
1036/* Driving the daemon */
1037/* ------------------------------------------------------------------ */
1038
1046static void
1047run_once (struct MHD_Daemon *d)
1048{
1049 fd_set rs;
1050 fd_set ws;
1051 fd_set es;
1053 struct timeval tv;
1054
1055 if (0 == cfg.loop_mode)
1056 {
1057 (void) MHD_run (d);
1058 return;
1059 }
1060 FD_ZERO (&rs);
1061 FD_ZERO (&ws);
1062 FD_ZERO (&es);
1063 if (1 == cfg.loop_mode)
1064 {
1065 /* Parenthesised so that the real v1 function is called: microhttpd.h
1066 also defines MHD_get_fdset as a macro forwarding to
1067 MHD_get_fdset2. Same trick for MHD_run_from_select below. */
1068 if (MHD_YES != (MHD_get_fdset) (d, &rs, &ws, &es, &max_fd))
1069 {
1070 (void) MHD_run (d);
1071 return;
1072 }
1073 }
1074 else
1075 {
1076 if (MHD_YES != MHD_get_fdset2 (d, &rs, &ws, &es, &max_fd,
1077 (unsigned int) FD_SETSIZE))
1078 {
1079 (void) MHD_run (d);
1080 return;
1081 }
1082 }
1083 tv.tv_sec = 0;
1084 tv.tv_usec = 0;
1085 if (MHD_INVALID_SOCKET != max_fd)
1086 (void) select ((int) max_fd + 1, &rs, &ws, &es, &tv);
1087 if (1 == cfg.loop_mode)
1088 (void) (MHD_run_from_select) (d, &rs, &ws, &es);
1089 else
1090 (void) MHD_run_from_select2 (d, &rs, &ws, &es, (unsigned int) FD_SETSIZE);
1091}
1092
1093
1094/* ------------------------------------------------------------------ */
1095/* The PSK credentials callback */
1096/* ------------------------------------------------------------------ */
1097
1098#if GNUTLS_VERSION_MAJOR >= 3
1099
1115static int
1116psk_cred_cb (void *cls,
1117 const struct MHD_Connection *connection,
1118 const char *username,
1119 void **psk,
1120 size_t *psk_size)
1121{
1122 unsigned char *buf;
1123 size_t len;
1124
1125 (void) cls;
1126 (void) connection;
1127 stat_psk_calls++;
1128
1129 switch (cfg.psk_mode)
1130 {
1131 case PSK_FAIL:
1132 return -1;
1133 case PSK_EMPTY:
1134 len = 0;
1135 break;
1136 case PSK_ONE_SHORT:
1137 /* One byte below the minimum the adapter enforces. Deliberately
1138 written in terms of sizeof (psk_key_bytes), which is exactly that
1139 minimum, so this stays on the boundary if the minimum changes. */
1140 len = sizeof (psk_key_bytes) - 1;
1141 break;
1142 case PSK_LONG:
1143 len = 4096;
1144 break;
1145 case PSK_FROM_ID:
1146 len = (NULL != username) ? strlen (username) : 0;
1147 if (len > 1024)
1148 len = 1024;
1149 break;
1150 case PSK_HUGE:
1151#if SIZE_MAX > UINT_MAX
1152 /* The size MHD is told about, not the size allocated: the point is
1153 the "PSK too long" branch, which rejects before reading @a psk.
1154 MHD still free()s the pointer, so it has to be a real one. */
1155 buf = (unsigned char *) malloc (1);
1156 if (NULL == buf)
1157 return -1;
1158 buf[0] = 0;
1159 *psk = buf;
1160 *psk_size = (size_t) UINT_MAX + 1u;
1161 return 0;
1162#else
1163 len = sizeof (psk_key_bytes);
1164 break;
1165#endif
1166 case PSK_OK:
1167 case PSK_NO_HANDLER: /* not reached: the option is not passed at all */
1168 case PSK_BEHAVIOUR_COUNT:
1169 default:
1170 len = sizeof (psk_key_bytes);
1171 break;
1172 }
1173
1174 /* malloc(0) may answer NULL, which would be indistinguishable from
1175 failure here; always ask for at least one byte and report the length
1176 separately. */
1177 buf = (unsigned char *) malloc (0 != len ? len : 1);
1178 if (NULL == buf)
1179 return -1;
1180 if (0 != len)
1181 {
1182 size_t i;
1183
1184 for (i = 0; i < len; i++)
1185 buf[i] = psk_key_bytes[i % sizeof (psk_key_bytes)];
1186 }
1187 else
1188 buf[0] = 0;
1189 *psk = buf;
1190 *psk_size = len;
1191 return 0;
1192}
1193
1194
1195#endif /* GNUTLS_VERSION_MAJOR >= 3 */
1196
1197
1198/* ------------------------------------------------------------------ */
1199/* The in-process TLS client */
1200/* ------------------------------------------------------------------ */
1201
1202struct tls_client
1203{
1204 gnutls_session_t sess;
1205 gnutls_certificate_credentials_t cred;
1206 gnutls_psk_client_credentials_t psk;
1207 int fd;
1208 int hs_done;
1209 int dead;
1210};
1211
1212
1213static void
1214pump (struct MHD_Daemon *d,
1215 unsigned int rounds)
1216{
1217 unsigned int i;
1218
1219 for (i = 0; i < rounds; i++)
1220 run_once (d);
1221}
1222
1223
1229static void
1230tc_drain (struct tls_client *tc)
1231{
1232 unsigned int i;
1233 char tmp[4096];
1234
1235 if (0 > tc->fd)
1236 return;
1237 if (NULL == tc->sess)
1238 {
1239 for (;;)
1240 {
1241 ssize_t n = recv (tc->fd, tmp, sizeof (tmp), MSG_DONTWAIT);
1242
1243 if (0 >= n)
1244 break;
1245 if (resp_len + (size_t) n < RESP_BUF_SIZE)
1246 {
1247 memcpy (resp_buf + resp_len, tmp, (size_t) n);
1248 resp_len += (size_t) n;
1249 }
1250 }
1251 return;
1252 }
1253 if (tc->dead || (! tc->hs_done))
1254 return;
1255 for (i = 0; i < 8; i++)
1256 {
1257 ssize_t n = gnutls_record_recv (tc->sess, tmp, sizeof (tmp));
1258
1259 if (0 < n)
1260 {
1261 if (resp_len + (size_t) n < RESP_BUF_SIZE)
1262 {
1263 memcpy (resp_buf + resp_len, tmp, (size_t) n);
1264 resp_len += (size_t) n;
1265 }
1266 continue;
1267 }
1268 if (0 == n)
1269 break; /* peer closed the TLS connection */
1270 if ( (GNUTLS_E_AGAIN == n) ||
1271 (GNUTLS_E_INTERRUPTED == n) )
1272 break;
1273 if (0 != gnutls_error_is_fatal ((int) n))
1274 tc->dead = 1;
1275 break;
1276 }
1277}
1278
1279
1280static void
1281pump_and_drain (struct MHD_Daemon *d,
1282 struct tls_client *tc,
1283 unsigned int rounds)
1284{
1285 unsigned int i;
1286
1287 for (i = 0; i < rounds; i++)
1288 {
1289 run_once (d);
1290 tc_drain (tc);
1291 }
1292}
1293
1294
1301static void
1302tc_handshake (struct MHD_Daemon *d,
1303 struct tls_client *tc,
1304 unsigned int rounds)
1305{
1306 unsigned int i;
1307
1308 if ( (NULL == tc->sess) ||
1309 (0 != tc->dead) ||
1310 (0 != tc->hs_done) )
1311 return;
1312 for (i = 0; i < rounds; i++)
1313 {
1314 int ret = gnutls_handshake (tc->sess);
1315
1316 if (GNUTLS_E_SUCCESS == ret)
1317 {
1318 tc->hs_done = 1;
1319 stat_handshakes_ok++;
1320 return;
1321 }
1322 if (0 != gnutls_error_is_fatal (ret))
1323 {
1324 tc->dead = 1;
1325 stat_handshakes_failed++;
1326 return;
1327 }
1328 /* GNUTLS_E_AGAIN / GNUTLS_E_INTERRUPTED / a warning alert: give the
1329 daemon a chance to answer. */
1330 run_once (d);
1331 }
1332}
1333
1334
1343static int
1344tc_open (struct MHD_Daemon *d,
1345 struct tls_client *tc)
1346{
1347 int sv[2];
1348 struct sockaddr_in sa;
1349 int fl;
1350#if GNUTLS_VERSION_NUMBER >= 0x030500
1351 gnutls_init_flags_t flags;
1352#else
1353 unsigned int flags;
1354#endif
1355
1356 memset (tc, 0, sizeof (*tc));
1357 tc->fd = -1;
1358 if (0 != socketpair (AF_UNIX, SOCK_STREAM, 0, sv))
1359 return -1;
1360 memset (&sa, 0, sizeof (sa));
1361 sa.sin_family = AF_INET;
1362 sa.sin_port = htons (44444);
1363 sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
1364 if (MHD_YES != MHD_add_connection (d,
1365 (MHD_socket) sv[1],
1366 (const struct sockaddr *) &sa,
1367 (socklen_t) sizeof (sa)))
1368 {
1369 /* MHD has already closed sv[1] in that case */
1370 (void) close (sv[0]);
1371 return -1;
1372 }
1373 tc->fd = sv[0];
1374 stat_connections++;
1375 /* Our end must never block: the daemon is pumped from this very
1376 thread, so a blocking write would deadlock the process. */
1377 fl = fcntl (tc->fd, F_GETFL, 0);
1378 if (0 <= fl)
1379 (void) fcntl (tc->fd, F_SETFL, fl | O_NONBLOCK);
1380 if ( (CLIENT_TLS != cfg.mode) &&
1381 (CLIENT_TLS_ABANDON != cfg.mode) )
1382 return 0;
1383
1384 if (GNUTLS_E_SUCCESS !=
1385 gnutls_certificate_allocate_credentials (&tc->cred))
1386 {
1387 tc->cred = NULL;
1388 tc->dead = 1;
1389 return 0;
1390 }
1391 if (cfg.client_cert)
1392 {
1393 gnutls_datum_t c;
1394 gnutls_datum_t k;
1395
1396 c.data = (unsigned char *) (intptr_t) srv_self_signed_cert_pem;
1397 c.size = (unsigned int) strlen (srv_self_signed_cert_pem);
1398 k.data = (unsigned char *) (intptr_t) srv_self_signed_key_pem;
1399 k.size = (unsigned int) strlen (srv_self_signed_key_pem);
1400 (void) gnutls_certificate_set_x509_key_mem (tc->cred, &c, &k,
1401 GNUTLS_X509_FMT_PEM);
1402 }
1403 flags = GNUTLS_CLIENT;
1404#if GNUTLS_VERSION_MAJOR >= 3
1405 flags |= GNUTLS_NONBLOCK;
1406#endif
1407#if GNUTLS_VERSION_NUMBER >= 0x030402
1408 flags |= GNUTLS_NO_SIGNAL;
1409#endif
1410 if (GNUTLS_E_SUCCESS != gnutls_init (&tc->sess, flags))
1411 {
1412 tc->sess = NULL;
1413 tc->dead = 1;
1414 return 0;
1415 }
1416 if (GNUTLS_E_SUCCESS !=
1417 gnutls_priority_set_direct (tc->sess,
1418 cfg.psk_scenario
1419 ? psk_prio_tbl[cfg.client_prio_idx]
1420 : client_prio_tbl[cfg.client_prio_idx],
1421 NULL))
1422 (void) gnutls_priority_set_direct (tc->sess, "NORMAL", NULL);
1423 if (GNUTLS_E_SUCCESS !=
1424 gnutls_credentials_set (tc->sess, GNUTLS_CRD_CERTIFICATE, tc->cred))
1425 tc->dead = 1;
1426 if (cfg.client_psk)
1427 {
1428 /* The identity is the same string byte 9 (or an op 1 segment) picked
1429 for SNI; it is what arrives as @a username in psk_gnutls_adapter().
1430 A client that offers no PSK credentials at all against a PSK-only
1431 server is the other half of this: the handshake then fails without
1432 the adapter ever being asked. */
1433 gnutls_datum_t k;
1434
1435 k.data = (unsigned char *) (intptr_t) psk_key_bytes;
1436 k.size = (unsigned int) sizeof (psk_key_bytes);
1437 if (GNUTLS_E_SUCCESS !=
1438 gnutls_psk_allocate_client_credentials (&tc->psk))
1439 tc->psk = NULL;
1440 else
1441 {
1442 if (GNUTLS_E_SUCCESS !=
1443 gnutls_psk_set_client_credentials (tc->psk,
1444 sni_name,
1445 &k,
1446 GNUTLS_PSK_KEY_RAW))
1447 tc->dead = 1;
1448 else if (GNUTLS_E_SUCCESS !=
1449 gnutls_credentials_set (tc->sess, GNUTLS_CRD_PSK, tc->psk))
1450 tc->dead = 1;
1451 }
1452 }
1453 if ( (cfg.client_sni) &&
1454 (0 != sni_name_len) )
1455 (void) gnutls_server_name_set (tc->sess,
1456 GNUTLS_NAME_DNS,
1457 sni_name,
1458 sni_name_len);
1459 gnutls_transport_set_int (tc->sess, tc->fd);
1460 /* GNUTLS_INDEFINITE_TIMEOUT: the default handshake timeout is a wall
1461 clock deadline, and this harness must not depend on the clock. */
1462 gnutls_handshake_set_timeout (tc->sess, 0);
1463 return 0;
1464}
1465
1466
1467static void
1468tc_send (struct MHD_Daemon *d,
1469 struct tls_client *tc,
1470 const uint8_t *buf,
1471 size_t len)
1472{
1473 size_t off = 0;
1474 unsigned int stall = 0;
1475
1476 if ( (0 > tc->fd) ||
1477 (0 == len) )
1478 return;
1479 if (NULL == tc->sess)
1480 {
1481 while ( (off < len) &&
1482 (stall < 64) )
1483 {
1484 ssize_t s = send (tc->fd, buf + off, len - off, MSG_DONTWAIT);
1485
1486 if (0 < s)
1487 {
1488 off += (size_t) s;
1489 stall = 0;
1490 continue;
1491 }
1492 stall++;
1493 pump_and_drain (d, tc, 2);
1494 if ( (0 > s) &&
1495 (EAGAIN != errno) &&
1496 (EWOULDBLOCK != errno) &&
1497 (EINTR != errno) )
1498 break;
1499 }
1500 return;
1501 }
1502 if ( (0 != tc->dead) ||
1503 (0 == tc->hs_done) )
1504 return;
1505 while ( (off < len) &&
1506 (stall < 64) )
1507 {
1508 /* On GNUTLS_E_AGAIN the call has to be repeated with exactly the
1509 same arguments, which is why @a off is only advanced on success. */
1510 ssize_t s = gnutls_record_send (tc->sess, buf + off, len - off);
1511
1512 if (0 < s)
1513 {
1514 off += (size_t) s;
1515 stall = 0;
1516 continue;
1517 }
1518 if ( (GNUTLS_E_AGAIN == s) ||
1519 (GNUTLS_E_INTERRUPTED == s) )
1520 {
1521 stall++;
1522 pump_and_drain (d, tc, 2);
1523 continue;
1524 }
1525 if (0 != gnutls_error_is_fatal ((int) s))
1526 tc->dead = 1;
1527 break;
1528 }
1529}
1530
1531
1536static void
1537tc_close (struct MHD_Daemon *d,
1538 struct tls_client *tc)
1539{
1540 if (NULL != tc->sess)
1541 {
1542 if ( (cfg.client_bye) &&
1543 (0 == tc->dead) &&
1544 (0 != tc->hs_done) )
1545 {
1546 unsigned int i;
1547
1548 for (i = 0; i < 8; i++)
1549 {
1550 int ret = gnutls_bye (tc->sess, GNUTLS_SHUT_WR);
1551
1552 if ( (GNUTLS_E_AGAIN != ret) &&
1553 (GNUTLS_E_INTERRUPTED != ret) )
1554 break;
1555 run_once (d);
1556 }
1557 }
1558 gnutls_deinit (tc->sess);
1559 tc->sess = NULL;
1560 }
1561 if (NULL != tc->cred)
1562 {
1563 gnutls_certificate_free_credentials (tc->cred);
1564 tc->cred = NULL;
1565 }
1566 if (NULL != tc->psk)
1567 {
1568 gnutls_psk_free_client_credentials (tc->psk);
1569 tc->psk = NULL;
1570 }
1571 if (0 <= tc->fd)
1572 {
1573 if (cfg.client_shut_wr)
1574 (void) shutdown (tc->fd, SHUT_WR);
1575 pump (d, 2);
1576 (void) close (tc->fd);
1577 tc->fd = -1;
1578 }
1579 tc->hs_done = 0;
1580 tc->dead = 1;
1581 pump (d, 4);
1582}
1583
1584
1595static int
1597{
1598 int sv[2];
1599 struct sockaddr_in sa;
1600
1601 if (0 != socketpair (AF_UNIX, SOCK_STREAM, 0, sv))
1602 return -1;
1603 memset (&sa, 0, sizeof (sa));
1604 sa.sin_family = AF_INET;
1605 sa.sin_port = htons (44444);
1606 sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
1607 if (MHD_YES != MHD_add_connection (d,
1608 (MHD_socket) sv[1],
1609 (const struct sockaddr *) &sa,
1610 (socklen_t) sizeof (sa)))
1611 {
1612 /* MHD has closed sv[1] already. */
1613 (void) close (sv[0]);
1614 return -1;
1615 }
1616 return sv[0];
1617}
1618
1619
1623static void
1624tc_start (struct MHD_Daemon *d,
1625 struct tls_client *tc)
1626{
1627 if (0 != tc_open (d, tc))
1628 {
1629 tc->fd = -1;
1630 return;
1631 }
1632 if (CLIENT_TLS == cfg.mode)
1633 tc_handshake (d, tc, HANDSHAKE_ROUNDS);
1634 else if (CLIENT_TLS_ABANDON == cfg.mode)
1635 tc_handshake (d, tc, cfg.hs_budget);
1636 else
1637 pump (d, 1);
1638}
1639
1640
1641/* ------------------------------------------------------------------ */
1642/* PEM blobs assembled from the input */
1643/* ------------------------------------------------------------------ */
1644
1650static void
1651build_fuzz_pem (char *out,
1652 size_t out_size,
1653 const char *label,
1654 const uint8_t *body,
1655 size_t body_len)
1656{
1657 size_t o = 0;
1658 size_t i;
1659 int n;
1660
1661 n = snprintf (out, out_size, "-----BEGIN %s-----\n", label);
1662 if ( (0 > n) ||
1663 ((size_t) n >= out_size) )
1664 {
1665 out[0] = '\0';
1666 return;
1667 }
1668 o = (size_t) n;
1669 if (body_len > FUZZ_PEM_BODY_MAX)
1670 body_len = FUZZ_PEM_BODY_MAX;
1671 for (i = 0; (i < body_len) && (o + 32 < out_size); i++)
1672 {
1673 /* Keep the blob a C string; a NUL inside would simply truncate it
1674 for MHD's strlen(), which is a less interesting shape. */
1675 out[o++] = (char) ((0 == body[i]) ? 'A' : body[i]);
1676 }
1677 n = snprintf (out + o, out_size - o, "\n-----END %s-----\n", label);
1678 if (0 > n)
1679 out[o] = '\0';
1680}
1681
1682
1683/* ------------------------------------------------------------------ */
1684/* The fuzz target */
1685/* ------------------------------------------------------------------ */
1686
1687int
1688LLVMFuzzerTestOneInput (const uint8_t *data,
1689 size_t size)
1690{
1691 struct MHD_Daemon *d;
1692 struct MHD_OptionItem opts[12];
1693 unsigned int nopt = 0;
1694 unsigned int flags;
1695 struct tls_client tc;
1696 size_t pos;
1697 unsigned int nseg = 0;
1698 unsigned int nconn = 1;
1699 int queued_fd = -1;
1701 /* Must happen before the first write() into the socketpair; see
1702 fuzz_ignore_sigpipe() in fuzz_common.h for why the process dies
1703 without it. Idempotent. */
1705
1706 /* The ten configuration bytes are mandatory. */
1707 if (size < 10)
1708 return 0;
1709
1710 resp_len = 0;
1711 memset (&cfg, 0, sizeof (cfg));
1712
1713 {
1714 const char *nm = sni_name_tbl[(data[9] & 0x07) % SNI_NAME_COUNT];
1715
1716 sni_name_len = strlen (nm);
1717 memcpy (sni_name, nm, sni_name_len + 1);
1718 }
1719
1720 cfg.cert = cred_tbl[data[0] % CRED_COUNT].cert;
1721 cfg.key = cred_tbl[data[0] % CRED_COUNT].key;
1722
1723 cfg.use_trust = (0 != (data[1] & 0x01));
1724 cfg.use_dhparams = (0 != (data[1] & 0x02));
1725 cfg.use_sni = (0 != (data[1] & 0x04));
1726 cfg.use_prio = (0 != (data[1] & 0x08));
1727 cfg.use_cred_type = (0 != (data[1] & 0x10));
1728 cfg.no_alpn = (0 != (data[1] & 0x20));
1729 cfg.key_password = (0 != (data[1] & 0x40));
1730 cfg.prio_append = (0 != (data[1] & 0x80));
1731
1732 cfg.prio_idx = (unsigned int) (data[2] % PRIO_COUNT);
1733
1734 cfg.cred_type_idx = (unsigned int) (data[3] & 0x07) % CRED_TYPE_COUNT;
1735 cfg.sni_mode =
1736 (enum sni_behaviour) (((unsigned int) (data[3] >> 3) & 0x07)
1737 % (unsigned int) SNI_BEHAVIOUR_COUNT);
1738 cfg.trust_garbage = (0 != (data[3] & 0x40));
1739 cfg.dh_garbage = (0 != (data[3] & 0x80));
1740
1741 cfg.prio_str = prio_tbl[cfg.prio_idx];
1742
1743 cfg.mode = (enum client_mode) (data[4] & 0x03);
1744 cfg.client_sni = (0 != (data[4] & 0x04));
1745 cfg.client_cert = (0 != (data[4] & 0x08));
1746 cfg.client_prio_idx = (unsigned int) ((data[4] >> 4) & 0x03);
1747 cfg.client_bye = (0 != (data[4] & 0x40));
1748 cfg.client_shut_wr = (0 != (data[4] & 0x80));
1749
1750 cfg.mem_limit = mem_limit_tbl[(data[5] & 0x0F) % MEM_LIMIT_COUNT];
1751 cfg.loop_mode = (unsigned int) ((data[5] >> 4) & 0x03);
1752 cfg.stop_with_queued = (0 != (data[5] & 0x40));
1753
1754 cfg.resp_kind = (unsigned int) (data[6] & 0x03);
1755 cfg.conn_info = (0 != (data[6] & 0x04));
1756 cfg.daemon_info = (0 != (data[6] & 0x08));
1757 cfg.conn_option = (0 != (data[6] & 0x10));
1758 cfg.error_reply = (0 != (data[6] & 0x20));
1759 cfg.resp_header = (0 != (data[6] & 0x40));
1760 cfg.quiesce = (0 != (data[6] & 0x80));
1761
1762 cfg.hs_budget = 1u + (unsigned int) (data[7] & 0x07);
1763 cfg.use_tls = (0 == (data[7] & 0x08));
1764 cfg.allow_upgrade =
1765 (0 != (data[7] & 0x10)) &&
1767 cfg.extra_pump = (unsigned int) ((data[7] >> 5) & 0x07);
1768
1769 cfg.psk_mode =
1770 (enum psk_behaviour) (((unsigned int) (data[9] >> 3) & 0x07)
1771 % (unsigned int) PSK_BEHAVIOUR_COUNT);
1772 cfg.client_psk = (0 != (data[9] & 0x40));
1773#if GNUTLS_VERSION_MAJOR >= 3
1774 cfg.psk_scenario = (0 != (data[9] & 0x80));
1775#else
1776 /* MHD refuses MHD_OPTION_GNUTLS_PSK_CRED_HANDLER outright when it was
1777 built against GnuTLS 2, so there is nothing to reach there. */
1778 cfg.psk_scenario = 0;
1779#endif
1780
1781 /* The PSK bundle. Four things have to line up before GnuTLS asks the
1782 server for a key at all; see the TLS-PSK note at the top of this
1783 file for why they are not four independent input bits. */
1784 if (cfg.psk_scenario)
1785 {
1786 cfg.use_tls = 1;
1787 cfg.use_cred_type = 1;
1788 cfg.cred_type_idx = PSK_CRED_TYPE_IDX;
1789 cfg.use_prio = 1;
1790 cfg.prio_append = 0;
1791 cfg.prio_str = psk_prio_tbl[cfg.client_prio_idx];
1792 /* Raw bytes never negotiate anything; the abandoning client is kept
1793 because stopping half way through a PSK handshake is its own
1794 shape. */
1795 if ( (CLIENT_TLS != cfg.mode) &&
1796 (CLIENT_TLS_ABANDON != cfg.mode) )
1797 cfg.mode = CLIENT_TLS;
1798 }
1799 else
1800 cfg.client_psk = 0;
1801
1802 /* A real handshake is pointless without a working credential setup on
1803 our own side; fall back to the raw modes if the SNI certificates
1804 could not be parsed. */
1805 if ( (cfg.use_sni) &&
1806 (0 != sni_hosts_init ()) )
1807 cfg.use_sni = 0;
1808
1809 /* The PEM blobs built from the input. They are only referenced by
1810 cred_tbl entries 12-14, but filling them unconditionally keeps this
1811 out of the option assembly below. */
1812 {
1813 size_t body = (size_t) data[8] * 4u;
1814
1815 if (body > size - 10)
1816 body = size - 10;
1817 build_fuzz_pem (fuzz_cert_pem, sizeof (fuzz_cert_pem),
1818 "CERTIFICATE", data + 10, body);
1819 build_fuzz_pem (fuzz_key_pem, sizeof (fuzz_key_pem),
1820 "PRIVATE KEY", data + 10, body);
1821 }
1822
1823 if (0 != cfg.mem_limit)
1824 {
1825 opts[nopt].option = MHD_OPTION_CONNECTION_MEMORY_LIMIT;
1826 opts[nopt].value = (intptr_t) cfg.mem_limit;
1827 opts[nopt].ptr_value = NULL;
1828 nopt++;
1829 }
1830 if (NULL != cfg.key)
1831 {
1832 opts[nopt].option = MHD_OPTION_HTTPS_MEM_KEY;
1833 opts[nopt].value = 0;
1834 opts[nopt].ptr_value = (void *) (intptr_t) cfg.key;
1835 nopt++;
1836 }
1837 if (NULL != cfg.cert)
1838 {
1839 opts[nopt].option = MHD_OPTION_HTTPS_MEM_CERT;
1840 opts[nopt].value = 0;
1841 opts[nopt].ptr_value = (void *) (intptr_t) cfg.cert;
1842 nopt++;
1843 }
1844 if (cfg.key_password)
1845 {
1846 opts[nopt].option = MHD_OPTION_HTTPS_KEY_PASSWORD;
1847 opts[nopt].value = 0;
1848 opts[nopt].ptr_value = (void *) (intptr_t) https_key_password;
1849 nopt++;
1850 }
1851 if (cfg.use_trust)
1852 {
1853 opts[nopt].option = MHD_OPTION_HTTPS_MEM_TRUST;
1854 opts[nopt].value = 0;
1855 opts[nopt].ptr_value = (void *) (intptr_t)
1856 (cfg.trust_garbage ? garbage_cert_pem
1857 : ca_cert_pem);
1858 nopt++;
1859 }
1860 if (cfg.use_dhparams)
1861 {
1862 opts[nopt].option = MHD_OPTION_HTTPS_MEM_DHPARAMS;
1863 opts[nopt].value = 0;
1864 opts[nopt].ptr_value = (void *) (intptr_t)
1865 (cfg.dh_garbage ? garbage_dh_pem : dh_params_pem);
1866 nopt++;
1867 }
1868 if (cfg.use_prio)
1869 {
1870 opts[nopt].option = cfg.prio_append
1873 opts[nopt].value = 0;
1874 opts[nopt].ptr_value = (void *) (intptr_t) cfg.prio_str;
1875 nopt++;
1876 }
1877 if (cfg.use_cred_type)
1878 {
1879 opts[nopt].option = MHD_OPTION_HTTPS_CRED_TYPE;
1880 opts[nopt].value = (intptr_t) cred_type_tbl[cfg.cred_type_idx];
1881 opts[nopt].ptr_value = NULL;
1882 nopt++;
1883 }
1884 if (cfg.no_alpn)
1885 {
1886 opts[nopt].option = MHD_OPTION_TLS_NO_ALPN;
1887 opts[nopt].value = 1;
1888 opts[nopt].ptr_value = NULL;
1889 nopt++;
1890 }
1891 opts[nopt].option = MHD_OPTION_END;
1892 opts[nopt].value = 0;
1893 opts[nopt].ptr_value = NULL;
1894
1896 if (cfg.use_tls)
1897 flags |= MHD_USE_TLS;
1898 if (fuzz_verbose)
1899 flags |= MHD_USE_ERROR_LOG;
1900 if (cfg.allow_upgrade)
1901 flags |= MHD_ALLOW_UPGRADE;
1902
1904 /* The callback options go through the varargs rather than through the
1905 option array: the array's ptr_value is a void *, and a function
1906 pointer does not portably fit in one. A NULL callback is exactly
1907 equivalent to not passing the option -- which is what makes
1908 PSK_NO_HANDLER (the "PSK not supported by this server" arm of
1909 psk_gnutls_adapter()) reachable without a second call site.
1910
1911 MHD_OPTION_GNUTLS_PSK_CRED_HANDLER is the exception: an MHD built
1912 against GnuTLS 2 rejects it whatever the callback is, and rejecting
1913 an option fails the whole MHD_start_daemon(), so on such a build the
1914 option must not be passed at all. */
1915#if GNUTLS_VERSION_MAJOR >= 3
1916 d = MHD_start_daemon (flags,
1917 0,
1918 NULL, NULL,
1919 &ahc, NULL,
1920 MHD_OPTION_ARRAY, opts,
1922 cfg.use_sni ? &sni_callback : NULL,
1924 (cfg.psk_scenario &&
1925 (PSK_NO_HANDLER != cfg.psk_mode))
1926 ? &psk_cred_cb : NULL,
1927 NULL,
1929#else
1930 d = MHD_start_daemon (flags,
1931 0,
1932 NULL, NULL,
1933 &ahc, NULL,
1934 MHD_OPTION_ARRAY, opts,
1936 cfg.use_sni ? &sni_callback : NULL,
1938#endif
1939 if (NULL == d)
1940 {
1942 return 0;
1943 }
1944 stat_daemons++;
1945 if (! stats_registered)
1946 {
1947 stats_registered = 1;
1948 (void) atexit (&print_stats);
1949 }
1950 if (cfg.daemon_info)
1951 {
1956 }
1957
1958 /* The connection is opened lazily, when the first segment that carries
1959 wire data is reached, so that a leading op 1 segment can still
1960 override the server name byte 9 selected. */
1961 tc.sess = NULL;
1962 tc.cred = NULL;
1963 tc.psk = NULL;
1964 tc.fd = -1;
1965 tc.hs_done = 0;
1966 tc.dead = 1;
1967
1968 pos = 10u;
1969 while ( (pos + 2 <= size) &&
1970 (nseg < MAX_SEGMENTS) )
1971 {
1972 unsigned int hdr = (unsigned int) data[pos]
1973 | ((unsigned int) data[pos + 1] << 8);
1974 unsigned int op = hdr >> 14;
1975 size_t slen = (size_t) (hdr & 0x3FFF);
1976
1977 pos += 2;
1978 nseg++;
1979 if (slen > size - pos)
1980 slen = size - pos;
1981
1982 if (1 == op)
1983 {
1984 /* Server name declaration for the next connection, not wire data. */
1985 size_t n = slen;
1986
1987 if (n > MAX_SNI_LEN)
1988 n = MAX_SNI_LEN;
1989 memcpy (sni_name, data + pos, n);
1990 /* GnuTLS wants a plain host name, and an embedded NUL would only
1991 shorten it behind our back. */
1992 while ( (0 != n) &&
1993 ('\0' == sni_name[n - 1]) )
1994 n--;
1995 sni_name[n] = '\0';
1996 sni_name_len = n;
1997 pos += slen;
1998 continue;
1999 }
2000 if (0 > tc.fd)
2001 {
2002 tc_start (d, &tc);
2003 if (0 > tc.fd)
2004 break;
2005 }
2006 else if ( (3 == op) &&
2007 (nconn < MAX_CONNECTIONS) )
2008 {
2009 tc_close (d, &tc);
2010 tc_start (d, &tc);
2011 nconn++;
2012 if (0 > tc.fd)
2013 break;
2014 }
2015 if (0 != slen)
2016 tc_send (d, &tc, data + pos, slen);
2017 pos += slen;
2018 pump_and_drain (d, &tc, (2 == op) ? (6u + cfg.extra_pump) : 3u);
2019 }
2020 if (0 > tc.fd)
2021 tc_start (d, &tc);
2022 pump_and_drain (d, &tc, 2u + cfg.extra_pump);
2023 tc_close (d, &tc);
2024
2025 if (cfg.quiesce)
2026 (void) MHD_quiesce_daemon (d);
2027 /* Last, so that no run can drain the list again. MHD_add_connection()
2028 on a thread-safe daemon (the default) only queues the socket, but
2029 new_connection_prepare_() has already built the GnuTLS session for
2030 it; stopping before the next run is what makes MHD free that session
2031 from new_connection_close_() rather than from the ordinary
2032 connection teardown. fuzz_eventloop covers the same shape without
2033 TLS -- see its byte 3 bit 4. */
2034 if (cfg.stop_with_queued)
2035 queued_fd = queue_unprocessed_conn (d);
2036 MHD_stop_daemon (d);
2037 if (0 <= queued_fd)
2038 (void) close (queued_fd);
2039 return 0;
2040}
2041
2042
2043/* ------------------------------------------------------------------ */
2044/* Structure-aware generator */
2045/* ------------------------------------------------------------------ */
2046
2047struct sbuf
2048{
2049 uint8_t *p;
2050 size_t len;
2051 size_t cap;
2052};
2053
2054
2055static void
2056sb_raw (struct sbuf *b,
2057 const void *v,
2058 size_t n)
2059{
2060 if (b->len + n > b->cap)
2061 n = b->cap - b->len;
2062 memcpy (b->p + b->len, v, n);
2063 b->len += n;
2064}
2065
2066
2067static void
2068sb_str (struct sbuf *b,
2069 const char *s)
2070{
2071 sb_raw (b, s, strlen (s));
2072}
2073
2074
2075static void
2076sb_u32 (struct sbuf *b,
2077 uint32_t v)
2078{
2079 char tmp[16];
2080 unsigned int n = 0;
2081
2082 do
2083 {
2084 tmp[n++] = (char) ('0' + (v % 10u));
2085 v /= 10u;
2086 }
2087 while ( (0 != v) &&
2088 (n < sizeof (tmp)) );
2089 while (0 != n)
2090 {
2091 char c = tmp[--n];
2092
2093 sb_raw (b, &c, 1);
2094 }
2095}
2096
2097
2098enum gen_shape
2099{
2100 SHAPE_TLS_HTTP = 0,
2101 SHAPE_RAW_BYTES,
2102 SHAPE_ABANDON,
2103 SHAPE_BAD_CREDS,
2104 SHAPE_BAD_OPTIONS,
2105 SHAPE_SNI,
2106 SHAPE_PEM_FUZZ,
2107 SHAPE_RECORDS,
2108 SHAPE_PSK,
2110};
2111
2112static int forced_shape = -1;
2113static int forced_shape_read;
2114
2115static const char *const gen_methods[] = {
2116 "GET", "POST", "HEAD", "PUT", "OPTIONS", "BREW"
2117};
2118
2119static const char *const gen_targets[] = {
2120 "/", "/a", "/index.html", "/a?b=c", "/%41%42", "*", "//"
2121};
2122
2123static const char *const gen_versions[] = {
2124 "HTTP/1.1", "HTTP/1.0", "HTTP/1.2", "HTTP/9.9"
2125};
2126
2127static const char *const gen_hdr_names[] = {
2128 "Host", "User-Agent", "Accept", "Connection", "X-Fuzz", "Cookie",
2129 "Content-Type", "Expect"
2130};
2131
2132static const char *const gen_hdr_values[] = {
2133 "x", "localhost", "*/*", "keep-alive", "close", "100-continue",
2134 "text/plain", "a=b"
2135};
2136
2137
2142static void
2143gen_http_request (struct fuzz_rng *rng,
2144 struct sbuf *b)
2145{
2146 unsigned int nh;
2147 unsigned int i;
2148 int with_body;
2149
2150 sb_str (b, gen_methods[fuzz_below (rng, (uint32_t)
2151 (sizeof (gen_methods)
2152 / sizeof (gen_methods[0])))]);
2153 sb_str (b, " ");
2154 sb_str (b, gen_targets[fuzz_below (rng, (uint32_t)
2155 (sizeof (gen_targets)
2156 / sizeof (gen_targets[0])))]);
2157 sb_str (b, " ");
2158 sb_str (b, gen_versions[fuzz_below (rng, (uint32_t)
2159 (sizeof (gen_versions)
2160 / sizeof (gen_versions[0])))]);
2161 sb_str (b, "\r\n");
2162 with_body = fuzz_chance (rng, 3);
2163 nh = fuzz_below (rng, 4);
2164 for (i = 0; i < nh; i++)
2165 {
2166 sb_str (b, gen_hdr_names[fuzz_below (rng, (uint32_t)
2167 (sizeof (gen_hdr_names)
2168 / sizeof (gen_hdr_names[0])))]);
2169 sb_str (b, ": ");
2170 sb_str (b, gen_hdr_values[fuzz_below (rng, (uint32_t)
2171 (sizeof (gen_hdr_values)
2172 / sizeof (gen_hdr_values[0])))]);
2173 sb_str (b, "\r\n");
2174 }
2175 if (with_body)
2176 {
2177 unsigned int blen = fuzz_below (rng, 64);
2178
2179 sb_str (b, "Content-Length: ");
2180 sb_u32 (b, blen);
2181 sb_str (b, "\r\n\r\n");
2182 for (i = 0; i < blen; i++)
2183 {
2184 char c = (char) ('a' + (int) fuzz_below (rng, 26));
2185
2186 sb_raw (b, &c, 1);
2187 }
2188 return;
2189 }
2190 sb_str (b, "\r\n");
2191}
2192
2193
2200static void
2201gen_tls_records (struct fuzz_rng *rng,
2202 struct sbuf *b)
2203{
2204 unsigned int n = 1 + fuzz_below (rng, 4);
2205 unsigned int i;
2206 unsigned int j;
2207
2208 for (i = 0; i < n; i++)
2209 {
2210 uint8_t hdr[5];
2211 unsigned int plen = fuzz_below (rng, 96);
2212 unsigned int declared = fuzz_chance (rng, 3)
2213 ? fuzz_below (rng, 0x4000)
2214 : plen;
2215
2216 hdr[0] = fuzz_chance (rng, 4)
2217 ? fuzz_byte (rng)
2218 : (uint8_t) (20 + fuzz_below (rng, 4));
2219 hdr[1] = 0x03;
2220 hdr[2] = (uint8_t) fuzz_below (rng, 5);
2221 hdr[3] = (uint8_t) ((declared >> 8) & 0xFF);
2222 hdr[4] = (uint8_t) (declared & 0xFF);
2223 sb_raw (b, hdr, sizeof (hdr));
2224 for (j = 0; j < plen; j++)
2225 {
2226 uint8_t v = fuzz_byte (rng);
2227
2228 sb_raw (b, &v, 1);
2229 }
2230 }
2231}
2232
2233
2239#define PRIO_VALID_COUNT 7
2240
2241
2248static void
2249make_daemon_startable (struct fuzz_rng *rng,
2250 uint8_t *cfg_bytes)
2251{
2252 cfg_bytes[1] &= (uint8_t) ~0x10u; /* no credential type override */
2253 cfg_bytes[3] &= (uint8_t) ~0xC0u; /* valid trust store, valid DH */
2254 if (0 != (cfg_bytes[1] & 0x08u))
2255 cfg_bytes[2] = (uint8_t) fuzz_below (rng, PRIO_VALID_COUNT);
2256 cfg_bytes[7] &= (uint8_t) ~0x08u; /* keep MHD_USE_TLS */
2257}
2258
2259
2263static void
2264emit_segment (struct sbuf *out,
2265 unsigned int op,
2266 const uint8_t *payload,
2267 size_t len)
2268{
2269 unsigned int hv;
2270 uint8_t hdr[2];
2271
2272 if (len > 0x3FFF)
2273 len = 0x3FFF;
2274 hv = (op << 14) | (unsigned int) len;
2275 hdr[0] = (uint8_t) (hv & 0xFF);
2276 hdr[1] = (uint8_t) (hv >> 8);
2277 sb_raw (out, hdr, 2);
2278 sb_raw (out, payload, len);
2279}
2280
2281
2282static size_t
2283fuzz_generate (struct fuzz_rng *rng,
2284 uint8_t *buf,
2285 size_t cap)
2286{
2287 struct sbuf out;
2288 struct sbuf rb;
2289 uint8_t req[GEN_BUF_SIZE];
2290 uint8_t cfg_bytes[10];
2291 enum gen_shape shape;
2292 unsigned int nreq;
2293 unsigned int i;
2294
2295 out.p = buf;
2296 out.len = 0;
2297 out.cap = cap;
2298
2299 if (! forced_shape_read)
2300 {
2301 const char *e = getenv ("MHD_FUZZ_SHAPE");
2302
2304 if (NULL != e)
2305 forced_shape = atoi (e);
2306 }
2307 if (0 <= forced_shape)
2308 shape = (enum gen_shape) (forced_shape % (int) SHAPE_COUNT);
2309 else
2310 shape = (enum gen_shape) fuzz_below (rng, (uint32_t) SHAPE_COUNT);
2311
2312 for (i = 0; i < sizeof (cfg_bytes); i++)
2313 cfg_bytes[i] = fuzz_byte (rng);
2314
2315 /* Byte 0 picks the credentials, byte 4 (bits 0-1) the client, and byte
2316 1 which options are passed at all; every shape below narrows exactly
2317 those and leaves the rest of the configuration space random. */
2318 cfg_bytes[7] &= (uint8_t) ~0x08u; /* keep MHD_USE_TLS by default */
2319 switch (shape)
2320 {
2321 case SHAPE_TLS_HTTP:
2322 cfg_bytes[0] = (uint8_t) (fuzz_chance (rng, 2) ? 0 : 1);
2323 cfg_bytes[4] = (uint8_t) ((cfg_bytes[4] & ~0x03u) | CLIENT_TLS);
2324 cfg_bytes[1] &= (uint8_t) ~0x04u; /* no SNI callback */
2325 make_daemon_startable (rng, cfg_bytes);
2326 break;
2327 case SHAPE_RAW_BYTES:
2328 cfg_bytes[0] = 0;
2329 cfg_bytes[4] = (uint8_t) ((cfg_bytes[4] & ~0x03u) | CLIENT_RAW);
2330 make_daemon_startable (rng, cfg_bytes);
2331 break;
2332 case SHAPE_ABANDON:
2333 cfg_bytes[0] = (uint8_t) (fuzz_chance (rng, 2) ? 0 : 1);
2334 cfg_bytes[4] = (uint8_t) ((cfg_bytes[4] & ~0x03u) | CLIENT_TLS_ABANDON);
2335 cfg_bytes[7] = (uint8_t) ((cfg_bytes[7] & ~0x07u)
2336 + fuzz_below (rng, 6));
2337 make_daemon_startable (rng, cfg_bytes);
2338 break;
2339 case SHAPE_BAD_CREDS:
2340 /* entries 2-11 of cred_tbl are the broken ones */
2341 cfg_bytes[0] = (uint8_t) (2 + fuzz_below (rng, 10));
2342 cfg_bytes[4] = (uint8_t) ((cfg_bytes[4] & ~0x03u)
2343 | (fuzz_chance (rng, 2) ? CLIENT_TLS
2344 : CLIENT_RAW));
2345 break;
2346 case SHAPE_BAD_OPTIONS:
2347 cfg_bytes[1] |= 0x18u; /* priorities + credential type */
2348 cfg_bytes[2] = (uint8_t) fuzz_below (rng, (uint32_t) PRIO_COUNT);
2349 cfg_bytes[3] = fuzz_byte (rng);
2350 if (fuzz_chance (rng, 4))
2351 cfg_bytes[7] |= 0x08u; /* HTTPS options, but no MHD_USE_TLS */
2352 cfg_bytes[4] = (uint8_t) ((cfg_bytes[4] & ~0x03u)
2353 | (fuzz_chance (rng, 2) ? CLIENT_TLS
2354 : CLIENT_RAW));
2355 break;
2356 case SHAPE_SNI:
2357 cfg_bytes[0] = (uint8_t) (fuzz_chance (rng, 3) ? 6 : 0);
2358 cfg_bytes[3] = (uint8_t)
2359 ((cfg_bytes[3] & ~0x38u)
2360 | (fuzz_below (rng, (uint32_t) SNI_BEHAVIOUR_COUNT) << 3));
2361 cfg_bytes[4] = (uint8_t) ((cfg_bytes[4] & ~0x03u) | CLIENT_TLS | 0x04u);
2362 cfg_bytes[9] = (uint8_t) fuzz_below (rng, (uint32_t) SNI_NAME_COUNT);
2363 make_daemon_startable (rng, cfg_bytes);
2364 cfg_bytes[1] |= 0x04u; /* the certificate callback */
2365 break;
2366 case SHAPE_PEM_FUZZ:
2367 cfg_bytes[0] = (uint8_t) (12 + fuzz_below (rng, 3));
2368 cfg_bytes[8] = (uint8_t) (1 + fuzz_below (rng, 64));
2369 cfg_bytes[4] = (uint8_t) ((cfg_bytes[4] & ~0x03u)
2370 | (fuzz_chance (rng, 2) ? CLIENT_TLS
2371 : CLIENT_RAW));
2372 break;
2373 case SHAPE_RECORDS:
2374 cfg_bytes[0] = 0;
2375 cfg_bytes[4] = (uint8_t) ((cfg_bytes[4] & ~0x03u) | CLIENT_RECORDS);
2376 make_daemon_startable (rng, cfg_bytes);
2377 break;
2378 case SHAPE_PSK:
2379 /* The certificate is irrelevant to a PSK handshake but still has to
2380 let the daemon start, so keep the valid pair. */
2381 cfg_bytes[0] = 0;
2382 cfg_bytes[4] = (uint8_t) ((cfg_bytes[4] & ~0x03u)
2383 | (fuzz_chance (rng, 5) ? CLIENT_TLS_ABANDON
2384 : CLIENT_TLS));
2385 cfg_bytes[1] &= (uint8_t) ~0x04u; /* no SNI callback */
2386 make_daemon_startable (rng, cfg_bytes);
2387 cfg_bytes[9] = (uint8_t)
2388 (0x80u /* the scenario itself */
2389 | (fuzz_chance (rng, 6) ? 0u : 0x40u) /* client PSK */
2390 | (uint8_t) (fuzz_below (rng,
2391 (uint32_t) PSK_BEHAVIOUR_COUNT)
2392 << 3)
2393 | (uint8_t) fuzz_below (rng, (uint32_t) SNI_NAME_COUNT));
2394 break;
2395 case SHAPE_COUNT:
2396 default:
2397 break;
2398 }
2399 /* Byte 9 already carries a server name; now and then hand the same
2400 one over as an op 1 segment instead, so that the segment form is
2401 exercised too. Generated inputs are never written to corpus/, so
2402 unlike the seeds they may use op 1 (see the note at the top). */
2403 sb_raw (&out, cfg_bytes, sizeof (cfg_bytes));
2404 if (fuzz_chance (rng, 4))
2405 {
2406 const char *nm = sni_name_tbl[cfg_bytes[9] & 0x07];
2407
2408 emit_segment (&out, 1u, (const uint8_t *) nm, strlen (nm));
2409 }
2410
2411 nreq = 1u + (fuzz_chance (rng, 4) ? 1u : 0u);
2412 for (i = 0; i < nreq; i++)
2413 {
2414 unsigned int op;
2415
2416 rb.p = req;
2417 rb.len = 0;
2418 rb.cap = sizeof (req);
2419 switch (shape)
2420 {
2421 case SHAPE_RECORDS:
2422 gen_tls_records (rng, &rb);
2423 break;
2424 case SHAPE_RAW_BYTES:
2425 {
2426 unsigned int n = 1 + fuzz_below (rng, 256);
2427 unsigned int j;
2428
2429 for (j = 0; j < n; j++)
2430 {
2431 uint8_t v = fuzz_byte (rng);
2432
2433 sb_raw (&rb, &v, 1);
2434 }
2435 break;
2436 }
2437 default:
2438 gen_http_request (rng, &rb);
2439 break;
2440 }
2441 if (0 != i)
2442 op = 3u; /* a fresh connection */
2443 else
2444 op = fuzz_chance (rng, 3) ? 2u : 0u;
2445 /* Split the payload now and then: MHD's parser is incremental and
2446 the TLS record boundaries move with the split. */
2447 if ( (rb.len > 8) &&
2448 fuzz_chance (rng, 3) )
2449 {
2450 size_t cut = 1 + fuzz_below (rng, (uint32_t) (rb.len - 1));
2451
2452 emit_segment (&out, op, req, cut);
2453 emit_segment (&out, 2u, req + cut, rb.len - cut);
2454 }
2455 else
2456 {
2457 emit_segment (&out, op, req, rb.len);
2458 }
2459 }
2460 return out.len;
2461}
2462
2463
2464/* ------------------------------------------------------------------ */
2465/* Built-in seed corpus */
2466/* ------------------------------------------------------------------ */
2467
2468struct seed_part
2469{
2470 unsigned int op;
2471 const char *txt;
2472};
2473
2474struct seed_def
2475{
2476 const char *name;
2477 unsigned char cfg[10];
2478 struct seed_part parts[4];
2479};
2480
2481#define P_END { 0, NULL }
2482
2483/* The configuration bytes are written out in full so that a seed can be
2484 read without decoding: see the input format at the top of this file. */
2485static const struct seed_def seeds[] = {
2486 /* A complete TLS 1.3 handshake followed by an ordinary request: the
2487 only shape that reaches the handshake -> HTTP parser transition. */
2488 { "tls-handshake-get",
2489 { 0, 0x00, 0, 0, 0x41, 0x00, 0x04, 0x00, 0, 0 },
2490 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2491
2492 /* The same, but the request arrives in two TLS records. */
2493 { "tls-handshake-split",
2494 { 0, 0x00, 0, 0, 0x41, 0x00, 0x04, 0x00, 0, 0 },
2495 { { 0, "GET / HTTP/1.1\r\nHo" },
2496 { 2, "st: x\r\n\r\n" }, P_END, P_END } },
2497
2498 /* Keep-alive over TLS: two requests on one session, then gnutls_bye(). */
2499 { "tls-keepalive",
2500 { 0, 0x00, 0, 0, 0x41, 0x00, 0x00, 0x00, 0, 0 },
2501 { { 0, "GET /a HTTP/1.1\r\nHost: x\r\n\r\n" },
2502 { 2, "GET /b HTTP/1.1\r\nHost: x\r\nConnection: close\r\n\r\n" },
2503 P_END, P_END } },
2504
2505 /* A second connection, i.e. a second handshake on the same daemon. */
2506 { "tls-second-connection",
2507 { 0, 0x00, 0, 0, 0x41, 0x00, 0x00, 0x00, 0, 0 },
2508 { { 0, "GET /a HTTP/1.1\r\nHost: x\r\n\r\n" },
2509 { 3, "GET /b HTTP/1.1\r\nHost: x\r\n\r\n" },
2510 P_END, P_END } },
2511
2512 /* Plain HTTP at a TLS port: the record layer sees "GET ..." and the
2513 handshake fails, which is MHD_run_tls_handshake_()'s error arm. */
2514 { "plain-http-at-tls-port",
2515 { 0, 0x00, 0, 0, 0x00, 0x00, 0x00, 0x00, 0, 0 },
2516 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2517
2518 /* Nothing at all, then EOF: the connection dies in MHD_TLS_CONN_INIT. */
2519 { "eof-in-init",
2520 { 0, 0x00, 0, 0, 0x80, 0x00, 0x00, 0x00, 0, 0 },
2521 { { 0, "" }, P_END, P_END, P_END } },
2522
2523 /* A real client that walks away after a single handshake round: MHD is
2524 left in MHD_TLS_CONN_HANDSHAKING when the socket closes. */
2525 { "abandon-handshake",
2526 { 0, 0x00, 0, 0, 0x02, 0x00, 0x00, 0x00, 0, 0 },
2527 { { 0, "" }, P_END, P_END, P_END } },
2528
2529 /* Certificate and key do not belong together. */
2530 { "mismatched-key",
2531 { 2, 0x00, 0, 0, 0x01, 0x00, 0x00, 0x00, 0, 0 },
2532 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2533
2534 /* No certificate at all: MHD_start_daemon() has to fail cleanly. */
2535 { "no-certificate",
2536 { 6, 0x00, 0, 0, 0x01, 0x00, 0x00, 0x00, 0, 0 },
2537 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2538
2539 /* PEM armour with a payload that is not base64. */
2540 { "garbage-pem",
2541 { 10, 0x00, 0, 0, 0x01, 0x00, 0x00, 0x00, 0, 0 },
2542 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2543
2544 /* A priority string GnuTLS rejects (index 9 of prio_tbl). */
2545 { "bogus-priorities",
2546 { 0, 0x08, 9, 0, 0x01, 0x00, 0x00, 0x00, 0, 0 },
2547 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2548
2549 /* The same string through MHD_OPTION_HTTPS_PRIORITIES_APPEND. */
2550 { "bogus-priorities-append",
2551 { 0, 0x88, 10, 0, 0x01, 0x00, 0x00, 0x00, 0, 0 },
2552 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2553
2554 /* TLS 1.2 only on both ends, with the trust store and a client
2555 certificate request. */
2556 { "tls12-with-trust",
2557 { 0, 0x01, 2, 0, 0x29, 0x00, 0x04, 0x00, 0, 0 },
2558 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2559
2560 /* Valid Diffie-Hellman parameters (RFC 3526 group 14). */
2561 { "valid-dhparams",
2562 { 0, 0x02, 0, 0, 0x21, 0x00, 0x00, 0x00, 0, 0 },
2563 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2564
2565 /* Malformed Diffie-Hellman parameters: MHD_start_daemon() must fail. */
2566 { "garbage-dhparams",
2567 { 0, 0x02, 0, 0x80, 0x01, 0x00, 0x00, 0x00, 0, 0 },
2568 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2569
2570 /* A credential type MHD does not support (GNUTLS_CRD_ANON). */
2571 { "cred-type-anon",
2572 { 0, 0x10, 0, 0x02, 0x01, 0x00, 0x00, 0x00, 0, 0 },
2573 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2574
2575 /* GNUTLS_CRD_PSK without a PSK callback: the daemon starts, the
2576 handshake cannot. */
2577 { "cred-type-psk",
2578 { 0, 0x10, 0, 0x01, 0x01, 0x00, 0x00, 0x00, 0, 0 },
2579 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2580
2581 /* The TLS-PSK scenario (byte 9 bit 7), one seed per branch of
2582 psk_gnutls_adapter(). Byte 9 is
2583 0x80 scenario | 0x40 client offers PSK | behaviour << 3 | identity.
2584 Byte 4 bits 4-5 pick the PSK priority string, which is what decides
2585 the protocol version the PSK key exchange runs under. */
2586
2587 /* The whole path end to end: identity accepted, key matches, handshake
2588 completes, and MHD then serves plain HTTP over a session that has no
2589 certificate at all (byte 6 bit 2 reads the TLS members back). */
2590 { "psk-handshake",
2591 { 0, 0x00, 0, 0, 0x11, 0x00, 0x04, 0x00, 0, 0xC0 },
2592 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2593
2594 /* The same over TLS 1.3, where GnuTLS treats the key as an external
2595 PSK and the exchange has a different shape. */
2596 { "psk-handshake-tls13",
2597 { 0, 0x00, 0, 0, 0x21, 0x00, 0x00, 0x00, 0, 0xC0 },
2598 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2599
2600 /* The application refuses the identity: the adapter's -1 arm. */
2601 { "psk-callback-fails",
2602 { 0, 0x00, 0, 0, 0x11, 0x00, 0x00, 0x00, 0, 0xC8 },
2603 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2604
2605 /* Zero length key: the "PSK too short" arm, and the reason MHD never
2606 reaches gnutls_malloc(0). */
2607 { "psk-empty-key",
2608 { 0, 0x00, 0, 0, 0x11, 0x00, 0x00, 0x00, 0, 0xD0 },
2609 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2610
2611 /* One byte below the minimum -- the other side of the boundary that
2612 psk-handshake (exactly the minimum) sits on. */
2613 { "psk-one-byte-short",
2614 { 0, 0x00, 0, 0, 0x11, 0x00, 0x00, 0x00, 0, 0xF8 },
2615 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2616
2617 /* 4 KiB key: the copy into the gnutls_malloc()ed buffer, at a size no
2618 ciphersuite expects. */
2619 { "psk-long-key",
2620 { 0, 0x00, 0, 0, 0x11, 0x00, 0x00, 0x00, 0, 0xD8 },
2621 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2622
2623 /* Key length taken from the identity, with the longest identity in the
2624 table (sni_name_tbl entry 7, 62 characters): the callback then hands
2625 back a 62 byte key, which no PSK ciphersuite expects. */
2626 { "psk-key-from-identity",
2627 { 0, 0x00, 0, 0, 0x11, 0x00, 0x00, 0x00, 0, 0xE7 },
2628 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2629
2630 /* A key size above UINT_MAX: the "PSK too long" arm, which has to
2631 free the application's buffer and fail. */
2632 { "psk-oversized-key",
2633 { 0, 0x00, 0, 0, 0x11, 0x00, 0x00, 0x00, 0, 0xE8 },
2634 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2635
2636 /* PSK credential type, PSK ciphersuite, but no credentials callback:
2637 the "PSK not supported by this server" arm. */
2638 { "psk-no-handler",
2639 { 0, 0x00, 0, 0, 0x11, 0x00, 0x00, 0x00, 0, 0xF0 },
2640 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2641
2642 /* A PSK-only server against a client that offers no PSK identity: the
2643 handshake fails before the adapter is ever asked. */
2644 { "psk-client-no-creds",
2645 { 0, 0x00, 0, 0, 0x11, 0x00, 0x00, 0x00, 0, 0x80 },
2646 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2647
2648 /* Byte 5 bit 6: stop the daemon with a connection queued but never
2649 started, so that its GnuTLS session is freed by
2650 new_connection_close_() instead of by the ordinary teardown. */
2651 { "stop-with-queued-connection",
2652 { 0, 0x00, 0, 0, 0x01, 0x40, 0x00, 0x00, 0, 0 },
2653 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2654
2655 /* The SNI callback, answering for the presented name (byte 9 = 0,
2656 "test-mhdserver"). No op 1 segment here or below: see the note on
2657 the shared corpus at the top of this file. */
2658 { "sni-by-name",
2659 { 6, 0x04, 0, 0x18, 0x05, 0x00, 0x04, 0x00, 0, 0 },
2660 { { 0, "GET / HTTP/1.1\r\nHost: test-mhdserver\r\n\r\n" },
2661 P_END, P_END, P_END } },
2662
2663 /* The SNI callback failing outright. */
2664 { "sni-callback-fails",
2665 { 6, 0x04, 0, 0x08, 0x05, 0x00, 0x00, 0x00, 0, 0 },
2666 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" },
2667 P_END, P_END, P_END } },
2668
2669 /* The SNI callback answering with an empty certificate list. */
2670 { "sni-callback-empty",
2671 { 6, 0x04, 0, 0x10, 0x05, 0x00, 0x00, 0x00, 0, 0 },
2672 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" },
2673 P_END, P_END, P_END } },
2674
2675 /* The SNI callback answering with a key that is not the certificate's
2676 (byte 9 = 1, "localhost"). */
2677 { "sni-callback-mismatch",
2678 { 6, 0x04, 0, 0x20, 0x05, 0x00, 0x00, 0x00, 0, 1 },
2679 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" },
2680 P_END, P_END, P_END } },
2681
2682 /* The SNI callback answering with a certificate but no key. */
2683 { "sni-callback-no-key",
2684 { 6, 0x04, 0, 0x28, 0x05, 0x00, 0x00, 0x00, 0, 0 },
2685 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" },
2686 P_END, P_END, P_END } },
2687
2688 /* An unknown server name with the by-name callback (byte 9 = 3,
2689 "nobody.example.org"): no certificate. */
2690 { "sni-unknown-name",
2691 { 6, 0x04, 0, 0x18, 0x05, 0x00, 0x00, 0x00, 0, 3 },
2692 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" },
2693 P_END, P_END, P_END } },
2694
2695 /* A PEM blob assembled from the payload below (cred_tbl entry 14). */
2696 { "fuzzed-pem",
2697 { 14, 0x00, 0, 0, 0x01, 0x00, 0x00, 0x00, 32, 0 },
2698 { { 0, "MIIFSzCCAzOgAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCUlUx" },
2699 P_END, P_END, P_END } },
2700
2701 /* A truncated TLS record header, then EOF. */
2702 { "short-record",
2703 { 0, 0x00, 0, 0, 0x00, 0x00, 0x00, 0x00, 0, 0 },
2704 { { 0, "\x16\x03\x01" }, P_END, P_END, P_END } },
2705
2706 /* A record that promises far more data than it delivers. */
2707 { "record-length-lie",
2708 { 0, 0x00, 0, 0, 0x00, 0x00, 0x00, 0x00, 0, 0 },
2709 { { 0, "\x16\x03\x01\x3f\xff\x01\x02\x03\x04" }, P_END, P_END, P_END } },
2710
2711 /* The HTTPS options on a daemon started without MHD_USE_TLS. */
2712 { "no-use-tls-flag",
2713 { 0, 0x0F, 0, 0, 0x00, 0x00, 0x00, 0x08, 0, 0 },
2714 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2715
2716 /* A tiny connection memory pool with a real TLS session. */
2717 { "small-pool-tls",
2718 { 0, 0x00, 0, 0, 0x41, 0x01, 0x00, 0x00, 0, 0 },
2719 { { 0, "GET /aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa HTTP/1.1\r\n"
2720 "Host: x\r\nX-Long: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n\r\n" },
2721 P_END, P_END, P_END } },
2722
2723 /* A request body over TLS, so that the receive adapter is used for
2724 more than the request line. */
2725 { "tls-request-body",
2726 { 0, 0x00, 0, 0, 0x41, 0x00, 0x00, 0x00, 0, 0 },
2727 { { 0, "POST /a HTTP/1.1\r\nHost: x\r\nContent-Length: 11\r\n\r\n"
2728 "hello world" },
2729 P_END, P_END, P_END } },
2730
2731 /* The external event loop (MHD_get_fdset() + MHD_run_from_select()). */
2732 { "tls-external-loop",
2733 { 0, 0x00, 0, 0, 0x41, 0x10, 0x04, 0x00, 0, 0 },
2734 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } },
2735
2736 /* MHD_quiesce_daemon() with a live TLS connection. */
2737 { "tls-quiesce",
2738 { 0, 0x00, 0, 0, 0x41, 0x00, 0x80, 0x00, 0, 0 },
2739 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } }
2740};
2741
2742static uint8_t seed_render_buf[2048];
2743
2744
2745static size_t
2746fuzz_seed_count (void)
2747{
2748 return sizeof (seeds) / sizeof (seeds[0]);
2749}
2750
2751
2752static const uint8_t *
2753fuzz_seed_get (size_t idx,
2754 size_t *len)
2755{
2756 const struct seed_def *sd = &seeds[idx];
2757 struct sbuf b;
2758 unsigned int i;
2759
2760 b.p = seed_render_buf;
2761 b.len = 0;
2762 b.cap = sizeof (seed_render_buf);
2763 sb_raw (&b, sd->cfg, sizeof (sd->cfg));
2764 for (i = 0; i < sizeof (sd->parts) / sizeof (sd->parts[0]); i++)
2765 {
2766 if (NULL == sd->parts[i].txt)
2767 break;
2768 emit_segment (&b, sd->parts[i].op,
2769 (const uint8_t *) sd->parts[i].txt,
2770 strlen (sd->parts[i].txt));
2771 }
2772 *len = b.len;
2773 return seed_render_buf;
2774}
2775
2776
2777#else /* ! HTTPS_SUPPORT */
2778
2779/*
2780 * MHD was configured without HTTPS (which is what
2781 * contrib/oss-fuzz/build.sh does for the MemorySanitizer build), so
2782 * there is no TLS layer to fuzz. The file still has to produce a valid
2783 * fuzz target: LLVMFuzzerTestOneInput() must exist unconditionally, or
2784 * an OSS-Fuzz build of this harness would silently be an empty binary.
2785 */
2786
2787int
2789 size_t size)
2790{
2792 (void) data;
2793 (void) size;
2794 return 0;
2795}
2796
2797
2798static size_t
2800 uint8_t *buf,
2801 size_t cap)
2802{
2803 (void) rng;
2804 if (0 == cap)
2805 return 0;
2806 buf[0] = 0;
2807 return 1;
2808}
2809
2810
2811static const uint8_t no_https_seed[] = { 0 };
2812
2813
2814static size_t
2816{
2817 return 1;
2818}
2819
2820
2821static const uint8_t *
2822fuzz_seed_get (size_t idx,
2823 size_t *len)
2824{
2825 (void) idx;
2826 *len = sizeof (no_https_seed);
2827 return no_https_seed;
2828}
2829
2830
2831#endif /* ! HTTPS_SUPPORT */
2832
2833/* end of fuzz_tls.c */
static void print_stats(void)
Shared, header-only fuzzing driver for the MHD in-process fuzzers.
static FUZZ_UNUSED void fuzz_ignore_sigpipe(void)
static FUZZ_UNUSED int fuzz_verbose
static FUZZ_UNUSED uint32_t fuzz_below(struct fuzz_rng *r, uint32_t n)
static FUZZ_UNUSED uint8_t fuzz_byte(struct fuzz_rng *r)
static FUZZ_UNUSED void fuzz_report_finding(const char *what)
static FUZZ_UNUSED int fuzz_chance(struct fuzz_rng *r, uint32_t n)
static const struct seed_def seeds[]
static int stats_registered
static unsigned long stat_daemons
static void panic_cb(void *cls, const char *file, unsigned int line, const char *reason)
static uint8_t seed_render_buf[64]
static enum MHD_Result ahc(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **req_cls)
static unsigned long stat_handler_calls
static int queue_unprocessed_conn(struct MHD_Daemon *d)
static struct el_cfg cfg
static const size_t mem_limit_tbl[]
#define MAX_CONNECTIONS
static const char *const gen_hdr_values[]
static void pump(struct MHD_Daemon *d, int sock, unsigned int rounds)
static void run_once(struct MHD_Daemon *d)
static const char *const gen_targets[]
static void sb_raw(struct sbuf *b, const void *s, size_t n)
static void sb_str(struct sbuf *b, const char *s)
#define MAX_SEGMENTS
#define GEN_BUF_SIZE
static const char *const gen_methods[]
static const char *const gen_hdr_names[]
static unsigned long stat_daemons_failed
static const char resp_body[]
static const char *const gen_versions[]
static size_t resp_len
static char resp_buf[RESP_BUF_SIZE]
#define P_END
gen_shape
@ SHAPE_COUNT
static int forced_shape
#define RESP_BUF_SIZE
static int forced_shape_read
static size_t fuzz_seed_count(void)
Definition fuzz_tls.c:2815
#define FUZZ_HARNESS_NAME
Definition fuzz_tls.c:178
static const uint8_t * fuzz_seed_get(size_t idx, size_t *len)
Definition fuzz_tls.c:2822
static const uint8_t no_https_seed[]
Definition fuzz_tls.c:2811
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
Definition fuzz_tls.c:2788
static size_t fuzz_generate(struct fuzz_rng *rng, uint8_t *buf, size_t cap)
Definition fuzz_tls.c:2799
#define MHD_run_from_select(d, r, w, e)
_MHD_EXTERN void MHD_stop_daemon(struct MHD_Daemon *daemon)
Definition daemon.c:9415
_MHD_EXTERN enum MHD_Result MHD_run(struct MHD_Daemon *daemon)
Definition daemon.c:5938
_MHD_EXTERN enum MHD_Result MHD_get_fdset2(struct MHD_Daemon *daemon, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *except_fd_set, MHD_socket *max_fd, unsigned int fd_setsize)
Definition daemon.c:1227
#define MHD_get_fdset(daemon, read_fd_set, write_fd_set, except_fd_set, max_fd)
_MHD_EXTERN enum MHD_Result MHD_run_from_select2(struct MHD_Daemon *daemon, const fd_set *read_fd_set, const fd_set *write_fd_set, const fd_set *except_fd_set, unsigned int fd_setsize)
Definition daemon.c:4746
_MHD_EXTERN struct MHD_Daemon * MHD_start_daemon(unsigned int flags, uint16_t port, MHD_AcceptPolicyCallback apc, void *apc_cls, MHD_AccessHandlerCallback dh, void *dh_cls,...)
Definition daemon.c:6217
#define MHD_HTTP_OK
Definition microhttpd.h:350
#define MHD_HTTP_FORBIDDEN
Definition microhttpd.h:397
_MHD_EXTERN void MHD_set_panic_func(MHD_PanicCallback cb, void *cls)
Definition mhd_panic.c:94
@ MHD_CONNECTION_INFO_GNUTLS_SESSION
@ MHD_CONNECTION_INFO_CIPHER_ALGO
@ MHD_CONNECTION_INFO_CLIENT_ADDRESS
@ MHD_CONNECTION_INFO_GNUTLS_CLIENT_CERT
@ MHD_CONNECTION_INFO_CONNECTION_FD
@ MHD_CONNECTION_INFO_PROTOCOL
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer_copy(size_t size, const void *buffer)
Definition response.c:1545
_MHD_EXTERN enum MHD_Result MHD_queue_response(struct MHD_Connection *connection, unsigned int status_code, struct MHD_Response *response)
_MHD_EXTERN void MHD_destroy_response(struct MHD_Response *response)
Definition response.c:2294
_MHD_EXTERN struct MHD_Response * MHD_create_response_empty(enum MHD_ResponseFlags flags)
Definition response.c:1831
_MHD_EXTERN struct MHD_Response * MHD_create_response_from_buffer_static(size_t size, const void *buffer)
Definition response.c:1512
_MHD_EXTERN enum MHD_Result MHD_add_response_header(struct MHD_Response *response, const char *header, const char *content)
Definition response.c:625
_MHD_EXTERN enum MHD_Result MHD_add_connection(struct MHD_Daemon *daemon, MHD_socket client_socket, const struct sockaddr *addr, socklen_t addrlen)
Definition daemon.c:3682
_MHD_EXTERN enum MHD_Result MHD_is_feature_supported(enum MHD_FEATURE feature)
Definition daemon.c:9722
_MHD_EXTERN enum MHD_Result MHD_set_connection_option(struct MHD_Connection *connection, enum MHD_CONNECTION_OPTION option,...)
_MHD_EXTERN MHD_socket MHD_quiesce_daemon(struct MHD_Daemon *daemon)
Definition daemon.c:6262
_MHD_EXTERN const union MHD_DaemonInfo * MHD_get_daemon_info(struct MHD_Daemon *daemon, enum MHD_DaemonInfoType info_type,...)
Definition daemon.c:9605
_MHD_EXTERN const union MHD_ConnectionInfo * MHD_get_connection_info(struct MHD_Connection *connection, enum MHD_ConnectionInfoType info_type,...)
#define UINT_MAX
Definition mhd_limits.h:53
#define NULL
additional automatic macros for MHD_config.h
public interface to libmicrohttpd
int MHD_socket
Definition microhttpd.h:206
@ MHD_FEATURE_UPGRADE
@ MHD_OPTION_HTTPS_PRIORITIES_APPEND
@ MHD_OPTION_HTTPS_CRED_TYPE
@ MHD_OPTION_TLS_NO_ALPN
@ MHD_OPTION_HTTPS_PRIORITIES
@ MHD_OPTION_HTTPS_MEM_DHPARAMS
@ MHD_OPTION_HTTPS_MEM_CERT
@ MHD_OPTION_HTTPS_MEM_KEY
@ MHD_OPTION_HTTPS_KEY_PASSWORD
@ MHD_OPTION_CONNECTION_MEMORY_LIMIT
@ MHD_OPTION_ARRAY
@ MHD_OPTION_GNUTLS_PSK_CRED_HANDLER
@ MHD_OPTION_END
@ MHD_OPTION_HTTPS_MEM_TRUST
@ MHD_OPTION_HTTPS_CERT_CALLBACK
MHD_Result
Definition microhttpd.h:163
@ MHD_YES
Definition microhttpd.h:172
@ MHD_NO
Definition microhttpd.h:167
int fd
void * data
#define MHD_INVALID_SOCKET
Definition microhttpd.h:207
@ MHD_DAEMON_INFO_BIND_PORT
@ MHD_DAEMON_INFO_FLAGS
@ MHD_DAEMON_INFO_CURRENT_CONNECTIONS
@ MHD_DAEMON_INFO_LISTEN_FD
@ MHD_USE_TLS
@ MHD_ALLOW_UPGRADE
@ MHD_USE_ERROR_LOG
@ MHD_USE_NO_LISTEN_SOCKET
@ MHD_RF_NONE
@ MHD_CONNECTION_OPTION_TIMEOUT