1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "apr_general.h"
18#include "apr_pools.h"
19#include "apr_random.h"
20#include "apr_thread_proc.h"
21#include <stdio.h>
22#include <stdlib.h>
23#include "testutil.h"
24
25#define RANDOM_BUF_SZ 128
26
27static void hexdump(const char *msg, const unsigned char *b, int n)
28{
29    int i;
30
31    printf("\n%s", msg);
32    for (i = 0; i < n; ++i) {
33#if 0
34        if ((i & 0xf) == 0)
35            printf("%04x", i);
36        printf(" %02x", b[i]);
37        if ((i & 0xf) == 0xf)
38            printf("\n");
39#else
40        printf("0x%02x,", b[i]);
41        if ((i & 7) == 7)
42            printf("\n");
43#endif
44    }
45    printf("\n");
46}
47
48static apr_random_t *r;
49
50typedef apr_status_t APR_THREAD_FUNC rnd_fn(apr_random_t * r, void *b,
51                                            apr_size_t n);
52
53static void rand_run_kat(abts_case *tc, rnd_fn *f, apr_random_t *r,
54                         const unsigned char expected[RANDOM_BUF_SZ])
55{
56    unsigned char c[RANDOM_BUF_SZ];
57    apr_status_t rv;
58
59    rv = f(r, c, RANDOM_BUF_SZ);
60    ABTS_INT_EQUAL(tc, 0, rv);
61    if (rv)
62        return;
63    if (memcmp(c, expected, RANDOM_BUF_SZ)) {
64        hexdump("Generated: ", c, RANDOM_BUF_SZ);
65        hexdump("Expected:  ", expected, RANDOM_BUF_SZ);
66        ABTS_FAIL(tc, "Randomness mismatch");
67    }
68}
69
70#if APR_HAS_FORK
71static int rand_check_kat(rnd_fn *f, apr_random_t *r,
72                          const unsigned char expected[RANDOM_BUF_SZ],
73                          apr_file_t *readp, apr_file_t *writep)
74{
75    apr_size_t nbytes = RANDOM_BUF_SZ;
76    apr_size_t cmd_size = 1;
77    unsigned char c[RANDOM_BUF_SZ];
78    char ack;
79    apr_status_t rv;
80
81    rv = f(r, c, RANDOM_BUF_SZ);
82    if (rv)
83        return 2;
84    rv = 0;
85    if (memcmp(c, expected, RANDOM_BUF_SZ)) {
86        rv = 1;
87    } else {
88        hexdump("Generated: ", c, RANDOM_BUF_SZ);
89        hexdump("Previous:  ", expected, RANDOM_BUF_SZ);
90    }
91    /* Report back our random values for comparison in another child */
92    apr_file_write(writep, c, &nbytes);
93    /* Wait for our parent ack the data */
94    apr_file_read(readp, &ack, &cmd_size);
95    return rv;
96}
97#endif
98
99static void rand_add_zeroes(apr_random_t *r)
100{
101    static unsigned char c[2048];
102
103    apr_random_add_entropy(r, c, sizeof c);
104}
105
106static void rand_run_seed_short(abts_case *tc, rnd_fn *f, apr_random_t *r,
107                                int count)
108{
109    int i;
110    apr_status_t rv;
111    char c[1];
112
113    for (i = 0; i < count; ++i)
114        rand_add_zeroes(r);
115    rv = f(r, c, 1);
116    ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOTENOUGHENTROPY(rv));
117}
118
119static void rand_seed_short(abts_case *tc, void *data)
120{
121    r = apr_random_standard_new(p);
122    rand_run_seed_short(tc, apr_random_insecure_bytes, r, 32);
123}
124
125static void rand_kat(abts_case *tc, void *data)
126{
127    unsigned char expected[RANDOM_BUF_SZ] = {
128        0x82, 0x04, 0xad, 0xd2, 0x0b, 0xd5, 0xac, 0xda,
129        0x3d, 0x85, 0x58, 0x38, 0x54, 0x6b, 0x69, 0x45,
130        0x37, 0x4c, 0xc7, 0xd7, 0x87, 0xeb, 0xbf, 0xd9,
131        0xb1, 0xb8, 0xb8, 0x2d, 0x9b, 0x33, 0x6e, 0x97,
132        0x04, 0x1d, 0x4c, 0xb0, 0xd1, 0xdf, 0x3d, 0xac,
133        0xd2, 0xaa, 0xfa, 0xcd, 0x96, 0xb7, 0xcf, 0xb1,
134        0x8e, 0x3d, 0xb3, 0xe5, 0x37, 0xa9, 0x95, 0xb4,
135        0xaa, 0x3d, 0x11, 0x1a, 0x08, 0x20, 0x21, 0x9f,
136        0xdb, 0x08, 0x3a, 0xb9, 0x57, 0x9f, 0xf2, 0x1f,
137        0x27, 0xdc, 0xb6, 0xc0, 0x85, 0x08, 0x05, 0xbb,
138        0x13, 0xbe, 0xb1, 0xe9, 0x63, 0x2a, 0xe2, 0xa4,
139        0x23, 0x15, 0x2a, 0x10, 0xbf, 0xdf, 0x09, 0xb3,
140        0xc7, 0xfb, 0x2d, 0x87, 0x48, 0x19, 0xfb, 0xc0,
141        0x15, 0x8c, 0xcb, 0xc6, 0xbd, 0x89, 0x38, 0x69,
142        0xa3, 0xae, 0xa3, 0x21, 0x58, 0x50, 0xe7, 0xc4,
143        0x87, 0xec, 0x2e, 0xb1, 0x2d, 0x6a, 0xbd, 0x46
144    };
145
146    rand_add_zeroes(r);
147    rand_run_kat(tc, apr_random_insecure_bytes, r, expected);
148}
149
150static void rand_seed_short2(abts_case *tc, void *data)
151{
152    rand_run_seed_short(tc, apr_random_secure_bytes, r, 320);
153}
154
155static void rand_kat2(abts_case *tc, void *data)
156{
157    unsigned char expected[RANDOM_BUF_SZ] = {
158        0x38, 0x8f, 0x01, 0x29, 0x5a, 0x5c, 0x1f, 0xa8,
159        0x00, 0xde, 0x16, 0x4c, 0xe5, 0xf7, 0x1f, 0x58,
160        0xc0, 0x67, 0xe2, 0x98, 0x3d, 0xde, 0x4a, 0x75,
161        0x61, 0x3f, 0x23, 0xd8, 0x45, 0x7a, 0x10, 0x60,
162        0x59, 0x9b, 0xd6, 0xaf, 0xcb, 0x0a, 0x2e, 0x34,
163        0x9c, 0x39, 0x5b, 0xd0, 0xbc, 0x9a, 0xf0, 0x7b,
164        0x7f, 0x40, 0x8b, 0x33, 0xc0, 0x0e, 0x2a, 0x56,
165        0xfc, 0xe5, 0xab, 0xde, 0x7b, 0x13, 0xf5, 0xec,
166        0x15, 0x68, 0xb8, 0x09, 0xbc, 0x2c, 0x15, 0xf0,
167        0x7b, 0xef, 0x2a, 0x97, 0x19, 0xa8, 0x69, 0x51,
168        0xdf, 0xb0, 0x5f, 0x1a, 0x4e, 0xdf, 0x42, 0x02,
169        0x71, 0x36, 0xa7, 0x25, 0x64, 0x85, 0xe2, 0x72,
170        0xc7, 0x87, 0x4d, 0x7d, 0x15, 0xbb, 0x15, 0xd1,
171        0xb1, 0x62, 0x0b, 0x25, 0xd9, 0xd3, 0xd9, 0x5a,
172        0xe3, 0x47, 0x1e, 0xae, 0x67, 0xb4, 0x19, 0x9e,
173        0xed, 0xd2, 0xde, 0xce, 0x18, 0x70, 0x57, 0x12
174    };
175
176    rand_add_zeroes(r);
177    rand_run_kat(tc, apr_random_secure_bytes, r, expected);
178}
179
180static void rand_barrier(abts_case *tc, void *data)
181{
182    apr_random_barrier(r);
183    rand_run_seed_short(tc, apr_random_secure_bytes, r, 320);
184}
185
186static void rand_kat3(abts_case *tc, void *data)
187{
188    unsigned char expected[RANDOM_BUF_SZ] = {
189        0xe8, 0xe7, 0xc9, 0x45, 0xe2, 0x2a, 0x54, 0xb2,
190        0xdd, 0xe0, 0xf9, 0xbc, 0x3d, 0xf9, 0xce, 0x3c,
191        0x4c, 0xbd, 0xc9, 0xe2, 0x20, 0x4a, 0x35, 0x1c,
192        0x04, 0x52, 0x7f, 0xb8, 0x0f, 0x60, 0x89, 0x63,
193        0x8a, 0xbe, 0x0a, 0x44, 0xac, 0x5d, 0xd8, 0xeb,
194        0x24, 0x7d, 0xd1, 0xda, 0x4d, 0x86, 0x9b, 0x94,
195        0x26, 0x56, 0x4a, 0x5e, 0x30, 0xea, 0xd4, 0xa9,
196        0x9a, 0xdf, 0xdd, 0xb6, 0xb1, 0x15, 0xe0, 0xfa,
197        0x28, 0xa4, 0xd6, 0x95, 0xa4, 0xf1, 0xd8, 0x6e,
198        0xeb, 0x8c, 0xa4, 0xac, 0x34, 0xfe, 0x06, 0x92,
199        0xc5, 0x09, 0x99, 0x86, 0xdc, 0x5a, 0x3c, 0x92,
200        0xc8, 0x3e, 0x52, 0x00, 0x4d, 0x01, 0x43, 0x6f,
201        0x69, 0xcf, 0xe2, 0x60, 0x9c, 0x23, 0xb3, 0xa5,
202        0x5f, 0x51, 0x47, 0x8c, 0x07, 0xde, 0x60, 0xc6,
203        0x04, 0xbf, 0x32, 0xd6, 0xdc, 0xb7, 0x31, 0x01,
204        0x29, 0x51, 0x51, 0xb3, 0x19, 0x6e, 0xe4, 0xf8
205    };
206
207    rand_run_kat(tc, apr_random_insecure_bytes, r, expected);
208}
209
210static void rand_kat4(abts_case *tc, void *data)
211{
212    unsigned char expected[RANDOM_BUF_SZ] = {
213        0x7d, 0x0e, 0xc4, 0x4e, 0x3e, 0xac, 0x86, 0x50,
214        0x37, 0x95, 0x7a, 0x98, 0x23, 0x26, 0xa7, 0xbf,
215        0x60, 0xfb, 0xa3, 0x70, 0x90, 0xc3, 0x58, 0xc6,
216        0xbd, 0xd9, 0x5e, 0xa6, 0x77, 0x62, 0x7a, 0x5c,
217        0x96, 0x83, 0x7f, 0x80, 0x3d, 0xf4, 0x9c, 0xcc,
218        0x9b, 0x0c, 0x8c, 0xe1, 0x72, 0xa8, 0xfb, 0xc9,
219        0xc5, 0x43, 0x91, 0xdc, 0x9d, 0x92, 0xc2, 0xce,
220        0x1c, 0x5e, 0x36, 0xc7, 0x87, 0xb1, 0xb4, 0xa3,
221        0xc8, 0x69, 0x76, 0xfc, 0x35, 0x75, 0xcb, 0x08,
222        0x2f, 0xe3, 0x98, 0x76, 0x37, 0x80, 0x04, 0x5c,
223        0xb8, 0xb0, 0x7f, 0xb2, 0xda, 0xe3, 0xa3, 0xba,
224        0xed, 0xff, 0xf5, 0x9d, 0x3b, 0x7b, 0xf3, 0x32,
225        0x6c, 0x50, 0xa5, 0x3e, 0xcc, 0xe1, 0x84, 0x9c,
226        0x17, 0x9e, 0x80, 0x64, 0x09, 0xbb, 0x62, 0xf1,
227        0x95, 0xf5, 0x2c, 0xc6, 0x9f, 0x6a, 0xee, 0x6d,
228        0x17, 0x35, 0x5f, 0x35, 0x8d, 0x55, 0x0c, 0x07
229    };
230
231    rand_add_zeroes(r);
232    rand_run_kat(tc, apr_random_secure_bytes, r, expected);
233}
234
235#if APR_HAS_FORK
236static void rand_fork(abts_case *tc, void *data)
237{
238    apr_proc_t proc;
239    apr_status_t rv;
240    apr_size_t nbytes = RANDOM_BUF_SZ;
241    apr_size_t cmd_size = 1;
242    char cmd = 'X';
243    unsigned char expected[RANDOM_BUF_SZ] = {
244        0xac, 0x93, 0xd2, 0x5c, 0xc7, 0xf5, 0x8d, 0xc2,
245        0xd8, 0x8d, 0xb6, 0x7a, 0x94, 0xe1, 0x83, 0x4c,
246        0x26, 0xe2, 0x38, 0x6d, 0xf5, 0xbd, 0x9d, 0x6e,
247        0x91, 0x77, 0x3a, 0x4b, 0x9b, 0xef, 0x9b, 0xa3,
248        0x9f, 0xf6, 0x6d, 0x0c, 0xdc, 0x4b, 0x02, 0xe9,
249        0x5d, 0x3d, 0xfc, 0x92, 0x6b, 0xdf, 0xc9, 0xef,
250        0xb9, 0xa8, 0x74, 0x09, 0xa3, 0xff, 0x64, 0x8d,
251        0x19, 0xc1, 0x31, 0x31, 0x17, 0xe1, 0xb7, 0x7a,
252        0xe7, 0x55, 0x14, 0x92, 0x05, 0xe3, 0x1e, 0xb8,
253        0x9b, 0x1b, 0xdc, 0xac, 0x0e, 0x15, 0x08, 0xa2,
254        0x93, 0x13, 0xf6, 0x04, 0xc6, 0x9d, 0xf8, 0x7f,
255        0x26, 0x32, 0x68, 0x43, 0x2e, 0x5a, 0x4f, 0x47,
256        0xe8, 0xf8, 0x59, 0xb7, 0xfb, 0xbe, 0x30, 0x04,
257        0xb6, 0x63, 0x6f, 0x19, 0xf3, 0x2c, 0xd4, 0xeb,
258        0x32, 0x8a, 0x54, 0x01, 0xd0, 0xaf, 0x3f, 0x13,
259        0xc1, 0x7f, 0x10, 0x2e, 0x08, 0x1c, 0x28, 0x4b,
260    };
261
262    apr_file_t *readdatap = NULL;
263    apr_file_t *writedatap = NULL;
264    apr_file_t *readcmdp = NULL;
265    apr_file_t *writecmdp = NULL;
266    apr_pool_t *p;
267    int i;
268
269    apr_pool_create(&p, NULL);
270    /* Set up data pipe for children */
271    rv = apr_file_pipe_create(&readdatap, &writedatap, p);
272    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
273    ABTS_PTR_NOTNULL(tc, readdatap);
274    ABTS_PTR_NOTNULL(tc, writedatap);
275    /* Set up cmd pipe for children */
276    rv = apr_file_pipe_create(&readcmdp, &writecmdp, p);
277    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
278    ABTS_PTR_NOTNULL(tc, readcmdp);
279    ABTS_PTR_NOTNULL(tc, writecmdp);
280
281    rand_run_kat(tc, apr_random_secure_bytes, r, expected);
282
283    for (i = 0; i< 10; i++)
284    {
285        rv = apr_proc_fork(&proc, p);
286        if (rv == APR_INCHILD) {
287            int n = rand_check_kat(apr_random_secure_bytes, r, expected, readcmdp, writedatap);
288            exit(n);
289        }
290        else if (rv == APR_INPARENT) {
291            int exitcode;
292            apr_exit_why_e why;
293
294            /* Read the random data generated by child */
295            rv = apr_file_read(readdatap, expected, &nbytes);
296            ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
297            /* Tell child to finish */
298            rv = apr_file_write(writecmdp, &cmd, &cmd_size);
299            ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
300            apr_proc_wait(&proc, &exitcode, &why, APR_WAIT);
301            if (why != APR_PROC_EXIT) {
302                ABTS_FAIL(tc, "Child terminated abnormally");
303            }
304            else if (exitcode == 0) {
305                if (i == 0)
306                {
307                    ABTS_FAIL(tc, "Child produced our randomness");
308                } else
309                {
310                    ABTS_FAIL(tc, "Child produced randomness of previous child");
311                }
312            }
313            else if (exitcode == 2) {
314                ABTS_FAIL(tc, "Child randomness failed");
315            }
316            else if (exitcode != 1) {
317                ABTS_FAIL(tc, "Unknown child error");
318            }
319        } else {
320            ABTS_FAIL(tc, "Fork failed");
321        }
322    }
323
324}
325#endif
326
327static void rand_exists(abts_case *tc, void *data)
328{
329#if !APR_HAS_RANDOM
330    ABTS_NOT_IMPL(tc, "apr_generate_random_bytes");
331#else
332    unsigned char c[42];
333
334    /* There must be a better way to test random-ness, but I don't know
335     * what it is right now.
336     */
337    APR_ASSERT_SUCCESS(tc, "apr_generate_random_bytes failed",
338                       apr_generate_random_bytes(c, sizeof c));
339#endif
340}
341
342abts_suite *testrand(abts_suite *suite)
343{
344    suite = ADD_SUITE(suite)
345
346    abts_run_test(suite, rand_exists, NULL);
347    abts_run_test(suite, rand_seed_short, NULL);
348    abts_run_test(suite, rand_kat, NULL);
349    abts_run_test(suite, rand_seed_short2, NULL);
350    abts_run_test(suite, rand_kat2, NULL);
351    abts_run_test(suite, rand_barrier, NULL);
352    abts_run_test(suite, rand_kat3, NULL);
353    abts_run_test(suite, rand_kat4, NULL);
354#if APR_HAS_FORK
355    abts_run_test(suite, rand_fork, NULL);
356#endif
357
358    return suite;
359}
360