Coverage Report

Created: 2025-06-13 06:55

/src/openssl/crypto/params_from_text.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved.
3
 * Copyright (c) 2019, Oracle and/or its affiliates.  All rights reserved.
4
 *
5
 * Licensed under the Apache License 2.0 (the "License").  You may not use
6
 * this file except in compliance with the License.  You can obtain a copy
7
 * in the file LICENSE in the source distribution or at
8
 * https://www.openssl.org/source/license.html
9
 */
10
11
#include "internal/common.h" /* for HAS_PREFIX */
12
#include <openssl/ebcdic.h>
13
#include <openssl/err.h>
14
#include <openssl/params.h>
15
#include <openssl/buffer.h>
16
17
/*
18
 * When processing text to params, we're trying to be smart with numbers.
19
 * Instead of handling each specific separate integer type, we use a bignum
20
 * and ensure that it isn't larger than the expected size, and we then make
21
 * sure it is the expected size...  if there is one given.
22
 * (if the size can be arbitrary, then we give whatever we have)
23
 */
24
25
static int prepare_from_text(const OSSL_PARAM *paramdefs, const char *key,
26
                             const char *value, size_t value_n,
27
                             /* Output parameters */
28
                             const OSSL_PARAM **paramdef, int *ishex,
29
                             size_t *buf_n, BIGNUM **tmpbn, int *found)
30
0
{
31
0
    const OSSL_PARAM *p;
32
0
    size_t buf_bits;
33
0
    int r;
34
35
    /*
36
     * ishex is used to translate legacy style string controls in hex format
37
     * to octet string parameters.
38
     */
39
0
    *ishex = CHECK_AND_SKIP_PREFIX(key, "hex");
40
41
0
    p = *paramdef = OSSL_PARAM_locate_const(paramdefs, key);
42
0
    if (found != NULL)
43
0
        *found = p != NULL;
44
0
    if (p == NULL)
45
0
        return 0;
46
47
0
    switch (p->data_type) {
48
0
    case OSSL_PARAM_INTEGER:
49
0
    case OSSL_PARAM_UNSIGNED_INTEGER:
50
0
        if (*ishex)
51
0
            r = BN_hex2bn(tmpbn, value);
52
0
        else
53
0
            r = BN_asc2bn(tmpbn, value);
54
55
0
        if (r == 0 || *tmpbn == NULL)
56
0
            return 0;
57
58
0
        if (p->data_type == OSSL_PARAM_UNSIGNED_INTEGER
59
0
            && BN_is_negative(*tmpbn)) {
60
0
            ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_INVALID_NEGATIVE_VALUE);
61
0
            return 0;
62
0
        }
63
64
        /*
65
         * 2's complement negate, part 1
66
         *
67
         * BN_bn2nativepad puts the absolute value of the number in the
68
         * buffer, i.e. if it's negative, we need to deal with it.  We do
69
         * it by subtracting 1 here and inverting the bytes in
70
         * construct_from_text() below.
71
         * To subtract 1 from an absolute value of a negative number we
72
         * actually have to add 1: -3 - 1 = -4, |-3| = 3 + 1 = 4.
73
         */
74
0
        if (p->data_type == OSSL_PARAM_INTEGER && BN_is_negative(*tmpbn)
75
0
            && !BN_add_word(*tmpbn, 1)) {
76
0
            return 0;
77
0
        }
78
79
0
        buf_bits = (size_t)BN_num_bits(*tmpbn);
80
81
        /*
82
         * Compensate for cases where the most significant bit in
83
         * the resulting OSSL_PARAM buffer will be set after the
84
         * BN_bn2nativepad() call, as the implied sign may not be
85
         * correct after the second part of the 2's complement
86
         * negation has been performed.
87
         * We fix these cases by extending the buffer by one byte
88
         * (8 bits), which will give some padding.  The second part
89
         * of the 2's complement negation will do the rest.
90
         */
91
0
        if (p->data_type == OSSL_PARAM_INTEGER && buf_bits % 8 == 0)
92
0
            buf_bits += 8;
93
94
0
        *buf_n = (buf_bits + 7) / 8;
95
96
        /*
97
         * A zero data size means "arbitrary size", so only do the
98
         * range checking if a size is specified.
99
         */
100
0
        if (p->data_size > 0) {
101
0
            if (buf_bits > p->data_size * 8) {
102
0
                ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_TOO_SMALL_BUFFER);
103
                /* Since this is a different error, we don't break */
104
0
                return 0;
105
0
            }
106
            /* Change actual size to become the desired size. */
107
0
            *buf_n = p->data_size;
108
0
        }
