summaryrefslogtreecommitdiffstats
path: root/crypto/params_from_text.c
diff options
context:
space:
mode:
authorRichard Levitte <levitte@openssl.org>2019-07-03 18:42:21 +0200
committerRichard Levitte <levitte@openssl.org>2019-08-12 12:50:41 +0200
commit246a1f3dfafc4a377bc7d7da65d9f8981a696abd (patch)
tree81754a3338e61308a5f9a43f1571837061f708d3 /crypto/params_from_text.c
parent82bd7c2cbd3a4b38321fb9053b8aa0f5d100cf54 (diff)
Add OSSL_PARAM_construct_from_text() and OSSL_PARAM_allocate_from_text()
These are utility functions that can be used to replace calls to ctrl_str type functions with get_params / set_params types of calls. They work by translating text values to something more suitable for OSSL_PARAM, and by interpretting parameter keys in a compatible fashion. Reviewed-by: Paul Dale <paul.dale@oracle.com> (Merged from https://github.com/openssl/openssl/pull/9303)
Diffstat (limited to 'crypto/params_from_text.c')
-rw-r--r--crypto/params_from_text.c219
1 files changed, 219 insertions, 0 deletions
diff --git a/crypto/params_from_text.c b/crypto/params_from_text.c
new file mode 100644
index 0000000000..2a861c94fe
--- /dev/null
+++ b/crypto/params_from_text.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include <openssl/err.h>
+#include <openssl/params.h>
+
+/*
+ * When processing text to params, we're trying to be smart with numbers.
+ * Instead of handling each specific separate integer type, we use a bignum
+ * and ensure that it isn't larger than the expected size, and we then make
+ * sure it is the expected size... if there is one given.
+ * (if the size can be arbitrary, then we give whatever we have)
+ */
+
+static int prepare_from_text(const OSSL_PARAM *paramdefs, const char *key,
+ const char *value, size_t value_n,
+ /* Output parameters */
+ const OSSL_PARAM **paramdef, int *ishex,
+ size_t *buf_n, BIGNUM **tmpbn)
+{
+ const OSSL_PARAM *p;
+
+ /*
+ * ishex is used to translate legacy style string controls in hex format
+ * to octet string parameters.
+ */
+ *ishex = strncmp(key, "hex", 3) == 0;
+
+ if (*ishex)
+ key += 3;
+
+ p = *paramdef = OSSL_PARAM_locate_const(paramdefs, key);
+ if (p == NULL)
+ return 0;
+
+ switch (p->data_type) {
+ case OSSL_PARAM_INTEGER:
+ case OSSL_PARAM_UNSIGNED_INTEGER:
+ if (*ishex)
+ BN_hex2bn(tmpbn, value);
+ else
+ BN_dec2bn(tmpbn, value);
+
+ if (*tmpbn == NULL)
+ return 0;
+
+ /*
+ * 2s complement negate, part 1
+ *
+ * BN_bn2nativepad puts the absolute value of the number in the
+ * buffer, i.e. if it's negative, we need to deal with it. We do
+ * it by subtracting 1 here and inverting the bytes in
+ * construct_from_text() below.
+ */
+ if (p->data_type == OSSL_PARAM_INTEGER && BN_is_negative(*tmpbn)
+ && !BN_sub_word(*tmpbn, 1)) {
+ return 0;
+ }
+
+ *buf_n = BN_num_bytes(*tmpbn);
+
+ /*
+ * TODO(v3.0) is this the right way to do this? This code expects
+ * a zero data size to simply mean "arbitrary size".
+ */
+ if (p->data_size > 0) {
+ if (*buf_n >= p->data_size) {
+ CRYPTOerr(0, CRYPTO_R_TOO_SMALL_BUFFER);
+ /* Since this is a different error, we don't break */
+ return 0;
+ }
+ /* Change actual size to become the desired size. */
+ *buf_n = p->data_size;
+ }
+ break;
+ case OSSL_PARAM_UTF8_STRING:
+ if (*ishex) {
+ CRYPTOerr(0, ERR_R_PASSED_INVALID_ARGUMENT);
+ return 0;
+ }
+ *buf_n = strlen(value) + 1;
+ break;
+ case OSSL_PARAM_OCTET_STRING:
+ if (*ishex) {
+ *buf_n = strlen(value) >> 1;
+ }
+ break;
+ }
+
+ return 1;
+}
+
+static int construct_from_text(OSSL_PARAM *to, const OSSL_PARAM *paramdef,
+ const char *value, size_t value_n, int ishex,
+ void *buf, size_t buf_n, BIGNUM *tmpbn)
+{
+ if (buf == NULL)
+ return 0;
+
+ switch (paramdef->data_type) {
+ case OSSL_PARAM_INTEGER:
+ case OSSL_PARAM_UNSIGNED_INTEGER:
+ /*
+ {
+ if ((new_value = OPENSSL_malloc(new_value_n)) == NULL) {
+ BN_free(a);
+ break;
+ }
+ */
+
+ BN_bn2nativepad(tmpbn, buf, buf_n);
+
+ /*
+ * 2s complement negate, part two.
+ *
+ * Because we did the first part on the BIGNUM itself, we can just
+ * invert all the bytes here and be done with it.
+ */
+ if (paramdef->data_type == OSSL_PARAM_INTEGER
+ && BN_is_negative(tmpbn)) {
+ unsigned char *cp;
+ size_t i = buf_n;
+
+ for (cp = buf; i-- > 0; cp++)
+ *cp ^= 0xFF;
+ }
+ break;
+ case OSSL_PARAM_UTF8_STRING:
+ strncpy(buf, value, buf_n);
+ break;
+ case OSSL_PARAM_OCTET_STRING:
+ if (ishex) {
+ size_t l = 0;
+
+ if (!OPENSSL_hexstr2buf_ex(buf, buf_n, &l, value))
+ return 0;
+ } else {
+ memcpy(buf, value, buf_n);
+
+ }
+ break;
+ }
+
+ *to = *paramdef;
+ to->data = buf;
+ to->data_size = buf_n;
+ to->return_size = 0;
+
+ return 1;
+}
+
+int OSSL_PARAM_construct_from_text(OSSL_PARAM *to,
+ const OSSL_PARAM *paramdefs,
+ const char *key, const char *value,
+ size_t value_n,
+ void *buf, size_t *buf_n)
+{
+ const OSSL_PARAM *paramdef = NULL;
+ int ishex = 0;
+ BIGNUM *tmpbn = NULL;
+ int ok = 0;
+
+ if (to == NULL || paramdefs == NULL)
+ return 0;
+
+ if (!prepare_from_text(paramdefs, key, value, value_n,
+ &paramdef, &ishex, buf_n, &tmpbn))
+ return 0;
+
+ /*
+ * The user gets the expected buffer size back even if the buffer isn't
+ * allocated.
+ */
+ if (buf == NULL)
+ return 1;
+
+ ok = construct_from_text(to, paramdef, value, value_n, ishex,
+ buf, *buf_n, tmpbn);
+ BN_free(tmpbn);
+ return ok;
+}
+
+int OSSL_PARAM_allocate_from_text(OSSL_PARAM *to,
+ const OSSL_PARAM *paramdefs,
+ const char *key, const char *value,
+ size_t value_n)
+{
+ const OSSL_PARAM *paramdef = NULL;
+ int ishex = 0;
+ void *buf = NULL;
+ size_t buf_n = 0;
+ BIGNUM *tmpbn = NULL;
+ int ok = 0;
+
+ if (to == NULL || paramdefs == NULL)
+ return 0;
+
+ if (!prepare_from_text(paramdefs, key, value, value_n,
+ &paramdef, &ishex, &buf_n, &tmpbn))
+ return 0;
+
+ if ((buf = OPENSSL_malloc(buf_n)) == NULL) {
+ CRYPTOerr(0, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ ok = construct_from_text(to, paramdef, value, value_n, ishex,
+ buf, buf_n, tmpbn);
+ BN_free(tmpbn);
+ return ok;
+}