1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci#include <stdlib.h>
11e1051a39Sopenharmony_ci#include <string.h>
12e1051a39Sopenharmony_ci#include <openssl/conf.h>
13e1051a39Sopenharmony_ci#include <openssl/err.h>
14e1051a39Sopenharmony_ci#include "testutil.h"
15e1051a39Sopenharmony_ci
16e1051a39Sopenharmony_ci#ifdef _WIN32
17e1051a39Sopenharmony_ci# include <direct.h>
18e1051a39Sopenharmony_ci# define DIRSEP "/\\"
19e1051a39Sopenharmony_ci# ifndef __BORLANDC__
20e1051a39Sopenharmony_ci#  define chdir _chdir
21e1051a39Sopenharmony_ci# endif
22e1051a39Sopenharmony_ci# define DIRSEP_PRESERVE 0
23e1051a39Sopenharmony_ci#elif !defined(OPENSSL_NO_POSIX_IO)
24e1051a39Sopenharmony_ci# include <unistd.h>
25e1051a39Sopenharmony_ci# ifndef OPENSSL_SYS_VMS
26e1051a39Sopenharmony_ci#  define DIRSEP "/"
27e1051a39Sopenharmony_ci#  define DIRSEP_PRESERVE 0
28e1051a39Sopenharmony_ci# else
29e1051a39Sopenharmony_ci#  define DIRSEP "/]:"
30e1051a39Sopenharmony_ci#  define DIRSEP_PRESERVE 1
31e1051a39Sopenharmony_ci# endif
32e1051a39Sopenharmony_ci#else
33e1051a39Sopenharmony_ci/* the test does not work without chdir() */
34e1051a39Sopenharmony_ci# define chdir(x) (-1);
35e1051a39Sopenharmony_ci# define DIRSEP "/"
36e1051a39Sopenharmony_ci#  define DIRSEP_PRESERVE 0
37e1051a39Sopenharmony_ci#endif
38e1051a39Sopenharmony_ci
39e1051a39Sopenharmony_ci/* changes path to that of the filename */
40e1051a39Sopenharmony_cistatic int change_path(const char *file)
41e1051a39Sopenharmony_ci{
42e1051a39Sopenharmony_ci    char *s = OPENSSL_strdup(file);
43e1051a39Sopenharmony_ci    char *p = s;
44e1051a39Sopenharmony_ci    char *last = NULL;
45e1051a39Sopenharmony_ci    int ret = 0;
46e1051a39Sopenharmony_ci
47e1051a39Sopenharmony_ci    if (s == NULL)
48e1051a39Sopenharmony_ci        return -1;
49e1051a39Sopenharmony_ci
50e1051a39Sopenharmony_ci    while ((p = strpbrk(p, DIRSEP)) != NULL) {
51e1051a39Sopenharmony_ci        last = p++;
52e1051a39Sopenharmony_ci    }
53e1051a39Sopenharmony_ci    if (last == NULL)
54e1051a39Sopenharmony_ci        goto err;
55e1051a39Sopenharmony_ci    last[DIRSEP_PRESERVE] = 0;
56e1051a39Sopenharmony_ci
57e1051a39Sopenharmony_ci    TEST_note("changing path to %s", s);
58e1051a39Sopenharmony_ci    ret = chdir(s);
59e1051a39Sopenharmony_ci err:
60e1051a39Sopenharmony_ci    OPENSSL_free(s);
61e1051a39Sopenharmony_ci    return ret;
62e1051a39Sopenharmony_ci}
63e1051a39Sopenharmony_ci
64e1051a39Sopenharmony_ci/*
65e1051a39Sopenharmony_ci * This test program checks the operation of the .include directive.
66e1051a39Sopenharmony_ci */
67e1051a39Sopenharmony_ci
68e1051a39Sopenharmony_cistatic CONF *conf;
69e1051a39Sopenharmony_cistatic BIO *in;
70e1051a39Sopenharmony_cistatic int expect_failure = 0;
71e1051a39Sopenharmony_ci
72e1051a39Sopenharmony_cistatic int test_load_config(void)
73e1051a39Sopenharmony_ci{
74e1051a39Sopenharmony_ci    long errline;
75e1051a39Sopenharmony_ci    long val;
76e1051a39Sopenharmony_ci    char *str;
77e1051a39Sopenharmony_ci    long err;
78e1051a39Sopenharmony_ci
79e1051a39Sopenharmony_ci    if (!TEST_int_gt(NCONF_load_bio(conf, in, &errline), 0)
80e1051a39Sopenharmony_ci        || !TEST_int_eq(err = ERR_peek_error(), 0)) {
81e1051a39Sopenharmony_ci        if (expect_failure)
82e1051a39Sopenharmony_ci            return 1;
83e1051a39Sopenharmony_ci        TEST_note("Failure loading the configuration at line %ld", errline);
84e1051a39Sopenharmony_ci        return 0;
85e1051a39Sopenharmony_ci    }
86e1051a39Sopenharmony_ci    if (expect_failure) {
87e1051a39Sopenharmony_ci        TEST_note("Failure expected but did not happen");
88e1051a39Sopenharmony_ci        return 0;
89e1051a39Sopenharmony_ci    }
90e1051a39Sopenharmony_ci
91e1051a39Sopenharmony_ci    if (!TEST_int_gt(CONF_modules_load(conf, NULL, 0), 0)) {
92e1051a39Sopenharmony_ci        TEST_note("Failed in CONF_modules_load");
93e1051a39Sopenharmony_ci        return 0;
94e1051a39Sopenharmony_ci    }
95e1051a39Sopenharmony_ci
96e1051a39Sopenharmony_ci    /* verify whether CA_default/default_days is set */
97e1051a39Sopenharmony_ci    val = 0;
98e1051a39Sopenharmony_ci    if (!TEST_int_eq(NCONF_get_number(conf, "CA_default", "default_days", &val), 1)
99e1051a39Sopenharmony_ci        || !TEST_int_eq(val, 365)) {
100e1051a39Sopenharmony_ci        TEST_note("default_days incorrect");
101e1051a39Sopenharmony_ci        return 0;
102e1051a39Sopenharmony_ci    }
103e1051a39Sopenharmony_ci
104e1051a39Sopenharmony_ci    /* verify whether req/default_bits is set */
105e1051a39Sopenharmony_ci    val = 0;
106e1051a39Sopenharmony_ci    if (!TEST_int_eq(NCONF_get_number(conf, "req", "default_bits", &val), 1)
107e1051a39Sopenharmony_ci        || !TEST_int_eq(val, 2048)) {
108e1051a39Sopenharmony_ci        TEST_note("default_bits incorrect");
109e1051a39Sopenharmony_ci        return 0;
110e1051a39Sopenharmony_ci    }
111e1051a39Sopenharmony_ci
112e1051a39Sopenharmony_ci    /* verify whether countryName_default is set correctly */
113e1051a39Sopenharmony_ci    str = NCONF_get_string(conf, "req_distinguished_name", "countryName_default");
114e1051a39Sopenharmony_ci    if (!TEST_ptr(str) || !TEST_str_eq(str, "AU")) {
115e1051a39Sopenharmony_ci        TEST_note("countryName_default incorrect");
116e1051a39Sopenharmony_ci        return 0;
117e1051a39Sopenharmony_ci    }
118e1051a39Sopenharmony_ci
119e1051a39Sopenharmony_ci    return 1;
120e1051a39Sopenharmony_ci}
121e1051a39Sopenharmony_ci
122e1051a39Sopenharmony_cistatic int test_check_null_numbers(void)
123e1051a39Sopenharmony_ci{
124e1051a39Sopenharmony_ci#if defined(_BSD_SOURCE) \
125e1051a39Sopenharmony_ci        || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) \
126e1051a39Sopenharmony_ci        || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600)
127e1051a39Sopenharmony_ci    long val = 0;
128e1051a39Sopenharmony_ci
129e1051a39Sopenharmony_ci    /* Verify that a NULL config with a present environment variable returns
130e1051a39Sopenharmony_ci     * success and the value.
131e1051a39Sopenharmony_ci     */
132e1051a39Sopenharmony_ci    if (!TEST_int_eq(setenv("FNORD", "123", 1), 0)
133e1051a39Sopenharmony_ci            || !TEST_true(NCONF_get_number(NULL, "missing", "FNORD", &val))
134e1051a39Sopenharmony_ci            || !TEST_long_eq(val, 123)) {
135e1051a39Sopenharmony_ci        TEST_note("environment variable with NULL conf failed");
136e1051a39Sopenharmony_ci        return 0;
137e1051a39Sopenharmony_ci    }
138e1051a39Sopenharmony_ci
139e1051a39Sopenharmony_ci    /*
140e1051a39Sopenharmony_ci     * Verify that a NULL config with a missing environment variable returns
141e1051a39Sopenharmony_ci     * a failure code.
142e1051a39Sopenharmony_ci     */
143e1051a39Sopenharmony_ci    if (!TEST_int_eq(unsetenv("FNORD"), 0)
144e1051a39Sopenharmony_ci            || !TEST_false(NCONF_get_number(NULL, "missing", "FNORD", &val))) {
145e1051a39Sopenharmony_ci        TEST_note("missing environment variable with NULL conf failed");
146e1051a39Sopenharmony_ci        return 0;
147e1051a39Sopenharmony_ci    }
148e1051a39Sopenharmony_ci#endif
149e1051a39Sopenharmony_ci    return 1;
150e1051a39Sopenharmony_ci}
151e1051a39Sopenharmony_ci
152e1051a39Sopenharmony_cistatic int test_check_overflow(void)
153e1051a39Sopenharmony_ci{
154e1051a39Sopenharmony_ci#if defined(_BSD_SOURCE) \
155e1051a39Sopenharmony_ci        || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) \
156e1051a39Sopenharmony_ci        || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600)
157e1051a39Sopenharmony_ci    long val = 0;
158e1051a39Sopenharmony_ci    char max[(sizeof(long) * 8) / 3 + 3];
159e1051a39Sopenharmony_ci    char *p;
160e1051a39Sopenharmony_ci
161e1051a39Sopenharmony_ci    p = max + sprintf(max, "0%ld", LONG_MAX) - 1;
162e1051a39Sopenharmony_ci    setenv("FNORD", max, 1);
163e1051a39Sopenharmony_ci    if (!TEST_true(NCONF_get_number(NULL, "missing", "FNORD", &val))
164e1051a39Sopenharmony_ci            || !TEST_long_eq(val, LONG_MAX))
165e1051a39Sopenharmony_ci        return 0;
166e1051a39Sopenharmony_ci
167e1051a39Sopenharmony_ci    while (++*p > '9')
168e1051a39Sopenharmony_ci        *p-- = '0';
169e1051a39Sopenharmony_ci
170e1051a39Sopenharmony_ci    setenv("FNORD", max, 1);
171e1051a39Sopenharmony_ci    if (!TEST_false(NCONF_get_number(NULL, "missing", "FNORD", &val)))
172e1051a39Sopenharmony_ci        return 0;
173e1051a39Sopenharmony_ci#endif
174e1051a39Sopenharmony_ci    return 1;
175e1051a39Sopenharmony_ci}
176e1051a39Sopenharmony_ci
177e1051a39Sopenharmony_citypedef enum OPTION_choice {
178e1051a39Sopenharmony_ci    OPT_ERR = -1,
179e1051a39Sopenharmony_ci    OPT_EOF = 0,
180e1051a39Sopenharmony_ci    OPT_FAIL,
181e1051a39Sopenharmony_ci    OPT_TEST_ENUM
182e1051a39Sopenharmony_ci} OPTION_CHOICE;
183e1051a39Sopenharmony_ci
184e1051a39Sopenharmony_ciconst OPTIONS *test_get_options(void)
185e1051a39Sopenharmony_ci{
186e1051a39Sopenharmony_ci    static const OPTIONS test_options[] = {
187e1051a39Sopenharmony_ci        OPT_TEST_OPTIONS_WITH_EXTRA_USAGE("conf_file\n"),
188e1051a39Sopenharmony_ci        { "f", OPT_FAIL, '-', "A failure is expected" },
189e1051a39Sopenharmony_ci        { NULL }
190e1051a39Sopenharmony_ci    };
191e1051a39Sopenharmony_ci    return test_options;
192e1051a39Sopenharmony_ci}
193e1051a39Sopenharmony_ci
194e1051a39Sopenharmony_ciint setup_tests(void)
195e1051a39Sopenharmony_ci{
196e1051a39Sopenharmony_ci    const char *conf_file;
197e1051a39Sopenharmony_ci    OPTION_CHOICE o;
198e1051a39Sopenharmony_ci
199e1051a39Sopenharmony_ci    if (!TEST_ptr(conf = NCONF_new(NULL)))
200e1051a39Sopenharmony_ci        return 0;
201e1051a39Sopenharmony_ci
202e1051a39Sopenharmony_ci    while ((o = opt_next()) != OPT_EOF) {
203e1051a39Sopenharmony_ci        switch (o) {
204e1051a39Sopenharmony_ci        case OPT_FAIL:
205e1051a39Sopenharmony_ci            expect_failure = 1;
206e1051a39Sopenharmony_ci            break;
207e1051a39Sopenharmony_ci        case OPT_TEST_CASES:
208e1051a39Sopenharmony_ci            break;
209e1051a39Sopenharmony_ci        default:
210e1051a39Sopenharmony_ci            return 0;
211e1051a39Sopenharmony_ci        }
212e1051a39Sopenharmony_ci    }
213e1051a39Sopenharmony_ci
214e1051a39Sopenharmony_ci    conf_file = test_get_argument(0);
215e1051a39Sopenharmony_ci    if (!TEST_ptr(conf_file)
216e1051a39Sopenharmony_ci        || !TEST_ptr(in = BIO_new_file(conf_file, "r"))) {
217e1051a39Sopenharmony_ci        TEST_note("Unable to open the file argument");
218e1051a39Sopenharmony_ci        return 0;
219e1051a39Sopenharmony_ci    }
220e1051a39Sopenharmony_ci
221e1051a39Sopenharmony_ci    /*
222e1051a39Sopenharmony_ci     * For this test we need to chdir as we use relative
223e1051a39Sopenharmony_ci     * path names in the config files.
224e1051a39Sopenharmony_ci     */
225e1051a39Sopenharmony_ci    change_path(conf_file);
226e1051a39Sopenharmony_ci
227e1051a39Sopenharmony_ci    ADD_TEST(test_load_config);
228e1051a39Sopenharmony_ci    ADD_TEST(test_check_null_numbers);
229e1051a39Sopenharmony_ci    ADD_TEST(test_check_overflow);
230e1051a39Sopenharmony_ci    return 1;
231e1051a39Sopenharmony_ci}
232e1051a39Sopenharmony_ci
233e1051a39Sopenharmony_civoid cleanup_tests(void)
234e1051a39Sopenharmony_ci{
235e1051a39Sopenharmony_ci    BIO_vfree(in);
236e1051a39Sopenharmony_ci    NCONF_free(conf);
237e1051a39Sopenharmony_ci    CONF_modules_unload(1);
238e1051a39Sopenharmony_ci}
239