Update copyright year
[openssl.git] / crypto / params_from_text.c
1 /*
2  * Copyright 2019-2021 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 <string.h>
12 #include <openssl/ebcdic.h>
13 #include <openssl/err.h>
14 #include <openssl/params.h>
15
16 /*
17  * When processing text to params, we're trying to be smart with numbers.
18  * Instead of handling each specific separate integer type, we use a bignum
19  * and ensure that it isn't larger than the expected size, and we then make
20  * sure it is the expected size...  if there is one given.
21  * (if the size can be arbitrary, then we give whatever we have)
22  */
23
24 static int prepare_from_text(const OSSL_PARAM *paramdefs, const char *key,
25                              const char *value, size_t value_n,
26                              /* Output parameters */
27                              const OSSL_PARAM **paramdef, int *ishex,
28                              size_t *buf_n, BIGNUM **tmpbn, int *found)
29 {
30     const OSSL_PARAM *p;
31
32     /*
33      * ishex is used to translate legacy style string controls in hex format
34      * to octet string parameters.
35      */
36     *ishex = strncmp(key, "hex", 3) == 0;
37
38     if (*ishex)
39         key += 3;
40
41     p = *paramdef = OSSL_PARAM_locate_const(paramdefs, key);
42     if (found != NULL)
43         *found = p != NULL;
44     if (p == NULL)
45         return 0;
46
47     switch (p->data_type) {
48     case OSSL_PARAM_INTEGER:
49     case OSSL_PARAM_UNSIGNED_INTEGER:
50         if (*ishex)
51             BN_hex2bn(tmpbn, value);
52         else
53             BN_dec2bn(tmpbn, value);
54
55         if (*tmpbn == NULL)
56             return 0;
57
58         /*
59          * 2s complement negate, part 1
60          *
61          * BN_bn2nativepad puts the absolute value of the number in the
62          * buffer, i.e. if it's negative, we need to deal with it.  We do
63          * it by subtracting 1 here and inverting the bytes in
64          * construct_from_text() below.
65          */
66         if (p->data_type == OSSL_PARAM_INTEGER && BN_is_negative(*tmpbn)
67             && !BN_sub_word(*tmpbn, 1)) {
68             return 0;
69         }
70
71         *buf_n = BN_num_bytes(*tmpbn);
72
73         /*
74          * TODO(v3.0) is this the right way to do this?  This code expects
75          * a zero data size to simply mean "arbitrary size".
76          */
77         if (p->data_size > 0) {
78             if (*buf_n >= p->data_size) {
79                 ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_TOO_SMALL_BUFFER);
80                 /* Since this is a different error, we don't break */
81                 return 0;
82             }
83             /* Change actual size to become the desired size. */
84             *buf_n = p->data_size;
85         }
86         break;
87     case OSSL_PARAM_UTF8_STRING:
88         if (*ishex) {
89             ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
90             return 0;
91         }
92         *buf_n = strlen(value) + 1;
93         break;
94     case OSSL_PARAM_OCTET_STRING:
95         if (*ishex) {
96             *buf_n = strlen(value) >> 1;
97         } else {
98             *buf_n = value_n;
99         }
100         break;
101     }
102
103     return 1;
104 }
105
106 static int construct_from_text(OSSL_PARAM *to, const OSSL_PARAM *paramdef,
107                                const char *value, size_t value_n, int ishex,
108                                void *buf, size_t buf_n, BIGNUM *tmpbn)
109 {
110     if (buf == NULL)
111         return 0;
112
113     if (buf_n > 0) {
114         switch (paramdef->data_type) {
115         case OSSL_PARAM_INTEGER:
116         case OSSL_PARAM_UNSIGNED_INTEGER:
117             /*
118             {
119                 if ((new_value = OPENSSL_malloc(new_value_n)) == NULL) {
120                     BN_free(a);
121                     break;
122                 }
123             */
124
125             BN_bn2nativepad(tmpbn, buf, buf_n);
126
127             /*
128              * 2s complement negate, part two.
129              *
130              * Because we did the first part on the BIGNUM itself, we can just
131              * invert all the bytes here and be done with it.
132              */
133             if (paramdef->data_type == OSSL_PARAM_INTEGER
134                 && BN_is_negative(tmpbn)) {
135                 unsigned char *cp;
136                 size_t i = buf_n;
137
138                 for (cp = buf; i-- > 0; cp++)
139                     *cp ^= 0xFF;
140             }
141             break;
142         case OSSL_PARAM_UTF8_STRING:
143 #ifdef CHARSET_EBCDIC
144             ebcdic2ascii(buf, value, buf_n);
145 #else
146             strncpy(buf, value, buf_n);
147 #endif
148             break;
149         case OSSL_PARAM_OCTET_STRING:
150             if (ishex) {
151                 size_t l = 0;
152
153                 if (!OPENSSL_hexstr2buf_ex(buf, buf_n, &l, value, ':'))
154                     return 0;
155             } else {
156                 memcpy(buf, value, buf_n);
157             }
158             break;
159         }
160     }
161
162     *to = *paramdef;
163     to->data = buf;
164     to->data_size = buf_n;
165     to->return_size = OSSL_PARAM_UNMODIFIED;
166
167     return 1;
168 }
169
170 int OSSL_PARAM_allocate_from_text(OSSL_PARAM *to,
171                                   const OSSL_PARAM *paramdefs,
172                                   const char *key, const char *value,
173                                   size_t value_n, int *found)
174 {
175     const OSSL_PARAM *paramdef = NULL;
176     int ishex = 0;
177     void *buf = NULL;
178     size_t buf_n = 0;
179     BIGNUM *tmpbn = NULL;
180     int ok = 0;
181
182     if (to == NULL || paramdefs == NULL)
183         return 0;
184
185     if (!prepare_from_text(paramdefs, key, value, value_n,
186                            &paramdef, &ishex, &buf_n, &tmpbn, found))
187         return 0;
188
189     if ((buf = OPENSSL_zalloc(buf_n > 0 ? buf_n : 1)) == NULL) {
190         ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
191         return 0;
192     }
193
194     ok = construct_from_text(to, paramdef, value, value_n, ishex,
195                              buf, buf_n, tmpbn);
196     BN_free(tmpbn);
197     if (!ok)
198         OPENSSL_free(buf);
199     return ok;
200 }