Parameter building utilities.
authorPauli <paul.dale@oracle.com>
Wed, 17 Jul 2019 06:59:09 +0000 (16:59 +1000)
committerPauli <paul.dale@oracle.com>
Wed, 17 Jul 2019 06:59:09 +0000 (16:59 +1000)
A fuller implementation of PARAMS_TEMPLATE as per #9266 but renamed.
This introduces a statis data type which can be used to constructor a
description of a parameter array.  It can then be converted into a OSSL_PARAM
array and the allocated storage freed by a single call to OPENSSL_free.

Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/9305)

crypto/build.info
crypto/cpt_err.c
crypto/err/openssl.txt
crypto/param_build.c [new file with mode: 0644]
doc/internal/man3/ossl_param_bld_init.pod [new file with mode: 0644]
include/internal/param_build.h [new file with mode: 0644]
include/openssl/cryptoerr.h
test/build.info
test/param_build_test.c [new file with mode: 0644]
test/recipes/04-test_param_build.t [new file with mode: 0644]

index 90ccbc8b543a84649112d454076e6d617220bd15..088ec87310b529cd38b40057127c4eb19d9c32c9 100644 (file)
@@ -68,7 +68,7 @@ SOURCE[../providers/fips]=$CORE_COMMON
 $UTIL_COMMON=\
         cryptlib.c params.c bsearch.c ex_data.c o_str.c \
         ctype.c threads_pthread.c threads_win.c threads_none.c initthread.c \
-        context.c sparse_array.c $CPUIDASM
+        context.c sparse_array.c param_build.c $CPUIDASM
 $UTIL_DEFINE=$CPUIDDEF
 
 SOURCE[../libcrypto]=$UTIL_COMMON \
index 94081344cae370af83758aa37d6d26dff8122574..fdf0e6ebce2f03d47cc4a398ea9df107cd34a15d 100644 (file)
@@ -18,12 +18,30 @@ static const ERR_STRING_DATA CRYPTO_str_reasons[] = {
     "fips mode not supported"},
     {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_ILLEGAL_HEX_DIGIT),
     "illegal hex digit"},
+    {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_INSUFFICIENT_DATA_SPACE),
+    "insufficient data space"},
+    {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_INSUFFICIENT_PARAM_SIZE),
+    "insufficient param size"},
+    {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_INSUFFICIENT_SECURE_DATA_SPACE),
+    "insufficient secure data space"},
+    {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_INVALID_NULL_ARGUMENT),
+    "invalid null argument"},
+    {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_INVALID_OSSL_PARAM_TYPE),
+    "invalid ossl param type"},
     {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_ODD_NUMBER_OF_DIGITS),
     "odd number of digits"},
     {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_PROVIDER_ALREADY_EXISTS),
     "provider already exists"},
     {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_PROVIDER_SECTION_ERROR),
     "provider section error"},
+    {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_SECURE_MALLOC_FAILURE),
+    "secure malloc failure"},
+    {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_STRING_TOO_LONG), "string too long"},
+    {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_TOO_MANY_BYTES), "too many bytes"},
+    {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_TOO_MANY_RECORDS),
+    "too many records"},
+    {ERR_PACK(ERR_LIB_CRYPTO, 0, CRYPTO_R_ZERO_LENGTH_NUMBER),
+    "zero length number"},
     {0, NULL}
 };
 
index 4608938ed56fbd77877048af7dc6bdee7dc5c688..8aa62a6c387fd0039285208ebdc33f23837933a9 100644 (file)
@@ -397,11 +397,21 @@ CRYPTO_F_OPENSSL_INIT_CRYPTO:116:OPENSSL_init_crypto
 CRYPTO_F_OPENSSL_LH_NEW:126:OPENSSL_LH_new
 CRYPTO_F_OPENSSL_SK_DEEP_COPY:127:OPENSSL_sk_deep_copy
 CRYPTO_F_OPENSSL_SK_DUP:128:OPENSSL_sk_dup
+CRYPTO_F_OSSL_PARAM_BLD_PUSH_BN:143:
+CRYPTO_F_OSSL_PARAM_BLD_PUSH_OCTET_PTR:144:
+CRYPTO_F_OSSL_PARAM_BLD_PUSH_OCTET_STRING:145:
+CRYPTO_F_OSSL_PARAM_BLD_PUSH_UTF8_PTR:146:
+CRYPTO_F_OSSL_PARAM_BLD_PUSH_UTF8_STRING:147:
+CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM:148:
+CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM_EX:149:
+CRYPTO_F_OSSL_PARAM_TYPE_TO_PARAM:150:
 CRYPTO_F_OSSL_PROVIDER_ACTIVATE:130:ossl_provider_activate
 CRYPTO_F_OSSL_PROVIDER_ADD_BUILTIN:132:OSSL_PROVIDER_add_builtin
 CRYPTO_F_OSSL_PROVIDER_ADD_PARAMETER:139:ossl_provider_add_parameter
 CRYPTO_F_OSSL_PROVIDER_NEW:131:ossl_provider_new
 CRYPTO_F_OSSL_PROVIDER_SET_MODULE_PATH:140:ossl_provider_set_module_path
+CRYPTO_F_PARAM_PUSH:151:
+CRYPTO_F_PARAM_PUSH_NUM:152:
 CRYPTO_F_PKEY_HMAC_INIT:123:pkey_hmac_init
 CRYPTO_F_PKEY_POLY1305_INIT:124:pkey_poly1305_init
 CRYPTO_F_PKEY_SIPHASH_INIT:125:pkey_siphash_init
@@ -807,11 +817,11 @@ EVP_F_EVP_DIGESTUPDATE:231:EVP_DigestUpdate
 EVP_F_EVP_ENCRYPTDECRYPTUPDATE:219:evp_EncryptDecryptUpdate
 EVP_F_EVP_ENCRYPTFINAL_EX:127:EVP_EncryptFinal_ex
 EVP_F_EVP_ENCRYPTUPDATE:167:EVP_EncryptUpdate
-EVP_F_EVP_KEYEXCH_FROM_DISPATCH:244:evp_keyexch_from_dispatch
 EVP_F_EVP_KDF_CTRL:224:EVP_KDF_ctrl
 EVP_F_EVP_KDF_CTRL_STR:225:EVP_KDF_ctrl_str
 EVP_F_EVP_KDF_CTX_NEW:240:EVP_KDF_CTX_new
 EVP_F_EVP_KDF_CTX_NEW_ID:226:EVP_KDF_CTX_new_id