109
0
        break;
110
0
    case OSSL_PARAM_UTF8_STRING:
111
0
        if (*ishex) {
112
0
            ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
113
0
            return 0;
114
0
        }
115
0
        *buf_n = strlen(value) + 1;
116
0
        break;
117
0
    case OSSL_PARAM_OCTET_STRING:
118
0
        if (*ishex) {
119
0
            size_t hexdigits = strlen(value);
120
0
            if ((hexdigits % 2) != 0) {
121
                /* We don't accept an odd number of hex digits */
122
0
                ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_ODD_NUMBER_OF_DIGITS);
123
0
                return 0;
124
0
            }
125
0
            *buf_n = hexdigits >> 1;
126
0
        } else {
127
0
            *buf_n = value_n;
128
0
        }
129
0
        break;
130
0
    }
131
132
0
    return 1;
133
0
}
134
135
static int construct_from_text(OSSL_PARAM *to, const OSSL_PARAM *paramdef,
136
                               const char *value, size_t value_n, int ishex,
137
                               void *buf, size_t buf_n, BIGNUM *tmpbn)
138
0
{
139
0
    if (buf == NULL)
140
0
        return 0;
141
142
0
    if (buf_n > 0) {
143
0
        switch (paramdef->data_type) {
144
0
        case OSSL_PARAM_INTEGER:
145
0
        case OSSL_PARAM_UNSIGNED_INTEGER:
146
            /*
147
            {
148
                if ((new_value = OPENSSL_malloc(new_value_n)) == NULL) {
149
                    BN_free(a);
150
                    break;
151
                }
152
            */
153
154
0
            BN_bn2nativepad(tmpbn, buf, buf_n);
155
156
            /*
157
             * 2's complement negation, part two.
158
             *
159
             * Because we did the first part on the BIGNUM itself, we can just
160
             * invert all the bytes here and be done with it.
161
             */
162
0
            if (paramdef->data_type == OSSL_PARAM_INTEGER
163
0
                && BN_is_negative(tmpbn)) {
164
0
                unsigned char *cp;
165
0
                size_t i = buf_n;
166
167
0
                for (cp = buf; i-- > 0; cp++)
168
0
                    *cp ^= 0xFF;
169
0
            }
170
0
            break;
171
0
        case OSSL_PARAM_UTF8_STRING:
172
#ifdef CHARSET_EBCDIC
173
            ebcdic2ascii(buf, value, buf_n);
174
#else
175
0
            strncpy(buf, value, buf_n);
176
0
#endif
177
            /* Don't count the terminating NUL byte as data */
178
0
            buf_n--;
179
0
            break;
180
0
        case OSSL_PARAM_OCTET_STRING:
181
0
            if (ishex) {
182
0
                size_t l = 0;
183
184
0
                if (!OPENSSL_hexstr2buf_ex(buf, buf_n, &l, value, ':'))
185
0
                    return 0;
186
0
            } else {
187
0
                memcpy(buf, value, buf_n);
188
0
            }
189
0
            break;
190
0
        }
191
0
    }
192
193
0
    *to = *paramdef;
194
0
    to->data = buf;
195
0
    to->data_size = buf_n;
196
0
    to->return_size = OSSL_PARAM_UNMODIFIED;
197
198
0
    return 1;
199
0
}
200
201
/**
202
 * OSSL_PARAM_print_to_bio - Print OSSL_PARAM array to a bio 
203
 *
204
 * @p:        Array of OSSL_PARAM structures containing keys and values.
205
 * @bio:      Pointer to bio where the formatted output will be written.
206
 * @print_values: If non-zero, prints both keys and values. If zero, only keys
207
 *                are printed.
208
 *
209
 * This function iterates through the given array of OSSL_PARAM structures,
210
 * printing each key to an in-memory buffer, and optionally printing its
211
 * value based on the provided data type. Supported types include integers,
212
 * strings, octet strings, and real numbers.
213
 *
214
 * Return:    1 on success, 0 on failure.
215
 */
