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#include <openssl/self_test.h>
11#include <openssl/core_names.h>
12#include <openssl/params.h>
13#include "internal/cryptlib.h"
14
15typedef struct self_test_cb_st
16{
17    OSSL_CALLBACK *cb;
18    void *cbarg;
19} SELF_TEST_CB;
20
21struct ossl_self_test_st
22{
23    /* local state variables */
24    const char *phase;
25    const char *type;
26    const char *desc;
27    OSSL_CALLBACK *cb;
28
29    /* callback related variables used to pass the state back to the user */
30    OSSL_PARAM params[4];
31    void *cb_arg;
32};
33
34#ifndef FIPS_MODULE
35static void *self_test_set_callback_new(OSSL_LIB_CTX *ctx)
36{
37    SELF_TEST_CB *stcb;
38
39    stcb = OPENSSL_zalloc(sizeof(*stcb));
40    return stcb;
41}
42
43static void self_test_set_callback_free(void *stcb)
44{
45    OPENSSL_free(stcb);
46}
47
48static const OSSL_LIB_CTX_METHOD self_test_set_callback_method = {
49    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
50    self_test_set_callback_new,
51    self_test_set_callback_free,
52};
53
54static SELF_TEST_CB *get_self_test_callback(OSSL_LIB_CTX *libctx)
55{
56    return ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_SELF_TEST_CB_INDEX,
57                                 &self_test_set_callback_method);
58}
59
60void OSSL_SELF_TEST_set_callback(OSSL_LIB_CTX *libctx, OSSL_CALLBACK *cb,
61                                 void *cbarg)
62{
63    SELF_TEST_CB *stcb = get_self_test_callback(libctx);
64
65    if (stcb != NULL) {
66        stcb->cb = cb;
67        stcb->cbarg = cbarg;
68    }
69}
70
71void OSSL_SELF_TEST_get_callback(OSSL_LIB_CTX *libctx, OSSL_CALLBACK **cb,
72                                 void **cbarg)
73{
74    SELF_TEST_CB *stcb = get_self_test_callback(libctx);
75
76    if (cb != NULL)
77        *cb = (stcb != NULL ? stcb->cb : NULL);
78    if (cbarg != NULL)
79        *cbarg = (stcb != NULL ? stcb->cbarg : NULL);
80}
81#endif /* FIPS_MODULE */
82
83static void self_test_setparams(OSSL_SELF_TEST *st)
84{
85    size_t n = 0;
86
87    if (st->cb != NULL) {
88        st->params[n++] =
89            OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_SELF_TEST_PHASE,
90                                             (char *)st->phase, 0);
91        st->params[n++] =
92            OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_SELF_TEST_TYPE,
93                                             (char *)st->type, 0);
94        st->params[n++] =
95            OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_SELF_TEST_DESC,
96                                             (char *)st->desc, 0);
97    }
98    st->params[n++] = OSSL_PARAM_construct_end();
99}
100
101OSSL_SELF_TEST *OSSL_SELF_TEST_new(OSSL_CALLBACK *cb, void *cbarg)
102{
103    OSSL_SELF_TEST *ret = OPENSSL_zalloc(sizeof(*ret));
104
105    if (ret == NULL)
106        return NULL;
107
108    ret->cb = cb;
109    ret->cb_arg = cbarg;
110    ret->phase = "";
111    ret->type = "";
112    ret->desc = "";
113    self_test_setparams(ret);
114    return ret;
115}
116
117void OSSL_SELF_TEST_free(OSSL_SELF_TEST *st)
118{
119    OPENSSL_free(st);
120}
121
122/* Can be used during application testing to log that a test has started. */
123void OSSL_SELF_TEST_onbegin(OSSL_SELF_TEST *st, const char *type,
124                            const char *desc)
125{
126    if (st != NULL && st->cb != NULL) {
127        st->phase = OSSL_SELF_TEST_PHASE_START;
128        st->type = type;
129        st->desc = desc;
130        self_test_setparams(st);
131        (void)st->cb(st->params, st->cb_arg);
132    }
133}
134
135/*
136 * Can be used during application testing to log that a test has either
137 * passed or failed.
138 */
139void OSSL_SELF_TEST_onend(OSSL_SELF_TEST *st, int ret)
140{
141    if (st != NULL && st->cb != NULL) {
142        st->phase =
143            (ret == 1 ? OSSL_SELF_TEST_PHASE_PASS : OSSL_SELF_TEST_PHASE_FAIL);
144        self_test_setparams(st);
145        (void)st->cb(st->params, st->cb_arg);
146
147        st->phase = OSSL_SELF_TEST_PHASE_NONE;
148        st->type = OSSL_SELF_TEST_TYPE_NONE;
149        st->desc = OSSL_SELF_TEST_DESC_NONE;
150    }
151}
152
153/*
154 * Used for failure testing.
155 *
156 * Call the applications SELF_TEST_cb() if it exists.
157 * If the application callback decides to return 0 then the first byte of 'bytes'
158 * is modified (corrupted). This is used to modify output signatures or
159 * ciphertext before they are verified or decrypted.
160 */
161int OSSL_SELF_TEST_oncorrupt_byte(OSSL_SELF_TEST *st, unsigned char *bytes)
162{
163    if (st != NULL && st->cb != NULL) {
164        st->phase = OSSL_SELF_TEST_PHASE_CORRUPT;
165        self_test_setparams(st);
166        if (!st->cb(st->params, st->cb_arg)) {
167            bytes[0] ^= 1;
168            return 1;
169        }
170    }
171    return 0;
172}
173