1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2021-2022 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#include <string.h> 11e1051a39Sopenharmony_ci#include <openssl/params.h> 12e1051a39Sopenharmony_ci#include <openssl/param_build.h> 13e1051a39Sopenharmony_ci#include "internal/param_build_set.h" 14e1051a39Sopenharmony_ci 15e1051a39Sopenharmony_ci#define OSSL_PARAM_ALLOCATED_END 127 16e1051a39Sopenharmony_ci#define OSSL_PARAM_MERGE_LIST_MAX 128 17e1051a39Sopenharmony_ci 18e1051a39Sopenharmony_ci#define OSSL_PARAM_BUF_PUBLIC 0 19e1051a39Sopenharmony_ci#define OSSL_PARAM_BUF_SECURE 1 20e1051a39Sopenharmony_ci#define OSSL_PARAM_BUF_MAX (OSSL_PARAM_BUF_SECURE + 1) 21e1051a39Sopenharmony_ci 22e1051a39Sopenharmony_citypedef struct { 23e1051a39Sopenharmony_ci OSSL_PARAM_ALIGNED_BLOCK *alloc; /* The allocated buffer */ 24e1051a39Sopenharmony_ci OSSL_PARAM_ALIGNED_BLOCK *cur; /* Current position in the allocated buf */ 25e1051a39Sopenharmony_ci size_t blocks; /* Number of aligned blocks */ 26e1051a39Sopenharmony_ci size_t alloc_sz; /* The size of the allocated buffer (in bytes) */ 27e1051a39Sopenharmony_ci} OSSL_PARAM_BUF; 28e1051a39Sopenharmony_ci 29e1051a39Sopenharmony_cisize_t ossl_param_bytes_to_blocks(size_t bytes) 30e1051a39Sopenharmony_ci{ 31e1051a39Sopenharmony_ci return (bytes + OSSL_PARAM_ALIGN_SIZE - 1) / OSSL_PARAM_ALIGN_SIZE; 32e1051a39Sopenharmony_ci} 33e1051a39Sopenharmony_ci 34e1051a39Sopenharmony_cistatic int ossl_param_buf_alloc(OSSL_PARAM_BUF *out, size_t extra_blocks, 35e1051a39Sopenharmony_ci int is_secure) 36e1051a39Sopenharmony_ci{ 37e1051a39Sopenharmony_ci size_t sz = OSSL_PARAM_ALIGN_SIZE * (extra_blocks + out->blocks); 38e1051a39Sopenharmony_ci 39e1051a39Sopenharmony_ci out->alloc = is_secure ? OPENSSL_secure_zalloc(sz) : OPENSSL_zalloc(sz); 40e1051a39Sopenharmony_ci if (out->alloc == NULL) { 41e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, is_secure ? CRYPTO_R_SECURE_MALLOC_FAILURE 42e1051a39Sopenharmony_ci : ERR_R_MALLOC_FAILURE); 43e1051a39Sopenharmony_ci return 0; 44e1051a39Sopenharmony_ci } 45e1051a39Sopenharmony_ci out->alloc_sz = sz; 46e1051a39Sopenharmony_ci out->cur = out->alloc + extra_blocks; 47e1051a39Sopenharmony_ci return 1; 48e1051a39Sopenharmony_ci} 49e1051a39Sopenharmony_ci 50e1051a39Sopenharmony_civoid ossl_param_set_secure_block(OSSL_PARAM *last, void *secure_buffer, 51e1051a39Sopenharmony_ci size_t secure_buffer_sz) 52e1051a39Sopenharmony_ci{ 53e1051a39Sopenharmony_ci last->key = NULL; 54e1051a39Sopenharmony_ci last->data_size = secure_buffer_sz; 55e1051a39Sopenharmony_ci last->data = secure_buffer; 56e1051a39Sopenharmony_ci last->data_type = OSSL_PARAM_ALLOCATED_END; 57e1051a39Sopenharmony_ci} 58e1051a39Sopenharmony_ci 59e1051a39Sopenharmony_cistatic OSSL_PARAM *ossl_param_dup(const OSSL_PARAM *src, OSSL_PARAM *dst, 60e1051a39Sopenharmony_ci OSSL_PARAM_BUF buf[OSSL_PARAM_BUF_MAX], 61e1051a39Sopenharmony_ci int *param_count) 62e1051a39Sopenharmony_ci{ 63e1051a39Sopenharmony_ci const OSSL_PARAM *in; 64e1051a39Sopenharmony_ci int has_dst = (dst != NULL); 65e1051a39Sopenharmony_ci int is_secure; 66e1051a39Sopenharmony_ci size_t param_sz, blks; 67e1051a39Sopenharmony_ci 68e1051a39Sopenharmony_ci for (in = src; in->key != NULL; in++) { 69e1051a39Sopenharmony_ci is_secure = CRYPTO_secure_allocated(in->data); 70e1051a39Sopenharmony_ci if (has_dst) { 71e1051a39Sopenharmony_ci *dst = *in; 72e1051a39Sopenharmony_ci dst->data = buf[is_secure].cur; 73e1051a39Sopenharmony_ci } 74e1051a39Sopenharmony_ci 75e1051a39Sopenharmony_ci if (in->data_type == OSSL_PARAM_OCTET_PTR 76e1051a39Sopenharmony_ci || in->data_type == OSSL_PARAM_UTF8_PTR) { 77e1051a39Sopenharmony_ci param_sz = sizeof(in->data); 78e1051a39Sopenharmony_ci if (has_dst) 79e1051a39Sopenharmony_ci *((const void **)dst->data) = *(const void **)in->data; 80e1051a39Sopenharmony_ci } else { 81e1051a39Sopenharmony_ci param_sz = in->data_size; 82e1051a39Sopenharmony_ci if (has_dst) 83e1051a39Sopenharmony_ci memcpy(dst->data, in->data, param_sz); 84e1051a39Sopenharmony_ci } 85e1051a39Sopenharmony_ci if (in->data_type == OSSL_PARAM_UTF8_STRING) 86e1051a39Sopenharmony_ci param_sz++; /* NULL terminator */ 87e1051a39Sopenharmony_ci blks = ossl_param_bytes_to_blocks(param_sz); 88e1051a39Sopenharmony_ci 89e1051a39Sopenharmony_ci if (has_dst) { 90e1051a39Sopenharmony_ci dst++; 91e1051a39Sopenharmony_ci buf[is_secure].cur += blks; 92e1051a39Sopenharmony_ci } else { 93e1051a39Sopenharmony_ci buf[is_secure].blocks += blks; 94e1051a39Sopenharmony_ci } 95e1051a39Sopenharmony_ci if (param_count != NULL) 96e1051a39Sopenharmony_ci ++*param_count; 97e1051a39Sopenharmony_ci } 98e1051a39Sopenharmony_ci return dst; 99e1051a39Sopenharmony_ci} 100e1051a39Sopenharmony_ci 101e1051a39Sopenharmony_ciOSSL_PARAM *OSSL_PARAM_dup(const OSSL_PARAM *src) 102e1051a39Sopenharmony_ci{ 103e1051a39Sopenharmony_ci size_t param_blocks; 104e1051a39Sopenharmony_ci OSSL_PARAM_BUF buf[OSSL_PARAM_BUF_MAX]; 105e1051a39Sopenharmony_ci OSSL_PARAM *last, *dst; 106e1051a39Sopenharmony_ci int param_count = 1; /* Include terminator in the count */ 107e1051a39Sopenharmony_ci 108e1051a39Sopenharmony_ci if (src == NULL) 109e1051a39Sopenharmony_ci return NULL; 110e1051a39Sopenharmony_ci 111e1051a39Sopenharmony_ci memset(buf, 0, sizeof(buf)); 112e1051a39Sopenharmony_ci 113e1051a39Sopenharmony_ci /* First Pass: get the param_count and block sizes required */ 114e1051a39Sopenharmony_ci (void)ossl_param_dup(src, NULL, buf, ¶m_count); 115e1051a39Sopenharmony_ci 116e1051a39Sopenharmony_ci param_blocks = ossl_param_bytes_to_blocks(param_count * sizeof(*src)); 117e1051a39Sopenharmony_ci /* 118e1051a39Sopenharmony_ci * The allocated buffer consists of an array of OSSL_PARAM followed by 119e1051a39Sopenharmony_ci * aligned data bytes that the array elements will point to. 120e1051a39Sopenharmony_ci */ 121e1051a39Sopenharmony_ci if (!ossl_param_buf_alloc(&buf[OSSL_PARAM_BUF_PUBLIC], param_blocks, 0)) 122e1051a39Sopenharmony_ci return NULL; 123e1051a39Sopenharmony_ci 124e1051a39Sopenharmony_ci /* Allocate a secure memory buffer if required */ 125e1051a39Sopenharmony_ci if (buf[OSSL_PARAM_BUF_SECURE].blocks > 0 126e1051a39Sopenharmony_ci && !ossl_param_buf_alloc(&buf[OSSL_PARAM_BUF_SECURE], 0, 1)) { 127e1051a39Sopenharmony_ci OPENSSL_free(buf[OSSL_PARAM_BUF_PUBLIC].alloc); 128e1051a39Sopenharmony_ci return NULL; 129e1051a39Sopenharmony_ci } 130e1051a39Sopenharmony_ci 131e1051a39Sopenharmony_ci dst = (OSSL_PARAM *)buf[OSSL_PARAM_BUF_PUBLIC].alloc; 132e1051a39Sopenharmony_ci last = ossl_param_dup(src, dst, buf, NULL); 133e1051a39Sopenharmony_ci /* Store the allocated secure memory buffer in the last param block */ 134e1051a39Sopenharmony_ci ossl_param_set_secure_block(last, buf[OSSL_PARAM_BUF_SECURE].alloc, 135e1051a39Sopenharmony_ci buf[OSSL_PARAM_BUF_SECURE].alloc_sz); 136e1051a39Sopenharmony_ci return dst; 137e1051a39Sopenharmony_ci} 138e1051a39Sopenharmony_ci 139e1051a39Sopenharmony_cistatic int compare_params(const void *left, const void *right) 140e1051a39Sopenharmony_ci{ 141e1051a39Sopenharmony_ci const OSSL_PARAM *l = *(const OSSL_PARAM **)left; 142e1051a39Sopenharmony_ci const OSSL_PARAM *r = *(const OSSL_PARAM **)right; 143e1051a39Sopenharmony_ci 144e1051a39Sopenharmony_ci return OPENSSL_strcasecmp(l->key, r->key); 145e1051a39Sopenharmony_ci} 146e1051a39Sopenharmony_ci 147e1051a39Sopenharmony_ciOSSL_PARAM *OSSL_PARAM_merge(const OSSL_PARAM *p1, const OSSL_PARAM *p2) 148e1051a39Sopenharmony_ci{ 149e1051a39Sopenharmony_ci const OSSL_PARAM *list1[OSSL_PARAM_MERGE_LIST_MAX + 1]; 150e1051a39Sopenharmony_ci const OSSL_PARAM *list2[OSSL_PARAM_MERGE_LIST_MAX + 1]; 151e1051a39Sopenharmony_ci const OSSL_PARAM *p = NULL; 152e1051a39Sopenharmony_ci const OSSL_PARAM **p1cur, **p2cur; 153e1051a39Sopenharmony_ci OSSL_PARAM *params, *dst; 154e1051a39Sopenharmony_ci size_t list1_sz = 0, list2_sz = 0; 155e1051a39Sopenharmony_ci int diff; 156e1051a39Sopenharmony_ci 157e1051a39Sopenharmony_ci if (p1 == NULL && p2 == NULL) 158e1051a39Sopenharmony_ci return NULL; 159e1051a39Sopenharmony_ci 160e1051a39Sopenharmony_ci /* Copy p1 to list1 */ 161e1051a39Sopenharmony_ci if (p1 != NULL) { 162e1051a39Sopenharmony_ci for (p = p1; p->key != NULL && list1_sz < OSSL_PARAM_MERGE_LIST_MAX; p++) 163e1051a39Sopenharmony_ci list1[list1_sz++] = p; 164e1051a39Sopenharmony_ci } 165e1051a39Sopenharmony_ci list1[list1_sz] = NULL; 166e1051a39Sopenharmony_ci 167e1051a39Sopenharmony_ci /* copy p2 to a list2 */ 168e1051a39Sopenharmony_ci if (p2 != NULL) { 169e1051a39Sopenharmony_ci for (p = p2; p->key != NULL && list2_sz < OSSL_PARAM_MERGE_LIST_MAX; p++) 170e1051a39Sopenharmony_ci list2[list2_sz++] = p; 171e1051a39Sopenharmony_ci } 172e1051a39Sopenharmony_ci list2[list2_sz] = NULL; 173e1051a39Sopenharmony_ci if (list1_sz == 0 && list2_sz == 0) 174e1051a39Sopenharmony_ci return NULL; 175e1051a39Sopenharmony_ci 176e1051a39Sopenharmony_ci /* Sort the 2 lists */ 177e1051a39Sopenharmony_ci qsort(list1, list1_sz, sizeof(OSSL_PARAM *), compare_params); 178e1051a39Sopenharmony_ci qsort(list2, list2_sz, sizeof(OSSL_PARAM *), compare_params); 179e1051a39Sopenharmony_ci 180e1051a39Sopenharmony_ci /* Allocate enough space to store the merged parameters */ 181e1051a39Sopenharmony_ci params = OPENSSL_zalloc((list1_sz + list2_sz + 1) * sizeof(*p1)); 182e1051a39Sopenharmony_ci if (params == NULL) { 183e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE); 184e1051a39Sopenharmony_ci return NULL; 185e1051a39Sopenharmony_ci } 186e1051a39Sopenharmony_ci dst = params; 187e1051a39Sopenharmony_ci p1cur = list1; 188e1051a39Sopenharmony_ci p2cur = list2; 189e1051a39Sopenharmony_ci while (1) { 190e1051a39Sopenharmony_ci /* If list1 is finished just tack list2 onto the end */ 191e1051a39Sopenharmony_ci if (*p1cur == NULL) { 192e1051a39Sopenharmony_ci do { 193e1051a39Sopenharmony_ci *dst++ = **p2cur; 194e1051a39Sopenharmony_ci p2cur++; 195e1051a39Sopenharmony_ci } while (*p2cur != NULL); 196e1051a39Sopenharmony_ci break; 197e1051a39Sopenharmony_ci } 198e1051a39Sopenharmony_ci /* If list2 is finished just tack list1 onto the end */ 199e1051a39Sopenharmony_ci if (*p2cur == NULL) { 200e1051a39Sopenharmony_ci do { 201e1051a39Sopenharmony_ci *dst++ = **p1cur; 202e1051a39Sopenharmony_ci p1cur++; 203e1051a39Sopenharmony_ci } while (*p1cur != NULL); 204e1051a39Sopenharmony_ci break; 205e1051a39Sopenharmony_ci } 206e1051a39Sopenharmony_ci /* consume the list element with the smaller key */ 207e1051a39Sopenharmony_ci diff = OPENSSL_strcasecmp((*p1cur)->key, (*p2cur)->key); 208e1051a39Sopenharmony_ci if (diff == 0) { 209e1051a39Sopenharmony_ci /* If the keys are the same then throw away the list1 element */ 210e1051a39Sopenharmony_ci *dst++ = **p2cur; 211e1051a39Sopenharmony_ci p2cur++; 212e1051a39Sopenharmony_ci p1cur++; 213e1051a39Sopenharmony_ci } else if (diff > 0) { 214e1051a39Sopenharmony_ci *dst++ = **p2cur; 215e1051a39Sopenharmony_ci p2cur++; 216e1051a39Sopenharmony_ci } else { 217e1051a39Sopenharmony_ci *dst++ = **p1cur; 218e1051a39Sopenharmony_ci p1cur++; 219e1051a39Sopenharmony_ci } 220e1051a39Sopenharmony_ci } 221e1051a39Sopenharmony_ci return params; 222e1051a39Sopenharmony_ci} 223e1051a39Sopenharmony_ci 224e1051a39Sopenharmony_civoid OSSL_PARAM_free(OSSL_PARAM *params) 225e1051a39Sopenharmony_ci{ 226e1051a39Sopenharmony_ci if (params != NULL) { 227e1051a39Sopenharmony_ci OSSL_PARAM *p; 228e1051a39Sopenharmony_ci 229e1051a39Sopenharmony_ci for (p = params; p->key != NULL; p++) 230e1051a39Sopenharmony_ci ; 231e1051a39Sopenharmony_ci if (p->data_type == OSSL_PARAM_ALLOCATED_END) 232e1051a39Sopenharmony_ci OPENSSL_secure_clear_free(p->data, p->data_size); 233e1051a39Sopenharmony_ci OPENSSL_free(params); 234e1051a39Sopenharmony_ci } 235e1051a39Sopenharmony_ci} 236