216
int OSSL_PARAM_print_to_bio(const OSSL_PARAM *p, BIO *bio, int print_values)
217
0
{
218
0
    int64_t i;
219
0
    uint64_t u;
220
0
    BIGNUM *bn;
221
0
#ifndef OPENSSL_SYS_UEFI
222
0
    double d;
223
0
    int dok;
224
0
#endif
225
0
    int ok = -1;
226
227
    /*
228
     * Iterate through each key in the array printing its key and value
229
     */
230
0
    for (; p->key != NULL; p++) {
231
0
        ok = -1;
232
0
        ok = BIO_printf(bio, "%s: ", p->key);
233
234
0
        if (ok == -1)
235
0
            goto end;
236
237
        /*
238
         * if printing of values was not requested, just move on
239
         * to the next param, after adding a newline to the buffer
240
         */
241
0
        if (print_values == 0) {
242
0
            BIO_printf(bio, "\n");
243
0
            continue;
244
0
        }
245
246
0
        switch (p->data_type) {
247
0
        case OSSL_PARAM_UNSIGNED_INTEGER:
248
0
            if (p->data_size > sizeof(int64_t)) {
249
0
                if (OSSL_PARAM_get_BN(p, &bn))
250
0
                    ok = BN_print(bio, bn);
251
0
                else
252
0
                    ok = BIO_printf(bio, "error getting value\n");
253
0
            } else {
254
0
                if (OSSL_PARAM_get_uint64(p, &u))
255
0
                    ok = BIO_printf(bio, "%llu\n", (unsigned long long int)u);
256
0
                else
257
0
                    ok = BIO_printf(bio, "error getting value\n");
258
0
            }
259
0
            break;
260
0
        case OSSL_PARAM_INTEGER:
261
0
            if (p->data_size > sizeof(int64_t)) {
262
0
                if (OSSL_PARAM_get_BN(p, &bn))
263
0
                    ok = BN_print(bio, bn);
264
0
                else
265
0
                    ok = BIO_printf(bio, "error getting value\n");
266
0
            } else {
267
0
                if (OSSL_PARAM_get_int64(p, &i))
268
0
                    ok = BIO_printf(bio, "%lld\n", (long long int)i);
269
0
                else
270
0
                    ok = BIO_printf(bio, "error getting value\n");
271
0
            }
272
0
            break;
273
0
        case OSSL_PARAM_UTF8_PTR:
274
0
            ok = BIO_dump(bio, p->data, p->data_size);
275
0
            break;
276
0
        case OSSL_PARAM_UTF8_STRING:
277
0
            ok = BIO_dump(bio, (char *)p->data, p->data_size);
278
0
            break;
279
0
        case OSSL_PARAM_OCTET_PTR:
280
0
        case OSSL_PARAM_OCTET_STRING:
281
0
            ok = BIO_dump(bio, (char *)p->data, p->data_size);
282
0
            break;
283
0
#ifndef OPENSSL_SYS_UEFI
284
0
        case OSSL_PARAM_REAL:
285
0
            dok = 0;
286
0
            dok = OSSL_PARAM_get_double(p, &d);
287
0
            if (dok == 1)
288
0
                ok = BIO_printf(bio, "%f\n", d);
289
0
            else
290
0
                ok = BIO_printf(bio, "error getting value\n");
291
0
            break;
292
0
#endif
293
0
        default:
294
0
            ok = BIO_printf(bio, "unknown type (%u) of %zu bytes\n",
295
0
                            p->data_type, p->data_size);
296
0
            break;
297
0
        }
298
0
        if (ok == -1)
299
0
            goto end;
300
0
    }
301
302
0
end:
303
0
    return ok == -1 ? 0 : 1;
304
0
}
305
306
int OSSL_PARAM_allocate_from_text(OSSL_PARAM *to,
307
                                  const OSSL_PARAM *paramdefs,
308
                                  const char *key, const char *value,
309
                                  size_t value_n, int *found)
310
0
{
311
0
    const OSSL_PARAM *paramdef = NULL;
312
0
    int ishex = 0;
313
0
    void *buf = NULL;
314
0
    size_t buf_n = 0;
315
0
    BIGNUM *tmpbn = NULL;
316
0
    int ok = 0;
317
318
0
    if (to == NULL || paramdefs == NULL)
319
0
        return 0;
320
321
0
    if (!prepare_from_text(paramdefs, key, value, value_n,
322
0
                           &paramdef, &ishex, &buf_n, &tmpbn, found))
323
0
        goto err;
324
325
0
    if ((buf = OPENSSL_zalloc(buf_n > 0 ? buf_n : 1)) == NULL)
326
0
        goto err;
327
328
0
    ok = construct_from_text(to, paramdef, value, value_n, ishex,
329
0
                             buf, buf_n, tmpbn);
330
0
    BN_free(tmpbn);
331
0
    if (!ok)
332
0
        OPENSSL_free(buf);
333
0
    return ok;
334
0
 err:
335
0
    BN_free(tmpbn);
336
0
    return 0;
337
0
}