fuzz_tls.c (97391B)
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 20 /** 21 * @file fuzz/fuzz_tls.c 22 * @brief In-process fuzzer for MHD's HTTPS/TLS integration layer. 23 * @author Christian Grothoff 24 * 25 * The target is **MHD's own TLS plumbing**, not GnuTLS. GnuTLS has its 26 * own OSS-Fuzz project and its record parser is not our bug surface, so 27 * only a small part of the input budget is spent throwing raw bytes at a 28 * TLS socket. What this harness really exercises is 29 * 30 * - the @c MHD_USE_TLS daemon option surface: #MHD_OPTION_HTTPS_MEM_KEY, 31 * #MHD_OPTION_HTTPS_MEM_CERT, #MHD_OPTION_HTTPS_MEM_TRUST, 32 * #MHD_OPTION_HTTPS_MEM_DHPARAMS, #MHD_OPTION_HTTPS_PRIORITIES, 33 * #MHD_OPTION_HTTPS_PRIORITIES_APPEND, #MHD_OPTION_HTTPS_CRED_TYPE, 34 * #MHD_OPTION_HTTPS_KEY_PASSWORD, #MHD_OPTION_TLS_NO_ALPN and the SNI 35 * callback #MHD_OPTION_HTTPS_CERT_CALLBACK -- with malformed PEM 36 * blobs, mismatched key/certificate pairs, bogus priority strings, 37 * credential types MHD does not support, and an SNI callback that 38 * fails or answers with garbage; 39 * - the pre-shared key path: #MHD_OPTION_GNUTLS_PSK_CRED_HANDLER and 40 * @c psk_gnutls_adapter(), which is the one place where MHD takes a 41 * buffer straight from an application callback and hands it to 42 * GnuTLS. See the "TLS-PSK" note below for why one input bit turns 43 * the whole scenario on rather than four independent ones; 44 * - the handshake state machine of connection_https.c 45 * (#MHD_TLS_CONN_INIT -> HANDSHAKING -> CONNECTED / TLS_FAILED) and 46 * what MHD does when the handshake fails, is abandoned half way, or 47 * the peer disappears while MHD is still in it; 48 * - the transition from the handshake to the ordinary HTTP parser, and 49 * the TLS receive/send adapters and @c gnutls_bye() shutdown path that 50 * the connection uses afterwards. 51 * 52 * To reach that last group the harness contains a real, in-process GnuTLS 53 * *client*. Both ends of an @c AF_UNIX @c socketpair() are non-blocking 54 * and everything runs in one thread: the client's @c gnutls_handshake() 55 * is called until it answers @c GNUTLS_E_AGAIN, then the daemon is pumped 56 * with MHD_run(), and so on. No threads, no ports, no TCP stack, and -- 57 * because the client's handshake timeout is set to 58 * @c GNUTLS_INDEFINITE_TIMEOUT -- no wall clock either. 59 * 60 * Input format (see README): 61 * 62 * byte 0 certificate/key pair selector (valid, mismatched, truncated, 63 * garbage, absent, or built from the fuzzer's own bytes) 64 * byte 1 which TLS daemon options to pass at all (bitmask) 65 * 0x01 MHD_OPTION_HTTPS_MEM_TRUST 66 * 0x02 MHD_OPTION_HTTPS_MEM_DHPARAMS 67 * 0x04 MHD_OPTION_HTTPS_CERT_CALLBACK (the SNI callback) 68 * 0x08 MHD_OPTION_HTTPS_PRIORITIES[_APPEND] 69 * 0x10 MHD_OPTION_HTTPS_CRED_TYPE 70 * 0x20 MHD_OPTION_TLS_NO_ALPN 71 * 0x40 MHD_OPTION_HTTPS_KEY_PASSWORD 72 * 0x80 use _PRIORITIES_APPEND instead of _PRIORITIES 73 * byte 2 priority string selector 74 * byte 3 bits 0-2 credential type (certificate, PSK, anon, SRP, IA, 75 * and two values GnuTLS does not define) 76 * bits 3-5 SNI callback behaviour 77 * bit 6 trust blob: CA certificate or garbage 78 * bit 7 DH parameters: valid or garbage 79 * byte 4 bits 0-1 client mode 80 * 0 raw bytes, 1 real TLS client, 81 * 2 real client, handshake abandoned half way, 82 * 3 raw bytes shaped like TLS records 83 * bit 2 client sends a server name (SNI) 84 * bit 3 client presents a client certificate 85 * bits 4-5 client priority string selector 86 * bit 6 gnutls_bye() before closing 87 * bit 7 shutdown(SHUT_WR) before closing 88 * byte 5 bits 0-3 MHD_OPTION_CONNECTION_MEMORY_LIMIT selector 89 * bits 4-5 event loop: MHD_run() vs MHD_get_fdset*() + 90 * MHD_run_from_select*() 91 * bit 6 hand the daemon one more connection at the very 92 * end and stop it without running the loop again, 93 * so that a TLS session is torn down for a 94 * connection MHD never started 95 * bit 7 unused 96 * byte 6 handler behaviour and introspection 97 * bits 0-1 response constructor 98 * bit 2 MHD_get_connection_info() for the TLS members 99 * bit 3 MHD_get_daemon_info() 100 * bit 4 MHD_set_connection_option() 101 * bit 5 answer 403 instead of 200 102 * bit 6 add a response header 103 * bit 7 MHD_quiesce_daemon() before stopping 104 * byte 7 bits 0-2 handshake round budget (client mode 2) 105 * bit 3 pass the HTTPS options to a daemon started *without* 106 * MHD_USE_TLS 107 * bit 4 MHD_ALLOW_UPGRADE 108 * bits 5-7 extra pump rounds 109 * byte 8 how many bytes of the segment stream are spliced into the 110 * fuzzer-built PEM blobs (see cred_tbl entries 12 and 13) 111 * byte 9 bits 0-2 the server name the client presents, as an index 112 * into a small built-in table; an op 1 segment overrides it. 113 * In the TLS-PSK scenario that same string is also the PSK 114 * identity the client sends, so an op 1 segment gives byte 115 * level control over the @a username that reaches 116 * psk_gnutls_adapter() 117 * bits 3-5 behaviour of the PSK credentials callback 118 * bit 6 the client offers PSK credentials 119 * bit 7 run the TLS-PSK scenario (see below) 120 * byte 10. a sequence of segments, each introduced by a little-endian 121 * 16 bit header (op << 14) | length 122 * op 0 send the payload 123 * op 1 the payload is the server name the *next* client 124 * connection presents; nothing is sent 125 * op 2 send the payload and pump the daemon extra rounds 126 * op 3 close the connection, open a fresh one (which means 127 * a fresh handshake), then send 128 * 129 * All ten configuration bytes are mandatory; a shorter input is 130 * rejected. 131 * 132 * The segment encoding is byte-for-byte the one fuzz_request uses, and 133 * `corpus/` is shared by every harness in this directory (see README 134 * section 3), so the seeds below deliberately contain **no op 1 135 * segment**: fuzz_request reads op 1 as the declared decoded request 136 * body of its own body oracle, and would report a spurious finding when 137 * it replays a fuzz_tls seed. That is what byte 9 is for. Inputs the 138 * generator or a mutator produces may use op 1 freely -- they never end 139 * up in `corpus/`. 140 * 141 * TLS-PSK. Reaching psk_gnutls_adapter() needs four unrelated things to 142 * be true at the same time: the daemon's credential type has to be 143 * #GNUTLS_CRD_PSK, both ends need a priority string that actually has a 144 * PSK key exchange in it ("NORMAL" does not), the daemon needs 145 * #MHD_OPTION_GNUTLS_PSK_CRED_HANDLER, and the client has to offer a PSK 146 * identity. Spread over four independent input bits that combination 147 * comes up once in a few hundred thousand inputs, and an 8 hour campaign 148 * duly left the function at zero coverage. Bit 7 of byte 9 therefore 149 * switches the whole scenario on at once and the remaining PSK bits only 150 * choose between its variants. 151 * 152 * The variants are the branches of psk_gnutls_adapter() itself: the 153 * callback is missing, fails, or answers 0 with a key of a workable 154 * size, of 4 KiB, of zero size, of one byte less than the 155 * @c MHD_PSK_MIN_SIZE the adapter enforces, and of a size that exceeds 156 * @c UINT_MAX. The two undersized ones and #PSK_OK bracket that 157 * minimum from both sides -- #PSK_OK is exactly @c MHD_PSK_MIN_SIZE 158 * bytes -- which is what makes an off-by-one in the check visible. 159 * 160 * One behaviour is deliberately *not* offered: answering 0 without 161 * writing the two output parameters. MHD would then read uninitialised 162 * memory, but the application has broken the documented contract, so a 163 * report from that would be a harness bug rather than an MHD bug. 164 * 165 * The certificates and keys are the ones from 166 * `src/testcurl/https/tls_test_keys.h` (the CA certificate, the 167 * CA-signed server certificate with its key, and the self-signed server 168 * certificate with its key), reproduced verbatim so that this harness 169 * stays a single translation unit. The DH parameters are RFC 3526 170 * group 14, as emitted by `certtool --get-dh-params --sec-param medium`. 171 * 172 * The whole harness is guarded by #HTTPS_SUPPORT: `contrib/oss-fuzz/ 173 * build.sh` configures `--disable-https` (that is what makes the 174 * MemorySanitizer build possible), and in such a build this file must 175 * still compile to a valid, trivially passing fuzz target. 176 */ 177 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 195 /** 196 * LeakSanitizer suppressions, compiled into the harness so that they 197 * cannot be forgotten on the command line. 198 * 199 * There is exactly one entry and it is *not* about MHD. GnuTLS 3.8.9 200 * leaks the partially parsed certificate when a PEM certificate blob 201 * ends before its "-----END CERTIFICATE-----" line: 202 * 203 * gnutls_certificate_allocate_credentials (&cred); 204 * gnutls_certificate_set_x509_key_mem (cred, &truncated_cert, 205 * &good_key, 206 * GNUTLS_X509_FMT_PEM); 207 * -> GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR (-207) 208 * gnutls_certificate_free_credentials (cred); 209 * 210 * leaks 9672 bytes in 57 allocations with no libmicrohttpd in the 211 * picture at all (reproduced with a 40 line program). MHD passes the 212 * blob straight through and frees the credentials on every path, so 213 * there is nothing for MHD to fix and nothing for this harness to find; 214 * GnuTLS is fuzzed separately by its own OSS-Fuzz project. 215 * 216 * The suppression matches only allocations made *inside* GnuTLS's 217 * certificate parser. A credential object leaked by MHD itself is a 218 * direct leak from gnutls_certificate_allocate_credentials() and is 219 * still reported, as is every other MHD allocation. 220 */ 221 const char * 222 __lsan_default_suppressions (void); 223 224 const 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 238 /** Number of client priority strings offered to the input. */ 239 #define CLIENT_PRIO_COUNT 4 240 241 /** 242 * Upper bound on the number of client/server round trips spent on one 243 * handshake. A TLS 1.3 handshake over a socketpair needs a handful; the 244 * cap only has to guarantee termination. 245 */ 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 261 static 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 299 static 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 330 static 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 364 static 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 386 static 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 417 static 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 427 /** A PEM blob whose armour is fine but whose payload is not base64. */ 428 static 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 433 static const char garbage_key_pem[] = 434 "-----BEGIN PRIVATE KEY-----\n" 435 "@@@@ neither is this @@@@\n" 436 "-----END PRIVATE KEY-----\n"; 437 438 /** Correct base64, but the armour never ends. */ 439 static const char truncated_cert_pem[] = 440 "-----BEGIN CERTIFICATE-----\n" 441 "MIIFSzCCAzOgAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCUlUx\n" 442 "DzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MRswGQYDVQQKDBJ0ZXN0\n"; 443 444 static const char truncated_key_pem[] = 445 "-----BEGIN PRIVATE KEY-----\n" 446 "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCff7amw9zNSE+h\n"; 447 448 /** Base64 of a certificate, but with no PEM armour at all. */ 449 static const char no_armour_pem[] = 450 "MIIFSzCCAzOgAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCUlUx\n" 451 "DzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MRswGQYDVQQKDBJ0ZXN0\n"; 452 453 static const char garbage_dh_pem[] = 454 "-----BEGIN DH PARAMETERS-----\n" 455 "not-dh-parameters\n" 456 "-----END DH PARAMETERS-----\n"; 457 458 /** 459 * PEM blobs assembled from the fuzzer's own bytes, see cred_tbl entries 460 * 12 and 13. Static so that the pointer handed to MHD stays valid for 461 * the whole lifetime of the daemon. 462 */ 463 static char fuzz_cert_pem[FUZZ_PEM_BODY_MAX + 128]; 464 static char fuzz_key_pem[FUZZ_PEM_BODY_MAX + 128]; 465 466 467 /** 468 * A certificate/key pair for #MHD_OPTION_HTTPS_MEM_CERT and 469 * #MHD_OPTION_HTTPS_MEM_KEY. A NULL member means "do not pass the 470 * option at all", which is a configuration MHD has to reject cleanly. 471 */ 472 struct cred_pair 473 { 474 const char *cert; 475 const char *key; 476 }; 477 478 static 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 499 /** 500 * Priority strings. The first entries are the ones a real server would 501 * use, the rest are what MHD has to reject without falling over. MHD 502 * hands these to gnutls_priority_init() (or appends them to its own 503 * base string) and fails daemon startup if GnuTLS does not like them. 504 */ 505 static 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 526 /** Priority strings offered to the *client* side. */ 527 static 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 534 /** 535 * Priority strings for the TLS-PSK scenario, used on both ends. 536 * "NORMAL" carries no PSK key exchange, so without one of these the 537 * ciphersuite is never negotiated, GnuTLS never asks the server for a 538 * key, and psk_gnutls_adapter() is never called. Index is the client 539 * priority selector (byte 4, bits 4-5), which the ordinary tables no 540 * longer use once the scenario is on. 541 * 542 * The TLS 1.2 entry has to remove the other key exchanges explicitly. 543 * A daemon with #GNUTLS_CRD_PSK has no certificate credentials, so with 544 * the certificate key exchanges still in the list the TLS 1.2 handshake 545 * dies with "received handshake message out of context" before GnuTLS 546 * ever asks for a key. Under TLS 1.3 the same list is fine, which is 547 * what entries 0 and 2 cover. 548 */ 549 static 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 556 /** 557 * Credential types. Only GNUTLS_CRD_CERTIFICATE and GNUTLS_CRD_PSK are 558 * accepted by MHD_TLS_init(); everything else must make daemon startup 559 * fail rather than reach the MHD_PANIC() in new_connection_prepare_(). 560 */ 561 static 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 574 /** Index of #GNUTLS_CRD_PSK in #cred_type_tbl. */ 575 #define PSK_CRED_TYPE_IDX 1u 576 577 /** 578 * The pre-shared key the client uses, and the one #PSK_OK hands back. 579 * They match, so that variant completes the handshake and MHD goes on to 580 * serve ordinary HTTP over a session with no certificate at all -- which 581 * is a different shape again for the connection introspection calls. 582 * 583 * Its length is exactly the @c MHD_PSK_MIN_SIZE that psk_gnutls_adapter() 584 * enforces (16, RFC 4279 section 7.1). That is not a coincidence and 585 * the two have to be kept in step: #PSK_OK and #PSK_ONE_SHORT bracket 586 * the check from both sides, and #PSK_ONE_SHORT derives its length from 587 * this array. The minimum is private to daemon.c, so this is a mirror 588 * rather than a shared constant; if daemon.c changes, so must this. 589 */ 590 static 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 595 static 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 602 static const char https_key_password[] = "not-the-password"; 603 604 605 /* ------------------------------------------------------------------ */ 606 /* Per-iteration configuration */ 607 /* ------------------------------------------------------------------ */ 608 609 /** Behaviour of the SNI callback, selected by bits 3-5 of byte 3. */ 610 enum sni_behaviour 611 { 612 SNI_ALWAYS_OK = 0, /**< always answer with the signed pair */ 613 SNI_FAIL, /**< always answer -1 */ 614 SNI_EMPTY, /**< answer 0 with an empty certificate list */ 615 SNI_BY_NAME, /**< look the server name up, -1 if unknown */ 616 SNI_MISMATCH, /**< answer with a key that is not the cert's */ 617 SNI_NO_KEY, /**< answer 0, certificate but no key */ 618 SNI_SELF_SIGNED, /**< always answer with the self-signed pair */ 619 SNI_BEHAVIOUR_COUNT 620 }; 621 622 /** 623 * Behaviour of the PSK credentials callback, selected by bits 3-5 of 624 * byte 9. Each entry corresponds to one branch of psk_gnutls_adapter(). 625 */ 626 enum psk_behaviour 627 { 628 PSK_OK = 0, /**< the key the client expects; handshake works */ 629 PSK_FAIL, /**< the callback answers -1 */ 630 PSK_EMPTY, /**< a zero length key: rejected as too short */ 631 PSK_LONG, /**< a 4 KiB key */ 632 PSK_FROM_ID, /**< key built from the identity the client sent, 633 so its length is attacker-chosen and lands 634 on either side of MHD_PSK_MIN_SIZE */ 635 PSK_HUGE, /**< a size above UINT_MAX */ 636 PSK_NO_HANDLER, /**< the option is not passed at all */ 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, /**< MHD_PSK_MIN_SIZE - 1 bytes: the boundary */ 641 PSK_BEHAVIOUR_COUNT 642 }; 643 644 /** Client behaviour, selected by bits 0-1 of byte 4. */ 645 enum client_mode 646 { 647 CLIENT_RAW = 0, /**< raw bytes straight at the TLS socket */ 648 CLIENT_TLS, /**< a real GnuTLS client */ 649 CLIENT_TLS_ABANDON, /**< a real client that stops mid-handshake */ 650 CLIENT_RECORDS /**< raw bytes shaped like TLS records */ 651 }; 652 653 struct fuzz_cfg 654 { 655 /* ---- daemon ---- */ 656 const char *cert; 657 const char *key; 658 int use_tls; /**< set MHD_USE_TLS at all */ 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; /**< what use_prio actually passes */ 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; /**< the whole PSK bundle is on */ 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; /**< offer PSK credentials */ 688 unsigned int client_prio_idx; 689 int client_bye; 690 int client_shut_wr; 691 unsigned int hs_budget; /**< handshake rounds in CLIENT_TLS_ABANDON */ 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; /**< stop with a connection still queued */ 703 }; 704 705 static struct fuzz_cfg cfg; 706 707 /** 708 * Server names the client can present. Which one is used comes from 709 * byte 9 of the input; an op 1 segment overrides it. MHD itself never 710 * looks at the name -- GnuTLS parses the extension and the application 711 * callback reads it back -- so a fixed table costs no MHD coverage. 712 */ 713 static 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 726 /** Server name the next client connection presents. */ 727 static char sni_name[MAX_SNI_LEN + 1]; 728 static size_t sni_name_len; 729 730 /** Bytes received from the daemon during the current iteration. */ 731 static char resp_buf[RESP_BUF_SIZE]; 732 static size_t resp_len; 733 734 /** Statistics, printed at exit with --verbose. */ 735 static unsigned long stat_daemons; 736 static unsigned long stat_daemons_failed; 737 static unsigned long stat_connections; 738 static unsigned long stat_handshakes_ok; 739 static unsigned long stat_handshakes_failed; 740 static unsigned long stat_handler_calls; 741 static unsigned long stat_sni_calls; 742 static unsigned long stat_psk_calls; 743 static int stats_registered; 744 745 746 static void 747 print_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", 755 FUZZ_HARNESS_NAME, 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 766 /** 767 * Certificates for the SNI callback, parsed once and then kept in these 768 * statics for the whole life of the process: they are configuration, not 769 * per-iteration state, and re-parsing them on every execution would cost 770 * more than everything else the harness does. They are reachable from 771 * globals, so LeakSanitizer does not count them. 772 */ 773 struct 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 783 static 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 788 static int sni_hosts_ready; 789 790 791 /** 792 * @return 0 if the certificates are usable 793 */ 794 static int 795 sni_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 843 /** 844 * #MHD_OPTION_HTTPS_CERT_CALLBACK. Deliberately badly behaved for most 845 * of the settings of @e cfg.sni_mode: an application callback that fails 846 * or answers with nothing is exactly the case MHD has to survive. 847 */ 848 static int 849 sni_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 928 static const char resp_body[] = "hello world over TLS"; 929 930 931 static enum MHD_Result 932 ahc (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; 950 stat_handler_calls++; 951 if (NULL == *req_cls) 952 { 953 /* first call: MHD only wants to know that we are interested */ 954 *req_cls = ▮ 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, 969 MHD_CONNECTION_INFO_CIPHER_ALGO); 970 (void) MHD_get_connection_info (connection, 971 MHD_CONNECTION_INFO_PROTOCOL); 972 (void) MHD_get_connection_info (connection, 973 MHD_CONNECTION_INFO_GNUTLS_SESSION); 974 (void) MHD_get_connection_info (connection, 975 MHD_CONNECTION_INFO_GNUTLS_CLIENT_CERT); 976 (void) MHD_get_connection_info (connection, 977 MHD_CONNECTION_INFO_CLIENT_ADDRESS); 978 (void) MHD_get_connection_info (connection, 979 MHD_CONNECTION_INFO_CONNECTION_FD); 980 } 981 if (cfg.conn_option) 982 (void) MHD_set_connection_option (connection, 983 MHD_CONNECTION_OPTION_TIMEOUT, 984 (unsigned int) 0); 985 switch (cfg.resp_kind) 986 { 987 case 1: 988 r = MHD_create_response_from_buffer_copy (sizeof (resp_body) - 1, 989 resp_body); 990 break; 991 case 2: 992 r = MHD_create_response_empty (MHD_RF_NONE); 993 break; 994 case 3: 995 r = MHD_create_response_from_buffer_static (0, ""); 996 break; 997 case 0: 998 default: 999 r = MHD_create_response_from_buffer_static (sizeof (resp_body) - 1, 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 1009 ? MHD_HTTP_FORBIDDEN 1010 : MHD_HTTP_OK, 1011 r); 1012 MHD_destroy_response (r); 1013 return ret; 1014 } 1015 1016 1017 static void 1018 panic_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 1039 /** 1040 * Advance the daemon by one cycle, through the event-loop API selected 1041 * by byte 5 of the input. The select() timeout is always zero: the 1042 * harness is single threaded, whatever the daemon is waiting for has 1043 * already been written into the socketpair, and blocking would only burn 1044 * wall clock. 1045 */ 1046 static void 1047 run_once (struct MHD_Daemon *d) 1048 { 1049 fd_set rs; 1050 fd_set ws; 1051 fd_set es; 1052 MHD_socket max_fd = MHD_INVALID_SOCKET; 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 1100 /** 1101 * #MHD_OPTION_GNUTLS_PSK_CRED_HANDLER. GnuTLS calls 1102 * psk_gnutls_adapter() with the identity the client sent, and that 1103 * function calls this; whatever comes back is copied into a 1104 * gnutls_malloc()ed buffer and handed to GnuTLS, with @a psk freed by 1105 * MHD on every path. The buffer therefore has to come from plain 1106 * malloc() -- see the doxygen on #MHD_PskServerCredentialsCallback. 1107 * 1108 * @param cls unused 1109 * @param connection the connection GnuTLS is handshaking 1110 * @param username the identity claimed by the client 1111 * @param[out] psk the key 1112 * @param[out] psk_size its length 1113 * @return 0 on success, -1 on error 1114 */ 1115 static int 1116 psk_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 1202 struct tls_client 1203 { 1204 gnutls_session_t sess; /**< NULL in the raw modes */ 1205 gnutls_certificate_credentials_t cred; 1206 gnutls_psk_client_credentials_t psk; /**< only in the PSK scenario */ 1207 int fd; /**< our end of the socketpair */ 1208 int hs_done; 1209 int dead; 1210 }; 1211 1212 1213 static void 1214 pump (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 1224 /** 1225 * Read whatever the daemon has produced so far. In the raw modes this 1226 * is a plain recv(); with a real client it goes through GnuTLS, which is 1227 * what actually drives MHD's send path and its TLS shutdown handling. 1228 */ 1229 static void 1230 tc_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 1280 static void 1281 pump_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 1295 /** 1296 * Let the client and the daemon take turns at the handshake until it 1297 * completes, fails, or @a rounds is exhausted. Exhausting @a rounds on 1298 * purpose (client mode 2) is what leaves MHD's connection parked in 1299 * #MHD_TLS_CONN_HANDSHAKING. 1300 */ 1301 static void 1302 tc_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 1335 /** 1336 * Open a fresh connection: a socketpair, one end handed to MHD with 1337 * MHD_add_connection(), the other end ours. With a real client the 1338 * GnuTLS session is set up here too, but the handshake itself is driven 1339 * by tc_handshake(). 1340 * 1341 * @return 0 on success 1342 */ 1343 static int 1344 tc_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 1467 static void 1468 tc_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 1532 /** 1533 * Tear the client end down. Every GnuTLS object is released on every 1534 * path, including the ones where the session never got off the ground. 1535 */ 1536 static void 1537 tc_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 1585 /** 1586 * Hand the daemon one more connection and do not run the loop again. 1587 * 1588 * See the comment at the call site: this is what leaves a fully prepared 1589 * connection -- GnuTLS session and all -- on the daemon's 1590 * new_connections list when MHD_stop_daemon() runs. 1591 * 1592 * @param d the daemon, about to be stopped 1593 * @return our end of the socket pair, or -1 if nothing was queued 1594 */ 1595 static int 1596 queue_unprocessed_conn (struct MHD_Daemon *d) 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 1620 /** 1621 * Bring a fresh connection up to the point where payload can be sent. 1622 */ 1623 static void 1624 tc_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 1645 /** 1646 * Build @a out as "-----BEGIN @a label-----\n<body>\n-----END @a 1647 * label-----\n", with @a body_len bytes of @a body as the payload. The 1648 * result is always NUL terminated, because MHD calls strlen() on it. 1649 */ 1650 static void 1651 build_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 1687 int 1688 LLVMFuzzerTestOneInput (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; /**< see queue_unprocessed_conn() */ 1700 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. */ 1704 fuzz_ignore_sigpipe (); 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)) && 1766 (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_UPGRADE)); 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 1871 ? MHD_OPTION_HTTPS_PRIORITIES_APPEND 1872 : MHD_OPTION_HTTPS_PRIORITIES; 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 1895 flags = MHD_USE_NO_LISTEN_SOCKET; 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 1903 MHD_set_panic_func (&panic_cb, NULL); 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, 1921 MHD_OPTION_HTTPS_CERT_CALLBACK, 1922 cfg.use_sni ? &sni_callback : NULL, 1923 MHD_OPTION_GNUTLS_PSK_CRED_HANDLER, 1924 (cfg.psk_scenario && 1925 (PSK_NO_HANDLER != cfg.psk_mode)) 1926 ? &psk_cred_cb : NULL, 1927 NULL, 1928 MHD_OPTION_END); 1929 #else 1930 d = MHD_start_daemon (flags, 1931 0, 1932 NULL, NULL, 1933 &ahc, NULL, 1934 MHD_OPTION_ARRAY, opts, 1935 MHD_OPTION_HTTPS_CERT_CALLBACK, 1936 cfg.use_sni ? &sni_callback : NULL, 1937 MHD_OPTION_END); 1938 #endif 1939 if (NULL == d) 1940 { 1941 stat_daemons_failed++; 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 { 1952 (void) MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD); 1953 (void) MHD_get_daemon_info (d, MHD_DAEMON_INFO_FLAGS); 1954 (void) MHD_get_daemon_info (d, MHD_DAEMON_INFO_CURRENT_CONNECTIONS); 1955 (void) MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 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 2047 struct sbuf 2048 { 2049 uint8_t *p; 2050 size_t len; 2051 size_t cap; 2052 }; 2053 2054 2055 static void 2056 sb_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 2067 static void 2068 sb_str (struct sbuf *b, 2069 const char *s) 2070 { 2071 sb_raw (b, s, strlen (s)); 2072 } 2073 2074 2075 static void 2076 sb_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 2098 enum gen_shape 2099 { 2100 SHAPE_TLS_HTTP = 0, /**< good credentials, real handshake, HTTP over TLS */ 2101 SHAPE_RAW_BYTES, /**< good credentials, junk at the TLS socket */ 2102 SHAPE_ABANDON, /**< a real client that walks away mid-handshake */ 2103 SHAPE_BAD_CREDS, /**< mismatched/garbage/absent key or certificate */ 2104 SHAPE_BAD_OPTIONS, /**< bogus priorities, credential types, no MHD_USE_TLS */ 2105 SHAPE_SNI, /**< the certificate callback, all behaviours */ 2106 SHAPE_PEM_FUZZ, /**< PEM blobs built from the generator's own bytes */ 2107 SHAPE_RECORDS, /**< hand-built TLS records */ 2108 SHAPE_PSK, /**< the pre-shared key credentials path */ 2109 SHAPE_COUNT 2110 }; 2111 2112 static int forced_shape = -1; 2113 static int forced_shape_read; 2114 2115 static const char *const gen_methods[] = { 2116 "GET", "POST", "HEAD", "PUT", "OPTIONS", "BREW" 2117 }; 2118 2119 static const char *const gen_targets[] = { 2120 "/", "/a", "/index.html", "/a?b=c", "/%41%42", "*", "//" 2121 }; 2122 2123 static const char *const gen_versions[] = { 2124 "HTTP/1.1", "HTTP/1.0", "HTTP/1.2", "HTTP/9.9" 2125 }; 2126 2127 static const char *const gen_hdr_names[] = { 2128 "Host", "User-Agent", "Accept", "Connection", "X-Fuzz", "Cookie", 2129 "Content-Type", "Expect" 2130 }; 2131 2132 static const char *const gen_hdr_values[] = { 2133 "x", "localhost", "*/*", "keep-alive", "close", "100-continue", 2134 "text/plain", "a=b" 2135 }; 2136 2137 2138 /** 2139 * A plain HTTP request; over TLS this is what makes MHD leave the 2140 * handshake state machine and enter the ordinary parser. 2141 */ 2142 static void 2143 gen_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 2194 /** 2195 * Something that looks like a TLS record: a content type, a version, a 2196 * length and a payload. Most of this lands in GnuTLS's record parser 2197 * rather than in MHD, which is why the generator spends only one shape 2198 * on it. 2199 */ 2200 static void 2201 gen_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 2234 /** 2235 * Number of leading entries of #prio_tbl that GnuTLS accepts. Beyond 2236 * that the daemon refuses to start, which is a fine thing to fuzz but a 2237 * poor way to reach the handshake. 2238 */ 2239 #define PRIO_VALID_COUNT 7 2240 2241 2242 /** 2243 * Constrain the configuration bytes so that MHD_start_daemon() actually 2244 * succeeds. Used by the shapes whose point is what happens *after* the 2245 * daemon is up; the option surface itself is fuzzed by the shapes that 2246 * do not call this. 2247 */ 2248 static void 2249 make_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 2260 /** 2261 * Emit one segment with the given op code. 2262 */ 2263 static void 2264 emit_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 2282 static size_t 2283 fuzz_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 2303 forced_shape_read = 1; 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 2468 struct seed_part 2469 { 2470 unsigned int op; /**< 0 send, 1 server name, 2 send+pump, 3 new */ 2471 const char *txt; /**< NUL terminated payload */ 2472 }; 2473 2474 struct 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. */ 2485 static 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 2742 static uint8_t seed_render_buf[2048]; 2743 2744 2745 static size_t 2746 fuzz_seed_count (void) 2747 { 2748 return sizeof (seeds) / sizeof (seeds[0]); 2749 } 2750 2751 2752 static const uint8_t * 2753 fuzz_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 2787 int 2788 LLVMFuzzerTestOneInput (const uint8_t *data, 2789 size_t size) 2790 { 2791 fuzz_ignore_sigpipe (); 2792 (void) data; 2793 (void) size; 2794 return 0; 2795 } 2796 2797 2798 static size_t 2799 fuzz_generate (struct fuzz_rng *rng, 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 2811 static const uint8_t no_https_seed[] = { 0 }; 2812 2813 2814 static size_t 2815 fuzz_seed_count (void) 2816 { 2817 return 1; 2818 } 2819 2820 2821 static const uint8_t * 2822 fuzz_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 */