+EVP_F_EVP_KEYEXCH_FROM_DISPATCH:244:evp_keyexch_from_dispatch
 EVP_F_EVP_MAC_CTRL:209:EVP_MAC_ctrl
 EVP_F_EVP_MAC_CTRL_STR:210:EVP_MAC_ctrl_str
 EVP_F_EVP_MAC_CTX_DUP:211:EVP_MAC_CTX_dup
@@ -2215,9 +2225,19 @@ CRMF_R_UNSUPPORTED_POPO_METHOD:116:unsupported popo method
 CRMF_R_UNSUPPORTED_POPO_NOT_ACCEPTED:117:unsupported popo not accepted
 CRYPTO_R_FIPS_MODE_NOT_SUPPORTED:101:fips mode not supported
 CRYPTO_R_ILLEGAL_HEX_DIGIT:102:illegal hex digit
+CRYPTO_R_INSUFFICIENT_DATA_SPACE:106:insufficient data space
+CRYPTO_R_INSUFFICIENT_PARAM_SIZE:107:insufficient param size
+CRYPTO_R_INSUFFICIENT_SECURE_DATA_SPACE:108:insufficient secure data space
+CRYPTO_R_INVALID_NULL_ARGUMENT:109:invalid null argument
+CRYPTO_R_INVALID_OSSL_PARAM_TYPE:110:invalid ossl param type
 CRYPTO_R_ODD_NUMBER_OF_DIGITS:103:odd number of digits
 CRYPTO_R_PROVIDER_ALREADY_EXISTS:104:provider already exists
 CRYPTO_R_PROVIDER_SECTION_ERROR:105:provider section error
+CRYPTO_R_SECURE_MALLOC_FAILURE:111:secure malloc failure
+CRYPTO_R_STRING_TOO_LONG:112:string too long
+CRYPTO_R_TOO_MANY_BYTES:113:too many bytes
+CRYPTO_R_TOO_MANY_RECORDS:114:too many records
+CRYPTO_R_ZERO_LENGTH_NUMBER:115:zero length number
 CT_R_BASE64_DECODE_ERROR:108:base64 decode error
 CT_R_INVALID_LOG_ID_LENGTH:100:invalid log id length
 CT_R_LOG_CONF_INVALID:109:log conf invalid
