1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci * Copyright (c) 2019, Oracle and/or its affiliates.  All rights reserved.
4e1051a39Sopenharmony_ci *
5e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
6e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
7e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
8e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
9e1051a39Sopenharmony_ci */
10e1051a39Sopenharmony_ci
11e1051a39Sopenharmony_ci#include <string.h>
12e1051a39Sopenharmony_ci#include <openssl/ebcdic.h>
13e1051a39Sopenharmony_ci#include <openssl/err.h>
14e1051a39Sopenharmony_ci#include <openssl/params.h>
15e1051a39Sopenharmony_ci
16e1051a39Sopenharmony_ci/*
17e1051a39Sopenharmony_ci * When processing text to params, we're trying to be smart with numbers.
18e1051a39Sopenharmony_ci * Instead of handling each specific separate integer type, we use a bignum
19e1051a39Sopenharmony_ci * and ensure that it isn't larger than the expected size, and we then make
20e1051a39Sopenharmony_ci * sure it is the expected size...  if there is one given.
21e1051a39Sopenharmony_ci * (if the size can be arbitrary, then we give whatever we have)
22e1051a39Sopenharmony_ci */
23e1051a39Sopenharmony_ci
24e1051a39Sopenharmony_cistatic int prepare_from_text(const OSSL_PARAM *paramdefs, const char *key,
25e1051a39Sopenharmony_ci                             const char *value, size_t value_n,
26e1051a39Sopenharmony_ci                             /* Output parameters */
27e1051a39Sopenharmony_ci                             const OSSL_PARAM **paramdef, int *ishex,
28e1051a39Sopenharmony_ci                             size_t *buf_n, BIGNUM **tmpbn, int *found)
29e1051a39Sopenharmony_ci{
30e1051a39Sopenharmony_ci    const OSSL_PARAM *p;
31e1051a39Sopenharmony_ci    size_t buf_bits;
32e1051a39Sopenharmony_ci    int r;
33e1051a39Sopenharmony_ci
34e1051a39Sopenharmony_ci    /*
35e1051a39Sopenharmony_ci     * ishex is used to translate legacy style string controls in hex format
36e1051a39Sopenharmony_ci     * to octet string parameters.
37e1051a39Sopenharmony_ci     */
38e1051a39Sopenharmony_ci    *ishex = strncmp(key, "hex", 3) == 0;
39e1051a39Sopenharmony_ci
40e1051a39Sopenharmony_ci    if (*ishex)
41e1051a39Sopenharmony_ci        key += 3;
42e1051a39Sopenharmony_ci
43e1051a39Sopenharmony_ci    p = *paramdef = OSSL_PARAM_locate_const(paramdefs, key);
44e1051a39Sopenharmony_ci    if (found != NULL)
45e1051a39Sopenharmony_ci        *found = p != NULL;
46e1051a39Sopenharmony_ci    if (p == NULL)
47e1051a39Sopenharmony_ci        return 0;
48e1051a39Sopenharmony_ci
49e1051a39Sopenharmony_ci    switch (p->data_type) {
50e1051a39Sopenharmony_ci    case OSSL_PARAM_INTEGER:
51e1051a39Sopenharmony_ci    case OSSL_PARAM_UNSIGNED_INTEGER:
52e1051a39Sopenharmony_ci        if (*ishex)
53e1051a39Sopenharmony_ci            r = BN_hex2bn(tmpbn, value);
54e1051a39Sopenharmony_ci        else
55e1051a39Sopenharmony_ci            r = BN_asc2bn(tmpbn, value);
56e1051a39Sopenharmony_ci
57e1051a39Sopenharmony_ci        if (r == 0 || *tmpbn == NULL)
58e1051a39Sopenharmony_ci            return 0;
59e1051a39Sopenharmony_ci
60e1051a39Sopenharmony_ci        if (p->data_type == OSSL_PARAM_UNSIGNED_INTEGER
61e1051a39Sopenharmony_ci            && BN_is_negative(*tmpbn)) {
62e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_INVALID_NEGATIVE_VALUE);
63e1051a39Sopenharmony_ci            return 0;
64e1051a39Sopenharmony_ci        }
65e1051a39Sopenharmony_ci
66e1051a39Sopenharmony_ci        /*
67e1051a39Sopenharmony_ci         * 2's complement negate, part 1
68e1051a39Sopenharmony_ci         *
69e1051a39Sopenharmony_ci         * BN_bn2nativepad puts the absolute value of the number in the
70e1051a39Sopenharmony_ci         * buffer, i.e. if it's negative, we need to deal with it.  We do
71e1051a39Sopenharmony_ci         * it by subtracting 1 here and inverting the bytes in
72e1051a39Sopenharmony_ci         * construct_from_text() below.
73e1051a39Sopenharmony_ci         * To subtract 1 from an absolute value of a negative number we
74e1051a39Sopenharmony_ci         * actually have to add 1: -3 - 1 = -4, |-3| = 3 + 1 = 4.
75e1051a39Sopenharmony_ci         */
76e1051a39Sopenharmony_ci        if (p->data_type == OSSL_PARAM_INTEGER && BN_is_negative(*tmpbn)
77e1051a39Sopenharmony_ci            && !BN_add_word(*tmpbn, 1)) {
78e1051a39Sopenharmony_ci            return 0;
79e1051a39Sopenharmony_ci        }
80e1051a39Sopenharmony_ci
81e1051a39Sopenharmony_ci        buf_bits = (size_t)BN_num_bits(*tmpbn);
82e1051a39Sopenharmony_ci
83e1051a39Sopenharmony_ci        /*
84e1051a39Sopenharmony_ci         * Compensate for cases where the most significant bit in
85e1051a39Sopenharmony_ci         * the resulting OSSL_PARAM buffer will be set after the
86e1051a39Sopenharmony_ci         * BN_bn2nativepad() call, as the implied sign may not be
87e1051a39Sopenharmony_ci         * correct after the second part of the 2's complement
88e1051a39Sopenharmony_ci         * negation has been performed.
89e1051a39Sopenharmony_ci         * We fix these cases by extending the buffer by one byte
90e1051a39Sopenharmony_ci         * (8 bits), which will give some padding.  The second part
91e1051a39Sopenharmony_ci         * of the 2's complement negation will do the rest.
92e1051a39Sopenharmony_ci         */
93e1051a39Sopenharmony_ci        if (p->data_type == OSSL_PARAM_INTEGER && buf_bits % 8 == 0)
94e1051a39Sopenharmony_ci            buf_bits += 8;
95e1051a39Sopenharmony_ci
96e1051a39Sopenharmony_ci        *buf_n = (buf_bits + 7) / 8;
97e1051a39Sopenharmony_ci
98e1051a39Sopenharmony_ci        /*
99e1051a39Sopenharmony_ci         * A zero data size means "arbitrary size", so only do the
100e1051a39Sopenharmony_ci         * range checking if a size is specified.
101e1051a39Sopenharmony_ci         */
102e1051a39Sopenharmony_ci        if (p->data_size > 0) {
103e1051a39Sopenharmony_ci            if (buf_bits > p->data_size * 8) {
104e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_TOO_SMALL_BUFFER);
105e1051a39Sopenharmony_ci                /* Since this is a different error, we don't break */
106e1051a39Sopenharmony_ci                return 0;
107e1051a39Sopenharmony_ci            }
108e1051a39Sopenharmony_ci            /* Change actual size to become the desired size. */
109e1051a39Sopenharmony_ci            *buf_n = p->data_size;
110e1051a39Sopenharmony_ci        }
111e1051a39Sopenharmony_ci        break;
112e1051a39Sopenharmony_ci    case OSSL_PARAM_UTF8_STRING:
113e1051a39Sopenharmony_ci        if (*ishex) {
114e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
115e1051a39Sopenharmony_ci            return 0;
116e1051a39Sopenharmony_ci        }
117e1051a39Sopenharmony_ci        *buf_n = strlen(value) + 1;
118e1051a39Sopenharmony_ci        break;
119e1051a39Sopenharmony_ci    case OSSL_PARAM_OCTET_STRING:
120e1051a39Sopenharmony_ci        if (*ishex) {
121e1051a39Sopenharmony_ci            *buf_n = strlen(value) >> 1;
122e1051a39Sopenharmony_ci        } else {
123e1051a39Sopenharmony_ci            *buf_n = value_n;
124e1051a39Sopenharmony_ci        }
125e1051a39Sopenharmony_ci        break;
126e1051a39Sopenharmony_ci    }
127e1051a39Sopenharmony_ci
128e1051a39Sopenharmony_ci    return 1;
129e1051a39Sopenharmony_ci}
130e1051a39Sopenharmony_ci
131e1051a39Sopenharmony_cistatic int construct_from_text(OSSL_PARAM *to, const OSSL_PARAM *paramdef,
132e1051a39Sopenharmony_ci                               const char *value, size_t value_n, int ishex,
133e1051a39Sopenharmony_ci                               void *buf, size_t buf_n, BIGNUM *tmpbn)
134e1051a39Sopenharmony_ci{
135e1051a39Sopenharmony_ci    if (buf == NULL)
136e1051a39Sopenharmony_ci        return 0;
137e1051a39Sopenharmony_ci
138e1051a39Sopenharmony_ci    if (buf_n > 0) {
139e1051a39Sopenharmony_ci        switch (paramdef->data_type) {
140e1051a39Sopenharmony_ci        case OSSL_PARAM_INTEGER:
141e1051a39Sopenharmony_ci        case OSSL_PARAM_UNSIGNED_INTEGER:
142e1051a39Sopenharmony_ci            /*
143e1051a39Sopenharmony_ci            {
144e1051a39Sopenharmony_ci                if ((new_value = OPENSSL_malloc(new_value_n)) == NULL) {
145e1051a39Sopenharmony_ci                    BN_free(a);
146e1051a39Sopenharmony_ci                    break;
147e1051a39Sopenharmony_ci                }
148e1051a39Sopenharmony_ci            */
149e1051a39Sopenharmony_ci
150e1051a39Sopenharmony_ci            BN_bn2nativepad(tmpbn, buf, buf_n);
151e1051a39Sopenharmony_ci
152e1051a39Sopenharmony_ci            /*
153e1051a39Sopenharmony_ci             * 2's complement negation, part two.
154e1051a39Sopenharmony_ci             *
155e1051a39Sopenharmony_ci             * Because we did the first part on the BIGNUM itself, we can just
156e1051a39Sopenharmony_ci             * invert all the bytes here and be done with it.
157e1051a39Sopenharmony_ci             */
158e1051a39Sopenharmony_ci            if (paramdef->data_type == OSSL_PARAM_INTEGER
159e1051a39Sopenharmony_ci                && BN_is_negative(tmpbn)) {
160e1051a39Sopenharmony_ci                unsigned char *cp;
161e1051a39Sopenharmony_ci                size_t i = buf_n;
162e1051a39Sopenharmony_ci
163e1051a39Sopenharmony_ci                for (cp = buf; i-- > 0; cp++)
164e1051a39Sopenharmony_ci                    *cp ^= 0xFF;
165e1051a39Sopenharmony_ci            }
166e1051a39Sopenharmony_ci            break;
167e1051a39Sopenharmony_ci        case OSSL_PARAM_UTF8_STRING:
168e1051a39Sopenharmony_ci#ifdef CHARSET_EBCDIC
169e1051a39Sopenharmony_ci            ebcdic2ascii(buf, value, buf_n);
170e1051a39Sopenharmony_ci#else
171e1051a39Sopenharmony_ci            strncpy(buf, value, buf_n);
172e1051a39Sopenharmony_ci#endif
173e1051a39Sopenharmony_ci            /* Don't count the terminating NUL byte as data */
174e1051a39Sopenharmony_ci            buf_n--;
175e1051a39Sopenharmony_ci            break;
176e1051a39Sopenharmony_ci        case OSSL_PARAM_OCTET_STRING:
177e1051a39Sopenharmony_ci            if (ishex) {
178e1051a39Sopenharmony_ci                size_t l = 0;
179e1051a39Sopenharmony_ci
180e1051a39Sopenharmony_ci                if (!OPENSSL_hexstr2buf_ex(buf, buf_n, &l, value, ':'))
181e1051a39Sopenharmony_ci                    return 0;
182e1051a39Sopenharmony_ci            } else {
183e1051a39Sopenharmony_ci                memcpy(buf, value, buf_n);
184e1051a39Sopenharmony_ci            }
185e1051a39Sopenharmony_ci            break;
186e1051a39Sopenharmony_ci        }
187e1051a39Sopenharmony_ci    }
188e1051a39Sopenharmony_ci
189e1051a39Sopenharmony_ci    *to = *paramdef;
190e1051a39Sopenharmony_ci    to->data = buf;
191e1051a39Sopenharmony_ci    to->data_size = buf_n;
192e1051a39Sopenharmony_ci    to->return_size = OSSL_PARAM_UNMODIFIED;
193e1051a39Sopenharmony_ci
194e1051a39Sopenharmony_ci    return 1;
195e1051a39Sopenharmony_ci}
196e1051a39Sopenharmony_ci
197e1051a39Sopenharmony_ciint OSSL_PARAM_allocate_from_text(OSSL_PARAM *to,
198e1051a39Sopenharmony_ci                                  const OSSL_PARAM *paramdefs,
199e1051a39Sopenharmony_ci                                  const char *key, const char *value,
200e1051a39Sopenharmony_ci                                  size_t value_n, int *found)
201e1051a39Sopenharmony_ci{
202e1051a39Sopenharmony_ci    const OSSL_PARAM *paramdef = NULL;
203e1051a39Sopenharmony_ci    int ishex = 0;
204e1051a39Sopenharmony_ci    void *buf = NULL;
205e1051a39Sopenharmony_ci    size_t buf_n = 0;
206e1051a39Sopenharmony_ci    BIGNUM *tmpbn = NULL;
207e1051a39Sopenharmony_ci    int ok = 0;
208e1051a39Sopenharmony_ci
209e1051a39Sopenharmony_ci    if (to == NULL || paramdefs == NULL)
210e1051a39Sopenharmony_ci        return 0;
211e1051a39Sopenharmony_ci
212e1051a39Sopenharmony_ci    if (!prepare_from_text(paramdefs, key, value, value_n,
213e1051a39Sopenharmony_ci                           &paramdef, &ishex, &buf_n, &tmpbn, found))
214e1051a39Sopenharmony_ci        goto err;
215e1051a39Sopenharmony_ci
216e1051a39Sopenharmony_ci    if ((buf = OPENSSL_zalloc(buf_n > 0 ? buf_n : 1)) == NULL) {
217e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
218e1051a39Sopenharmony_ci        goto err;
219e1051a39Sopenharmony_ci    }
220e1051a39Sopenharmony_ci
221e1051a39Sopenharmony_ci    ok = construct_from_text(to, paramdef, value, value_n, ishex,
222e1051a39Sopenharmony_ci                             buf, buf_n, tmpbn);
223e1051a39Sopenharmony_ci    BN_free(tmpbn);
224e1051a39Sopenharmony_ci    if (!ok)
225e1051a39Sopenharmony_ci        OPENSSL_free(buf);
226e1051a39Sopenharmony_ci    return ok;
227e1051a39Sopenharmony_ci err:
228e1051a39Sopenharmony_ci    BN_free(tmpbn);
229e1051a39Sopenharmony_ci    return 0;
230e1051a39Sopenharmony_ci}
231