fuzz_tls.c (78790B)
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 handshake state machine of connection_https.c 40 * (#MHD_TLS_CONN_INIT -> HANDSHAKING -> CONNECTED / TLS_FAILED) and 41 * what MHD does when the handshake fails, is abandoned half way, or 42 * the peer disappears while MHD is still in it; 43 * - the transition from the handshake to the ordinary HTTP parser, and 44 * the TLS receive/send adapters and @c gnutls_bye() shutdown path that 45 * the connection uses afterwards. 46 * 47 * To reach that last group the harness contains a real, in-process GnuTLS 48 * *client*. Both ends of an @c AF_UNIX @c socketpair() are non-blocking 49 * and everything runs in one thread: the client's @c gnutls_handshake() 50 * is called until it answers @c GNUTLS_E_AGAIN, then the daemon is pumped 51 * with MHD_run(), and so on. No threads, no ports, no TCP stack, and -- 52 * because the client's handshake timeout is set to 53 * @c GNUTLS_INDEFINITE_TIMEOUT -- no wall clock either. 54 * 55 * Input format (see README): 56 * 57 * byte 0 certificate/key pair selector (valid, mismatched, truncated, 58 * garbage, absent, or built from the fuzzer's own bytes) 59 * byte 1 which TLS daemon options to pass at all (bitmask) 60 * 0x01 MHD_OPTION_HTTPS_MEM_TRUST 61 * 0x02 MHD_OPTION_HTTPS_MEM_DHPARAMS 62 * 0x04 MHD_OPTION_HTTPS_CERT_CALLBACK (the SNI callback) 63 * 0x08 MHD_OPTION_HTTPS_PRIORITIES[_APPEND] 64 * 0x10 MHD_OPTION_HTTPS_CRED_TYPE 65 * 0x20 MHD_OPTION_TLS_NO_ALPN 66 * 0x40 MHD_OPTION_HTTPS_KEY_PASSWORD 67 * 0x80 use _PRIORITIES_APPEND instead of _PRIORITIES 68 * byte 2 priority string selector 69 * byte 3 bits 0-2 credential type (certificate, PSK, anon, SRP, IA, 70 * and two values GnuTLS does not define) 71 * bits 3-5 SNI callback behaviour 72 * bit 6 trust blob: CA certificate or garbage 73 * bit 7 DH parameters: valid or garbage 74 * byte 4 bits 0-1 client mode 75 * 0 raw bytes, 1 real TLS client, 76 * 2 real client, handshake abandoned half way, 77 * 3 raw bytes shaped like TLS records 78 * bit 2 client sends a server name (SNI) 79 * bit 3 client presents a client certificate 80 * bits 4-5 client priority string selector 81 * bit 6 gnutls_bye() before closing 82 * bit 7 shutdown(SHUT_WR) before closing 83 * byte 5 low nibble MHD_OPTION_CONNECTION_MEMORY_LIMIT selector 84 * high nibble event loop: MHD_run() vs MHD_get_fdset*() + 85 * MHD_run_from_select*() 86 * byte 6 handler behaviour and introspection 87 * bits 0-1 response constructor 88 * bit 2 MHD_get_connection_info() for the TLS members 89 * bit 3 MHD_get_daemon_info() 90 * bit 4 MHD_set_connection_option() 91 * bit 5 answer 403 instead of 200 92 * bit 6 add a response header 93 * bit 7 MHD_quiesce_daemon() before stopping 94 * byte 7 bits 0-2 handshake round budget (client mode 2) 95 * bit 3 pass the HTTPS options to a daemon started *without* 96 * MHD_USE_TLS 97 * bit 4 MHD_ALLOW_UPGRADE 98 * bits 5-7 extra pump rounds 99 * byte 8 how many bytes of the segment stream are spliced into the 100 * fuzzer-built PEM blobs (see cred_tbl entries 12 and 13) 101 * byte 9 bits 0-2 the server name the client presents, as an index 102 * into a small built-in table; an op 1 segment overrides it 103 * byte 10. a sequence of segments, each introduced by a little-endian 104 * 16 bit header (op << 14) | length 105 * op 0 send the payload 106 * op 1 the payload is the server name the *next* client 107 * connection presents; nothing is sent 108 * op 2 send the payload and pump the daemon extra rounds 109 * op 3 close the connection, open a fresh one (which means 110 * a fresh handshake), then send 111 * 112 * All ten configuration bytes are mandatory; a shorter input is 113 * rejected. 114 * 115 * The segment encoding is byte-for-byte the one fuzz_request uses, and 116 * `corpus/` is shared by every harness in this directory (see README 117 * section 3), so the seeds below deliberately contain **no op 1 118 * segment**: fuzz_request reads op 1 as the declared decoded request 119 * body of its own body oracle, and would report a spurious finding when 120 * it replays a fuzz_tls seed. That is what byte 9 is for. Inputs the 121 * generator or a mutator produces may use op 1 freely -- they never end 122 * up in `corpus/`. 123 * 124 * The certificates and keys are the ones from 125 * `src/testcurl/https/tls_test_keys.h` (the CA certificate, the 126 * CA-signed server certificate with its key, and the self-signed server 127 * certificate with its key), reproduced verbatim so that this harness 128 * stays a single translation unit. The DH parameters are RFC 3526 129 * group 14, as emitted by `certtool --get-dh-params --sec-param medium`. 130 * 131 * The whole harness is guarded by #HTTPS_SUPPORT: `contrib/oss-fuzz/ 132 * build.sh` configures `--disable-https` (that is what makes the 133 * MemorySanitizer build possible), and in such a build this file must 134 * still compile to a valid, trivially passing fuzz target. 135 */ 136 137 #define FUZZ_HARNESS_NAME "fuzz_tls" 138 #include "fuzz_common.h" 139 140 /* Pulls in MHD_config.h, which is where HTTPS_SUPPORT is defined. It 141 must come before <microhttpd.h>: it also settles FD_SETSIZE. */ 142 #include "mhd_options.h" 143 144 #ifdef HTTPS_SUPPORT 145 146 #include <microhttpd.h> 147 #include <gnutls/gnutls.h> 148 #include <gnutls/abstract.h> 149 #include <sys/socket.h> 150 #include <netinet/in.h> 151 #include <sys/select.h> 152 #include <arpa/inet.h> 153 154 /** 155 * LeakSanitizer suppressions, compiled into the harness so that they 156 * cannot be forgotten on the command line. 157 * 158 * There is exactly one entry and it is *not* about MHD. GnuTLS 3.8.9 159 * leaks the partially parsed certificate when a PEM certificate blob 160 * ends before its "-----END CERTIFICATE-----" line: 161 * 162 * gnutls_certificate_allocate_credentials (&cred); 163 * gnutls_certificate_set_x509_key_mem (cred, &truncated_cert, 164 * &good_key, 165 * GNUTLS_X509_FMT_PEM); 166 * -> GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR (-207) 167 * gnutls_certificate_free_credentials (cred); 168 * 169 * leaks 9672 bytes in 57 allocations with no libmicrohttpd in the 170 * picture at all (reproduced with a 40 line program). MHD passes the 171 * blob straight through and frees the credentials on every path, so 172 * there is nothing for MHD to fix and nothing for this harness to find; 173 * GnuTLS is fuzzed separately by its own OSS-Fuzz project. 174 * 175 * The suppression matches only allocations made *inside* GnuTLS's 176 * certificate parser. A credential object leaked by MHD itself is a 177 * direct leak from gnutls_certificate_allocate_credentials() and is 178 * still reported, as is every other MHD allocation. 179 */ 180 const char * 181 __lsan_default_suppressions (void); 182 183 const char * 184 __lsan_default_suppressions (void) 185 { 186 return "leak:gnutls_x509_crt_init\n"; 187 } 188 189 190 #define MAX_SEGMENTS 48 191 #define MAX_CONNECTIONS 3 192 #define RESP_BUF_SIZE 16384 193 #define GEN_BUF_SIZE 4096 194 #define MAX_SNI_LEN 255 195 #define FUZZ_PEM_BODY_MAX 1024 196 197 /** Number of client priority strings offered to the input. */ 198 #define CLIENT_PRIO_COUNT 4 199 200 /** 201 * Upper bound on the number of client/server round trips spent on one 202 * handshake. A TLS 1.3 handshake over a socketpair needs a handful; the 203 * cap only has to guarantee termination. 204 */ 205 #define HANDSHAKE_ROUNDS 64 206 207 208 /* ------------------------------------------------------------------ */ 209 /* Test credentials */ 210 /* ------------------------------------------------------------------ */ 211 212 /* 213 * Taken verbatim from src/testcurl/https/tls_test_keys.h (the CA 214 * certificate, the CA-signed server certificate and its key, and the 215 * self-signed server certificate and its key), so that this harness 216 * stays a single translation unit. dh_params_pem is RFC 3526 group 14, 217 * as emitted by "certtool --get-dh-params --sec-param medium". 218 */ 219 220 static const char ca_cert_pem[] = 221 "-----BEGIN CERTIFICATE-----\n" 222 "MIIGITCCBAmgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCUlUx\n" 223 "DzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MRswGQYDVQQKDBJ0ZXN0\n" 224 "LWxpYm1pY3JvaHR0cGQxITAfBgkqhkiG9w0BCQEWEm5vYm9keUBleGFtcGxlLm9y\n" 225 "ZzEQMA4GA1UEAwwHdGVzdC1DQTAgFw0yMTA0MDcxNzM2MThaGA8yMTIxMDMxNDE3\n" 226 "MzYxOFowgYExCzAJBgNVBAYTAlJVMQ8wDQYDVQQIDAZNb3Njb3cxDzANBgNVBAcM\n" 227 "Bk1vc2NvdzEbMBkGA1UECgwSdGVzdC1saWJtaWNyb2h0dHBkMSEwHwYJKoZIhvcN\n" 228 "AQkBFhJub2JvZHlAZXhhbXBsZS5vcmcxEDAOBgNVBAMMB3Rlc3QtQ0EwggIiMA0G\n" 229 "CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDdaWupA4qZjCBNkJoJOm5xnCaizl36\n" 230 "ZLUwp4xBL/YfXPWE3LkmAREiVI/YnAb8l6G7CJnz8dTsOJWkNXG6T1KVP5/2RvBI\n" 231 "IaaaufRIAl7hEnj1j9E2hQlV2fxF2ZNhz+nqi0LqKV4LJSpclkXADf2FA9HsVRP/\n" 232 "B7zYh+DP0fSU8V6bsu8XCeRGshroAPrc8rH8lFEEXpNLNIqQr8yKx6SmdB6hfja6\n" 233 "6SQ0++qBhl0aJtn4LHWZohgjBmkIaGFPYIJLgxQ/xyp2Grz2q7lGKJ+zBkBF8iOP\n" 234 "t3x+F1hSCBnr/DGYWmjEm5tYm+7pyuriPddXdCc8+qa2LxMZo3EXxLo5YISpPCyw\n" 235 "Z7V3YAOZTr3m1C24LiYvPehCq1CTIkhhmqtlVJXU7ISD48cx9y+5Pi34wtbTI/gN\n" 236 "x4voyTLAfyavKMmIpxxIRsWldiF2n06HdvCRVdihDQUad10ygTmWf1J/s2ZETAtH\n" 237 "QaSd7MD389t6nQFtTIXigsNKnnDPlrtxt7rOLvLQeR0K04Gzrf/scheOanRAfOXH\n" 238 "KNBFU7YkDFG8rqizlC65rx9qeXFYXQcHZTuqxK7tgZnSgJat3E70VbTSCsEEG7eR\n" 239 "bNX/fChUKAIIpWaiW6HDlKLl6m2y+BzM91umBsKOqTvntMVFBSF9pVYlXK854aIR\n" 240 "q8A2Xujd012seQIDAQABo4GfMIGcMAsGA1UdDwQEAwICpDASBgNVHRMBAf8ECDAG\n" 241 "AQH/AgEBMB0GA1UdDgQWBBRYdUPApWoxw4U13Rqsjf9AHdbpLDATBgNVHSUEDDAK\n" 242 "BggrBgEFBQcDATAkBglghkgBhvhCAQ0EFxYVVGVzdCBsaWJtaWNyb2h0dHBkIENB\n" 243 "MB8GA1UdIwQYMBaAFFh1Q8ClajHDhTXdGqyN/0Ad1uksMA0GCSqGSIb3DQEBCwUA\n" 244 "A4ICAQBvrrcTKVeI1EYnXo4BQD4oCvf9z1fYQmL21EbHwgjg1nmaPkvStgWAc5p1\n" 245 "kKwySrpEMKXfu68X76RccXZyWWIamEjz2OCWYZgjX6d6FpjhLphL8WxXDy5C9eay\n" 246 "ixN7+URz2XQoi22wqR+tCPDhrIzcMPyMkx/6gRgcYeDnaFrkdSeSsKsID4plfcIj\n" 247 "ISWJDvv+IAgrtsG1NVHnGwpAv0od3A8/4/fR6PPyewaU3aydvjZ7Au8O9DGDjlU9\n" 248 "9HdlOkkY6GVJ1pfGZib7cV7lhy0D2kj1g9xZh97YjpoUfppPl9r+6A8gDm0hXlAD\n" 249 "TlzNYlwTb681ZEoSd9PiLEY8HETssHlays2dYXdcNwAEp69iIHz8q1Q98Be9LScl\n" 250 "WEzgaOT9U7lpIw/MWbELoMsC+Ecs1cVWBIuiIq8aSG2kRr1x3S8yVXbAohAXif2s\n" 251 "E6puieM/VJ25iaNhkbLmDkk58QVVmn9NZNv6ETxuSQMp9e0EwbVlj68vzClQ91Y/\n" 252 "nmAiGcLFUEwB9G0szv9+vR+oDW4IkvdFZSUbcICd2cnynnwAD395onqS4hEZO1xM\n" 253 "Gy5ZldbTMTjgn7fChNopz15ChPBnwFIjhm+S0CyiLRQAowfknRVq2IBkj7/5kOWg\n" 254 "4mcxcq76HoQWK/8X/8RFL1eFVAvY7TNHYJ0RS51DMuwCNQictA==\n" 255 "-----END CERTIFICATE-----\n"; 256 257 258 static const char srv_signed_key_pem[] = 259 "-----BEGIN PRIVATE KEY-----\n" 260 "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCff7amw9zNSE+h\n" 261 "rOMhBrzbbsJluUP3gmd8nOKY5MUimoPkxmAXfp2L0il+MPZT/ZEmo11q0k6J2jfG\n" 262 "UBQ+oZW9ahNZ9gCDjbYlBblo/mqTai+LdeLO3qk53d0zrZKXvCO6sA3uKpG2WR+g\n" 263 "+sNKxfYpIHCpanqBU6O+degIV/+WKy3nQ2Fwp7K5HUNj1u0pg0QQ18yf68LTnKFU\n" 264 "HFjZmmaaopWki5wKSBieHivzQy6w+04HSTogHHRK/y/UcoJNSG7xnHmoPPo1vLT8\n" 265 "CMRIYnSSgU3wJ43XBJ80WxrC2dcoZjV2XZz+XdQwCD4ZrC1ihykcAmiQA+sauNm7\n" 266 "dztOMkGzAgMBAAECggEAIbKDzlvXDG/YkxnJqrKXt+yAmak4mNQuNP+YSCEdHSBz\n" 267 "+SOILa6MbnvqVETX5grOXdFp7SWdfjZiTj2g6VKOJkSA7iKxHRoVf2DkOTB3J8np\n" 268 "XZd8YaRdMGKVV1O2guQ20Dxd1RGdU18k9YfFNsj4Jtw5sTFTzHr1P0n9ybV9xCXp\n" 269 "znSxVfRg8U6TcMHoRDJR9EMKQMO4W3OQEmreEPoGt2/+kMuiHjclxLtbwDxKXTLP\n" 270 "pD0gdg3ibvlufk/ccKl/yAglDmd0dfW22oS7NgvRKUve7tzDxY1Q6O5v8BCnLFSW\n" 271 "D+z4hS1PzooYRXRkM0xYudvPkryPyu+1kEpw3fNsoQKBgQDRfXJo82XQvlX8WPdZ\n" 272 "Ts3PfBKKMVu3Wf8J3SYpuvYT816qR3ot6e4Ivv5ZCQkdDwzzBKe2jAv6JddMJIhx\n" 273 "pkGHc0KKOodd9HoBewOd8Td++hapJAGaGblhL5beIidLKjXDjLqtgoHRGlv5Cojo\n" 274 "zHa7Viel1eOPPcBumhp83oJ+mQKBgQDC6PmdETZdrW3QPm7ZXxRzF1vvpC55wmPg\n" 275 "pRfTRM059jzRzAk0QiBgVp3yk2a6Ob3mB2MLfQVDgzGf37h2oO07s5nspSFZTFnM\n" 276 "KgSjFy0xVOAVDLe+0VpbmLp1YUTYvdCNowaoTE7++5rpePUDu3BjAifx07/yaSB+\n" 277 "W+YPOfOuKwKBgQCGK6g5G5qcJSuBIaHZ6yTZvIdLRu2M8vDral5k3793a6m3uWvB\n" 278 "OFAh/eF9ONJDcD5E7zhTLEMHhXDs7YEN+QODMwjs6yuDu27gv97DK5j1lEsrLUpx\n" 279 "XgRjAE3KG2m7NF+WzO1K74khWZaKXHrvTvTEaxudlO3X8h7rN3u7ee9uEQKBgQC2\n" 280 "wI1zeTUZhsiFTlTPWfgppchdHPs6zUqq0wFQ5Zzr8Pa72+zxY+NJkU2NqinTCNsG\n" 281 "ePykQ/gQgk2gUrt595AYv2De40IuoYk9BlTMuql0LNniwsbykwd/BOgnsSlFdEy8\n" 282 "0RQn70zOhgmNSg2qDzDklJvxghLi7zE5aV9//V1/ewKBgFRHHZN1a8q/v8AAOeoB\n" 283 "ROuXfgDDpxNNUKbzLL5MO5odgZGi61PBZlxffrSOqyZoJkzawXycNtoBP47tcVzT\n" 284 "QPq5ZOB3kjHTcN7dRLmPWjji9h4O3eHCX67XaPVMSWiMuNtOZIg2an06+jxGFhLE\n" 285 "qdJNJ1DkyUc9dN2cliX4R+rG\n" 286 "-----END PRIVATE KEY-----\n"; 287 288 289 static const char srv_signed_cert_pem[] = 290 "-----BEGIN CERTIFICATE-----\n" 291 "MIIFSzCCAzOgAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCUlUx\n" 292 "DzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MRswGQYDVQQKDBJ0ZXN0\n" 293 "LWxpYm1pY3JvaHR0cGQxITAfBgkqhkiG9w0BCQEWEm5vYm9keUBleGFtcGxlLm9y\n" 294 "ZzEQMA4GA1UEAwwHdGVzdC1DQTAgFw0yMjA0MjAxODQzMDJaGA8yMTIyMDMyNjE4\n" 295 "NDMwMlowZTELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwG\n" 296 "TW9zY293MRswGQYDVQQKDBJ0ZXN0LWxpYm1pY3JvaHR0cGQxFzAVBgNVBAMMDnRl\n" 297 "c3QtbWhkc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn3+2\n" 298 "psPczUhPoazjIQa8227CZblD94JnfJzimOTFIpqD5MZgF36di9IpfjD2U/2RJqNd\n" 299 "atJOido3xlAUPqGVvWoTWfYAg422JQW5aP5qk2ovi3Xizt6pOd3dM62Sl7wjurAN\n" 300 "7iqRtlkfoPrDSsX2KSBwqWp6gVOjvnXoCFf/list50NhcKeyuR1DY9btKYNEENfM\n" 301 "n+vC05yhVBxY2ZpmmqKVpIucCkgYnh4r80MusPtOB0k6IBx0Sv8v1HKCTUhu8Zx5\n" 302 "qDz6Nby0/AjESGJ0koFN8CeN1wSfNFsawtnXKGY1dl2c/l3UMAg+GawtYocpHAJo\n" 303 "kAPrGrjZu3c7TjJBswIDAQABo4HmMIHjMAsGA1UdDwQEAwIFoDAMBgNVHRMBAf8E\n" 304 "AjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMBMDEGA1UdEQQqMCiCDnRlc3QtbWhk\n" 305 "c2VydmVyhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMB0GA1UdDgQWBBQ57Z06WJae\n" 306 "8fJIHId4QGx/HsRgDDAoBglghkgBhvhCAQ0EGxYZVGVzdCBsaWJtaWNyb2h0dHBk\n" 307 "IHNlcnZlcjARBglghkgBhvhCAQEEBAMCBkAwHwYDVR0jBBgwFoAUWHVDwKVqMcOF\n" 308 "Nd0arI3/QB3W6SwwDQYJKoZIhvcNAQELBQADggIBAI7Lggm/XzpugV93H5+KV48x\n" 309 "X+Ct8unNmPCSzCaI5hAHGeBBJpvD0KME5oiJ5p2wfCtK5Dt9zzf0S0xYdRKqU8+N\n" 310 "aKIvPoU1hFixXLwTte1qOp6TviGvA9Xn2Fc4n36dLt6e9aiqDnqPbJgBwcVO82ll\n" 311 "HJxVr3WbrAcQTB3irFUMqgAke/Cva9Bw79VZgX4ghb5EnejDzuyup4pHGzV10Myv\n" 312 "hdg+VWZbAxpCe0S4eKmstZC7mWsFCLeoRTf/9Pk1kQ6+azbTuV/9QOBNfFi8QNyb\n" 313 "18jUjmm8sc2HKo8miCGqb2sFqaGD918hfkWmR+fFkzQ3DZQrT+eYbKq2un3k0pMy\n" 314 "UySy8SRn1eadfab+GwBVb68I9TrPRMrJsIzysNXMX4iKYl2fFE/RSNnaHtPw0C8y\n" 315 "B7memyxPRl+H2xg6UjpoKYh3+8e44/XKm0rNIzXjrwA8f8gnw2TbqmMDkj1YqGnC\n" 316 "SCj5A27zUzaf2pT/YsnQXIWOJjVvbEI+YKj34wKWyTrXA093y8YI8T3mal7Kr9YM\n" 317 "WiIyPts0/aVeziM0Gunglz+8Rj1VesL52FTurobqusPgM/AME82+qb/qnxuPaCKj\n" 318 "OT1qAbIblaRuWqCsid8BzP7ZQiAnAWgMRSUg1gzDwSwRhrYQRRWAyn/Qipzec+27\n" 319 "/w0gW9EVWzFhsFeGEssi\n" 320 "-----END CERTIFICATE-----\n"; 321 322 323 static const char srv_self_signed_cert_pem[] = 324 "-----BEGIN CERTIFICATE-----\n" 325 "MIIDJzCCAg+gAwIBAgIUOKf6e6Heee2XA+yF5St3t+fVM40wDQYJKoZIhvcNAQEF\n" 326 "BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTIyMTAxMDA4MzQ0N1oYDzIxMjIw\n" 327 "OTE2MDgzNDQ3WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB\n" 328 "AQUAA4IBDwAwggEKAoIBAQClivgF8Xq0ekQli++0l7Q5JFwJCuLf04Cb1UKIS80U\n" 329 "CfphFd1ILJepNw4bWR3OV1sRI1vFiw6LnCz53vOwVNyiZ+sMGi4bDX4AV9Xd+F83\n" 330 "xhG8AjOmKTayW0TxSIvt47Qd5S/4fgraxMtvqrRRBen30iKOwX7uNF/4dYb9vdin\n" 331 "OldV/e8uzbqSurMGkNDznOeSaNBmdO/7x0VMFZM2hwmHyiiw75/j4BhUlLCcMEvK\n" 332 "oN+YHNCNcTt3Qm1vVuiGXmh9QreOV09Gc1SzAltxF2gmI0jzw8r/duz18QXMNsMw\n" 333 "El/Ah4+02gR70L7qlgttN1NPU3RJpK/L34J7yg649wHTAgMBAAGjbzBtMB0GA1Ud\n" 334 "DgQWBBROVferD+YYcV1YEnFgC0jYm5X9BjAfBgNVHSMEGDAWgBROVferD+YYcV1Y\n" 335 "EnFgC0jYm5X9BjAPBgNVHRMBAf8EBTADAQH/MBoGA1UdEQQTMBGCCWxvY2FsaG9z\n" 336 "dIcEfwAAATANBgkqhkiG9w0BAQUFAAOCAQEAoRbozsm5xXdNX3VO++s2LMzw5KM9\n" 337 "RpIInHNkMJbnyLJFKJ8DF7nTxSGCA38YMkX3tphPNKZXbg+V64Dqr/XpzOVyiinU\n" 338 "7hIwyUdSSKKyErZxIWR97lY6Q3SOyPAg8ZElbtvSsSzmd772VE23VTXGDi7AW0PQ\n" 339 "hag9N2EEnHURMvID15O+UXyFpDdyUyQIbx3HuswsGDH9xBTm4irLyrZwO0KwKg5a\n" 340 "JBeUiPs0SYRRfn9/MoE6VwAnmOCg3LLR6ZPU3hQtTPLHj2Op1g5fey3X3X6lC+JC\n" 341 "K6dNZc1zBFPz8KANGUsFYbmoP2bvAAA+6KwCnZZEflUgE7/HFEmQhVOezw==\n" 342 "-----END CERTIFICATE-----\n"; 343 344 345 static const char srv_self_signed_key_pem[] = 346 "-----BEGIN PRIVATE KEY-----\n" 347 "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQClivgF8Xq0ekQl\n" 348 "i++0l7Q5JFwJCuLf04Cb1UKIS80UCfphFd1ILJepNw4bWR3OV1sRI1vFiw6LnCz5\n" 349 "3vOwVNyiZ+sMGi4bDX4AV9Xd+F83xhG8AjOmKTayW0TxSIvt47Qd5S/4fgraxMtv\n" 350 "qrRRBen30iKOwX7uNF/4dYb9vdinOldV/e8uzbqSurMGkNDznOeSaNBmdO/7x0VM\n" 351 "FZM2hwmHyiiw75/j4BhUlLCcMEvKoN+YHNCNcTt3Qm1vVuiGXmh9QreOV09Gc1Sz\n" 352 "AltxF2gmI0jzw8r/duz18QXMNsMwEl/Ah4+02gR70L7qlgttN1NPU3RJpK/L34J7\n" 353 "yg649wHTAgMBAAECggEAERbbCtYGakoy7cNX8Ac3Kiz4OVC/4gZWAQBPeX2FwrtS\n" 354 "9yHIMbK0x1mxIZ6eBpabBpZlW2vDCSOKuxLKiloAWt2qdJnhR5apesSWhe8leT7/\n" 355 "xq5dgZpAlMH6SIRKObknd2yY+qicW0A0licDrVeUcypkueL8xP9wJtiPInOuQXkI\n" 356 "QROhB13eStRuRKYwOn5gtwAHJ+J1DFKKiqpBOkrSYf4625StGegJO9+bjK0ei+0W\n" 357 "tp6unpiwA/lXTgz6Xim1Z3fzWs4XjFgVKzK5s/6yBJjr8spHX6lv7QsahP4w6HZ/\n" 358 "VcRxP6cJNd/otiTEtJXpbxiiyccwXm/AOcOn22P1cQKBgQDAnY/0G/ap/G98pneE\n" 359 "suzNXhWOQ8JoL8d66Io8vwTvfiJggfgUcwblI7pPCrSlaZMR7/q6JImE53lZtPk8\n" 360 "eI3c9lN0ocr8E7+huDpYdk7cMYj9SuxySsXoMLiMqzHFi+NcIhKMF56kk6a5CFCt\n" 361 "yP1Ofy76LVweGE3XvTwpwE7wUQKBgQDcBLyH1cC71s0I0Gz28AyELV9hPhasjAKO\n" 362 "12CVbeBVTPd+28uk/3o80wSrTksc6H5ehAA2aTvrb4OhwssWNL+D0fS8YK2cJ3V0\n" 363 "FJxGAM266+vC4d/8jRTHJnc+6PP3ix5t6vAt+K2Y0fePtefLqf4ebgXx/ODAj3J2\n" 364 "aZKBldjK4wKBgGIRFpTLk/eR/dUyEBHw4x3gdAsdtqJDCUYrlQ4+ly20Q55tLbiD\n" 365 "pBQP77CEm9rH+MgeLcKODbIsBB3HRUojet7wTydHpMhY6a1V1ebqPVZgpgWIGwBJ\n" 366 "z59bBusf0lRo15Y2Bslq0SurvSvh7um8NjO8D1fytj7gUumvgC0lq0sxAoGBAI1+\n" 367 "kkx9IBTtIDER8XGhkTsT/uoHxwcyh5abVmbjIclZ1TUFX2L+Vft17ePJVy8BKfvY\n" 368 "wlY7uShBMBNAteDTDXNV/CGFv0DUc4myk4nFjIkwng9XufeuN3WX/Eo+AF/rXSdt\n" 369 "VwcJjYLhTWdjoe1tppqlQTeN3HCaEA+s92ZVGvXnAoGAMCXGS6WZl1e5wsHRq0Yy\n" 370 "8Ef2Wrk620bBjKHolkTfvgfhlvxeZM1sv1ioZGsOeQ0z7O7wdJhvL0M/WAG+3yQj\n" 371 "HSXp81T1vOICPwNYZf8xcvbLKmvj7rHFt6ZAZF2o4EK8ReZTRyA3DUpBCDY+s3FN\n" 372 "GmBv0D7N3QP0CT3SzfQrPkc=\n" 373 "-----END PRIVATE KEY-----\n"; 374 375 376 static const char dh_params_pem[] = 377 "-----BEGIN DH PARAMETERS-----\n" 378 "MIIBDAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n" 379 "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n" 380 "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\n" 381 "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n" 382 "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\n" 383 "ssbzSibBsu/6iGtCOGEoXJf//////////wIBAgICAQA=\n" 384 "-----END DH PARAMETERS-----\n"; 385 386 /** A PEM blob whose armour is fine but whose payload is not base64. */ 387 static const char garbage_cert_pem[] = 388 "-----BEGIN CERTIFICATE-----\n" 389 "this is not base64 at all, not even close !!!! ????\n" 390 "-----END CERTIFICATE-----\n"; 391 392 static const char garbage_key_pem[] = 393 "-----BEGIN PRIVATE KEY-----\n" 394 "@@@@ neither is this @@@@\n" 395 "-----END PRIVATE KEY-----\n"; 396 397 /** Correct base64, but the armour never ends. */ 398 static const char truncated_cert_pem[] = 399 "-----BEGIN CERTIFICATE-----\n" 400 "MIIFSzCCAzOgAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCUlUx\n" 401 "DzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MRswGQYDVQQKDBJ0ZXN0\n"; 402 403 static const char truncated_key_pem[] = 404 "-----BEGIN PRIVATE KEY-----\n" 405 "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCff7amw9zNSE+h\n"; 406 407 /** Base64 of a certificate, but with no PEM armour at all. */ 408 static const char no_armour_pem[] = 409 "MIIFSzCCAzOgAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCUlUx\n" 410 "DzANBgNVBAgMBk1vc2NvdzEPMA0GA1UEBwwGTW9zY293MRswGQYDVQQKDBJ0ZXN0\n"; 411 412 static const char garbage_dh_pem[] = 413 "-----BEGIN DH PARAMETERS-----\n" 414 "not-dh-parameters\n" 415 "-----END DH PARAMETERS-----\n"; 416 417 /** 418 * PEM blobs assembled from the fuzzer's own bytes, see cred_tbl entries 419 * 12 and 13. Static so that the pointer handed to MHD stays valid for 420 * the whole lifetime of the daemon. 421 */ 422 static char fuzz_cert_pem[FUZZ_PEM_BODY_MAX + 128]; 423 static char fuzz_key_pem[FUZZ_PEM_BODY_MAX + 128]; 424 425 426 /** 427 * A certificate/key pair for #MHD_OPTION_HTTPS_MEM_CERT and 428 * #MHD_OPTION_HTTPS_MEM_KEY. A NULL member means "do not pass the 429 * option at all", which is a configuration MHD has to reject cleanly. 430 */ 431 struct cred_pair 432 { 433 const char *cert; 434 const char *key; 435 }; 436 437 static const struct cred_pair cred_tbl[] = { 438 { srv_signed_cert_pem, srv_signed_key_pem }, /* 0 valid, CA signed */ 439 { srv_self_signed_cert_pem, srv_self_signed_key_pem }, /* 1 valid, self signed */ 440 { srv_signed_cert_pem, srv_self_signed_key_pem }, /* 2 key does not match */ 441 { srv_self_signed_cert_pem, srv_signed_key_pem }, /* 3 key does not match */ 442 { srv_signed_cert_pem, NULL }, /* 4 certificate only */ 443 { NULL, srv_signed_key_pem }, /* 5 key only */ 444 { NULL, NULL }, /* 6 neither */ 445 { "", "" }, /* 7 empty strings */ 446 { truncated_cert_pem, srv_signed_key_pem }, /* 8 truncated armour */ 447 { srv_signed_cert_pem, truncated_key_pem }, /* 9 truncated armour */ 448 { garbage_cert_pem, garbage_key_pem }, /* 10 armour, no base64 */ 449 { no_armour_pem, srv_signed_key_pem }, /* 11 base64, no armour */ 450 { fuzz_cert_pem, srv_signed_key_pem }, /* 12 PEM from the input */ 451 { srv_signed_cert_pem, fuzz_key_pem }, /* 13 PEM from the input */ 452 { fuzz_cert_pem, fuzz_key_pem }, /* 14 PEM from the input */ 453 { srv_signed_cert_pem, srv_signed_key_pem } /* 15 valid (bias) */ 454 }; 455 456 #define CRED_COUNT (sizeof (cred_tbl) / sizeof (cred_tbl[0])) 457 458 /** 459 * Priority strings. The first entries are the ones a real server would 460 * use, the rest are what MHD has to reject without falling over. MHD 461 * hands these to gnutls_priority_init() (or appends them to its own 462 * base string) and fails daemon startup if GnuTLS does not like them. 463 */ 464 static const char *const prio_tbl[] = { 465 "NORMAL", 466 "NORMAL:-VERS-ALL:+VERS-TLS1.3", 467 "NORMAL:-VERS-ALL:+VERS-TLS1.2", 468 "SECURE128", 469 "PERFORMANCE", 470 "@LIBMICROHTTPD", 471 "@SYSTEM", 472 "NONE", 473 "", 474 "BOGUS-PRIORITY-STRING", 475 "NORMAL:!!!", 476 "NORMAL:-VERS-ALL", 477 "NORMAL:+ANON-ECDH", 478 "NORMAL:%SERVER_PRECEDENCE", 479 "SECURE256:-CIPHER-ALL", 480 ":::::" 481 }; 482 483 #define PRIO_COUNT (sizeof (prio_tbl) / sizeof (prio_tbl[0])) 484 485 /** Priority strings offered to the *client* side. */ 486 static const char *const client_prio_tbl[CLIENT_PRIO_COUNT] = { 487 "NORMAL", 488 "NORMAL:-VERS-ALL:+VERS-TLS1.3", 489 "NORMAL:-VERS-ALL:+VERS-TLS1.2", 490 "PERFORMANCE" 491 }; 492 493 /** 494 * Credential types. Only GNUTLS_CRD_CERTIFICATE and GNUTLS_CRD_PSK are 495 * accepted by MHD_TLS_init(); everything else must make daemon startup 496 * fail rather than reach the MHD_PANIC() in new_connection_prepare_(). 497 */ 498 static const int cred_type_tbl[] = { 499 (int) GNUTLS_CRD_CERTIFICATE, 500 (int) GNUTLS_CRD_PSK, 501 (int) GNUTLS_CRD_ANON, 502 (int) GNUTLS_CRD_SRP, 503 (int) GNUTLS_CRD_IA, 504 (int) GNUTLS_CRD_CERTIFICATE, 505 99, 506 -1 507 }; 508 509 #define CRED_TYPE_COUNT (sizeof (cred_type_tbl) / sizeof (cred_type_tbl[0])) 510 511 static const size_t mem_limit_tbl[] = { 512 0 /* MHD default */, 256, 512, 1024, 1400, 1500, 2048, 4096, 8192, 32768, 513 0, 1024, 2048, 4096, 16384, 0 514 }; 515 516 #define MEM_LIMIT_COUNT (sizeof (mem_limit_tbl) / sizeof (mem_limit_tbl[0])) 517 518 static const char https_key_password[] = "not-the-password"; 519 520 521 /* ------------------------------------------------------------------ */ 522 /* Per-iteration configuration */ 523 /* ------------------------------------------------------------------ */ 524 525 /** Behaviour of the SNI callback, selected by bits 3-5 of byte 3. */ 526 enum sni_behaviour 527 { 528 SNI_ALWAYS_OK = 0, /**< always answer with the signed pair */ 529 SNI_FAIL, /**< always answer -1 */ 530 SNI_EMPTY, /**< answer 0 with an empty certificate list */ 531 SNI_BY_NAME, /**< look the server name up, -1 if unknown */ 532 SNI_MISMATCH, /**< answer with a key that is not the cert's */ 533 SNI_NO_KEY, /**< answer 0, certificate but no key */ 534 SNI_SELF_SIGNED, /**< always answer with the self-signed pair */ 535 SNI_BEHAVIOUR_COUNT 536 }; 537 538 /** Client behaviour, selected by bits 0-1 of byte 4. */ 539 enum client_mode 540 { 541 CLIENT_RAW = 0, /**< raw bytes straight at the TLS socket */ 542 CLIENT_TLS, /**< a real GnuTLS client */ 543 CLIENT_TLS_ABANDON, /**< a real client that stops mid-handshake */ 544 CLIENT_RECORDS /**< raw bytes shaped like TLS records */ 545 }; 546 547 struct fuzz_cfg 548 { 549 /* ---- daemon ---- */ 550 const char *cert; 551 const char *key; 552 int use_tls; /**< set MHD_USE_TLS at all */ 553 int use_trust; 554 int trust_garbage; 555 int use_dhparams; 556 int dh_garbage; 557 int use_sni; 558 int use_prio; 559 int prio_append; 560 unsigned int prio_idx; 561 int use_cred_type; 562 unsigned int cred_type_idx; 563 int no_alpn; 564 int key_password; 565 int allow_upgrade; 566 size_t mem_limit; 567 unsigned int loop_mode; 568 569 /* ---- SNI callback ---- */ 570 enum sni_behaviour sni_mode; 571 572 /* ---- client ---- */ 573 enum client_mode mode; 574 int client_sni; 575 int client_cert; 576 unsigned int client_prio_idx; 577 int client_bye; 578 int client_shut_wr; 579 unsigned int hs_budget; /**< handshake rounds in CLIENT_TLS_ABANDON */ 580 unsigned int extra_pump; 581 582 /* ---- handler ---- */ 583 unsigned int resp_kind; 584 int conn_info; 585 int daemon_info; 586 int conn_option; 587 int error_reply; 588 int resp_header; 589 int quiesce; 590 }; 591 592 static struct fuzz_cfg cfg; 593 594 /** 595 * Server names the client can present. Which one is used comes from 596 * byte 9 of the input; an op 1 segment overrides it. MHD itself never 597 * looks at the name -- GnuTLS parses the extension and the application 598 * callback reads it back -- so a fixed table costs no MHD coverage. 599 */ 600 static const char *const sni_name_tbl[] = { 601 "test-mhdserver", 602 "localhost", 603 "mhdhost1", 604 "nobody.example.org", 605 "", 606 "example.org", 607 "TEST-MHDSERVER", 608 "a.very.long.name.that.nobody.has.a.certificate.for.example.org" 609 }; 610 611 #define SNI_NAME_COUNT (sizeof (sni_name_tbl) / sizeof (sni_name_tbl[0])) 612 613 /** Server name the next client connection presents. */ 614 static char sni_name[MAX_SNI_LEN + 1]; 615 static size_t sni_name_len; 616 617 /** Bytes received from the daemon during the current iteration. */ 618 static char resp_buf[RESP_BUF_SIZE]; 619 static size_t resp_len; 620 621 /** Statistics, printed at exit with --verbose. */ 622 static unsigned long stat_daemons; 623 static unsigned long stat_daemons_failed; 624 static unsigned long stat_connections; 625 static unsigned long stat_handshakes_ok; 626 static unsigned long stat_handshakes_failed; 627 static unsigned long stat_handler_calls; 628 static unsigned long stat_sni_calls; 629 static int stats_registered; 630 631 632 static void 633 print_stats (void) 634 { 635 if (! fuzz_verbose) 636 return; 637 fprintf (stderr, 638 "%s: daemons=%lu (start failed=%lu) connections=%lu " 639 "handshakes ok=%lu failed=%lu handler calls=%lu SNI calls=%lu\n", 640 FUZZ_HARNESS_NAME, 641 stat_daemons, stat_daemons_failed, stat_connections, 642 stat_handshakes_ok, stat_handshakes_failed, stat_handler_calls, 643 stat_sni_calls); 644 } 645 646 647 /* ------------------------------------------------------------------ */ 648 /* The SNI (certificate retrieve) callback */ 649 /* ------------------------------------------------------------------ */ 650 651 /** 652 * Certificates for the SNI callback, parsed once and then kept in these 653 * statics for the whole life of the process: they are configuration, not 654 * per-iteration state, and re-parsing them on every execution would cost 655 * more than everything else the harness does. They are reachable from 656 * globals, so LeakSanitizer does not count them. 657 */ 658 struct sni_host 659 { 660 const char *name; 661 const char *cert_pem; 662 const char *key_pem; 663 gnutls_pcert_st pcrt; 664 gnutls_privkey_t key; 665 int loaded; 666 }; 667 668 static struct sni_host sni_hosts[2] = { 669 { "test-mhdserver", NULL, NULL, { 0, { NULL, 0 }, 0 }, NULL, 0 }, 670 { "localhost", NULL, NULL, { 0, { NULL, 0 }, 0 }, NULL, 0 } 671 }; 672 673 static int sni_hosts_ready; 674 675 676 /** 677 * @return 0 if the certificates are usable 678 */ 679 static int 680 sni_hosts_init (void) 681 { 682 unsigned int i; 683 684 if (0 != sni_hosts_ready) 685 return (1 == sni_hosts_ready) ? 0 : -1; 686 sni_hosts[0].cert_pem = srv_signed_cert_pem; 687 sni_hosts[0].key_pem = srv_signed_key_pem; 688 sni_hosts[1].cert_pem = srv_self_signed_cert_pem; 689 sni_hosts[1].key_pem = srv_self_signed_key_pem; 690 sni_hosts_ready = 1; 691 for (i = 0; i < sizeof (sni_hosts) / sizeof (sni_hosts[0]); i++) 692 { 693 struct sni_host *h = &sni_hosts[i]; 694 gnutls_datum_t d; 695 696 d.data = (unsigned char *) (intptr_t) h->cert_pem; 697 d.size = (unsigned int) strlen (h->cert_pem); 698 if (GNUTLS_E_SUCCESS != 699 gnutls_pcert_import_x509_raw (&h->pcrt, &d, GNUTLS_X509_FMT_PEM, 0)) 700 { 701 sni_hosts_ready = -1; 702 continue; 703 } 704 if (GNUTLS_E_SUCCESS != gnutls_privkey_init (&h->key)) 705 { 706 gnutls_pcert_deinit (&h->pcrt); 707 sni_hosts_ready = -1; 708 continue; 709 } 710 d.data = (unsigned char *) (intptr_t) h->key_pem; 711 d.size = (unsigned int) strlen (h->key_pem); 712 if (GNUTLS_E_SUCCESS != 713 gnutls_privkey_import_x509_raw (h->key, &d, GNUTLS_X509_FMT_PEM, 714 NULL, 0)) 715 { 716 gnutls_privkey_deinit (h->key); 717 h->key = NULL; 718 gnutls_pcert_deinit (&h->pcrt); 719 sni_hosts_ready = -1; 720 continue; 721 } 722 h->loaded = 1; 723 } 724 return (1 == sni_hosts_ready) ? 0 : -1; 725 } 726 727 728 /** 729 * #MHD_OPTION_HTTPS_CERT_CALLBACK. Deliberately badly behaved for most 730 * of the settings of @e cfg.sni_mode: an application callback that fails 731 * or answers with nothing is exactly the case MHD has to survive. 732 */ 733 static int 734 sni_callback (gnutls_session_t session, 735 const gnutls_datum_t *req_ca_dn, 736 int nreqs, 737 const gnutls_pk_algorithm_t *pk_algos, 738 int pk_algos_length, 739 gnutls_pcert_st **pcert, 740 unsigned int *pcert_length, 741 gnutls_privkey_t *pkey) 742 { 743 char name[MAX_SNI_LEN + 1]; 744 size_t name_len = sizeof (name); 745 unsigned int type; 746 unsigned int i; 747 748 (void) req_ca_dn; 749 (void) nreqs; 750 (void) pk_algos; 751 (void) pk_algos_length; 752 stat_sni_calls++; 753 if (! sni_hosts[0].loaded) 754 return -1; 755 switch (cfg.sni_mode) 756 { 757 case SNI_FAIL: 758 return -1; 759 case SNI_EMPTY: 760 *pcert = NULL; 761 *pcert_length = 0; 762 *pkey = NULL; 763 return 0; 764 case SNI_NO_KEY: 765 *pcert = &sni_hosts[0].pcrt; 766 *pcert_length = 1; 767 *pkey = NULL; 768 return 0; 769 case SNI_MISMATCH: 770 if (! sni_hosts[1].loaded) 771 return -1; 772 *pcert = &sni_hosts[0].pcrt; 773 *pcert_length = 1; 774 *pkey = sni_hosts[1].key; 775 return 0; 776 case SNI_SELF_SIGNED: 777 if (! sni_hosts[1].loaded) 778 return -1; 779 *pcert = &sni_hosts[1].pcrt; 780 *pcert_length = 1; 781 *pkey = sni_hosts[1].key; 782 return 0; 783 case SNI_BY_NAME: 784 if (GNUTLS_E_SUCCESS != 785 gnutls_server_name_get (session, name, &name_len, &type, 0)) 786 return -1; 787 for (i = 0; i < sizeof (sni_hosts) / sizeof (sni_hosts[0]); i++) 788 if ( (sni_hosts[i].loaded) && 789 (0 == strncmp (name, sni_hosts[i].name, name_len)) ) 790 { 791 *pcert = &sni_hosts[i].pcrt; 792 *pcert_length = 1; 793 *pkey = sni_hosts[i].key; 794 return 0; 795 } 796 return -1; 797 case SNI_ALWAYS_OK: 798 case SNI_BEHAVIOUR_COUNT: 799 default: 800 break; 801 } 802 *pcert = &sni_hosts[0].pcrt; 803 *pcert_length = 1; 804 *pkey = sni_hosts[0].key; 805 return 0; 806 } 807 808 809 /* ------------------------------------------------------------------ */ 810 /* The application */ 811 /* ------------------------------------------------------------------ */ 812 813 static const char resp_body[] = "hello world over TLS"; 814 815 816 static enum MHD_Result 817 ahc (void *cls, 818 struct MHD_Connection *connection, 819 const char *url, 820 const char *method, 821 const char *version, 822 const char *upload_data, 823 size_t *upload_data_size, 824 void **req_cls) 825 { 826 static int marker; 827 struct MHD_Response *r; 828 enum MHD_Result ret; 829 830 (void) cls; 831 (void) url; 832 (void) method; 833 (void) version; 834 (void) upload_data; 835 stat_handler_calls++; 836 if (NULL == *req_cls) 837 { 838 /* first call: MHD only wants to know that we are interested */ 839 *req_cls = ▮ 840 return MHD_YES; 841 } 842 if (0 != *upload_data_size) 843 { 844 /* discard the request body */ 845 *upload_data_size = 0; 846 return MHD_YES; 847 } 848 if (cfg.conn_info) 849 { 850 /* The TLS-specific members of MHD_ConnectionInfo; all three answer 851 NULL on a connection without a session, which is a state this 852 harness can produce. */ 853 (void) MHD_get_connection_info (connection, 854 MHD_CONNECTION_INFO_CIPHER_ALGO); 855 (void) MHD_get_connection_info (connection, 856 MHD_CONNECTION_INFO_PROTOCOL); 857 (void) MHD_get_connection_info (connection, 858 MHD_CONNECTION_INFO_GNUTLS_SESSION); 859 (void) MHD_get_connection_info (connection, 860 MHD_CONNECTION_INFO_GNUTLS_CLIENT_CERT); 861 (void) MHD_get_connection_info (connection, 862 MHD_CONNECTION_INFO_CLIENT_ADDRESS); 863 (void) MHD_get_connection_info (connection, 864 MHD_CONNECTION_INFO_CONNECTION_FD); 865 } 866 if (cfg.conn_option) 867 (void) MHD_set_connection_option (connection, 868 MHD_CONNECTION_OPTION_TIMEOUT, 869 (unsigned int) 0); 870 switch (cfg.resp_kind) 871 { 872 case 1: 873 r = MHD_create_response_from_buffer_copy (sizeof (resp_body) - 1, 874 resp_body); 875 break; 876 case 2: 877 r = MHD_create_response_empty (MHD_RF_NONE); 878 break; 879 case 3: 880 r = MHD_create_response_from_buffer_static (0, ""); 881 break; 882 case 0: 883 default: 884 r = MHD_create_response_from_buffer_static (sizeof (resp_body) - 1, 885 resp_body); 886 break; 887 } 888 if (NULL == r) 889 return MHD_NO; 890 if (cfg.resp_header) 891 (void) MHD_add_response_header (r, "X-Fuzz", "tls"); 892 ret = MHD_queue_response (connection, 893 cfg.error_reply 894 ? MHD_HTTP_FORBIDDEN 895 : MHD_HTTP_OK, 896 r); 897 MHD_destroy_response (r); 898 return ret; 899 } 900 901 902 static void 903 panic_cb (void *cls, 904 const char *file, 905 unsigned int line, 906 const char *reason) 907 { 908 char msg[512]; 909 910 (void) cls; 911 (void) snprintf (msg, sizeof (msg), 912 "MHD_PANIC() reached at %s:%u: %s", 913 (NULL != file) ? file : "?", 914 line, 915 (NULL != reason) ? reason : "?"); 916 fuzz_report_finding (msg); 917 } 918 919 920 /* ------------------------------------------------------------------ */ 921 /* Driving the daemon */ 922 /* ------------------------------------------------------------------ */ 923 924 /** 925 * Advance the daemon by one cycle, through the event-loop API selected 926 * by byte 5 of the input. The select() timeout is always zero: the 927 * harness is single threaded, whatever the daemon is waiting for has 928 * already been written into the socketpair, and blocking would only burn 929 * wall clock. 930 */ 931 static void 932 run_once (struct MHD_Daemon *d) 933 { 934 fd_set rs; 935 fd_set ws; 936 fd_set es; 937 MHD_socket max_fd = MHD_INVALID_SOCKET; 938 struct timeval tv; 939 940 if (0 == cfg.loop_mode) 941 { 942 (void) MHD_run (d); 943 return; 944 } 945 FD_ZERO (&rs); 946 FD_ZERO (&ws); 947 FD_ZERO (&es); 948 if (1 == cfg.loop_mode) 949 { 950 /* Parenthesised so that the real v1 function is called: microhttpd.h 951 also defines MHD_get_fdset as a macro forwarding to 952 MHD_get_fdset2. Same trick for MHD_run_from_select below. */ 953 if (MHD_YES != (MHD_get_fdset) (d, &rs, &ws, &es, &max_fd)) 954 { 955 (void) MHD_run (d); 956 return; 957 } 958 } 959 else 960 { 961 if (MHD_YES != MHD_get_fdset2 (d, &rs, &ws, &es, &max_fd, 962 (unsigned int) FD_SETSIZE)) 963 { 964 (void) MHD_run (d); 965 return; 966 } 967 } 968 tv.tv_sec = 0; 969 tv.tv_usec = 0; 970 if (MHD_INVALID_SOCKET != max_fd) 971 (void) select ((int) max_fd + 1, &rs, &ws, &es, &tv); 972 if (1 == cfg.loop_mode) 973 (void) (MHD_run_from_select) (d, &rs, &ws, &es); 974 else 975 (void) MHD_run_from_select2 (d, &rs, &ws, &es, (unsigned int) FD_SETSIZE); 976 } 977 978 979 /* ------------------------------------------------------------------ */ 980 /* The in-process TLS client */ 981 /* ------------------------------------------------------------------ */ 982 983 struct tls_client 984 { 985 gnutls_session_t sess; /**< NULL in the raw modes */ 986 gnutls_certificate_credentials_t cred; 987 int fd; /**< our end of the socketpair */ 988 int hs_done; 989 int dead; 990 }; 991 992 993 static void 994 pump (struct MHD_Daemon *d, 995 unsigned int rounds) 996 { 997 unsigned int i; 998 999 for (i = 0; i < rounds; i++) 1000 run_once (d); 1001 } 1002 1003 1004 /** 1005 * Read whatever the daemon has produced so far. In the raw modes this 1006 * is a plain recv(); with a real client it goes through GnuTLS, which is 1007 * what actually drives MHD's send path and its TLS shutdown handling. 1008 */ 1009 static void 1010 tc_drain (struct tls_client *tc) 1011 { 1012 unsigned int i; 1013 char tmp[4096]; 1014 1015 if (0 > tc->fd) 1016 return; 1017 if (NULL == tc->sess) 1018 { 1019 for (;;) 1020 { 1021 ssize_t n = recv (tc->fd, tmp, sizeof (tmp), MSG_DONTWAIT); 1022 1023 if (0 >= n) 1024 break; 1025 if (resp_len + (size_t) n < RESP_BUF_SIZE) 1026 { 1027 memcpy (resp_buf + resp_len, tmp, (size_t) n); 1028 resp_len += (size_t) n; 1029 } 1030 } 1031 return; 1032 } 1033 if (tc->dead || (! tc->hs_done)) 1034 return; 1035 for (i = 0; i < 8; i++) 1036 { 1037 ssize_t n = gnutls_record_recv (tc->sess, tmp, sizeof (tmp)); 1038 1039 if (0 < n) 1040 { 1041 if (resp_len + (size_t) n < RESP_BUF_SIZE) 1042 { 1043 memcpy (resp_buf + resp_len, tmp, (size_t) n); 1044 resp_len += (size_t) n; 1045 } 1046 continue; 1047 } 1048 if (0 == n) 1049 break; /* peer closed the TLS connection */ 1050 if ( (GNUTLS_E_AGAIN == n) || 1051 (GNUTLS_E_INTERRUPTED == n) ) 1052 break; 1053 if (0 != gnutls_error_is_fatal ((int) n)) 1054 tc->dead = 1; 1055 break; 1056 } 1057 } 1058 1059 1060 static void 1061 pump_and_drain (struct MHD_Daemon *d, 1062 struct tls_client *tc, 1063 unsigned int rounds) 1064 { 1065 unsigned int i; 1066 1067 for (i = 0; i < rounds; i++) 1068 { 1069 run_once (d); 1070 tc_drain (tc); 1071 } 1072 } 1073 1074 1075 /** 1076 * Let the client and the daemon take turns at the handshake until it 1077 * completes, fails, or @a rounds is exhausted. Exhausting @a rounds on 1078 * purpose (client mode 2) is what leaves MHD's connection parked in 1079 * #MHD_TLS_CONN_HANDSHAKING. 1080 */ 1081 static void 1082 tc_handshake (struct MHD_Daemon *d, 1083 struct tls_client *tc, 1084 unsigned int rounds) 1085 { 1086 unsigned int i; 1087 1088 if ( (NULL == tc->sess) || 1089 (0 != tc->dead) || 1090 (0 != tc->hs_done) ) 1091 return; 1092 for (i = 0; i < rounds; i++) 1093 { 1094 int ret = gnutls_handshake (tc->sess); 1095 1096 if (GNUTLS_E_SUCCESS == ret) 1097 { 1098 tc->hs_done = 1; 1099 stat_handshakes_ok++; 1100 return; 1101 } 1102 if (0 != gnutls_error_is_fatal (ret)) 1103 { 1104 tc->dead = 1; 1105 stat_handshakes_failed++; 1106 return; 1107 } 1108 /* GNUTLS_E_AGAIN / GNUTLS_E_INTERRUPTED / a warning alert: give the 1109 daemon a chance to answer. */ 1110 run_once (d); 1111 } 1112 } 1113 1114 1115 /** 1116 * Open a fresh connection: a socketpair, one end handed to MHD with 1117 * MHD_add_connection(), the other end ours. With a real client the 1118 * GnuTLS session is set up here too, but the handshake itself is driven 1119 * by tc_handshake(). 1120 * 1121 * @return 0 on success 1122 */ 1123 static int 1124 tc_open (struct MHD_Daemon *d, 1125 struct tls_client *tc) 1126 { 1127 int sv[2]; 1128 struct sockaddr_in sa; 1129 int fl; 1130 #if GNUTLS_VERSION_NUMBER >= 0x030500 1131 gnutls_init_flags_t flags; 1132 #else 1133 unsigned int flags; 1134 #endif 1135 1136 memset (tc, 0, sizeof (*tc)); 1137 tc->fd = -1; 1138 if (0 != socketpair (AF_UNIX, SOCK_STREAM, 0, sv)) 1139 return -1; 1140 memset (&sa, 0, sizeof (sa)); 1141 sa.sin_family = AF_INET; 1142 sa.sin_port = htons (44444); 1143 sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); 1144 if (MHD_YES != MHD_add_connection (d, 1145 (MHD_socket) sv[1], 1146 (const struct sockaddr *) &sa, 1147 (socklen_t) sizeof (sa))) 1148 { 1149 /* MHD has already closed sv[1] in that case */ 1150 (void) close (sv[0]); 1151 return -1; 1152 } 1153 tc->fd = sv[0]; 1154 stat_connections++; 1155 /* Our end must never block: the daemon is pumped from this very 1156 thread, so a blocking write would deadlock the process. */ 1157 fl = fcntl (tc->fd, F_GETFL, 0); 1158 if (0 <= fl) 1159 (void) fcntl (tc->fd, F_SETFL, fl | O_NONBLOCK); 1160 if ( (CLIENT_TLS != cfg.mode) && 1161 (CLIENT_TLS_ABANDON != cfg.mode) ) 1162 return 0; 1163 1164 if (GNUTLS_E_SUCCESS != 1165 gnutls_certificate_allocate_credentials (&tc->cred)) 1166 { 1167 tc->cred = NULL; 1168 tc->dead = 1; 1169 return 0; 1170 } 1171 if (cfg.client_cert) 1172 { 1173 gnutls_datum_t c; 1174 gnutls_datum_t k; 1175 1176 c.data = (unsigned char *) (intptr_t) srv_self_signed_cert_pem; 1177 c.size = (unsigned int) strlen (srv_self_signed_cert_pem); 1178 k.data = (unsigned char *) (intptr_t) srv_self_signed_key_pem; 1179 k.size = (unsigned int) strlen (srv_self_signed_key_pem); 1180 (void) gnutls_certificate_set_x509_key_mem (tc->cred, &c, &k, 1181 GNUTLS_X509_FMT_PEM); 1182 } 1183 flags = GNUTLS_CLIENT; 1184 #if GNUTLS_VERSION_MAJOR >= 3 1185 flags |= GNUTLS_NONBLOCK; 1186 #endif 1187 #if GNUTLS_VERSION_NUMBER >= 0x030402 1188 flags |= GNUTLS_NO_SIGNAL; 1189 #endif 1190 if (GNUTLS_E_SUCCESS != gnutls_init (&tc->sess, flags)) 1191 { 1192 tc->sess = NULL; 1193 tc->dead = 1; 1194 return 0; 1195 } 1196 if (GNUTLS_E_SUCCESS != 1197 gnutls_priority_set_direct (tc->sess, 1198 client_prio_tbl[cfg.client_prio_idx], 1199 NULL)) 1200 (void) gnutls_priority_set_direct (tc->sess, "NORMAL", NULL); 1201 if (GNUTLS_E_SUCCESS != 1202 gnutls_credentials_set (tc->sess, GNUTLS_CRD_CERTIFICATE, tc->cred)) 1203 tc->dead = 1; 1204 if ( (cfg.client_sni) && 1205 (0 != sni_name_len) ) 1206 (void) gnutls_server_name_set (tc->sess, 1207 GNUTLS_NAME_DNS, 1208 sni_name, 1209 sni_name_len); 1210 gnutls_transport_set_int (tc->sess, tc->fd); 1211 /* GNUTLS_INDEFINITE_TIMEOUT: the default handshake timeout is a wall 1212 clock deadline, and this harness must not depend on the clock. */ 1213 gnutls_handshake_set_timeout (tc->sess, 0); 1214 return 0; 1215 } 1216 1217 1218 static void 1219 tc_send (struct MHD_Daemon *d, 1220 struct tls_client *tc, 1221 const uint8_t *buf, 1222 size_t len) 1223 { 1224 size_t off = 0; 1225 unsigned int stall = 0; 1226 1227 if ( (0 > tc->fd) || 1228 (0 == len) ) 1229 return; 1230 if (NULL == tc->sess) 1231 { 1232 while ( (off < len) && 1233 (stall < 64) ) 1234 { 1235 ssize_t s = send (tc->fd, buf + off, len - off, MSG_DONTWAIT); 1236 1237 if (0 < s) 1238 { 1239 off += (size_t) s; 1240 stall = 0; 1241 continue; 1242 } 1243 stall++; 1244 pump_and_drain (d, tc, 2); 1245 if ( (0 > s) && 1246 (EAGAIN != errno) && 1247 (EWOULDBLOCK != errno) && 1248 (EINTR != errno) ) 1249 break; 1250 } 1251 return; 1252 } 1253 if ( (0 != tc->dead) || 1254 (0 == tc->hs_done) ) 1255 return; 1256 while ( (off < len) && 1257 (stall < 64) ) 1258 { 1259 /* On GNUTLS_E_AGAIN the call has to be repeated with exactly the 1260 same arguments, which is why @a off is only advanced on success. */ 1261 ssize_t s = gnutls_record_send (tc->sess, buf + off, len - off); 1262 1263 if (0 < s) 1264 { 1265 off += (size_t) s; 1266 stall = 0; 1267 continue; 1268 } 1269 if ( (GNUTLS_E_AGAIN == s) || 1270 (GNUTLS_E_INTERRUPTED == s) ) 1271 { 1272 stall++; 1273 pump_and_drain (d, tc, 2); 1274 continue; 1275 } 1276 if (0 != gnutls_error_is_fatal ((int) s)) 1277 tc->dead = 1; 1278 break; 1279 } 1280 } 1281 1282 1283 /** 1284 * Tear the client end down. Every GnuTLS object is released on every 1285 * path, including the ones where the session never got off the ground. 1286 */ 1287 static void 1288 tc_close (struct MHD_Daemon *d, 1289 struct tls_client *tc) 1290 { 1291 if (NULL != tc->sess) 1292 { 1293 if ( (cfg.client_bye) && 1294 (0 == tc->dead) && 1295 (0 != tc->hs_done) ) 1296 { 1297 unsigned int i; 1298 1299 for (i = 0; i < 8; i++) 1300 { 1301 int ret = gnutls_bye (tc->sess, GNUTLS_SHUT_WR); 1302 1303 if ( (GNUTLS_E_AGAIN != ret) && 1304 (GNUTLS_E_INTERRUPTED != ret) ) 1305 break; 1306 run_once (d); 1307 } 1308 } 1309 gnutls_deinit (tc->sess); 1310 tc->sess = NULL; 1311 } 1312 if (NULL != tc->cred) 1313 { 1314 gnutls_certificate_free_credentials (tc->cred); 1315 tc->cred = NULL; 1316 } 1317 if (0 <= tc->fd) 1318 { 1319 if (cfg.client_shut_wr) 1320 (void) shutdown (tc->fd, SHUT_WR); 1321 pump (d, 2); 1322 (void) close (tc->fd); 1323 tc->fd = -1; 1324 } 1325 tc->hs_done = 0; 1326 tc->dead = 1; 1327 pump (d, 4); 1328 } 1329 1330 1331 /** 1332 * Bring a fresh connection up to the point where payload can be sent. 1333 */ 1334 static void 1335 tc_start (struct MHD_Daemon *d, 1336 struct tls_client *tc) 1337 { 1338 if (0 != tc_open (d, tc)) 1339 { 1340 tc->fd = -1; 1341 return; 1342 } 1343 if (CLIENT_TLS == cfg.mode) 1344 tc_handshake (d, tc, HANDSHAKE_ROUNDS); 1345 else if (CLIENT_TLS_ABANDON == cfg.mode) 1346 tc_handshake (d, tc, cfg.hs_budget); 1347 else 1348 pump (d, 1); 1349 } 1350 1351 1352 /* ------------------------------------------------------------------ */ 1353 /* PEM blobs assembled from the input */ 1354 /* ------------------------------------------------------------------ */ 1355 1356 /** 1357 * Build @a out as "-----BEGIN @a label-----\n<body>\n-----END @a 1358 * label-----\n", with @a body_len bytes of @a body as the payload. The 1359 * result is always NUL terminated, because MHD calls strlen() on it. 1360 */ 1361 static void 1362 build_fuzz_pem (char *out, 1363 size_t out_size, 1364 const char *label, 1365 const uint8_t *body, 1366 size_t body_len) 1367 { 1368 size_t o = 0; 1369 size_t i; 1370 int n; 1371 1372 n = snprintf (out, out_size, "-----BEGIN %s-----\n", label); 1373 if ( (0 > n) || 1374 ((size_t) n >= out_size) ) 1375 { 1376 out[0] = '\0'; 1377 return; 1378 } 1379 o = (size_t) n; 1380 if (body_len > FUZZ_PEM_BODY_MAX) 1381 body_len = FUZZ_PEM_BODY_MAX; 1382 for (i = 0; (i < body_len) && (o + 32 < out_size); i++) 1383 { 1384 /* Keep the blob a C string; a NUL inside would simply truncate it 1385 for MHD's strlen(), which is a less interesting shape. */ 1386 out[o++] = (char) ((0 == body[i]) ? 'A' : body[i]); 1387 } 1388 n = snprintf (out + o, out_size - o, "\n-----END %s-----\n", label); 1389 if (0 > n) 1390 out[o] = '\0'; 1391 } 1392 1393 1394 /* ------------------------------------------------------------------ */ 1395 /* The fuzz target */ 1396 /* ------------------------------------------------------------------ */ 1397 1398 int 1399 LLVMFuzzerTestOneInput (const uint8_t *data, 1400 size_t size) 1401 { 1402 struct MHD_Daemon *d; 1403 struct MHD_OptionItem opts[12]; 1404 unsigned int nopt = 0; 1405 unsigned int flags; 1406 struct tls_client tc; 1407 size_t pos; 1408 unsigned int nseg = 0; 1409 unsigned int nconn = 1; 1410 1411 /* Must happen before the first write() into the socketpair; see 1412 fuzz_ignore_sigpipe() in fuzz_common.h for why the process dies 1413 without it. Idempotent. */ 1414 fuzz_ignore_sigpipe (); 1415 1416 /* The ten configuration bytes are mandatory. */ 1417 if (size < 10) 1418 return 0; 1419 1420 resp_len = 0; 1421 memset (&cfg, 0, sizeof (cfg)); 1422 1423 { 1424 const char *nm = sni_name_tbl[(data[9] & 0x07) % SNI_NAME_COUNT]; 1425 1426 sni_name_len = strlen (nm); 1427 memcpy (sni_name, nm, sni_name_len + 1); 1428 } 1429 1430 cfg.cert = cred_tbl[data[0] % CRED_COUNT].cert; 1431 cfg.key = cred_tbl[data[0] % CRED_COUNT].key; 1432 1433 cfg.use_trust = (0 != (data[1] & 0x01)); 1434 cfg.use_dhparams = (0 != (data[1] & 0x02)); 1435 cfg.use_sni = (0 != (data[1] & 0x04)); 1436 cfg.use_prio = (0 != (data[1] & 0x08)); 1437 cfg.use_cred_type = (0 != (data[1] & 0x10)); 1438 cfg.no_alpn = (0 != (data[1] & 0x20)); 1439 cfg.key_password = (0 != (data[1] & 0x40)); 1440 cfg.prio_append = (0 != (data[1] & 0x80)); 1441 1442 cfg.prio_idx = (unsigned int) (data[2] % PRIO_COUNT); 1443 1444 cfg.cred_type_idx = (unsigned int) (data[3] & 0x07) % CRED_TYPE_COUNT; 1445 cfg.sni_mode = 1446 (enum sni_behaviour) (((unsigned int) (data[3] >> 3) & 0x07) 1447 % (unsigned int) SNI_BEHAVIOUR_COUNT); 1448 cfg.trust_garbage = (0 != (data[3] & 0x40)); 1449 cfg.dh_garbage = (0 != (data[3] & 0x80)); 1450 1451 cfg.mode = (enum client_mode) (data[4] & 0x03); 1452 cfg.client_sni = (0 != (data[4] & 0x04)); 1453 cfg.client_cert = (0 != (data[4] & 0x08)); 1454 cfg.client_prio_idx = (unsigned int) ((data[4] >> 4) & 0x03); 1455 cfg.client_bye = (0 != (data[4] & 0x40)); 1456 cfg.client_shut_wr = (0 != (data[4] & 0x80)); 1457 1458 cfg.mem_limit = mem_limit_tbl[(data[5] & 0x0F) % MEM_LIMIT_COUNT]; 1459 cfg.loop_mode = (unsigned int) ((data[5] >> 4) & 0x03); 1460 1461 cfg.resp_kind = (unsigned int) (data[6] & 0x03); 1462 cfg.conn_info = (0 != (data[6] & 0x04)); 1463 cfg.daemon_info = (0 != (data[6] & 0x08)); 1464 cfg.conn_option = (0 != (data[6] & 0x10)); 1465 cfg.error_reply = (0 != (data[6] & 0x20)); 1466 cfg.resp_header = (0 != (data[6] & 0x40)); 1467 cfg.quiesce = (0 != (data[6] & 0x80)); 1468 1469 cfg.hs_budget = 1u + (unsigned int) (data[7] & 0x07); 1470 cfg.use_tls = (0 == (data[7] & 0x08)); 1471 cfg.allow_upgrade = 1472 (0 != (data[7] & 0x10)) && 1473 (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_UPGRADE)); 1474 cfg.extra_pump = (unsigned int) ((data[7] >> 5) & 0x07); 1475 1476 /* A real handshake is pointless without a working credential setup on 1477 our own side; fall back to the raw modes if the SNI certificates 1478 could not be parsed. */ 1479 if ( (cfg.use_sni) && 1480 (0 != sni_hosts_init ()) ) 1481 cfg.use_sni = 0; 1482 1483 /* The PEM blobs built from the input. They are only referenced by 1484 cred_tbl entries 12-14, but filling them unconditionally keeps this 1485 out of the option assembly below. */ 1486 { 1487 size_t body = (size_t) data[8] * 4u; 1488 1489 if (body > size - 10) 1490 body = size - 10; 1491 build_fuzz_pem (fuzz_cert_pem, sizeof (fuzz_cert_pem), 1492 "CERTIFICATE", data + 10, body); 1493 build_fuzz_pem (fuzz_key_pem, sizeof (fuzz_key_pem), 1494 "PRIVATE KEY", data + 10, body); 1495 } 1496 1497 if (0 != cfg.mem_limit) 1498 { 1499 opts[nopt].option = MHD_OPTION_CONNECTION_MEMORY_LIMIT; 1500 opts[nopt].value = (intptr_t) cfg.mem_limit; 1501 opts[nopt].ptr_value = NULL; 1502 nopt++; 1503 } 1504 if (NULL != cfg.key) 1505 { 1506 opts[nopt].option = MHD_OPTION_HTTPS_MEM_KEY; 1507 opts[nopt].value = 0; 1508 opts[nopt].ptr_value = (void *) (intptr_t) cfg.key; 1509 nopt++; 1510 } 1511 if (NULL != cfg.cert) 1512 { 1513 opts[nopt].option = MHD_OPTION_HTTPS_MEM_CERT; 1514 opts[nopt].value = 0; 1515 opts[nopt].ptr_value = (void *) (intptr_t) cfg.cert; 1516 nopt++; 1517 } 1518 if (cfg.key_password) 1519 { 1520 opts[nopt].option = MHD_OPTION_HTTPS_KEY_PASSWORD; 1521 opts[nopt].value = 0; 1522 opts[nopt].ptr_value = (void *) (intptr_t) https_key_password; 1523 nopt++; 1524 } 1525 if (cfg.use_trust) 1526 { 1527 opts[nopt].option = MHD_OPTION_HTTPS_MEM_TRUST; 1528 opts[nopt].value = 0; 1529 opts[nopt].ptr_value = (void *) (intptr_t) 1530 (cfg.trust_garbage ? garbage_cert_pem 1531 : ca_cert_pem); 1532 nopt++; 1533 } 1534 if (cfg.use_dhparams) 1535 { 1536 opts[nopt].option = MHD_OPTION_HTTPS_MEM_DHPARAMS; 1537 opts[nopt].value = 0; 1538 opts[nopt].ptr_value = (void *) (intptr_t) 1539 (cfg.dh_garbage ? garbage_dh_pem : dh_params_pem); 1540 nopt++; 1541 } 1542 if (cfg.use_prio) 1543 { 1544 opts[nopt].option = cfg.prio_append 1545 ? MHD_OPTION_HTTPS_PRIORITIES_APPEND 1546 : MHD_OPTION_HTTPS_PRIORITIES; 1547 opts[nopt].value = 0; 1548 opts[nopt].ptr_value = (void *) (intptr_t) prio_tbl[cfg.prio_idx]; 1549 nopt++; 1550 } 1551 if (cfg.use_cred_type) 1552 { 1553 opts[nopt].option = MHD_OPTION_HTTPS_CRED_TYPE; 1554 opts[nopt].value = (intptr_t) cred_type_tbl[cfg.cred_type_idx]; 1555 opts[nopt].ptr_value = NULL; 1556 nopt++; 1557 } 1558 if (cfg.no_alpn) 1559 { 1560 opts[nopt].option = MHD_OPTION_TLS_NO_ALPN; 1561 opts[nopt].value = 1; 1562 opts[nopt].ptr_value = NULL; 1563 nopt++; 1564 } 1565 opts[nopt].option = MHD_OPTION_END; 1566 opts[nopt].value = 0; 1567 opts[nopt].ptr_value = NULL; 1568 1569 flags = MHD_USE_NO_LISTEN_SOCKET; 1570 if (cfg.use_tls) 1571 flags |= MHD_USE_TLS; 1572 if (fuzz_verbose) 1573 flags |= MHD_USE_ERROR_LOG; 1574 if (cfg.allow_upgrade) 1575 flags |= MHD_ALLOW_UPGRADE; 1576 1577 MHD_set_panic_func (&panic_cb, NULL); 1578 d = MHD_start_daemon (flags, 1579 0, 1580 NULL, NULL, 1581 &ahc, NULL, 1582 MHD_OPTION_ARRAY, opts, 1583 /* Passed through the varargs rather than through 1584 the option array: the array's ptr_value is a 1585 void *, and a function pointer does not 1586 portably fit in one. A NULL here is exactly 1587 equivalent to not passing the option. */ 1588 MHD_OPTION_HTTPS_CERT_CALLBACK, 1589 cfg.use_sni ? &sni_callback : NULL, 1590 MHD_OPTION_END); 1591 if (NULL == d) 1592 { 1593 stat_daemons_failed++; 1594 return 0; 1595 } 1596 stat_daemons++; 1597 if (! stats_registered) 1598 { 1599 stats_registered = 1; 1600 (void) atexit (&print_stats); 1601 } 1602 if (cfg.daemon_info) 1603 { 1604 (void) MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD); 1605 (void) MHD_get_daemon_info (d, MHD_DAEMON_INFO_FLAGS); 1606 (void) MHD_get_daemon_info (d, MHD_DAEMON_INFO_CURRENT_CONNECTIONS); 1607 (void) MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 1608 } 1609 1610 /* The connection is opened lazily, when the first segment that carries 1611 wire data is reached, so that a leading op 1 segment can still 1612 override the server name byte 9 selected. */ 1613 tc.sess = NULL; 1614 tc.cred = NULL; 1615 tc.fd = -1; 1616 tc.hs_done = 0; 1617 tc.dead = 1; 1618 1619 pos = 10u; 1620 while ( (pos + 2 <= size) && 1621 (nseg < MAX_SEGMENTS) ) 1622 { 1623 unsigned int hdr = (unsigned int) data[pos] 1624 | ((unsigned int) data[pos + 1] << 8); 1625 unsigned int op = hdr >> 14; 1626 size_t slen = (size_t) (hdr & 0x3FFF); 1627 1628 pos += 2; 1629 nseg++; 1630 if (slen > size - pos) 1631 slen = size - pos; 1632 1633 if (1 == op) 1634 { 1635 /* Server name declaration for the next connection, not wire data. */ 1636 size_t n = slen; 1637 1638 if (n > MAX_SNI_LEN) 1639 n = MAX_SNI_LEN; 1640 memcpy (sni_name, data + pos, n); 1641 /* GnuTLS wants a plain host name, and an embedded NUL would only 1642 shorten it behind our back. */ 1643 while ( (0 != n) && 1644 ('\0' == sni_name[n - 1]) ) 1645 n--; 1646 sni_name[n] = '\0'; 1647 sni_name_len = n; 1648 pos += slen; 1649 continue; 1650 } 1651 if (0 > tc.fd) 1652 { 1653 tc_start (d, &tc); 1654 if (0 > tc.fd) 1655 break; 1656 } 1657 else if ( (3 == op) && 1658 (nconn < MAX_CONNECTIONS) ) 1659 { 1660 tc_close (d, &tc); 1661 tc_start (d, &tc); 1662 nconn++; 1663 if (0 > tc.fd) 1664 break; 1665 } 1666 if (0 != slen) 1667 tc_send (d, &tc, data + pos, slen); 1668 pos += slen; 1669 pump_and_drain (d, &tc, (2 == op) ? (6u + cfg.extra_pump) : 3u); 1670 } 1671 if (0 > tc.fd) 1672 tc_start (d, &tc); 1673 pump_and_drain (d, &tc, 2u + cfg.extra_pump); 1674 tc_close (d, &tc); 1675 1676 if (cfg.quiesce) 1677 (void) MHD_quiesce_daemon (d); 1678 MHD_stop_daemon (d); 1679 return 0; 1680 } 1681 1682 1683 /* ------------------------------------------------------------------ */ 1684 /* Structure-aware generator */ 1685 /* ------------------------------------------------------------------ */ 1686 1687 struct sbuf 1688 { 1689 uint8_t *p; 1690 size_t len; 1691 size_t cap; 1692 }; 1693 1694 1695 static void 1696 sb_raw (struct sbuf *b, 1697 const void *v, 1698 size_t n) 1699 { 1700 if (b->len + n > b->cap) 1701 n = b->cap - b->len; 1702 memcpy (b->p + b->len, v, n); 1703 b->len += n; 1704 } 1705 1706 1707 static void 1708 sb_str (struct sbuf *b, 1709 const char *s) 1710 { 1711 sb_raw (b, s, strlen (s)); 1712 } 1713 1714 1715 static void 1716 sb_u32 (struct sbuf *b, 1717 uint32_t v) 1718 { 1719 char tmp[16]; 1720 unsigned int n = 0; 1721 1722 do 1723 { 1724 tmp[n++] = (char) ('0' + (v % 10u)); 1725 v /= 10u; 1726 } 1727 while ( (0 != v) && 1728 (n < sizeof (tmp)) ); 1729 while (0 != n) 1730 { 1731 char c = tmp[--n]; 1732 1733 sb_raw (b, &c, 1); 1734 } 1735 } 1736 1737 1738 enum gen_shape 1739 { 1740 SHAPE_TLS_HTTP = 0, /**< good credentials, real handshake, HTTP over TLS */ 1741 SHAPE_RAW_BYTES, /**< good credentials, junk at the TLS socket */ 1742 SHAPE_ABANDON, /**< a real client that walks away mid-handshake */ 1743 SHAPE_BAD_CREDS, /**< mismatched/garbage/absent key or certificate */ 1744 SHAPE_BAD_OPTIONS, /**< bogus priorities, credential types, no MHD_USE_TLS */ 1745 SHAPE_SNI, /**< the certificate callback, all behaviours */ 1746 SHAPE_PEM_FUZZ, /**< PEM blobs built from the generator's own bytes */ 1747 SHAPE_RECORDS, /**< hand-built TLS records */ 1748 SHAPE_COUNT 1749 }; 1750 1751 static int forced_shape = -1; 1752 static int forced_shape_read; 1753 1754 static const char *const gen_methods[] = { 1755 "GET", "POST", "HEAD", "PUT", "OPTIONS", "BREW" 1756 }; 1757 1758 static const char *const gen_targets[] = { 1759 "/", "/a", "/index.html", "/a?b=c", "/%41%42", "*", "//" 1760 }; 1761 1762 static const char *const gen_versions[] = { 1763 "HTTP/1.1", "HTTP/1.0", "HTTP/1.2", "HTTP/9.9" 1764 }; 1765 1766 static const char *const gen_hdr_names[] = { 1767 "Host", "User-Agent", "Accept", "Connection", "X-Fuzz", "Cookie", 1768 "Content-Type", "Expect" 1769 }; 1770 1771 static const char *const gen_hdr_values[] = { 1772 "x", "localhost", "*/*", "keep-alive", "close", "100-continue", 1773 "text/plain", "a=b" 1774 }; 1775 1776 1777 /** 1778 * A plain HTTP request; over TLS this is what makes MHD leave the 1779 * handshake state machine and enter the ordinary parser. 1780 */ 1781 static void 1782 gen_http_request (struct fuzz_rng *rng, 1783 struct sbuf *b) 1784 { 1785 unsigned int nh; 1786 unsigned int i; 1787 int with_body; 1788 1789 sb_str (b, gen_methods[fuzz_below (rng, (uint32_t) 1790 (sizeof (gen_methods) 1791 / sizeof (gen_methods[0])))]); 1792 sb_str (b, " "); 1793 sb_str (b, gen_targets[fuzz_below (rng, (uint32_t) 1794 (sizeof (gen_targets) 1795 / sizeof (gen_targets[0])))]); 1796 sb_str (b, " "); 1797 sb_str (b, gen_versions[fuzz_below (rng, (uint32_t) 1798 (sizeof (gen_versions) 1799 / sizeof (gen_versions[0])))]); 1800 sb_str (b, "\r\n"); 1801 with_body = fuzz_chance (rng, 3); 1802 nh = fuzz_below (rng, 4); 1803 for (i = 0; i < nh; i++) 1804 { 1805 sb_str (b, gen_hdr_names[fuzz_below (rng, (uint32_t) 1806 (sizeof (gen_hdr_names) 1807 / sizeof (gen_hdr_names[0])))]); 1808 sb_str (b, ": "); 1809 sb_str (b, gen_hdr_values[fuzz_below (rng, (uint32_t) 1810 (sizeof (gen_hdr_values) 1811 / sizeof (gen_hdr_values[0])))]); 1812 sb_str (b, "\r\n"); 1813 } 1814 if (with_body) 1815 { 1816 unsigned int blen = fuzz_below (rng, 64); 1817 1818 sb_str (b, "Content-Length: "); 1819 sb_u32 (b, blen); 1820 sb_str (b, "\r\n\r\n"); 1821 for (i = 0; i < blen; i++) 1822 { 1823 char c = (char) ('a' + (int) fuzz_below (rng, 26)); 1824 1825 sb_raw (b, &c, 1); 1826 } 1827 return; 1828 } 1829 sb_str (b, "\r\n"); 1830 } 1831 1832 1833 /** 1834 * Something that looks like a TLS record: a content type, a version, a 1835 * length and a payload. Most of this lands in GnuTLS's record parser 1836 * rather than in MHD, which is why the generator spends only one shape 1837 * on it. 1838 */ 1839 static void 1840 gen_tls_records (struct fuzz_rng *rng, 1841 struct sbuf *b) 1842 { 1843 unsigned int n = 1 + fuzz_below (rng, 4); 1844 unsigned int i; 1845 unsigned int j; 1846 1847 for (i = 0; i < n; i++) 1848 { 1849 uint8_t hdr[5]; 1850 unsigned int plen = fuzz_below (rng, 96); 1851 unsigned int declared = fuzz_chance (rng, 3) 1852 ? fuzz_below (rng, 0x4000) 1853 : plen; 1854 1855 hdr[0] = fuzz_chance (rng, 4) 1856 ? fuzz_byte (rng) 1857 : (uint8_t) (20 + fuzz_below (rng, 4)); 1858 hdr[1] = 0x03; 1859 hdr[2] = (uint8_t) fuzz_below (rng, 5); 1860 hdr[3] = (uint8_t) ((declared >> 8) & 0xFF); 1861 hdr[4] = (uint8_t) (declared & 0xFF); 1862 sb_raw (b, hdr, sizeof (hdr)); 1863 for (j = 0; j < plen; j++) 1864 { 1865 uint8_t v = fuzz_byte (rng); 1866 1867 sb_raw (b, &v, 1); 1868 } 1869 } 1870 } 1871 1872 1873 /** 1874 * Number of leading entries of #prio_tbl that GnuTLS accepts. Beyond 1875 * that the daemon refuses to start, which is a fine thing to fuzz but a 1876 * poor way to reach the handshake. 1877 */ 1878 #define PRIO_VALID_COUNT 7 1879 1880 1881 /** 1882 * Constrain the configuration bytes so that MHD_start_daemon() actually 1883 * succeeds. Used by the shapes whose point is what happens *after* the 1884 * daemon is up; the option surface itself is fuzzed by the shapes that 1885 * do not call this. 1886 */ 1887 static void 1888 make_daemon_startable (struct fuzz_rng *rng, 1889 uint8_t *cfg_bytes) 1890 { 1891 cfg_bytes[1] &= (uint8_t) ~0x10u; /* no credential type override */ 1892 cfg_bytes[3] &= (uint8_t) ~0xC0u; /* valid trust store, valid DH */ 1893 if (0 != (cfg_bytes[1] & 0x08u)) 1894 cfg_bytes[2] = (uint8_t) fuzz_below (rng, PRIO_VALID_COUNT); 1895 cfg_bytes[7] &= (uint8_t) ~0x08u; /* keep MHD_USE_TLS */ 1896 } 1897 1898 1899 /** 1900 * Emit one segment with the given op code. 1901 */ 1902 static void 1903 emit_segment (struct sbuf *out, 1904 unsigned int op, 1905 const uint8_t *payload, 1906 size_t len) 1907 { 1908 unsigned int hv; 1909 uint8_t hdr[2]; 1910 1911 if (len > 0x3FFF) 1912 len = 0x3FFF; 1913 hv = (op << 14) | (unsigned int) len; 1914 hdr[0] = (uint8_t) (hv & 0xFF); 1915 hdr[1] = (uint8_t) (hv >> 8); 1916 sb_raw (out, hdr, 2); 1917 sb_raw (out, payload, len); 1918 } 1919 1920 1921 static size_t 1922 fuzz_generate (struct fuzz_rng *rng, 1923 uint8_t *buf, 1924 size_t cap) 1925 { 1926 struct sbuf out; 1927 struct sbuf rb; 1928 uint8_t req[GEN_BUF_SIZE]; 1929 uint8_t cfg_bytes[10]; 1930 enum gen_shape shape; 1931 unsigned int nreq; 1932 unsigned int i; 1933 1934 out.p = buf; 1935 out.len = 0; 1936 out.cap = cap; 1937 1938 if (! forced_shape_read) 1939 { 1940 const char *e = getenv ("MHD_FUZZ_SHAPE"); 1941 1942 forced_shape_read = 1; 1943 if (NULL != e) 1944 forced_shape = atoi (e); 1945 } 1946 if (0 <= forced_shape) 1947 shape = (enum gen_shape) (forced_shape % (int) SHAPE_COUNT); 1948 else 1949 shape = (enum gen_shape) fuzz_below (rng, (uint32_t) SHAPE_COUNT); 1950 1951 for (i = 0; i < sizeof (cfg_bytes); i++) 1952 cfg_bytes[i] = fuzz_byte (rng); 1953 1954 /* Byte 0 picks the credentials, byte 4 (bits 0-1) the client, and byte 1955 1 which options are passed at all; every shape below narrows exactly 1956 those and leaves the rest of the configuration space random. */ 1957 cfg_bytes[7] &= (uint8_t) ~0x08u; /* keep MHD_USE_TLS by default */ 1958 switch (shape) 1959 { 1960 case SHAPE_TLS_HTTP: 1961 cfg_bytes[0] = (uint8_t) (fuzz_chance (rng, 2) ? 0 : 1); 1962 cfg_bytes[4] = (uint8_t) ((cfg_bytes[4] & ~0x03u) | CLIENT_TLS); 1963 cfg_bytes[1] &= (uint8_t) ~0x04u; /* no SNI callback */ 1964 make_daemon_startable (rng, cfg_bytes); 1965 break; 1966 case SHAPE_RAW_BYTES: 1967 cfg_bytes[0] = 0; 1968 cfg_bytes[4] = (uint8_t) ((cfg_bytes[4] & ~0x03u) | CLIENT_RAW); 1969 make_daemon_startable (rng, cfg_bytes); 1970 break; 1971 case SHAPE_ABANDON: 1972 cfg_bytes[0] = (uint8_t) (fuzz_chance (rng, 2) ? 0 : 1); 1973 cfg_bytes[4] = (uint8_t) ((cfg_bytes[4] & ~0x03u) | CLIENT_TLS_ABANDON); 1974 cfg_bytes[7] = (uint8_t) ((cfg_bytes[7] & ~0x07u) 1975 + fuzz_below (rng, 6)); 1976 make_daemon_startable (rng, cfg_bytes); 1977 break; 1978 case SHAPE_BAD_CREDS: 1979 /* entries 2-11 of cred_tbl are the broken ones */ 1980 cfg_bytes[0] = (uint8_t) (2 + fuzz_below (rng, 10)); 1981 cfg_bytes[4] = (uint8_t) ((cfg_bytes[4] & ~0x03u) 1982 | (fuzz_chance (rng, 2) ? CLIENT_TLS 1983 : CLIENT_RAW)); 1984 break; 1985 case SHAPE_BAD_OPTIONS: 1986 cfg_bytes[1] |= 0x18u; /* priorities + credential type */ 1987 cfg_bytes[2] = (uint8_t) fuzz_below (rng, (uint32_t) PRIO_COUNT); 1988 cfg_bytes[3] = fuzz_byte (rng); 1989 if (fuzz_chance (rng, 4)) 1990 cfg_bytes[7] |= 0x08u; /* HTTPS options, but no MHD_USE_TLS */ 1991 cfg_bytes[4] = (uint8_t) ((cfg_bytes[4] & ~0x03u) 1992 | (fuzz_chance (rng, 2) ? CLIENT_TLS 1993 : CLIENT_RAW)); 1994 break; 1995 case SHAPE_SNI: 1996 cfg_bytes[0] = (uint8_t) (fuzz_chance (rng, 3) ? 6 : 0); 1997 cfg_bytes[3] = (uint8_t) 1998 ((cfg_bytes[3] & ~0x38u) 1999 | (fuzz_below (rng, (uint32_t) SNI_BEHAVIOUR_COUNT) << 3)); 2000 cfg_bytes[4] = (uint8_t) ((cfg_bytes[4] & ~0x03u) | CLIENT_TLS | 0x04u); 2001 cfg_bytes[9] = (uint8_t) fuzz_below (rng, (uint32_t) SNI_NAME_COUNT); 2002 make_daemon_startable (rng, cfg_bytes); 2003 cfg_bytes[1] |= 0x04u; /* the certificate callback */ 2004 break; 2005 case SHAPE_PEM_FUZZ: 2006 cfg_bytes[0] = (uint8_t) (12 + fuzz_below (rng, 3)); 2007 cfg_bytes[8] = (uint8_t) (1 + fuzz_below (rng, 64)); 2008 cfg_bytes[4] = (uint8_t) ((cfg_bytes[4] & ~0x03u) 2009 | (fuzz_chance (rng, 2) ? CLIENT_TLS 2010 : CLIENT_RAW)); 2011 break; 2012 case SHAPE_RECORDS: 2013 cfg_bytes[0] = 0; 2014 cfg_bytes[4] = (uint8_t) ((cfg_bytes[4] & ~0x03u) | CLIENT_RECORDS); 2015 make_daemon_startable (rng, cfg_bytes); 2016 break; 2017 case SHAPE_COUNT: 2018 default: 2019 break; 2020 } 2021 /* Byte 9 already carries a server name; now and then hand the same 2022 one over as an op 1 segment instead, so that the segment form is 2023 exercised too. Generated inputs are never written to corpus/, so 2024 unlike the seeds they may use op 1 (see the note at the top). */ 2025 sb_raw (&out, cfg_bytes, sizeof (cfg_bytes)); 2026 if (fuzz_chance (rng, 4)) 2027 { 2028 const char *nm = sni_name_tbl[cfg_bytes[9] & 0x07]; 2029 2030 emit_segment (&out, 1u, (const uint8_t *) nm, strlen (nm)); 2031 } 2032 2033 nreq = 1u + (fuzz_chance (rng, 4) ? 1u : 0u); 2034 for (i = 0; i < nreq; i++) 2035 { 2036 unsigned int op; 2037 2038 rb.p = req; 2039 rb.len = 0; 2040 rb.cap = sizeof (req); 2041 switch (shape) 2042 { 2043 case SHAPE_RECORDS: 2044 gen_tls_records (rng, &rb); 2045 break; 2046 case SHAPE_RAW_BYTES: 2047 { 2048 unsigned int n = 1 + fuzz_below (rng, 256); 2049 unsigned int j; 2050 2051 for (j = 0; j < n; j++) 2052 { 2053 uint8_t v = fuzz_byte (rng); 2054 2055 sb_raw (&rb, &v, 1); 2056 } 2057 break; 2058 } 2059 default: 2060 gen_http_request (rng, &rb); 2061 break; 2062 } 2063 if (0 != i) 2064 op = 3u; /* a fresh connection */ 2065 else 2066 op = fuzz_chance (rng, 3) ? 2u : 0u; 2067 /* Split the payload now and then: MHD's parser is incremental and 2068 the TLS record boundaries move with the split. */ 2069 if ( (rb.len > 8) && 2070 fuzz_chance (rng, 3) ) 2071 { 2072 size_t cut = 1 + fuzz_below (rng, (uint32_t) (rb.len - 1)); 2073 2074 emit_segment (&out, op, req, cut); 2075 emit_segment (&out, 2u, req + cut, rb.len - cut); 2076 } 2077 else 2078 { 2079 emit_segment (&out, op, req, rb.len); 2080 } 2081 } 2082 return out.len; 2083 } 2084 2085 2086 /* ------------------------------------------------------------------ */ 2087 /* Built-in seed corpus */ 2088 /* ------------------------------------------------------------------ */ 2089 2090 struct seed_part 2091 { 2092 unsigned int op; /**< 0 send, 1 server name, 2 send+pump, 3 new */ 2093 const char *txt; /**< NUL terminated payload */ 2094 }; 2095 2096 struct seed_def 2097 { 2098 const char *name; 2099 unsigned char cfg[10]; 2100 struct seed_part parts[4]; 2101 }; 2102 2103 #define P_END { 0, NULL } 2104 2105 /* The configuration bytes are written out in full so that a seed can be 2106 read without decoding: see the input format at the top of this file. */ 2107 static const struct seed_def seeds[] = { 2108 /* A complete TLS 1.3 handshake followed by an ordinary request: the 2109 only shape that reaches the handshake -> HTTP parser transition. */ 2110 { "tls-handshake-get", 2111 { 0, 0x00, 0, 0, 0x41, 0x00, 0x04, 0x00, 0, 0 }, 2112 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } }, 2113 2114 /* The same, but the request arrives in two TLS records. */ 2115 { "tls-handshake-split", 2116 { 0, 0x00, 0, 0, 0x41, 0x00, 0x04, 0x00, 0, 0 }, 2117 { { 0, "GET / HTTP/1.1\r\nHo" }, 2118 { 2, "st: x\r\n\r\n" }, P_END, P_END } }, 2119 2120 /* Keep-alive over TLS: two requests on one session, then gnutls_bye(). */ 2121 { "tls-keepalive", 2122 { 0, 0x00, 0, 0, 0x41, 0x00, 0x00, 0x00, 0, 0 }, 2123 { { 0, "GET /a HTTP/1.1\r\nHost: x\r\n\r\n" }, 2124 { 2, "GET /b HTTP/1.1\r\nHost: x\r\nConnection: close\r\n\r\n" }, 2125 P_END, P_END } }, 2126 2127 /* A second connection, i.e. a second handshake on the same daemon. */ 2128 { "tls-second-connection", 2129 { 0, 0x00, 0, 0, 0x41, 0x00, 0x00, 0x00, 0, 0 }, 2130 { { 0, "GET /a HTTP/1.1\r\nHost: x\r\n\r\n" }, 2131 { 3, "GET /b HTTP/1.1\r\nHost: x\r\n\r\n" }, 2132 P_END, P_END } }, 2133 2134 /* Plain HTTP at a TLS port: the record layer sees "GET ..." and the 2135 handshake fails, which is MHD_run_tls_handshake_()'s error arm. */ 2136 { "plain-http-at-tls-port", 2137 { 0, 0x00, 0, 0, 0x00, 0x00, 0x00, 0x00, 0, 0 }, 2138 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } }, 2139 2140 /* Nothing at all, then EOF: the connection dies in MHD_TLS_CONN_INIT. */ 2141 { "eof-in-init", 2142 { 0, 0x00, 0, 0, 0x80, 0x00, 0x00, 0x00, 0, 0 }, 2143 { { 0, "" }, P_END, P_END, P_END } }, 2144 2145 /* A real client that walks away after a single handshake round: MHD is 2146 left in MHD_TLS_CONN_HANDSHAKING when the socket closes. */ 2147 { "abandon-handshake", 2148 { 0, 0x00, 0, 0, 0x02, 0x00, 0x00, 0x00, 0, 0 }, 2149 { { 0, "" }, P_END, P_END, P_END } }, 2150 2151 /* Certificate and key do not belong together. */ 2152 { "mismatched-key", 2153 { 2, 0x00, 0, 0, 0x01, 0x00, 0x00, 0x00, 0, 0 }, 2154 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } }, 2155 2156 /* No certificate at all: MHD_start_daemon() has to fail cleanly. */ 2157 { "no-certificate", 2158 { 6, 0x00, 0, 0, 0x01, 0x00, 0x00, 0x00, 0, 0 }, 2159 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } }, 2160 2161 /* PEM armour with a payload that is not base64. */ 2162 { "garbage-pem", 2163 { 10, 0x00, 0, 0, 0x01, 0x00, 0x00, 0x00, 0, 0 }, 2164 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } }, 2165 2166 /* A priority string GnuTLS rejects (index 9 of prio_tbl). */ 2167 { "bogus-priorities", 2168 { 0, 0x08, 9, 0, 0x01, 0x00, 0x00, 0x00, 0, 0 }, 2169 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } }, 2170 2171 /* The same string through MHD_OPTION_HTTPS_PRIORITIES_APPEND. */ 2172 { "bogus-priorities-append", 2173 { 0, 0x88, 10, 0, 0x01, 0x00, 0x00, 0x00, 0, 0 }, 2174 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } }, 2175 2176 /* TLS 1.2 only on both ends, with the trust store and a client 2177 certificate request. */ 2178 { "tls12-with-trust", 2179 { 0, 0x01, 2, 0, 0x29, 0x00, 0x04, 0x00, 0, 0 }, 2180 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } }, 2181 2182 /* Valid Diffie-Hellman parameters (RFC 3526 group 14). */ 2183 { "valid-dhparams", 2184 { 0, 0x02, 0, 0, 0x21, 0x00, 0x00, 0x00, 0, 0 }, 2185 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } }, 2186 2187 /* Malformed Diffie-Hellman parameters: MHD_start_daemon() must fail. */ 2188 { "garbage-dhparams", 2189 { 0, 0x02, 0, 0x80, 0x01, 0x00, 0x00, 0x00, 0, 0 }, 2190 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } }, 2191 2192 /* A credential type MHD does not support (GNUTLS_CRD_ANON). */ 2193 { "cred-type-anon", 2194 { 0, 0x10, 0, 0x02, 0x01, 0x00, 0x00, 0x00, 0, 0 }, 2195 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } }, 2196 2197 /* GNUTLS_CRD_PSK without a PSK callback: the daemon starts, the 2198 handshake cannot. */ 2199 { "cred-type-psk", 2200 { 0, 0x10, 0, 0x01, 0x01, 0x00, 0x00, 0x00, 0, 0 }, 2201 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } }, 2202 2203 /* The SNI callback, answering for the presented name (byte 9 = 0, 2204 "test-mhdserver"). No op 1 segment here or below: see the note on 2205 the shared corpus at the top of this file. */ 2206 { "sni-by-name", 2207 { 6, 0x04, 0, 0x18, 0x05, 0x00, 0x04, 0x00, 0, 0 }, 2208 { { 0, "GET / HTTP/1.1\r\nHost: test-mhdserver\r\n\r\n" }, 2209 P_END, P_END, P_END } }, 2210 2211 /* The SNI callback failing outright. */ 2212 { "sni-callback-fails", 2213 { 6, 0x04, 0, 0x08, 0x05, 0x00, 0x00, 0x00, 0, 0 }, 2214 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, 2215 P_END, P_END, P_END } }, 2216 2217 /* The SNI callback answering with an empty certificate list. */ 2218 { "sni-callback-empty", 2219 { 6, 0x04, 0, 0x10, 0x05, 0x00, 0x00, 0x00, 0, 0 }, 2220 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, 2221 P_END, P_END, P_END } }, 2222 2223 /* The SNI callback answering with a key that is not the certificate's 2224 (byte 9 = 1, "localhost"). */ 2225 { "sni-callback-mismatch", 2226 { 6, 0x04, 0, 0x20, 0x05, 0x00, 0x00, 0x00, 0, 1 }, 2227 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, 2228 P_END, P_END, P_END } }, 2229 2230 /* The SNI callback answering with a certificate but no key. */ 2231 { "sni-callback-no-key", 2232 { 6, 0x04, 0, 0x28, 0x05, 0x00, 0x00, 0x00, 0, 0 }, 2233 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, 2234 P_END, P_END, P_END } }, 2235 2236 /* An unknown server name with the by-name callback (byte 9 = 3, 2237 "nobody.example.org"): no certificate. */ 2238 { "sni-unknown-name", 2239 { 6, 0x04, 0, 0x18, 0x05, 0x00, 0x00, 0x00, 0, 3 }, 2240 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, 2241 P_END, P_END, P_END } }, 2242 2243 /* A PEM blob assembled from the payload below (cred_tbl entry 14). */ 2244 { "fuzzed-pem", 2245 { 14, 0x00, 0, 0, 0x01, 0x00, 0x00, 0x00, 32, 0 }, 2246 { { 0, "MIIFSzCCAzOgAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBgTELMAkGA1UEBhMCUlUx" }, 2247 P_END, P_END, P_END } }, 2248 2249 /* A truncated TLS record header, then EOF. */ 2250 { "short-record", 2251 { 0, 0x00, 0, 0, 0x00, 0x00, 0x00, 0x00, 0, 0 }, 2252 { { 0, "\x16\x03\x01" }, P_END, P_END, P_END } }, 2253 2254 /* A record that promises far more data than it delivers. */ 2255 { "record-length-lie", 2256 { 0, 0x00, 0, 0, 0x00, 0x00, 0x00, 0x00, 0, 0 }, 2257 { { 0, "\x16\x03\x01\x3f\xff\x01\x02\x03\x04" }, P_END, P_END, P_END } }, 2258 2259 /* The HTTPS options on a daemon started without MHD_USE_TLS. */ 2260 { "no-use-tls-flag", 2261 { 0, 0x0F, 0, 0, 0x00, 0x00, 0x00, 0x08, 0, 0 }, 2262 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } }, 2263 2264 /* A tiny connection memory pool with a real TLS session. */ 2265 { "small-pool-tls", 2266 { 0, 0x00, 0, 0, 0x41, 0x01, 0x00, 0x00, 0, 0 }, 2267 { { 0, "GET /aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa HTTP/1.1\r\n" 2268 "Host: x\r\nX-Long: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n\r\n" }, 2269 P_END, P_END, P_END } }, 2270 2271 /* A request body over TLS, so that the receive adapter is used for 2272 more than the request line. */ 2273 { "tls-request-body", 2274 { 0, 0x00, 0, 0, 0x41, 0x00, 0x00, 0x00, 0, 0 }, 2275 { { 0, "POST /a HTTP/1.1\r\nHost: x\r\nContent-Length: 11\r\n\r\n" 2276 "hello world" }, 2277 P_END, P_END, P_END } }, 2278 2279 /* The external event loop (MHD_get_fdset() + MHD_run_from_select()). */ 2280 { "tls-external-loop", 2281 { 0, 0x00, 0, 0, 0x41, 0x10, 0x04, 0x00, 0, 0 }, 2282 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } }, 2283 2284 /* MHD_quiesce_daemon() with a live TLS connection. */ 2285 { "tls-quiesce", 2286 { 0, 0x00, 0, 0, 0x41, 0x00, 0x80, 0x00, 0, 0 }, 2287 { { 0, "GET / HTTP/1.1\r\nHost: x\r\n\r\n" }, P_END, P_END, P_END } } 2288 }; 2289 2290 static uint8_t seed_render_buf[2048]; 2291 2292 2293 static size_t 2294 fuzz_seed_count (void) 2295 { 2296 return sizeof (seeds) / sizeof (seeds[0]); 2297 } 2298 2299 2300 static const uint8_t * 2301 fuzz_seed_get (size_t idx, 2302 size_t *len) 2303 { 2304 const struct seed_def *sd = &seeds[idx]; 2305 struct sbuf b; 2306 unsigned int i; 2307 2308 b.p = seed_render_buf; 2309 b.len = 0; 2310 b.cap = sizeof (seed_render_buf); 2311 sb_raw (&b, sd->cfg, sizeof (sd->cfg)); 2312 for (i = 0; i < sizeof (sd->parts) / sizeof (sd->parts[0]); i++) 2313 { 2314 if (NULL == sd->parts[i].txt) 2315 break; 2316 emit_segment (&b, sd->parts[i].op, 2317 (const uint8_t *) sd->parts[i].txt, 2318 strlen (sd->parts[i].txt)); 2319 } 2320 *len = b.len; 2321 return seed_render_buf; 2322 } 2323 2324 2325 #else /* ! HTTPS_SUPPORT */ 2326 2327 /* 2328 * MHD was configured without HTTPS (which is what 2329 * contrib/oss-fuzz/build.sh does for the MemorySanitizer build), so 2330 * there is no TLS layer to fuzz. The file still has to produce a valid 2331 * fuzz target: LLVMFuzzerTestOneInput() must exist unconditionally, or 2332 * an OSS-Fuzz build of this harness would silently be an empty binary. 2333 */ 2334 2335 int 2336 LLVMFuzzerTestOneInput (const uint8_t *data, 2337 size_t size) 2338 { 2339 fuzz_ignore_sigpipe (); 2340 (void) data; 2341 (void) size; 2342 return 0; 2343 } 2344 2345 2346 static size_t 2347 fuzz_generate (struct fuzz_rng *rng, 2348 uint8_t *buf, 2349 size_t cap) 2350 { 2351 (void) rng; 2352 if (0 == cap) 2353 return 0; 2354 buf[0] = 0; 2355 return 1; 2356 } 2357 2358 2359 static const uint8_t no_https_seed[] = { 0 }; 2360 2361 2362 static size_t 2363 fuzz_seed_count (void) 2364 { 2365 return 1; 2366 } 2367 2368 2369 static const uint8_t * 2370 fuzz_seed_get (size_t idx, 2371 size_t *len) 2372 { 2373 (void) idx; 2374 *len = sizeof (no_https_seed); 2375 return no_https_seed; 2376 } 2377 2378 2379 #endif /* ! HTTPS_SUPPORT */ 2380 2381 /* end of fuzz_tls.c */