diff --git a/crypto/param_build.c b/crypto/param_build.c
new file mode 100644 (file)
index 0000000..851b735
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * 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/cryptoerr.h>
+#include <openssl/params.h>
+#include "internal/cryptlib.h"
+#include "internal/param_build.h"
+
+typedef union {
+    OSSL_UNION_ALIGN;
+} OSSL_PARAM_BLD_BLOCK;
+
+#define ALIGN_SIZE  sizeof(OSSL_PARAM_BLD_BLOCK)
+
+static size_t bytes_to_blocks(size_t bytes)
+{
+    return (bytes + ALIGN_SIZE - 1) / ALIGN_SIZE;
+}
+
+static OSSL_PARAM_BLD_DEF *param_push(OSSL_PARAM_BLD *bld, const char *key,
+                                      int size, size_t alloc, int type,
+                                      int secure)
+{
+    OSSL_PARAM_BLD_DEF *pd;
+
+    if (bld->curr >= OSSL_PARAM_BLD_MAX) {
+        CRYPTOerr(CRYPTO_F_PARAM_PUSH, CRYPTO_R_TOO_MANY_RECORDS);
+        return NULL;
+    }
+    pd = bld->params + bld->curr++;
+    memset(pd, 0, sizeof(*pd));
+    pd->key = key;
+    pd->type = type;
+    pd->size = size;
+    pd->alloc_blocks = bytes_to_blocks(size);
+    if ((pd->secure = secure) != 0)
+        bld->secure_blocks += pd->alloc_blocks;
+    else
+        bld->total_blocks += pd->alloc_blocks;
+    return pd;
+}
+
+static int param_push_num(OSSL_PARAM_BLD *bld, const char *key,
+                          void *num, size_t size, int type)
+{
+    OSSL_PARAM_BLD_DEF *pd = param_push(bld, key, size, size, type, 0);
+
+    if (pd == NULL)
+        return 0;
+    if (size > sizeof(pd->num)) {
+        CRYPTOerr(CRYPTO_F_PARAM_PUSH_NUM, CRYPTO_R_TOO_MANY_BYTES);
+        return 0;
+    }
+    memcpy(&pd->num, num, size);
+    return 1;
+}
+
+void ossl_param_bld_init(OSSL_PARAM_BLD *bld)
+{
+    memset(bld, 0, sizeof(*bld));
+}
+
+int ossl_param_bld_push_int(OSSL_PARAM_BLD *bld, const char *key, int num)
+{
+    return param_push_num(bld, key, &num, sizeof(num), OSSL_PARAM_INTEGER);
+}
+
+int ossl_param_bld_push_uint(OSSL_PARAM_BLD *bld, const char *key,
+                             unsigned int num)
+{
+    return param_push_num(bld, key, &num, sizeof(num),
+                          OSSL_PARAM_UNSIGNED_INTEGER);
+}
+
+int ossl_param_bld_push_long(OSSL_PARAM_BLD *bld, const char *key,
+                             long int num)
+{
+    return param_push_num(bld, key, &num, sizeof(num), OSSL_PARAM_INTEGER);
+}
+
+int ossl_param_bld_push_ulong(OSSL_PARAM_BLD *bld, const char *key,
+                              unsigned long int num)
+{
+    return param_push_num(bld, key, &num, sizeof(num),
+                          OSSL_PARAM_UNSIGNED_INTEGER);
+}
+
+int ossl_param_bld_push_int32(OSSL_PARAM_BLD *bld, const char *key,
+                              int32_t num)
+{
+    return param_push_num(bld, key, &num, sizeof(num), OSSL_PARAM_INTEGER);
+}
+
+int ossl_param_bld_push_uint32(OSSL_PARAM_BLD *bld, const char *key,
+                               uint32_t num)
+{
+    return param_push_num(bld, key, &num, sizeof(num),
+                          OSSL_PARAM_UNSIGNED_INTEGER);
+}
+
+int ossl_param_bld_push_int64(OSSL_PARAM_BLD *bld, const char *key,
+                              int64_t num)
+{
+    return param_push_num(bld, key, &num, sizeof(num), OSSL_PARAM_INTEGER);
+}
+
+int ossl_param_bld_push_uint64(OSSL_PARAM_BLD *bld, const char *key,
+                               uint64_t num)
+{
+    return param_push_num(bld, key, &num, sizeof(num),
+                          OSSL_PARAM_UNSIGNED_INTEGER);
+}
+
+int ossl_param_bld_push_size_t(OSSL_PARAM_BLD *bld, const char *key,
+                               size_t num)
+{
+    return param_push_num(bld, key, &num, sizeof(num),
+                          OSSL_PARAM_UNSIGNED_INTEGER);
+}
+
+int ossl_param_bld_push_double(OSSL_PARAM_BLD *bld, const char *key,
+                               double num)
+{
+    return param_push_num(bld, key, &num, sizeof(num), OSSL_PARAM_REAL);
+}
+
+int ossl_param_bld_push_BN(OSSL_PARAM_BLD *bld, const char *key,
+                           const BIGNUM *bn)
+{
+    int sz = -1, secure = 0;
+    OSSL_PARAM_BLD_DEF *pd;
+
+    if (bn != NULL) {
+        sz = BN_num_bytes(bn);
+        if (sz < 0) {
+            CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_PUSH_BN,
+                      CRYPTO_R_ZERO_LENGTH_NUMBER);
+            return 0;
+        }
+        if (BN_get_flags(bn, BN_FLG_SECURE) == BN_FLG_SECURE)
+            secure = 1;
+    }
+    pd = param_push(bld, key, sz, sz >= 0 ? sz : 0,
+                    OSSL_PARAM_UNSIGNED_INTEGER, secure);
+    if (pd == NULL)
+        return 0;
+    pd->bn = bn;
+    return 1;
+}
+
+int ossl_param_bld_push_utf8_string(OSSL_PARAM_BLD *bld, const char *key,
+                                    char *buf, size_t bsize)
+{
+    OSSL_PARAM_BLD_DEF *pd;
+
+    if (bsize == 0) {
+        bsize = strlen(buf) + 1;
+    } else if (bsize > INT_MAX) {
+        CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_PUSH_UTF8_STRING,
+                  CRYPTO_R_STRING_TOO_LONG);
+        return 0;
+    }
+    pd = param_push(bld, key, bsize, bsize, OSSL_PARAM_UTF8_STRING, 0);
+    if (pd == NULL)
+        return 0;
+    pd->string = buf;
+    return 1;
+}
+
+int ossl_param_bld_push_utf8_ptr(OSSL_PARAM_BLD *bld, const char *key,
+                                 char *buf, size_t bsize)
+{
+    OSSL_PARAM_BLD_DEF *pd;
+
+    if (bsize == 0) {
+        bsize = strlen(buf) + 1;
+    } else if (bsize > INT_MAX) {
+        CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_PUSH_UTF8_PTR,
+                  CRYPTO_R_STRING_TOO_LONG);
+        return 0;
+    }
+    pd = param_push(bld, key, bsize, sizeof(buf), OSSL_PARAM_UTF8_PTR, 0);
+    if (pd == NULL)
+        return 0;
+    pd->string = buf;
+    return 1;
+}
+
+int ossl_param_bld_push_octet_string(OSSL_PARAM_BLD *bld, const char *key,
+                                     void *buf, size_t bsize)
+{
+    OSSL_PARAM_BLD_DEF *pd;
+
+    if (bsize > INT_MAX) {
+        CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_PUSH_OCTET_STRING,
+                  CRYPTO_R_STRING_TOO_LONG);
+        return 0;
+    }
+    pd = param_push(bld, key, bsize, bsize, OSSL_PARAM_OCTET_STRING, 0);
+    if (pd == NULL)
+        return 0;
+    pd->string = buf;
+    return 1;
+}
+
+int ossl_param_bld_push_octet_ptr(OSSL_PARAM_BLD *bld, const char *key,
+                                  void *buf, size_t bsize)
+{
+    OSSL_PARAM_BLD_DEF *pd;
+
+    if (bsize > INT_MAX) {
+        CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_PUSH_OCTET_PTR,
+                  CRYPTO_R_STRING_TOO_LONG);
+        return 0;
+    }
+    pd = param_push(bld, key, bsize, sizeof(buf), OSSL_PARAM_OCTET_PTR, 0);
+    if (pd == NULL)
+        return 0;
+    pd->string = buf;
+    return 1;
+}
+
+static OSSL_PARAM *param_bld_convert(OSSL_PARAM_BLD *bld, OSSL_PARAM *param,
+                                     OSSL_PARAM_BLD_BLOCK *blk,
+                                     OSSL_PARAM_BLD_BLOCK *secure)
+{
+    size_t i;
+    OSSL_PARAM_BLD_DEF *pd;
+    void *p;
+
+    for (i = 0; i < bld->curr; i++) {
+        pd = bld->params + i;
+        param[i].key = pd->key;
+        param[i].data_type = pd->type;
+        param[i].data_size = pd->size;
+        param[i].return_size = 0;
+
+        if (pd->secure) {
+            p = secure;
+            secure += pd->alloc_blocks;
+        } else {
+            p = blk;
+            blk += pd->alloc_blocks;
+        }
+        param[i].data = p;
+        if (pd->bn != NULL) {
+            /* BIGNUM */
+            BN_bn2nativepad(pd->bn, (unsigned char *)p, pd->size);
+        } else if (pd->type == OSSL_PARAM_OCTET_PTR
+                   || pd->type == OSSL_PARAM_UTF8_PTR) {
+            /* PTR */
+            *(void **)p = pd->string;
+        } else if (pd->type == OSSL_PARAM_OCTET_STRING
+                   || pd->type == OSSL_PARAM_UTF8_STRING) {
+            if (pd->string != NULL)
+                memcpy(p, pd->string, pd->size);
+            else
+                memset(p, 0, pd->size);
+        } else {
+            /* Number, but could also be a NULL BIGNUM */
+            if (pd->size > sizeof(pd->num))
+                memset(p, 0, pd->size);
+            else if (pd->size > 0)
+                memcpy(p, &pd->num, pd->size);
+        }
+    }
+    param[i] = OSSL_PARAM_construct_end();
+    return param;
+}
+
+OSSL_PARAM *ossl_param_bld_to_param(OSSL_PARAM_BLD *bld, void **secure)
+{
+    OSSL_PARAM_BLD_BLOCK *blk, *s = NULL;
+    OSSL_PARAM *param;
+    const size_t p_blks = bytes_to_blocks((bld->curr + 1) * sizeof(*param));
+    const size_t total = ALIGN_SIZE * (p_blks + bld->total_blocks);
+
+    if (bld->secure_blocks > 0) {
+        if (secure == NULL) {
+            CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM,
+                      CRYPTO_R_INVALID_NULL_ARGUMENT);
+            return NULL;
+        }
+        s = OPENSSL_secure_malloc(bld->secure_blocks * ALIGN_SIZE);
+        if (s == NULL) {
+            CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM,
+                      CRYPTO_R_SECURE_MALLOC_FAILURE);
+            return NULL;
+        }
+    }
+    param = OPENSSL_malloc(total);
+    if (param == NULL) {
+        CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM, ERR_R_MALLOC_FAILURE);
+        OPENSSL_secure_free(s);
+        return NULL;
+    }
+    if (secure != NULL)
+        *secure = s;
+    blk = p_blks + (OSSL_PARAM_BLD_BLOCK *)(param);
+    param_bld_convert(bld, param, blk, s);
+    return param;
+}
+
+OSSL_PARAM *ossl_param_bld_to_param_ex(OSSL_PARAM_BLD *bld, OSSL_PARAM *params,
+                                       size_t param_n, void *data,
+                                       size_t data_n, void *secure,
+                                       size_t secure_n)
+{
+    if (params == NULL || data == NULL) {
+        CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM_EX,
+                  CRYPTO_R_INVALID_NULL_ARGUMENT);
+        return NULL;
+    }
+    if (param_n < bld->curr + 1) {
+        CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM_EX,
+                  CRYPTO_R_INSUFFICIENT_PARAM_SIZE);
+        return NULL;
+    }
+    if (data_n < ALIGN_SIZE * bld->total_blocks) {
+        CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM_EX,
+                  CRYPTO_R_INSUFFICIENT_DATA_SPACE);
+        return NULL;
+    }
+    if (bld->secure_blocks > 0 && secure_n < ALIGN_SIZE * bld->secure_blocks) {
+        CRYPTOerr(CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM_EX,
+                  CRYPTO_R_INSUFFICIENT_SECURE_DATA_SPACE);
+        return NULL;
+    }
+    param_bld_convert(bld, params, (OSSL_PARAM_BLD_BLOCK *)data,
+                      (OSSL_PARAM_BLD_BLOCK *)secure);
+    return params;
+}
diff --git a/doc/internal/man3/ossl_param_bld_init.pod b/doc/internal/man3/ossl_param_bld_init.pod
new file mode 100644 (file)
index 0000000..ca206c7
--- /dev/null
@@ -0,0 +1,191 @@
+=pod
+
+=head1 NAME
+
+ossl_param_build_init,
+ossl_param_build_to_param, ossl_param_build_push_int,
+ossl_param_build_push_uint, ossl_param_build_push_long,
+ossl_param_build_push_ulong, ossl_param_build_push_int32,
+ossl_param_build_push_uint32, ossl_param_build_push_int64,
+ossl_param_build_push_uint64, ossl_param_build_push_size_t,
+ossl_param_build_push_double, ossl_param_build_push_BN,
+ossl_param_build_push_utf8_string, ossl_param_build_push_utf8_ptr,
+ossl_param_build_push_octet_string, ossl_param_build_push_octet_ptr
+- functions to assist in the creation of OSSL_PARAM arrays
+
+=head1 SYNOPSIS
+
+=for comment generic
+
+ #include "internal/params_template.h"
+
+ #define OSSL_PARAM_BLD_MAX 10
+ typedef struct { ... } OSSL_PARAM_BLD;
+
+ void ossl_param_build_init(OSSL_PARAM_BLD *bld);
+ OSSL_PARAM *ossl_param_build_to_param(OSSL_PARAM_BLD *bld, void **secure);
+ OSSL_PARAM *ossl_param_build_to_param_ex(OSSL_PARAM_BLD *bld,
+                                        OSSL_PARAM *params, size_t param_n,
+                                        void *data, size_t data_n,
+                                        void *secure, size_t secure_n);
+
+ int ossl_param_build_push_TYPE(OSSL_PARAM_BLD *bld, const char *key, TYPE val);
+
+ int ossl_param_build_push_BN(OSSL_PARAM_BLD *bld, const char *key,
+                            const BIGNUM *bn);
+
+ int ossl_param_build_push_utf8_string(OSSL_PARAM_BLD *bld, const char *key,
+                                     char *buf, size_t bsize);
+ int ossl_param_build_push_utf8_ptr(OSSL_PARAM_BLD *bld, const char *key,
+                                  char *buf, size_t bsize);
+ int ossl_param_build_push_octet_string(OSSL_PARAM_BLD *bld, const char *key,
+                                      void *buf, size_t bsize);
+ int ossl_param_build_push_octet_ptr(OSSL_PARAM_BLD *bld, const char *key,
+                                   void *buf, size_t bsize);
+
+
+=head1 DESCRIPTION
+
+A collection of utility functions that simplify the creation of OSSL_PARAM
+arrays.  The B<TYPE> names are as per L<OSSL_PARAM_int(3)>.
+
+ossl_param_build_init() initialises the OSSL_PARAM_BLD structure so that values
+can be added.
+Any existing values are cleared.
+
+ossl_param_build_to_param() converts a built up OSSL_PARAM_BLD structure
+B<bld> into an allocated OSSL_PARAM array.
+The pointer referenced by the B<secure> argument is set to point to an
+allocated block of secure memory if required and to NULL it not. 
+The OSSL_PARAM array and all associated storage can be freed by calling
+OPENSSL_free() with the functions return value and OPENSSL_secure_free()
+with the pointer referenced by B<secure>.
+
+ossl_param_build_to_param_ex() behaves like ossl_param_build_to_param(), except that
+no additional memory is allocated.
+An OSSL_PARAM array of at least B<param_n> elements is passed in as B<params>.
+The auxiliary storage for the parameters is a block of memory pointed to
+by B<data> of at least B<data_n> bytes in size.
+If required, secure memory for private BIGNUMs should be pointed to by
+B<secure> of at least B<secure_n> bytes in size.
+
+ossl_param_build_push_TYPE() are a series of functions which will create
+OSSL_PARAM objects of the specified size and correct type for the B<val>
+argument.
+B<val> is stored by value and an expression or auto variable can be used.
+
+ossl_param_build_push_BN() is a function that will create an OSSL_PARAM object
+that holds the specified BIGNUM B<bn>.
+If B<bn> is marked as being securely allocated, the secure flag is
+set in the OSSL_PARAM_BLD structure.
+The B<bn> argument is stored by reference and the underlying BIGNUM object
+must exist until after ossl_param_build_to_param() has been called.
+
+ossl_param_build_push_utf8_string() is a function that will create an OSSL_PARAM
+object that references the UTF8 string specified by B<buf>.
+If the length of the string, B<bsize>, is zero then it will be calculated.
+The string that B<buf> points to is stored by reference and must remain in
+scope until after ossl_param_build_to_param() has been called.
+
+ossl_param_build_push_octet_string() is a function that will create an OSSL_PARAM
+object that references the octet string specified by B<buf> and <bsize>.
+The memory that B<buf> points to is stored by reference and must remain in
+scope until after ossl_param_build_to_param() has been called.
+
+ossl_param_build_push_utf8_ptr() is a function that will create an OSSL_PARAM
+object that references the UTF8 string specified by B<buf>.
+If the length of the string, B<bsize>, is zero then it will be calculated.
+The string B<buf> points to is stored by reference and must remain in
+scope until the OSSL_PARAM array is freed.
+
+ossl_param_build_push_octet_ptr() is a function that will create an OSSL_PARAM
+object that references the octet string specified by B<buf>.
+The memory B<buf> points to is stored by reference and must remain in
+scope until the OSSL_PARAM array is freed.
+
+=head1 RETURN VALUES
+
+ossl_param_build_to_param() and ossl_param_bld_to_param_ex() return the
+allocated OSSL_PARAM array, or NULL on error.
+
+All of the ossl_param_build_push_TYPE functions return 1 on success and 0
+on error.
+
+=head1 NOTES
+
+The constant B<OSSL_PARAM_BLD_MAX> specifies the maximum number of parameters
+that can be added.
+Exceeding this will result in the push functions returning errors.
+
+The structure B<OSSL_PARAM_BLD> should be considered opaque and subject to
+change between versions.
+
+=head1 EXAMPLES
+
+Both examples creating an OSSL_PARAM array that contains an RSA key.
+For both, the predefined key variables are:
+
+    BIGNUM *p, *q;  /* both prime */
+    BIGNUM *n;      /* = p * q */
+    unsigned int e; /* exponent, usually 65537 */
+    BIGNUM *d;      /* e^-1 */
+
+=head2 Example 1
+
+This example shows how to create an OSSL_PARAM array that contains an RSA
+private key.
+
+    OSSL_PARAM_BLD bld;
+    OSSL_PARAM *params;
+    void *secure;
+
+    ossl_param_build_init(&bld, &secure);
+    if (!ossl_param_build_push_BN(&bld, "p", p)
+        || !ossl_param_build_push_BN(&bld, "q", q)
+        || !ossl_param_build_push_uint(&bld, "e", e)
+        || !ossl_param_build_push_BN(&bld, "n", n)
+        || !ossl_param_build_push_BN(&bld, "d", d)
+        || (params = ossl_param_build_to_param(&bld)) == NULL)
+        goto err;
+    /* Use params */
+    ...
+    OPENSSL_free(params);
+    OPENSSL_secure_free(secure);
+
+=head2 Example 2
+
+This example shows how to create an OSSL_PARAM array that contains an RSA
+public key.
+
+    OSSL_PARAM_BLD bld;
+    OSSL_PARAM *params;
+    void *secure;
+
+    ossl_param_build_init(&bld, &secure);
+    if (!ossl_param_build_push_BN(&bld, "n", n)
+        || !ossl_param_build_push_BN(&bld, "d", d)
+        || (params = ossl_param_build_to_param(&bld)) == NULL)
+        goto err;
+    /* Use params */
+    ...
+    OPENSSL_free(params);
+    OPENSSL_secure_free(secure);
+
+=head1 SEE ALSO
+
+L<OSSL_PARAM_int>, L<OSSL_PARAM>
+
+=head1 HISTORY
+
+The functions described here were all added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2019 The OpenSSL Project Authors. 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
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/include/internal/param_build.h b/include/internal/param_build.h
new file mode 100644 (file)
index 0000000..762d7b1
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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 <openssl/params.h>
+#include <openssl/ossl_typ.h>
+
+#define OSSL_PARAM_BLD_MAX 10
+
+typedef struct {
+    const char *key;
+    int type;
+    int secure;
+    size_t size;
+    size_t alloc_blocks;
+    const BIGNUM *bn;
+    void *string;
+    union {
+        /*
+         * These fields are never directly addressed, but their sizes are
+         * imporant so that all native types can be copied here without overrun.
+         */
+        ossl_intmax_t i;
+        ossl_uintmax_t u;
+        double d;
+    } num;
+} OSSL_PARAM_BLD_DEF;
+
+typedef struct {
+    size_t curr;
+    size_t total_blocks;
+    size_t secure_blocks;
+    OSSL_PARAM_BLD_DEF params[OSSL_PARAM_BLD_MAX];
+} OSSL_PARAM_BLD;
+
+void ossl_param_bld_init(OSSL_PARAM_BLD *bld);
+OSSL_PARAM *ossl_param_bld_to_param(OSSL_PARAM_BLD *bld, void **secure);
+OSSL_PARAM *ossl_param_bld_to_param_ex(OSSL_PARAM_BLD *bld,
+                                       OSSL_PARAM *params, size_t param_n,
+                                       void *data, size_t data_n,
+                                       void *secure, size_t secure_n);
+
+int ossl_param_bld_push_int(OSSL_PARAM_BLD *bld, const char *key, int val);
+int ossl_param_bld_push_uint(OSSL_PARAM_BLD *bld, const char *key,
+                             unsigned int val);
+int ossl_param_bld_push_long(OSSL_PARAM_BLD *bld, const char *key,
+                             long int val);
+int ossl_param_bld_push_ulong(OSSL_PARAM_BLD *bld, const char *key,
+                              unsigned long int val);
+int ossl_param_bld_push_int32(OSSL_PARAM_BLD *bld, const char *key,
+                              int32_t val);
+int ossl_param_bld_push_uint32(OSSL_PARAM_BLD *bld, const char *key,
+                               uint32_t val);
+int ossl_param_bld_push_int64(OSSL_PARAM_BLD *bld, const char *key,
+                              int64_t val);
+int ossl_param_bld_push_uint64(OSSL_PARAM_BLD *bld, const char *key,
+                               uint64_t val);
+int ossl_param_bld_push_size_t(OSSL_PARAM_BLD *bld, const char *key,
+                               size_t val);
+int ossl_param_bld_push_double(OSSL_PARAM_BLD *bld, const char *key,
+                               double val);
+int ossl_param_bld_push_BN(OSSL_PARAM_BLD *bld, const char *key,
+                           const BIGNUM *bn);
+int ossl_param_bld_push_utf8_string(OSSL_PARAM_BLD *bld, const char *key,
+                                    char *buf, size_t bsize);
+int ossl_param_bld_push_utf8_ptr(OSSL_PARAM_BLD *bld, const char *key,
+                                 char *buf, size_t bsize);
+int ossl_param_bld_push_octet_string(OSSL_PARAM_BLD *bld, const char *key,
+                                     void *buf, size_t bsize);
+int ossl_param_bld_push_octet_ptr(OSSL_PARAM_BLD *bld, const char *key,
+                                  void *buf, size_t bsize);
index 5df2247161474bf86ab5cc7fbfff52c44d2a02df..9fdf52c0c138c847060e1dd51c27dda8566110a2 100644 (file)
@@ -46,11 +46,21 @@ int ERR_load_CRYPTO_strings(void);
 #  define CRYPTO_F_OPENSSL_LH_NEW                          0
 #  define CRYPTO_F_OPENSSL_SK_DEEP_COPY                    0
 #  define CRYPTO_F_OPENSSL_SK_DUP                          0
