1*fad7f654SGordon Tetlow /*
2*fad7f654SGordon Tetlow * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
3*fad7f654SGordon Tetlow *
4*fad7f654SGordon Tetlow * Licensed under the Apache License 2.0 (the "License"). You may not use
5*fad7f654SGordon Tetlow * this file except in compliance with the License. You can obtain a copy
6*fad7f654SGordon Tetlow * in the file LICENSE in the source distribution or at
7*fad7f654SGordon Tetlow * https://www.openssl.org/source/license.html
8*fad7f654SGordon Tetlow */
9*fad7f654SGordon Tetlow
10*fad7f654SGordon Tetlow /*
11*fad7f654SGordon Tetlow * Regression test for: CMP server unauthenticated memory/CPU DoS via
12*fad7f654SGordon Tetlow * cached extraCerts on failed protection checks.
13*fad7f654SGordon Tetlow *
14*fad7f654SGordon Tetlow * Root cause (crypto/cmp/cmp_vfy.c, ossl_cmp_msg_check_update(), current
15*fad7f654SGordon Tetlow * master as of this writing):
16*fad7f654SGordon Tetlow *
17*fad7f654SGordon Tetlow * res = ossl_x509_add_certs_new(&ctx->untrusted, msg->extraCerts, ...);
18*fad7f654SGordon Tetlow * ...
19*fad7f654SGordon Tetlow * res = OSSL_CMP_validate_msg(ctx, msg) || (cb...); // may be 0 (rejected)
20*fad7f654SGordon Tetlow *
21*fad7f654SGordon Tetlow * if (ctx->noCacheExtraCerts) // <-- rollback is
22*fad7f654SGordon Tetlow * while (num_added-- > 0) // gated on this
23*fad7f654SGordon Tetlow * X509_free(sk_X509_shift(ctx->untrusted)); // flag only, NOT
24*fad7f654SGordon Tetlow * // on the
25*fad7f654SGordon Tetlow * // validation
26*fad7f654SGordon Tetlow * // result (res)
27*fad7f654SGordon Tetlow *
28*fad7f654SGordon Tetlow * if (!res) { ...; return 0; } // certs from a REJECTED msg are kept
29*fad7f654SGordon Tetlow *
30*fad7f654SGordon Tetlow * This test exercises ossl_cmp_msg_check_update() directly -- no sockets,
31*fad7f654SGordon Tetlow * no HTTP server, no apps/cmp.c -- and asserts on the resulting size of
32*fad7f654SGordon Tetlow * ctx->untrusted. It builds a genuinely PBM-protected OSSL_CMP_MSG using
33*fad7f654SGordon Tetlow * the project's own internal message-creation function
34*fad7f654SGordon Tetlow * (ossl_cmp_genm_new(), same one exercised in test/cmp_msg_test.c) so the
35*fad7f654SGordon Tetlow * message is not hand-crafted to "look" rejectable -- it is rejected for a
36*fad7f654SGordon Tetlow * real reason (the receiving ctx has no matching secret configured), the
37*fad7f654SGordon Tetlow * same way OSSL_CMP_validate_msg() would reject any unauthenticated CMP
38*fad7f654SGordon Tetlow * request in the field.
39*fad7f654SGordon Tetlow *
40*fad7f654SGordon Tetlow * Expected results:
41*fad7f654SGordon Tetlow * - BEFORE the fix: untrusted_count_after == untrusted_count_before + N
42*fad7f654SGordon Tetlow * (every rejected message's extraCerts persist)
43*fad7f654SGordon Tetlow * - AFTER the fix: untrusted_count_after == untrusted_count_before
44*fad7f654SGordon Tetlow * (rejected messages leave no residue)
45*fad7f654SGordon Tetlow */
46*fad7f654SGordon Tetlow
47*fad7f654SGordon Tetlow #include "helpers/cmp_testlib.h"
48*fad7f654SGordon Tetlow
49*fad7f654SGordon Tetlow #define NUM_REJECTED_REQUESTS 25 /* "attacker" sends this many distinct certs */
50*fad7f654SGordon Tetlow
51*fad7f654SGordon Tetlow typedef struct test_fixture {
52*fad7f654SGordon Tetlow const char *test_case_name;
53*fad7f654SGordon Tetlow OSSL_CMP_CTX *server_ctx; /* long-lived ctx under test, mirrors srv_ctx->ctx */
54*fad7f654SGordon Tetlow } CMP_DOS_TEST_FIXTURE;
55*fad7f654SGordon Tetlow
56*fad7f654SGordon Tetlow static OSSL_LIB_CTX *libctx = NULL;
57*fad7f654SGordon Tetlow
set_up(const char * const test_case_name)58*fad7f654SGordon Tetlow static CMP_DOS_TEST_FIXTURE *set_up(const char *const test_case_name)
59*fad7f654SGordon Tetlow {
60*fad7f654SGordon Tetlow CMP_DOS_TEST_FIXTURE *fixture;
61*fad7f654SGordon Tetlow
62*fad7f654SGordon Tetlow if (!TEST_ptr(fixture = OPENSSL_zalloc(sizeof(*fixture))))
63*fad7f654SGordon Tetlow return NULL;
64*fad7f654SGordon Tetlow fixture->test_case_name = test_case_name;
65*fad7f654SGordon Tetlow
66*fad7f654SGordon Tetlow if (!TEST_ptr(fixture->server_ctx = OSSL_CMP_CTX_new(libctx, NULL))) {
67*fad7f654SGordon Tetlow OPENSSL_free(fixture);
68*fad7f654SGordon Tetlow return NULL;
69*fad7f654SGordon Tetlow }
70*fad7f654SGordon Tetlow /*
71*fad7f654SGordon Tetlow * Deliberately do NOT call OSSL_CMP_CTX_set1_secretValue() on the
72*fad7f654SGordon Tetlow * server ctx. Per OSSL_CMP_validate_msg() (crypto/cmp/cmp_vfy.c):
73*fad7f654SGordon Tetlow * case NID_id_PasswordBasedMAC:
74*fad7f654SGordon Tetlow * if (ctx->secretValue == NULL) {
75*fad7f654SGordon Tetlow * ossl_cmp_info(ctx, "no secret available for verifying..");
76*fad7f654SGordon Tetlow * ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_PROTECTION);
77*fad7f654SGordon Tetlow * return 0;
78*fad7f654SGordon Tetlow * }
79*fad7f654SGordon Tetlow * so every PBM-protected message this ctx receives is unconditionally
80*fad7f654SGordon Tetlow * rejected -- a deterministic, content-independent rejection path that
81*fad7f654SGordon Tetlow * models "missing or invalid protection" from the report's repro
82*fad7f654SGordon Tetlow * steps, without needing to forge a bad MAC by hand.
83*fad7f654SGordon Tetlow * ctx->noCacheExtraCerts is left at its default (0), exactly as in the
84*fad7f654SGordon Tetlow * vulnerable deployment ("not setting -no_cache_extracerts").
85*fad7f654SGordon Tetlow */
86*fad7f654SGordon Tetlow return fixture;
87*fad7f654SGordon Tetlow }
88*fad7f654SGordon Tetlow
tear_down(CMP_DOS_TEST_FIXTURE * fixture)89*fad7f654SGordon Tetlow static void tear_down(CMP_DOS_TEST_FIXTURE *fixture)
90*fad7f654SGordon Tetlow {
91*fad7f654SGordon Tetlow if (fixture == NULL)
92*fad7f654SGordon Tetlow return;
93*fad7f654SGordon Tetlow OSSL_CMP_CTX_free(fixture->server_ctx);
94*fad7f654SGordon Tetlow OPENSSL_free(fixture);
95*fad7f654SGordon Tetlow }
96*fad7f654SGordon Tetlow
97*fad7f654SGordon Tetlow /* Generates a throwaway EC P-256 keypair; cheap, and key strength is
98*fad7f654SGordon Tetlow * irrelevant to this test. */
generate_throwaway_keypair(void)99*fad7f654SGordon Tetlow static EVP_PKEY *generate_throwaway_keypair(void)
100*fad7f654SGordon Tetlow {
101*fad7f654SGordon Tetlow EVP_PKEY_CTX *pctx = NULL;
102*fad7f654SGordon Tetlow EVP_PKEY *pkey = NULL;
103*fad7f654SGordon Tetlow
104*fad7f654SGordon Tetlow if (!TEST_ptr(pctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", NULL)))
105*fad7f654SGordon Tetlow return NULL;
106*fad7f654SGordon Tetlow if (!TEST_int_gt(EVP_PKEY_keygen_init(pctx), 0)
107*fad7f654SGordon Tetlow || !TEST_int_gt(EVP_PKEY_CTX_set_group_name(pctx, "P-256"), 0)
108*fad7f654SGordon Tetlow || !TEST_int_gt(EVP_PKEY_generate(pctx, &pkey), 0))
109*fad7f654SGordon Tetlow pkey = NULL;
110*fad7f654SGordon Tetlow EVP_PKEY_CTX_free(pctx);
111*fad7f654SGordon Tetlow return pkey;
112*fad7f654SGordon Tetlow }
113*fad7f654SGordon Tetlow
114*fad7f654SGordon Tetlow /*
115*fad7f654SGordon Tetlow * Builds a minimal, self-signed, syntactically valid X509 with a unique
116*fad7f654SGordon Tetlow * subject/issuer per index, so X509_ADD_FLAG_NO_DUP cannot collapse it
117*fad7f654SGordon Tetlow * with any other generated cert (matching the report's exploitation
118*fad7f654SGordon Tetlow * requirement of "unique certificates across requests").
119*fad7f654SGordon Tetlow */
generate_unique_self_signed_cert(EVP_PKEY * pkey,int index)120*fad7f654SGordon Tetlow static X509 *generate_unique_self_signed_cert(EVP_PKEY *pkey, int index)
121*fad7f654SGordon Tetlow {
122*fad7f654SGordon Tetlow X509 *cert = NULL;
123*fad7f654SGordon Tetlow X509_NAME *name = NULL;
124*fad7f654SGordon Tetlow ASN1_INTEGER *serial = NULL;
125*fad7f654SGordon Tetlow char cn[64];
126*fad7f654SGordon Tetlow
127*fad7f654SGordon Tetlow BIO_snprintf(cn, sizeof(cn), "attacker-cert-%d", index);
128*fad7f654SGordon Tetlow
129*fad7f654SGordon Tetlow if (!TEST_ptr(cert = X509_new())
130*fad7f654SGordon Tetlow || !TEST_true(X509_set_version(cert, X509_VERSION_3)))
131*fad7f654SGordon Tetlow goto err;
132*fad7f654SGordon Tetlow
133*fad7f654SGordon Tetlow if (!TEST_ptr(serial = ASN1_INTEGER_new())
134*fad7f654SGordon Tetlow || !TEST_true(ASN1_INTEGER_set(serial, 1000L + index))
135*fad7f654SGordon Tetlow || !TEST_true(X509_set_serialNumber(cert, serial)))
136*fad7f654SGordon Tetlow goto err;
137*fad7f654SGordon Tetlow
138*fad7f654SGordon Tetlow if (!TEST_ptr(X509_gmtime_adj(X509_getm_notBefore(cert), 0))
139*fad7f654SGordon Tetlow || !TEST_ptr(X509_gmtime_adj(X509_getm_notAfter(cert),
140*fad7f654SGordon Tetlow 60L * 60L * 24L * 365L)))
141*fad7f654SGordon Tetlow goto err;
142*fad7f654SGordon Tetlow
143*fad7f654SGordon Tetlow if (!TEST_true(X509_set_pubkey(cert, pkey)))
144*fad7f654SGordon Tetlow goto err;
145*fad7f654SGordon Tetlow
146*fad7f654SGordon Tetlow if (!TEST_ptr(name = X509_NAME_new())
147*fad7f654SGordon Tetlow || !TEST_true(X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
148*fad7f654SGordon Tetlow (unsigned char *)"cmp-dos-test",
149*fad7f654SGordon Tetlow -1, -1, 0))
150*fad7f654SGordon Tetlow || !TEST_true(X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
151*fad7f654SGordon Tetlow (unsigned char *)cn,
152*fad7f654SGordon Tetlow -1, -1, 0))
153*fad7f654SGordon Tetlow || !TEST_true(X509_set_subject_name(cert, name))
154*fad7f654SGordon Tetlow || !TEST_true(X509_set_issuer_name(cert, name)))
155*fad7f654SGordon Tetlow goto err;
156*fad7f654SGordon Tetlow
157*fad7f654SGordon Tetlow if (!TEST_int_gt(X509_sign(cert, pkey, EVP_sha256()), 0))
158*fad7f654SGordon Tetlow goto err;
159*fad7f654SGordon Tetlow
160*fad7f654SGordon Tetlow X509_NAME_free(name);
161*fad7f654SGordon Tetlow ASN1_INTEGER_free(serial);
162*fad7f654SGordon Tetlow return cert;
163*fad7f654SGordon Tetlow
164*fad7f654SGordon Tetlow err:
165*fad7f654SGordon Tetlow X509_NAME_free(name);
166*fad7f654SGordon Tetlow ASN1_INTEGER_free(serial);
167*fad7f654SGordon Tetlow X509_free(cert);
168*fad7f654SGordon Tetlow return NULL;
169*fad7f654SGordon Tetlow }
170*fad7f654SGordon Tetlow
171*fad7f654SGordon Tetlow /*
172*fad7f654SGordon Tetlow * Builds a real, internally consistent, PBM-protected CMP GenMsg carrying
173*fad7f654SGordon Tetlow * exactly one never-before-seen self-signed cert as its sole extraCert.
174*fad7f654SGordon Tetlow * Uses a throwaway *client*-side OSSL_CMP_CTX purely to drive message
175*fad7f654SGordon Tetlow * creation/protection (ossl_cmp_genm_new() both builds the body and calls
176*fad7f654SGordon Tetlow * ossl_cmp_msg_protect() internally, same as in test/cmp_msg_test.c). The
177*fad7f654SGordon Tetlow * client ctx's secret is intentionally never shared with the server ctx
178*fad7f654SGordon Tetlow * under test, so the message is protected (syntactically well-formed,
179*fad7f654SGordon Tetlow * non-empty protection field) but NOT verifiable by the receiver -- this
180*fad7f654SGordon Tetlow * is what "missing or invalid protection" means for a real attacker who
181*fad7f654SGordon Tetlow * has no credentials, not an empty/garbage protection field.
182*fad7f654SGordon Tetlow */
build_rejectable_msg_with_unique_cert(int index)183*fad7f654SGordon Tetlow static OSSL_CMP_MSG *build_rejectable_msg_with_unique_cert(int index)
184*fad7f654SGordon Tetlow {
185*fad7f654SGordon Tetlow OSSL_CMP_CTX *client_ctx = NULL;
186*fad7f654SGordon Tetlow OSSL_CMP_MSG *msg = NULL;
187*fad7f654SGordon Tetlow EVP_PKEY *pkey = NULL;
188*fad7f654SGordon Tetlow X509 *fresh_cert = NULL;
189*fad7f654SGordon Tetlow STACK_OF(X509) *extra = NULL;
190*fad7f654SGordon Tetlow unsigned char ref[16], secret[16];
191*fad7f654SGordon Tetlow
192*fad7f654SGordon Tetlow if (!TEST_ptr(client_ctx = OSSL_CMP_CTX_new(libctx, NULL)))
193*fad7f654SGordon Tetlow goto err;
194*fad7f654SGordon Tetlow
195*fad7f654SGordon Tetlow if (!TEST_ptr(pkey = generate_throwaway_keypair())
196*fad7f654SGordon Tetlow || !TEST_ptr(fresh_cert = generate_unique_self_signed_cert(pkey, index)))
197*fad7f654SGordon Tetlow goto err;
198*fad7f654SGordon Tetlow
199*fad7f654SGordon Tetlow if (!TEST_ptr(extra = sk_X509_new_null())
200*fad7f654SGordon Tetlow || !TEST_true(sk_X509_push(extra, fresh_cert)))
201*fad7f654SGordon Tetlow goto err;
202*fad7f654SGordon Tetlow fresh_cert = NULL; /* ownership now with the stack */
203*fad7f654SGordon Tetlow
204*fad7f654SGordon Tetlow if (!TEST_true(OSSL_CMP_CTX_set1_extraCertsOut(client_ctx, extra)))
205*fad7f654SGordon Tetlow goto err;
206*fad7f654SGordon Tetlow
207*fad7f654SGordon Tetlow /* PBM protection with a secret the server ctx will never be given */
208*fad7f654SGordon Tetlow memset(ref, (unsigned char)(0xA0 + (index & 0x0F)), sizeof(ref));
209*fad7f654SGordon Tetlow memset(secret, (unsigned char)(0x50 + (index & 0x0F)), sizeof(secret));
210*fad7f654SGordon Tetlow if (!TEST_true(OSSL_CMP_CTX_set_option(client_ctx,
211*fad7f654SGordon Tetlow OSSL_CMP_OPT_UNPROTECTED_SEND, 0))
212*fad7f654SGordon Tetlow || !TEST_true(OSSL_CMP_CTX_set1_referenceValue(client_ctx, ref,
213*fad7f654SGordon Tetlow sizeof(ref)))
214*fad7f654SGordon Tetlow || !TEST_true(OSSL_CMP_CTX_set1_secretValue(client_ctx, secret,
215*fad7f654SGordon Tetlow sizeof(secret))))
216*fad7f654SGordon Tetlow goto err;
217*fad7f654SGordon Tetlow
218*fad7f654SGordon Tetlow /* GenMsg is the lightest standard body type for this purpose */
219*fad7f654SGordon Tetlow if (!TEST_ptr(msg = ossl_cmp_genm_new(client_ctx)))
220*fad7f654SGordon Tetlow goto err;
221*fad7f654SGordon Tetlow
222*fad7f654SGordon Tetlow sk_X509_pop_free(extra, X509_free);
223*fad7f654SGordon Tetlow X509_free(fresh_cert);
224*fad7f654SGordon Tetlow EVP_PKEY_free(pkey);
225*fad7f654SGordon Tetlow OSSL_CMP_CTX_free(client_ctx);
226*fad7f654SGordon Tetlow return msg;
227*fad7f654SGordon Tetlow
228*fad7f654SGordon Tetlow err:
229*fad7f654SGordon Tetlow sk_X509_pop_free(extra, X509_free);
230*fad7f654SGordon Tetlow X509_free(fresh_cert);
231*fad7f654SGordon Tetlow EVP_PKEY_free(pkey);
232*fad7f654SGordon Tetlow OSSL_CMP_CTX_free(client_ctx);
233*fad7f654SGordon Tetlow OSSL_CMP_MSG_free(msg);
234*fad7f654SGordon Tetlow return NULL;
235*fad7f654SGordon Tetlow }
236*fad7f654SGordon Tetlow
237*fad7f654SGordon Tetlow /*
238*fad7f654SGordon Tetlow * Core assertion: N distinct rejected requests must not grow
239*fad7f654SGordon Tetlow * server_ctx->untrusted at all.
240*fad7f654SGordon Tetlow *
241*fad7f654SGordon Tetlow * Before the fix this fails with e.g.:
242*fad7f654SGordon Tetlow * ERROR: untrusted count after (25) != count before (0)
243*fad7f654SGordon Tetlow */
execute_no_unbounded_growth_test(CMP_DOS_TEST_FIXTURE * fixture)244*fad7f654SGordon Tetlow static int execute_no_unbounded_growth_test(CMP_DOS_TEST_FIXTURE *fixture)
245*fad7f654SGordon Tetlow {
246*fad7f654SGordon Tetlow OSSL_CMP_CTX *server_ctx = fixture->server_ctx;
247*fad7f654SGordon Tetlow int count_before, count_after, i;
248*fad7f654SGordon Tetlow
249*fad7f654SGordon Tetlow count_before = sk_X509_num(OSSL_CMP_CTX_get0_untrusted(server_ctx));
250*fad7f654SGordon Tetlow if (count_before < 0)
251*fad7f654SGordon Tetlow count_before = 0;
252*fad7f654SGordon Tetlow
253*fad7f654SGordon Tetlow for (i = 0; i < NUM_REJECTED_REQUESTS; i++) {
254*fad7f654SGordon Tetlow OSSL_CMP_MSG *msg = build_rejectable_msg_with_unique_cert(i);
255*fad7f654SGordon Tetlow int check_result;
256*fad7f654SGordon Tetlow
257*fad7f654SGordon Tetlow if (!TEST_ptr(msg))
258*fad7f654SGordon Tetlow return 0;
259*fad7f654SGordon Tetlow
260*fad7f654SGordon Tetlow check_result = ossl_cmp_msg_check_update(server_ctx, msg, NULL, 0);
261*fad7f654SGordon Tetlow OSSL_CMP_MSG_free(msg);
262*fad7f654SGordon Tetlow
263*fad7f654SGordon Tetlow if (!TEST_int_eq(check_result, 0)) {
264*fad7f654SGordon Tetlow TEST_note("expected request #%d to be rejected (server ctx has"
265*fad7f654SGordon Tetlow " no matching PBM secret) but it was accepted -- test"
266*fad7f654SGordon Tetlow " setup is wrong, not exercising the rejection path",
267*fad7f654SGordon Tetlow i);
268*fad7f654SGordon Tetlow return 0;
269*fad7f654SGordon Tetlow }
270*fad7f654SGordon Tetlow }
271*fad7f654SGordon Tetlow
272*fad7f654SGordon Tetlow count_after = sk_X509_num(OSSL_CMP_CTX_get0_untrusted(server_ctx));
273*fad7f654SGordon Tetlow if (count_after < 0)
274*fad7f654SGordon Tetlow count_after = 0;
275*fad7f654SGordon Tetlow
276*fad7f654SGordon Tetlow if (!TEST_int_eq(count_after, count_before)) {
277*fad7f654SGordon Tetlow TEST_note("server_ctx->untrusted grew from %d to %d after %d"
278*fad7f654SGordon Tetlow " rejected requests -- failed-request extraCerts caching"
279*fad7f654SGordon Tetlow " bug is present (see ossl_cmp_msg_check_update() in"
280*fad7f654SGordon Tetlow " crypto/cmp/cmp_vfy.c)",
281*fad7f654SGordon Tetlow count_before, count_after,
282*fad7f654SGordon Tetlow NUM_REJECTED_REQUESTS);
283*fad7f654SGordon Tetlow return 0;
284*fad7f654SGordon Tetlow }
285*fad7f654SGordon Tetlow return 1;
286*fad7f654SGordon Tetlow }
287*fad7f654SGordon Tetlow
288*fad7f654SGordon Tetlow /*
289*fad7f654SGordon Tetlow * Single-request variant of the same check, useful in isolation since it
290*fad7f654SGordon Tetlow * pins down that even ONE rejected request leaves no residue -- ruling out
291*fad7f654SGordon Tetlow * X509_ADD_FLAG_NO_DUP coincidentally masking the bug in the N-request test.
292*fad7f654SGordon Tetlow */
execute_single_rejected_request_test(CMP_DOS_TEST_FIXTURE * fixture)293*fad7f654SGordon Tetlow static int execute_single_rejected_request_test(CMP_DOS_TEST_FIXTURE *fixture)
294*fad7f654SGordon Tetlow {
295*fad7f654SGordon Tetlow OSSL_CMP_CTX *server_ctx = fixture->server_ctx;
296*fad7f654SGordon Tetlow OSSL_CMP_MSG *msg = build_rejectable_msg_with_unique_cert(999);
297*fad7f654SGordon Tetlow int count_before, count_after;
298*fad7f654SGordon Tetlow
299*fad7f654SGordon Tetlow if (!TEST_ptr(msg))
300*fad7f654SGordon Tetlow return 0;
301*fad7f654SGordon Tetlow
302*fad7f654SGordon Tetlow count_before = sk_X509_num(OSSL_CMP_CTX_get0_untrusted(server_ctx));
303*fad7f654SGordon Tetlow if (count_before < 0)
304*fad7f654SGordon Tetlow count_before = 0;
305*fad7f654SGordon Tetlow
306*fad7f654SGordon Tetlow if (!TEST_int_eq(ossl_cmp_msg_check_update(server_ctx, msg, NULL, 0), 0)) {
307*fad7f654SGordon Tetlow OSSL_CMP_MSG_free(msg);
308*fad7f654SGordon Tetlow return 0;
309*fad7f654SGordon Tetlow }
310*fad7f654SGordon Tetlow OSSL_CMP_MSG_free(msg);
311*fad7f654SGordon Tetlow
312*fad7f654SGordon Tetlow count_after = sk_X509_num(OSSL_CMP_CTX_get0_untrusted(server_ctx));
313*fad7f654SGordon Tetlow if (count_after < 0)
314*fad7f654SGordon Tetlow count_after = 0;
315*fad7f654SGordon Tetlow
316*fad7f654SGordon Tetlow return TEST_int_eq(count_after, count_before);
317*fad7f654SGordon Tetlow }
318*fad7f654SGordon Tetlow
test_single_rejected_request_leaves_no_residue(void)319*fad7f654SGordon Tetlow static int test_single_rejected_request_leaves_no_residue(void)
320*fad7f654SGordon Tetlow {
321*fad7f654SGordon Tetlow SETUP_TEST_FIXTURE(CMP_DOS_TEST_FIXTURE, set_up);
322*fad7f654SGordon Tetlow EXECUTE_TEST(execute_single_rejected_request_test, tear_down);
323*fad7f654SGordon Tetlow return result;
324*fad7f654SGordon Tetlow }
325*fad7f654SGordon Tetlow
test_no_unbounded_growth_on_rejected_requests(void)326*fad7f654SGordon Tetlow static int test_no_unbounded_growth_on_rejected_requests(void)
327*fad7f654SGordon Tetlow {
328*fad7f654SGordon Tetlow SETUP_TEST_FIXTURE(CMP_DOS_TEST_FIXTURE, set_up);
329*fad7f654SGordon Tetlow EXECUTE_TEST(execute_no_unbounded_growth_test, tear_down);
330*fad7f654SGordon Tetlow return result;
331*fad7f654SGordon Tetlow }
332*fad7f654SGordon Tetlow
setup_tests(void)333*fad7f654SGordon Tetlow int setup_tests(void)
334*fad7f654SGordon Tetlow {
335*fad7f654SGordon Tetlow ADD_TEST(test_single_rejected_request_leaves_no_residue);
336*fad7f654SGordon Tetlow ADD_TEST(test_no_unbounded_growth_on_rejected_requests);
337*fad7f654SGordon Tetlow return 1;
338*fad7f654SGordon Tetlow }
339