/src/mod_auth_openidc/test/fuzz/fuzz_cookie.c
Line | Count | Source |
1 | | /* |
2 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
3 | | * contributor license agreements. Licensed under the Apache License, |
4 | | * Version 2.0 (the "License"); you may not use this file except in |
5 | | * compliance with the License. You may obtain a copy of the License at |
6 | | * |
7 | | * http://www.apache.org/licenses/LICENSE-2.0 |
8 | | * |
9 | | * Copyright (C) 2017-2026 ZmartZone Holding BV - hans.zandbelt@openidc.com |
10 | | * |
11 | | * Fuzz target for the raw browser-supplied Cookie request header -- as |
12 | | * directly attacker-controlled as input gets, any client sets it -- and the |
13 | | * three consumers the module runs over it: |
14 | | * |
15 | | * - oidc_http_get_cookie(): the header tokenizer, per cookie name; |
16 | | * - oidc_http_get_chunked_cookie(): the reassembly of a session cookie that |
17 | | * was split over "<name>_chunks" plus "<name>_0".."<name>_N" cookies, i.e. |
18 | | * a browser-supplied chunk count driving a lookup loop (this is where a |
19 | | * missing-chunk truncation bug was fixed, see commit "fix: return NULL |
20 | | * when a chunked cookie is missing a chunk"); |
21 | | * - oidc_state_cookies_clean_expired(): the sweep over every cookie in the |
22 | | * header that decrypts each "mod_auth_openidc_state_*" value, drops the |
23 | | * expired ones and enforces OIDCStateMaxNumberOfCookies -- it runs on |
24 | | * every authentication request and every authorization response. |
25 | | */ |
26 | | |
27 | | #include "fuzz.h" |
28 | | /* util.h pulls in const.h before any Apache header does, so config.h's |
29 | | * PACKAGE_* defines win the race against Apache's own (empty) ones in |
30 | | * ap_config_auto.h; keep it ahead of http.h, see cfg/cfg.h's own ordering |
31 | | * (clang-format's include sorting would undo exactly that, hence the guard) */ |
32 | | /* clang-format off */ |
33 | | #include "util.h" /* test fixture */ |
34 | | #include "http.h" /* oidc_http_get_cookie, oidc_http_get_chunked_cookie */ |
35 | | #include "state.h" /* oidc_state_cookies_clean_expired */ |
36 | | /* clang-format on */ |
37 | | |
38 | | #include <apr_pools.h> |
39 | | #include <apr_strings.h> |
40 | | #include <apr_tables.h> |
41 | | |
42 | | static int g_ready = 0; |
43 | | |
44 | | /* engine-called one-time init, pre-forkserver on AFL++: see fuzz.h */ |
45 | 34 | int LLVMFuzzerInitialize(int *argc, char ***argv) { |
46 | 34 | (void)argc; |
47 | 34 | (void)argv; |
48 | 34 | if (!g_ready) { |
49 | 34 | oidc_test_setup(); |
50 | 34 | g_ready = 1; |
51 | 34 | } |
52 | 34 | return 0; |
53 | 34 | } |
54 | | |
55 | 6.63k | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
56 | 6.63k | if (!g_ready) |
57 | 0 | LLVMFuzzerInitialize(NULL, NULL); |
58 | | |
59 | 6.63k | apr_pool_t *pool = NULL; |
60 | 6.63k | apr_pool_create(&pool, oidc_test_pool_get()); |
61 | | |
62 | | /* shallow-copy the fixture request and give it a per-input pool, plus a |
63 | | * fresh headers_in table so the fuzzed Cookie value never touches the |
64 | | * shared fixture's table (which would otherwise leak across inputs), and |
65 | | * fresh output tables for the Set-Cookie deletions the sweep emits */ |
66 | 6.63k | request_rec r = *oidc_test_request_get(); |
67 | 6.63k | r.pool = pool; |
68 | 6.63k | r.headers_in = apr_table_make(pool, 1); |
69 | 6.63k | r.headers_out = apr_table_make(pool, 8); |
70 | 6.63k | r.err_headers_out = apr_table_make(pool, 8); |
71 | 6.63k | apr_table_set(r.headers_in, "Cookie", apr_pstrmemdup(pool, (const char *)data, size)); |
72 | | |
73 | 6.63k | oidc_http_get_cookie(&r, "mod_auth_openidc_session"); |
74 | | /* the chunk size only decides whether reassembly is attempted at all */ |
75 | 6.63k | oidc_http_get_chunked_cookie(&r, "mod_auth_openidc_session", 4000); |
76 | 6.63k | oidc_state_cookies_clean_expired(&r, oidc_test_cfg_get(), NULL, 1); |
77 | | |
78 | 6.63k | apr_pool_destroy(pool); |
79 | 6.63k | return 0; |
80 | 6.63k | } |