+#  define CRYPTO_F_OSSL_PARAM_BLD_PUSH_BN                  0
+#  define CRYPTO_F_OSSL_PARAM_BLD_PUSH_OCTET_PTR           0
+#  define CRYPTO_F_OSSL_PARAM_BLD_PUSH_OCTET_STRING        0
+#  define CRYPTO_F_OSSL_PARAM_BLD_PUSH_UTF8_PTR            0
+#  define CRYPTO_F_OSSL_PARAM_BLD_PUSH_UTF8_STRING         0
+#  define CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM                 0
+#  define CRYPTO_F_OSSL_PARAM_BLD_TO_PARAM_EX              0
+#  define CRYPTO_F_OSSL_PARAM_TYPE_TO_PARAM                0
 #  define CRYPTO_F_OSSL_PROVIDER_ACTIVATE                  0
 #  define CRYPTO_F_OSSL_PROVIDER_ADD_BUILTIN               0
 #  define CRYPTO_F_OSSL_PROVIDER_ADD_PARAMETER             0
 #  define CRYPTO_F_OSSL_PROVIDER_NEW                       0
 #  define CRYPTO_F_OSSL_PROVIDER_SET_MODULE_PATH           0
+#  define CRYPTO_F_PARAM_PUSH                              0
+#  define CRYPTO_F_PARAM_PUSH_NUM                          0
 #  define CRYPTO_F_PKEY_HMAC_INIT                          0
 #  define CRYPTO_F_PKEY_POLY1305_INIT                      0
 #  define CRYPTO_F_PKEY_SIPHASH_INIT                       0
