1/*
2 * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License").  You may not use
5 * this file except in compliance with the License.  You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10/*
11 * SHA256 low level APIs are deprecated for public use, but still ok for
12 * internal use.  Note, that due to symbols not being exported, only the
13 * #defines can be accessed.  In this case SHA256_CBLOCK.
14 */
15#include "internal/deprecated.h"
16
17#include <string.h>
18#include <openssl/sha.h>
19#include <openssl/evp.h>
20#include <openssl/provider.h>
21#include "internal/sizes.h"
22#include "testutil.h"
23
24static char *config_file = NULL;
25static char *alg = "digest";
26static int use_default_ctx = 0;
27static char *fetch_property = NULL;
28static int expected_fetch_result = 1;
29
30typedef enum OPTION_choice {
31    OPT_ERR = -1,
32    OPT_EOF = 0,
33    OPT_ALG_FETCH_TYPE,
34    OPT_FETCH_PROPERTY,
35    OPT_FETCH_FAILURE,
36    OPT_USE_DEFAULTCTX,
37    OPT_CONFIG_FILE,
38    OPT_TEST_ENUM
39} OPTION_CHOICE;
40
41const OPTIONS *test_get_options(void)
42{
43    static const OPTIONS test_options[] = {
44        OPT_TEST_OPTIONS_WITH_EXTRA_USAGE("[provname...]\n"),
45        { "config", OPT_CONFIG_FILE, '<', "The configuration file to use for the libctx" },
46        { "type", OPT_ALG_FETCH_TYPE, 's', "The fetch type to test" },
47        { "property", OPT_FETCH_PROPERTY, 's', "The fetch property e.g. provider=fips" },
48        { "fetchfail", OPT_FETCH_FAILURE, '-', "fetch is expected to fail" },
49        { "defaultctx", OPT_USE_DEFAULTCTX, '-',
50          "Use the default context if this is set" },
51        { OPT_HELP_STR, 1, '-', "file\tProvider names to explicitly load\n" },
52        { NULL }
53    };
54    return test_options;
55}
56
57static int calculate_digest(const EVP_MD *md, const char *msg, size_t len,
58                            const unsigned char *exptd)
59{
60    unsigned char out[SHA256_DIGEST_LENGTH];
61    EVP_MD_CTX *ctx;
62    int ret = 0;
63
64    if (!TEST_ptr(ctx = EVP_MD_CTX_new())
65            || !TEST_true(EVP_DigestInit_ex(ctx, md, NULL))
66            || !TEST_true(EVP_DigestUpdate(ctx, msg, len))
67            || !TEST_true(EVP_DigestFinal_ex(ctx, out, NULL))
68            || !TEST_mem_eq(out, SHA256_DIGEST_LENGTH, exptd,
69                            SHA256_DIGEST_LENGTH)
70            || !TEST_true(md == EVP_MD_CTX_get0_md(ctx)))
71        goto err;
72
73    ret = 1;
74 err:
75    EVP_MD_CTX_free(ctx);
76    return ret;
77}
78
79static int load_providers(OSSL_LIB_CTX **libctx, OSSL_PROVIDER *prov[])
80{
81    OSSL_LIB_CTX *ctx = NULL;
82    int ret = 0;
83    size_t i;
84
85    ctx = OSSL_LIB_CTX_new();
86    if (!TEST_ptr(ctx))
87        goto err;
88
89    if (!TEST_true(OSSL_LIB_CTX_load_config(ctx, config_file)))
90        goto err;
91    if (test_get_argument_count() > 2)
92        goto err;
93
94    for (i = 0; i < test_get_argument_count(); ++i) {
95        char *provname = test_get_argument(i);
96        prov[i] = OSSL_PROVIDER_load(ctx, provname);
97        if (!TEST_ptr(prov[i]))
98            goto err;
99    }
100
101    ret = 1;
102    *libctx = ctx;
103err:
104    if (ret == 0)
105        OSSL_LIB_CTX_free(ctx);
106    return ret;
107}
108
109static void unload_providers(OSSL_LIB_CTX **libctx, OSSL_PROVIDER *prov[])
110{
111    if (prov[0] != NULL)
112        OSSL_PROVIDER_unload(prov[0]);
113    if (prov[1] != NULL)
114        OSSL_PROVIDER_unload(prov[1]);
115    /* Not normally needed, but we would like to test that
116     * OPENSSL_thread_stop_ex() behaves as expected.
117     */
118    if (libctx != NULL && *libctx != NULL) {
119        OPENSSL_thread_stop_ex(*libctx);
120        OSSL_LIB_CTX_free(*libctx);
121    }
122}
123
124static X509_ALGOR *make_algor(int nid)
125{
126    X509_ALGOR *algor;
127
128    if (!TEST_ptr(algor = X509_ALGOR_new())
129        || !TEST_true(X509_ALGOR_set0(algor, OBJ_nid2obj(nid),
130                                      V_ASN1_UNDEF, NULL))) {
131        X509_ALGOR_free(algor);
132        return NULL;
133    }
134    return algor;
135}
136
137/*
138 * Test EVP_MD_fetch()
139 */
140static int test_md(const EVP_MD *md)
141{
142    const char testmsg[] = "Hello world";
143    const unsigned char exptd[] = {
144      0x27, 0x51, 0x8b, 0xa9, 0x68, 0x30, 0x11, 0xf6, 0xb3, 0x96, 0x07, 0x2c,
145      0x05, 0xf6, 0x65, 0x6d, 0x04, 0xf5, 0xfb, 0xc3, 0x78, 0x7c, 0xf9, 0x24,
146      0x90, 0xec, 0x60, 0x6e, 0x50, 0x92, 0xe3, 0x26
147    };
148
149    return TEST_ptr(md)
150        && TEST_true(EVP_MD_is_a(md, "SHA256"))
151        && TEST_true(calculate_digest(md, testmsg, sizeof(testmsg), exptd))
152        && TEST_int_eq(EVP_MD_get_size(md), SHA256_DIGEST_LENGTH)
153        && TEST_int_eq(EVP_MD_get_block_size(md), SHA256_CBLOCK);
154}
155
156static int test_implicit_EVP_MD_fetch(void)
157{
158    OSSL_LIB_CTX *ctx = NULL;
159    OSSL_PROVIDER *prov[2] = {NULL, NULL};
160    int ret = 0;
161
162    ret = (use_default_ctx == 0 || load_providers(&ctx, prov))
163        && test_md(EVP_sha256());
164
165    unload_providers(&ctx, prov);
166    return ret;
167}
168
169static int test_explicit_EVP_MD_fetch(const char *id)
170{
171    OSSL_LIB_CTX *ctx = NULL;
172    EVP_MD *md = NULL;
173    OSSL_PROVIDER *prov[2] = {NULL, NULL};
174    int ret = 0;
175
176    if (use_default_ctx == 0 && !load_providers(&ctx, prov))
177        goto err;
178
179    md = EVP_MD_fetch(ctx, id, fetch_property);
180    if (expected_fetch_result != 0) {
181        if (!test_md(md))
182            goto err;
183
184        /* Also test EVP_MD_up_ref() while we're doing this */
185        if (!TEST_true(EVP_MD_up_ref(md)))
186            goto err;
187        /* Ref count should now be 2. Release first one here */
188        EVP_MD_free(md);
189    } else {
190        if (!TEST_ptr_null(md))
191            goto err;
192    }
193    ret = 1;
194
195 err:
196    EVP_MD_free(md);
197    unload_providers(&ctx, prov);
198    return ret;
199}
200
201static int test_explicit_EVP_MD_fetch_by_name(void)
202{
203    return test_explicit_EVP_MD_fetch("SHA256");
204}
205
206/*
207 * idx 0: Allow names from OBJ_obj2txt()
208 * idx 1: Force an OID in text form from OBJ_obj2txt()
209 */
210static int test_explicit_EVP_MD_fetch_by_X509_ALGOR(int idx)
211{
212    int ret = 0;
213    X509_ALGOR *algor = make_algor(NID_sha256);
214    const ASN1_OBJECT *obj;
215    char id[OSSL_MAX_NAME_SIZE];
216
217    if (algor == NULL)
218        return 0;
219
220    X509_ALGOR_get0(&obj, NULL, NULL, algor);
221    switch (idx) {
222    case 0:
223        if (!TEST_int_gt(OBJ_obj2txt(id, sizeof(id), obj, 0), 0))
224            goto end;
225        break;
226    case 1:
227        if (!TEST_int_gt(OBJ_obj2txt(id, sizeof(id), obj, 1), 0))
228            goto end;
229        break;
230    }
231
232    ret = test_explicit_EVP_MD_fetch(id);
233 end:
234    X509_ALGOR_free(algor);
235    return ret;
236}
237
238/*
239 * Test EVP_CIPHER_fetch()
240 */
241static int encrypt_decrypt(const EVP_CIPHER *cipher, const unsigned char *msg,
242                           size_t len)
243{
244    int ret = 0, ctlen, ptlen;
245    EVP_CIPHER_CTX *ctx = NULL;
246    unsigned char key[128 / 8];
247    unsigned char ct[64], pt[64];
248
249    memset(key, 0, sizeof(key));
250    if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())
251            || !TEST_true(EVP_CipherInit_ex(ctx, cipher, NULL, key, NULL, 1))
252            || !TEST_true(EVP_CipherUpdate(ctx, ct, &ctlen, msg, len))
253            || !TEST_true(EVP_CipherFinal_ex(ctx, ct, &ctlen))
254            || !TEST_true(EVP_CipherInit_ex(ctx, cipher, NULL, key, NULL, 0))
255            || !TEST_true(EVP_CipherUpdate(ctx, pt, &ptlen, ct, ctlen))
256            || !TEST_true(EVP_CipherFinal_ex(ctx, pt, &ptlen))
257            || !TEST_mem_eq(pt, ptlen, msg, len))
258        goto err;
259
260    ret = 1;
261err:
262    EVP_CIPHER_CTX_free(ctx);
263    return ret;
264}
265
266static int test_cipher(const EVP_CIPHER *cipher)
267{
268    const unsigned char testmsg[] = "Hello world";
269
270    return TEST_ptr(cipher)
271        && TEST_true(encrypt_decrypt(cipher, testmsg, sizeof(testmsg)));
272}
273
274static int test_implicit_EVP_CIPHER_fetch(void)
275{
276    OSSL_LIB_CTX *ctx = NULL;
277    OSSL_PROVIDER *prov[2] = {NULL, NULL};
278    int ret = 0;
279
280    ret = (use_default_ctx == 0 || load_providers(&ctx, prov))
281        && test_cipher(EVP_aes_128_cbc());
282
283    unload_providers(&ctx, prov);
284    return ret;
285}
286
287static int test_explicit_EVP_CIPHER_fetch(const char *id)
288{
289    OSSL_LIB_CTX *ctx = NULL;
290    EVP_CIPHER *cipher = NULL;
291    OSSL_PROVIDER *prov[2] = {NULL, NULL};
292    int ret = 0;
293
294    if (use_default_ctx == 0 && !load_providers(&ctx, prov))
295        goto err;
296
297    cipher = EVP_CIPHER_fetch(ctx, id, fetch_property);
298    if (expected_fetch_result != 0) {
299        if (!test_cipher(cipher))
300            goto err;
301
302        if (!TEST_true(EVP_CIPHER_up_ref(cipher)))
303            goto err;
304        /* Ref count should now be 2. Release first one here */
305        EVP_CIPHER_free(cipher);
306    } else {
307        if (!TEST_ptr_null(cipher))
308            goto err;
309    }
310    ret = 1;
311err:
312    EVP_CIPHER_free(cipher);
313    unload_providers(&ctx, prov);
314    return ret;
315}
316
317static int test_explicit_EVP_CIPHER_fetch_by_name(void)
318{
319    return test_explicit_EVP_CIPHER_fetch("AES-128-CBC");
320}
321
322/*
323 * idx 0: Allow names from OBJ_obj2txt()
324 * idx 1: Force an OID in text form from OBJ_obj2txt()
325 */
326static int test_explicit_EVP_CIPHER_fetch_by_X509_ALGOR(int idx)
327{
328    int ret = 0;
329    X509_ALGOR *algor = make_algor(NID_aes_128_cbc);
330    const ASN1_OBJECT *obj;
331    char id[OSSL_MAX_NAME_SIZE];
332
333    if (algor == NULL)
334        return 0;
335
336    X509_ALGOR_get0(&obj, NULL, NULL, algor);
337    switch (idx) {
338    case 0:
339        if (!TEST_int_gt(OBJ_obj2txt(id, sizeof(id), obj, 0), 0))
340            goto end;
341        break;
342    case 1:
343        if (!TEST_int_gt(OBJ_obj2txt(id, sizeof(id), obj, 1), 0))
344            goto end;
345        break;
346    }
347
348    ret = test_explicit_EVP_CIPHER_fetch(id);
349 end:
350    X509_ALGOR_free(algor);
351    return ret;
352}
353
354int setup_tests(void)
355{
356    OPTION_CHOICE o;
357
358    while ((o = opt_next()) != OPT_EOF) {
359        switch (o) {
360        case OPT_CONFIG_FILE:
361            config_file = opt_arg();
362            break;
363        case OPT_ALG_FETCH_TYPE:
364            alg = opt_arg();
365            break;
366        case OPT_FETCH_PROPERTY:
367            fetch_property = opt_arg();
368            break;
369        case OPT_FETCH_FAILURE:
370            expected_fetch_result = 0;
371            break;
372        case OPT_USE_DEFAULTCTX:
373            use_default_ctx = 1;
374            break;
375        case OPT_TEST_CASES:
376           break;
377        default:
378        case OPT_ERR:
379            return 0;
380        }
381    }
382    if (strcmp(alg, "digest") == 0) {
383        ADD_TEST(test_implicit_EVP_MD_fetch);
384        ADD_TEST(test_explicit_EVP_MD_fetch_by_name);
385        ADD_ALL_TESTS_NOSUBTEST(test_explicit_EVP_MD_fetch_by_X509_ALGOR, 2);
386    } else {
387        ADD_TEST(test_implicit_EVP_CIPHER_fetch);
388        ADD_TEST(test_explicit_EVP_CIPHER_fetch_by_name);
389        ADD_ALL_TESTS_NOSUBTEST(test_explicit_EVP_CIPHER_fetch_by_X509_ALGOR, 2);
390    }
391    return 1;
392}
393