@@ -67,8 +77,18 @@ int ERR_load_CRYPTO_strings(void);
  */
 # define CRYPTO_R_FIPS_MODE_NOT_SUPPORTED                 101
 # define CRYPTO_R_ILLEGAL_HEX_DIGIT                       102
+# define CRYPTO_R_INSUFFICIENT_DATA_SPACE                 106
+# define CRYPTO_R_INSUFFICIENT_PARAM_SIZE                 107
+# define CRYPTO_R_INSUFFICIENT_SECURE_DATA_SPACE          108
+# define CRYPTO_R_INVALID_NULL_ARGUMENT                   109
+# define CRYPTO_R_INVALID_OSSL_PARAM_TYPE                 110
 # define CRYPTO_R_ODD_NUMBER_OF_DIGITS                    103
 # define CRYPTO_R_PROVIDER_ALREADY_EXISTS                 104
 # define CRYPTO_R_PROVIDER_SECTION_ERROR                  105
+# define CRYPTO_R_SECURE_MALLOC_FAILURE                   111
+# define CRYPTO_R_STRING_TOO_LONG                         112
+# define CRYPTO_R_TOO_MANY_BYTES                          113
+# define CRYPTO_R_TOO_MANY_RECORDS                        114
+# define CRYPTO_R_ZERO_LENGTH_NUMBER                      115
 
 #endif
index 6966149811a0cffcc602bba44e59d058eadb7936..f9d429eba86ecdc767538dd676a746b92c40485a 100644 (file)
@@ -44,7 +44,7 @@ IF[{- !$disabled{tests} -}]
           packettest asynctest secmemtest srptest memleaktest stack_test \
           dtlsv1listentest ct_test threadstest afalgtest d2i_test \
           ssl_test_ctx_test ssl_test x509aux cipherlist_test asynciotest \
-          bio_callback_test bio_memleak_test \
+          bio_callback_test bio_memleak_test param_build_test \
           bioprinttest sslapitest dtlstest sslcorrupttest bio_enc_test \
           pkey_meth_test pkey_meth_kdf_test evp_kdf_test uitest \
           cipherbytes_test \
@@ -326,6 +326,10 @@ IF[{- !$disabled{tests} -}]
   INCLUDE[params_conversion_test]=../include ../apps/include
   DEPEND[params_conversion_test]=../libcrypto libtestutil.a
 
+  SOURCE[param_build_test]=param_build_test.c
+  INCLUDE[param_build_test]=../include ../apps/include
+  DEPEND[param_build_test]=../libcrypto.a libtestutil.a
+
   SOURCE[sslapitest]=sslapitest.c ssltestlib.c
   INCLUDE[sslapitest]=../include ../apps/include ..
   DEPEND[sslapitest]=../libcrypto ../libssl libtestutil.a
diff --git a/test/param_build_test.c b/test/param_build_test.c
new file mode 100644 (file)
index 0000000..278553d
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * 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/params.h>
+#include "internal/param_build.h"
+#include "internal/nelem.h"
+#include "testutil.h"
+
+static int template_public_test(void)
+{
+    OSSL_PARAM_BLD bld;
+    OSSL_PARAM *params = NULL, *p;
+    void *secure = (void *)"abc";
+    int i;
+    long int l;
+    int32_t i32;
+    int64_t i64;
+    double d;
+    char *utf = NULL;
+    const char *cutf;
+    int res = 0;
+
+    ossl_param_bld_init(&bld);
+    if (!TEST_true(ossl_param_bld_push_int(&bld, "i", -6))
+        || !TEST_true(ossl_param_bld_push_long(&bld, "l", 42))
+        || !TEST_true(ossl_param_bld_push_int32(&bld, "i32", 1532))
+        || !TEST_true(ossl_param_bld_push_int64(&bld, "i64", -9999999))
+        || !TEST_true(ossl_param_bld_push_double(&bld, "d", 1.61803398875))
+        || !TEST_true(ossl_param_bld_push_utf8_string(&bld, "utf8_s", "foo",
+                                                      sizeof("foo")))
+        || !TEST_true(ossl_param_bld_push_utf8_ptr(&bld, "utf8_p", "bar-boom",
+                                                   0))
+        || !TEST_ptr(params = ossl_param_bld_to_param(&bld, &secure))
+        || !TEST_ptr_null(secure)
+        /* Check int */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "i"))
+        || !TEST_true(OSSL_PARAM_get_int(p, &i))
+        || !TEST_str_eq(p->key, "i")
+        || !TEST_uint_eq(p->data_type, OSSL_PARAM_INTEGER)
+        || !TEST_size_t_eq(p->data_size, sizeof(int))
+        || !TEST_int_eq(i, -6)
+        /* Check int32 */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "i32"))
+        || !TEST_true(OSSL_PARAM_get_int32(p, &i32))
+        || !TEST_str_eq(p->key, "i32")
+        || !TEST_uint_eq(p->data_type, OSSL_PARAM_INTEGER)
+        || !TEST_size_t_eq(p->data_size, sizeof(int32_t))
+        || !TEST_int_eq((int)i32, 1532)
+        /* Check int64 */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "i64"))
+        || !TEST_str_eq(p->key, "i64")
+        || !TEST_uint_eq(p->data_type, OSSL_PARAM_INTEGER)
+        || !TEST_size_t_eq(p->data_size, sizeof(int64_t))
+        || !TEST_true(OSSL_PARAM_get_int64(p, &i64))
+        || !TEST_long_eq((long)i64, -9999999)
+        /* Check long */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "l"))
+        || !TEST_str_eq(p->key, "l")
+        || !TEST_uint_eq(p->data_type, OSSL_PARAM_INTEGER)
+        || !TEST_size_t_eq(p->data_size, sizeof(long int))
+        || !TEST_true(OSSL_PARAM_get_long(p, &l))
+        || !TEST_long_eq(l, 42)
+        /* Check double */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "d"))
+        || !TEST_true(OSSL_PARAM_get_double(p, &d))
+        || !TEST_str_eq(p->key, "d")
+        || !TEST_uint_eq(p->data_type, OSSL_PARAM_REAL)
+        || !TEST_size_t_eq(p->data_size, sizeof(double))
+        || !TEST_double_eq(d, 1.61803398875)
+        /* Check UTF8 string */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "utf8_s"))
+        || !TEST_str_eq(p->data, "foo")
+        || !TEST_true(OSSL_PARAM_get_utf8_string(p, &utf, 0))
+        || !TEST_str_eq(utf, "foo")
+        /* Check UTF8 pointer */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "utf8_p"))
+        || !TEST_true(OSSL_PARAM_get_utf8_ptr(p, &cutf))
+        || !TEST_str_eq(cutf, "bar-boom"))
+        goto err;
+    res = 1;
+err:
+    OPENSSL_free(params);
+    OPENSSL_secure_free(secure);
+    OPENSSL_free(utf);
+    return res;
+}
+
+static int template_private_test(void)
+{
+    static int data1[] = { 2, 3, 5, 7, 11, 15, 17 };
+    static unsigned char data2[] = { 2, 4, 6, 8, 10 };
+    OSSL_PARAM_BLD bld;
+    OSSL_PARAM *params = NULL, *p;
+    void *secure = (void *)"abc";
+    unsigned int i;
+    unsigned long int l;
+    uint32_t i32;
+    uint64_t i64;
+    size_t st;
+    BIGNUM *bn = NULL, *bn_res = NULL;
+    int res = 0;
+
+    ossl_param_bld_init(&bld);
+    if (!TEST_true(ossl_param_bld_push_uint(&bld, "i", 6))
+        || !TEST_true(ossl_param_bld_push_ulong(&bld, "l", 42))
+        || !TEST_true(ossl_param_bld_push_uint32(&bld, "i32", 1532))
+        || !TEST_true(ossl_param_bld_push_uint64(&bld, "i64", 9999999))
+        || !TEST_true(ossl_param_bld_push_size_t(&bld, "st", 65537))
+        || !TEST_ptr(bn = BN_new())
+        || !TEST_true(BN_set_word(bn, 1729))
+        || !TEST_true(ossl_param_bld_push_BN(&bld, "bignumber", bn))
+        || !TEST_true(ossl_param_bld_push_octet_string(&bld, "oct_s", data1,
+                                                       sizeof(data1)))
+        || !TEST_true(ossl_param_bld_push_octet_ptr(&bld, "oct_p", data2,
+                                                    sizeof(data2)))
+        || !TEST_ptr(params = ossl_param_bld_to_param(&bld, &secure))
+        /* Check unsigned int */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "i"))
+        || !TEST_true(OSSL_PARAM_get_uint(p, &i))
+        || !TEST_str_eq(p->key, "i")
+        || !TEST_uint_eq(p->data_type, OSSL_PARAM_UNSIGNED_INTEGER)
+        || !TEST_size_t_eq(p->data_size, sizeof(int))
+        || !TEST_uint_eq(i, 6)
+        /* Check unsigned int32 */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "i32"))
+        || !TEST_true(OSSL_PARAM_get_uint32(p, &i32))
+        || !TEST_str_eq(p->key, "i32")
+        || !TEST_uint_eq(p->data_type, OSSL_PARAM_UNSIGNED_INTEGER)
+        || !TEST_size_t_eq(p->data_size, sizeof(int32_t))
+        || !TEST_uint_eq((unsigned int)i32, 1532)
+        /* Check unsigned int64 */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "i64"))
+        || !TEST_str_eq(p->key, "i64")
+        || !TEST_uint_eq(p->data_type, OSSL_PARAM_UNSIGNED_INTEGER)
+        || !TEST_size_t_eq(p->data_size, sizeof(int64_t))
+        || !TEST_true(OSSL_PARAM_get_uint64(p, &i64))
+        || !TEST_ulong_eq((unsigned long)i64, 9999999)
+        /* Check unsigned long int */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "l"))
+        || !TEST_str_eq(p->key, "l")
+        || !TEST_uint_eq(p->data_type, OSSL_PARAM_UNSIGNED_INTEGER)
+        || !TEST_size_t_eq(p->data_size, sizeof(unsigned long int))
+        || !TEST_true(OSSL_PARAM_get_ulong(p, &l))
+        || !TEST_ulong_eq(l, 42)
+        /* Check size_t */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "st"))
+        || !TEST_str_eq(p->key, "st")
+        || !TEST_uint_eq(p->data_type, OSSL_PARAM_UNSIGNED_INTEGER)
+        || !TEST_size_t_eq(p->data_size, sizeof(size_t))
+        || !TEST_true(OSSL_PARAM_get_size_t(p, &st))
+        || !TEST_size_t_eq(st, 65537)
+        /* Check octet string */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "oct_s"))
+        || !TEST_str_eq(p->key, "oct_s")
+        || !TEST_uint_eq(p->data_type, OSSL_PARAM_OCTET_STRING)
+        || !TEST_mem_eq(p->data, p->data_size, data1, sizeof(data1))
+        /* Check octet pointer */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "oct_p"))
+        || !TEST_str_eq(p->key, "oct_p")
+        || !TEST_uint_eq(p->data_type, OSSL_PARAM_OCTET_PTR)
+        || !TEST_mem_eq(*(void **)p->data, p->data_size, data2, sizeof(data2))
+        /* Check BN */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "bignumber"))
+        || !TEST_str_eq(p->key, "bignumber")
+        || !TEST_uint_eq(p->data_type, OSSL_PARAM_UNSIGNED_INTEGER)
+        || !TEST_true(OSSL_PARAM_get_BN(p, &bn_res))
+        || !TEST_int_eq(BN_cmp(bn_res, bn), 0))
+        goto err;
+    res = 1;
+err:
+    OPENSSL_secure_free(secure);
+    OPENSSL_free(params);
+    BN_free(bn);
+    BN_free(bn_res);
+    return res;
+}
+
+static int template_static_params_test(int n)
+{
+    unsigned char data[1000], secure[500];
+    OSSL_PARAM_BLD bld;
+    OSSL_PARAM params[20], *p;
+    BIGNUM *bn = NULL, *bn_r = NULL;
+    unsigned int i;
+    char *utf = NULL;
+    int res = 0;
+
+    ossl_param_bld_init(&bld);
+    if (!TEST_true(ossl_param_bld_push_uint(&bld, "i", 6))
+        || !TEST_ptr(bn = (n & 1) == 0 ? BN_new() : BN_secure_new())
+        || !TEST_true(BN_set_word(bn, 1337))
+        || !TEST_true(ossl_param_bld_push_BN(&bld, "bn", bn))
+        || !TEST_true(ossl_param_bld_push_utf8_string(&bld, "utf8_s", "bar",
+                                                      0))
+        || !TEST_ptr(ossl_param_bld_to_param_ex(&bld, params,
+                                                OSSL_NELEM(params),
+                                                data, sizeof(data),
+                                                secure, sizeof(secure)))
+        /* Check unsigned int */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "i"))
+        || !TEST_true(OSSL_PARAM_get_uint(p, &i))
+        || !TEST_str_eq(p->key, "i")
+        || !TEST_uint_eq(p->data_type, OSSL_PARAM_UNSIGNED_INTEGER)
+        || !TEST_size_t_eq(p->data_size, sizeof(int))
+        || !TEST_uint_eq(i, 6)
+        /* Check BIGNUM */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "bn"))
+        || !TEST_true(OSSL_PARAM_get_BN(p, &bn_r))
+        || !TEST_str_eq(p->key, "bn")
+        || !TEST_uint_eq(p->data_type, OSSL_PARAM_UNSIGNED_INTEGER)
+        || !TEST_size_t_le(p->data_size, sizeof(BN_ULONG))
+        || !TEST_uint_eq((unsigned int)BN_get_word(bn_r), 1337)
+        /* Check UTF8 string */
+        || !TEST_ptr(p = OSSL_PARAM_locate(params, "utf8_s"))
+        || !TEST_str_eq(p->data, "bar")
+        || !TEST_true(OSSL_PARAM_get_utf8_string(p, &utf, 0))
+        || !TEST_str_eq(utf, "bar"))
+        goto err;
+    res = 1;
+err:
+    OPENSSL_free(utf);
+    BN_free(bn);
+    BN_free(bn_r);
+    return res;
+}
+
+static int template_static_fail_test(int n)
+{
+    unsigned char data[10000], secure[500];
+    OSSL_PARAM_BLD bld;
+    OSSL_PARAM prms[20];
+    BIGNUM *bn = NULL;
+    int res = 0;
+
+    ossl_param_bld_init(&bld);
+    if (!TEST_true(ossl_param_bld_push_uint(&bld, "i", 6))
+        || !TEST_ptr(bn = (n & 1) == 0 ? BN_new() : BN_secure_new())
+        || !TEST_true(BN_hex2bn(&bn, "ABCDEF78901234567890ABCDEF0987987654321"))
+        || !TEST_true(ossl_param_bld_push_BN(&bld, "bn", bn))
+        || !TEST_true(ossl_param_bld_push_utf8_string(&bld, "utf8_s", "abc",
+                                                      1000))
+        /* No OSSL_PARAMS */
+        || !TEST_ptr_null(ossl_param_bld_to_param_ex(&bld, NULL, 0, data,
+                                                     sizeof(data), secure,
+                                                     sizeof(secure)))
+        /* Short OSSL_PARAMS */
+        || !TEST_ptr_null(ossl_param_bld_to_param_ex(&bld, prms, 2,
+                                                     data, sizeof(data),
+                                                     secure, sizeof(secure)))
+        /* No normal data */
+        || !TEST_ptr_null(ossl_param_bld_to_param_ex(&bld, prms,
+                                                     OSSL_NELEM(prms),
+                                                     NULL, 0, secure,
+                                                     sizeof(secure)))
+        /* Not enough normal data */
+        || !TEST_ptr_null(ossl_param_bld_to_param_ex(&bld, prms,
+                                                     OSSL_NELEM(prms),
+                                                     data, 50, secure,
+                                                     sizeof(secure))))
+            goto err;
+        if ((n & 1) == 1) {
+            /* No secure data */
+            if (!TEST_ptr_null(ossl_param_bld_to_param_ex(&bld, prms,
+                                                          OSSL_NELEM(prms),
+                                                          data, sizeof(data),
+                                                          NULL, 0))
+            /* Not enough secure data */
+            || !TEST_ptr_null(ossl_param_bld_to_param_ex(&bld, prms,
+                                                         OSSL_NELEM(prms),
+                                                         data, sizeof(data),
+                                                         secure, 4)))
+                goto err;
+        }
+    res = 1;
+err:
+    BN_free(bn);
+    return res;
+}
+
+int setup_tests(void)
+{
+    ADD_TEST(template_public_test);
+    ADD_TEST(template_private_test);
+    ADD_ALL_TESTS(template_static_params_test, 2);
+    ADD_ALL_TESTS(template_static_fail_test, 2);
+    return 1;
+}
diff --git a/test/recipes/04-test_param_build.t b/test/recipes/04-test_param_build.t
new file mode 100644 (file)
index 0000000..b9846c5
--- /dev/null
@@ -0,0 +1,15 @@
+#! /usr/bin/env perl
+# Copyright 2019 The OpenSSL Project Authors. 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
+
+use strict;
+use OpenSSL::Test;
+use OpenSSL::Test::Simple;
+
+setup("test_param_build");
+
+simple_test("test_param_build", "param_build_test");