1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2019-2022 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/crypto.h> 13e1051a39Sopenharmony_ci#include <openssl/lhash.h> 14e1051a39Sopenharmony_ci#include "crypto/lhash.h" 15e1051a39Sopenharmony_ci#include "property_local.h" 16e1051a39Sopenharmony_ci 17e1051a39Sopenharmony_ci/* 18e1051a39Sopenharmony_ci * Property strings are a consolidation of all strings seen by the property 19e1051a39Sopenharmony_ci * subsystem. There are two name spaces to keep property names separate from 20e1051a39Sopenharmony_ci * property values (numeric values are not expected to be cached however). 21e1051a39Sopenharmony_ci * They allow a rapid conversion from a string to a unique index and any 22e1051a39Sopenharmony_ci * subsequent string comparison can be done via an integer compare. 23e1051a39Sopenharmony_ci * 24e1051a39Sopenharmony_ci * This implementation uses OpenSSL's standard hash table. There are more 25e1051a39Sopenharmony_ci * space and time efficient algorithms if this becomes a bottleneck. 26e1051a39Sopenharmony_ci */ 27e1051a39Sopenharmony_ci 28e1051a39Sopenharmony_citypedef struct { 29e1051a39Sopenharmony_ci const char *s; 30e1051a39Sopenharmony_ci OSSL_PROPERTY_IDX idx; 31e1051a39Sopenharmony_ci char body[1]; 32e1051a39Sopenharmony_ci} PROPERTY_STRING; 33e1051a39Sopenharmony_ci 34e1051a39Sopenharmony_ciDEFINE_LHASH_OF(PROPERTY_STRING); 35e1051a39Sopenharmony_citypedef LHASH_OF(PROPERTY_STRING) PROP_TABLE; 36e1051a39Sopenharmony_ci 37e1051a39Sopenharmony_citypedef struct { 38e1051a39Sopenharmony_ci CRYPTO_RWLOCK *lock; 39e1051a39Sopenharmony_ci PROP_TABLE *prop_names; 40e1051a39Sopenharmony_ci PROP_TABLE *prop_values; 41e1051a39Sopenharmony_ci OSSL_PROPERTY_IDX prop_name_idx; 42e1051a39Sopenharmony_ci OSSL_PROPERTY_IDX prop_value_idx; 43e1051a39Sopenharmony_ci} PROPERTY_STRING_DATA; 44e1051a39Sopenharmony_ci 45e1051a39Sopenharmony_cistatic unsigned long property_hash(const PROPERTY_STRING *a) 46e1051a39Sopenharmony_ci{ 47e1051a39Sopenharmony_ci return OPENSSL_LH_strhash(a->s); 48e1051a39Sopenharmony_ci} 49e1051a39Sopenharmony_ci 50e1051a39Sopenharmony_cistatic int property_cmp(const PROPERTY_STRING *a, const PROPERTY_STRING *b) 51e1051a39Sopenharmony_ci{ 52e1051a39Sopenharmony_ci return strcmp(a->s, b->s); 53e1051a39Sopenharmony_ci} 54e1051a39Sopenharmony_ci 55e1051a39Sopenharmony_cistatic void property_free(PROPERTY_STRING *ps) 56e1051a39Sopenharmony_ci{ 57e1051a39Sopenharmony_ci OPENSSL_free(ps); 58e1051a39Sopenharmony_ci} 59e1051a39Sopenharmony_ci 60e1051a39Sopenharmony_cistatic void property_table_free(PROP_TABLE **pt) 61e1051a39Sopenharmony_ci{ 62e1051a39Sopenharmony_ci PROP_TABLE *t = *pt; 63e1051a39Sopenharmony_ci 64e1051a39Sopenharmony_ci if (t != NULL) { 65e1051a39Sopenharmony_ci lh_PROPERTY_STRING_doall(t, &property_free); 66e1051a39Sopenharmony_ci lh_PROPERTY_STRING_free(t); 67e1051a39Sopenharmony_ci *pt = NULL; 68e1051a39Sopenharmony_ci } 69e1051a39Sopenharmony_ci} 70e1051a39Sopenharmony_ci 71e1051a39Sopenharmony_cistatic void property_string_data_free(void *vpropdata) 72e1051a39Sopenharmony_ci{ 73e1051a39Sopenharmony_ci PROPERTY_STRING_DATA *propdata = vpropdata; 74e1051a39Sopenharmony_ci 75e1051a39Sopenharmony_ci if (propdata == NULL) 76e1051a39Sopenharmony_ci return; 77e1051a39Sopenharmony_ci 78e1051a39Sopenharmony_ci CRYPTO_THREAD_lock_free(propdata->lock); 79e1051a39Sopenharmony_ci property_table_free(&propdata->prop_names); 80e1051a39Sopenharmony_ci property_table_free(&propdata->prop_values); 81e1051a39Sopenharmony_ci propdata->prop_name_idx = propdata->prop_value_idx = 0; 82e1051a39Sopenharmony_ci 83e1051a39Sopenharmony_ci OPENSSL_free(propdata); 84e1051a39Sopenharmony_ci} 85e1051a39Sopenharmony_ci 86e1051a39Sopenharmony_cistatic void *property_string_data_new(OSSL_LIB_CTX *ctx) { 87e1051a39Sopenharmony_ci PROPERTY_STRING_DATA *propdata = OPENSSL_zalloc(sizeof(*propdata)); 88e1051a39Sopenharmony_ci 89e1051a39Sopenharmony_ci if (propdata == NULL) 90e1051a39Sopenharmony_ci return NULL; 91e1051a39Sopenharmony_ci 92e1051a39Sopenharmony_ci propdata->lock = CRYPTO_THREAD_lock_new(); 93e1051a39Sopenharmony_ci if (propdata->lock == NULL) 94e1051a39Sopenharmony_ci goto err; 95e1051a39Sopenharmony_ci 96e1051a39Sopenharmony_ci propdata->prop_names = lh_PROPERTY_STRING_new(&property_hash, 97e1051a39Sopenharmony_ci &property_cmp); 98e1051a39Sopenharmony_ci if (propdata->prop_names == NULL) 99e1051a39Sopenharmony_ci goto err; 100e1051a39Sopenharmony_ci 101e1051a39Sopenharmony_ci propdata->prop_values = lh_PROPERTY_STRING_new(&property_hash, 102e1051a39Sopenharmony_ci &property_cmp); 103e1051a39Sopenharmony_ci if (propdata->prop_values == NULL) 104e1051a39Sopenharmony_ci goto err; 105e1051a39Sopenharmony_ci 106e1051a39Sopenharmony_ci return propdata; 107e1051a39Sopenharmony_ci 108e1051a39Sopenharmony_cierr: 109e1051a39Sopenharmony_ci property_string_data_free(propdata); 110e1051a39Sopenharmony_ci return NULL; 111e1051a39Sopenharmony_ci} 112e1051a39Sopenharmony_ci 113e1051a39Sopenharmony_cistatic const OSSL_LIB_CTX_METHOD property_string_data_method = { 114e1051a39Sopenharmony_ci OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY, 115e1051a39Sopenharmony_ci property_string_data_new, 116e1051a39Sopenharmony_ci property_string_data_free, 117e1051a39Sopenharmony_ci}; 118e1051a39Sopenharmony_ci 119e1051a39Sopenharmony_cistatic PROPERTY_STRING *new_property_string(const char *s, 120e1051a39Sopenharmony_ci OSSL_PROPERTY_IDX *pidx) 121e1051a39Sopenharmony_ci{ 122e1051a39Sopenharmony_ci const size_t l = strlen(s); 123e1051a39Sopenharmony_ci PROPERTY_STRING *ps = OPENSSL_malloc(sizeof(*ps) + l); 124e1051a39Sopenharmony_ci 125e1051a39Sopenharmony_ci if (ps != NULL) { 126e1051a39Sopenharmony_ci memcpy(ps->body, s, l + 1); 127e1051a39Sopenharmony_ci ps->s = ps->body; 128e1051a39Sopenharmony_ci ps->idx = ++*pidx; 129e1051a39Sopenharmony_ci if (ps->idx == 0) { 130e1051a39Sopenharmony_ci OPENSSL_free(ps); 131e1051a39Sopenharmony_ci return NULL; 132e1051a39Sopenharmony_ci } 133e1051a39Sopenharmony_ci } 134e1051a39Sopenharmony_ci return ps; 135e1051a39Sopenharmony_ci} 136e1051a39Sopenharmony_ci 137e1051a39Sopenharmony_cistatic OSSL_PROPERTY_IDX ossl_property_string(CRYPTO_RWLOCK *lock, 138e1051a39Sopenharmony_ci PROP_TABLE *t, 139e1051a39Sopenharmony_ci OSSL_PROPERTY_IDX *pidx, 140e1051a39Sopenharmony_ci const char *s) 141e1051a39Sopenharmony_ci{ 142e1051a39Sopenharmony_ci PROPERTY_STRING p, *ps, *ps_new; 143e1051a39Sopenharmony_ci 144e1051a39Sopenharmony_ci p.s = s; 145e1051a39Sopenharmony_ci if (!CRYPTO_THREAD_read_lock(lock)) { 146e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_READ_LOCK); 147e1051a39Sopenharmony_ci return 0; 148e1051a39Sopenharmony_ci } 149e1051a39Sopenharmony_ci ps = lh_PROPERTY_STRING_retrieve(t, &p); 150e1051a39Sopenharmony_ci if (ps == NULL && pidx != NULL) { 151e1051a39Sopenharmony_ci CRYPTO_THREAD_unlock(lock); 152e1051a39Sopenharmony_ci if (!CRYPTO_THREAD_write_lock(lock)) { 153e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_WRITE_LOCK); 154e1051a39Sopenharmony_ci return 0; 155e1051a39Sopenharmony_ci } 156e1051a39Sopenharmony_ci ps = lh_PROPERTY_STRING_retrieve(t, &p); 157e1051a39Sopenharmony_ci if (ps == NULL && (ps_new = new_property_string(s, pidx)) != NULL) { 158e1051a39Sopenharmony_ci lh_PROPERTY_STRING_insert(t, ps_new); 159e1051a39Sopenharmony_ci if (lh_PROPERTY_STRING_error(t)) { 160e1051a39Sopenharmony_ci property_free(ps_new); 161e1051a39Sopenharmony_ci CRYPTO_THREAD_unlock(lock); 162e1051a39Sopenharmony_ci return 0; 163e1051a39Sopenharmony_ci } 164e1051a39Sopenharmony_ci ps = ps_new; 165e1051a39Sopenharmony_ci } 166e1051a39Sopenharmony_ci } 167e1051a39Sopenharmony_ci CRYPTO_THREAD_unlock(lock); 168e1051a39Sopenharmony_ci return ps != NULL ? ps->idx : 0; 169e1051a39Sopenharmony_ci} 170e1051a39Sopenharmony_ci 171e1051a39Sopenharmony_cistruct find_str_st { 172e1051a39Sopenharmony_ci const char *str; 173e1051a39Sopenharmony_ci OSSL_PROPERTY_IDX idx; 174e1051a39Sopenharmony_ci}; 175e1051a39Sopenharmony_ci 176e1051a39Sopenharmony_cistatic void find_str_fn(PROPERTY_STRING *prop, void *vfindstr) 177e1051a39Sopenharmony_ci{ 178e1051a39Sopenharmony_ci struct find_str_st *findstr = vfindstr; 179e1051a39Sopenharmony_ci 180e1051a39Sopenharmony_ci if (prop->idx == findstr->idx) 181e1051a39Sopenharmony_ci findstr->str = prop->s; 182e1051a39Sopenharmony_ci} 183e1051a39Sopenharmony_ci 184e1051a39Sopenharmony_cistatic const char *ossl_property_str(int name, OSSL_LIB_CTX *ctx, 185e1051a39Sopenharmony_ci OSSL_PROPERTY_IDX idx) 186e1051a39Sopenharmony_ci{ 187e1051a39Sopenharmony_ci struct find_str_st findstr; 188e1051a39Sopenharmony_ci PROPERTY_STRING_DATA *propdata 189e1051a39Sopenharmony_ci = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX, 190e1051a39Sopenharmony_ci &property_string_data_method); 191e1051a39Sopenharmony_ci 192e1051a39Sopenharmony_ci if (propdata == NULL) 193e1051a39Sopenharmony_ci return NULL; 194e1051a39Sopenharmony_ci 195e1051a39Sopenharmony_ci findstr.str = NULL; 196e1051a39Sopenharmony_ci findstr.idx = idx; 197e1051a39Sopenharmony_ci 198e1051a39Sopenharmony_ci if (!CRYPTO_THREAD_read_lock(propdata->lock)) { 199e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_READ_LOCK); 200e1051a39Sopenharmony_ci return NULL; 201e1051a39Sopenharmony_ci } 202e1051a39Sopenharmony_ci lh_PROPERTY_STRING_doall_arg(name ? propdata->prop_names 203e1051a39Sopenharmony_ci : propdata->prop_values, 204e1051a39Sopenharmony_ci find_str_fn, &findstr); 205e1051a39Sopenharmony_ci CRYPTO_THREAD_unlock(propdata->lock); 206e1051a39Sopenharmony_ci 207e1051a39Sopenharmony_ci return findstr.str; 208e1051a39Sopenharmony_ci} 209e1051a39Sopenharmony_ci 210e1051a39Sopenharmony_ciOSSL_PROPERTY_IDX ossl_property_name(OSSL_LIB_CTX *ctx, const char *s, 211e1051a39Sopenharmony_ci int create) 212e1051a39Sopenharmony_ci{ 213e1051a39Sopenharmony_ci PROPERTY_STRING_DATA *propdata 214e1051a39Sopenharmony_ci = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX, 215e1051a39Sopenharmony_ci &property_string_data_method); 216e1051a39Sopenharmony_ci 217e1051a39Sopenharmony_ci if (propdata == NULL) 218e1051a39Sopenharmony_ci return 0; 219e1051a39Sopenharmony_ci return ossl_property_string(propdata->lock, propdata->prop_names, 220e1051a39Sopenharmony_ci create ? &propdata->prop_name_idx : NULL, 221e1051a39Sopenharmony_ci s); 222e1051a39Sopenharmony_ci} 223e1051a39Sopenharmony_ci 224e1051a39Sopenharmony_ciconst char *ossl_property_name_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx) 225e1051a39Sopenharmony_ci{ 226e1051a39Sopenharmony_ci return ossl_property_str(1, ctx, idx); 227e1051a39Sopenharmony_ci} 228e1051a39Sopenharmony_ci 229e1051a39Sopenharmony_ciOSSL_PROPERTY_IDX ossl_property_value(OSSL_LIB_CTX *ctx, const char *s, 230e1051a39Sopenharmony_ci int create) 231e1051a39Sopenharmony_ci{ 232e1051a39Sopenharmony_ci PROPERTY_STRING_DATA *propdata 233e1051a39Sopenharmony_ci = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX, 234e1051a39Sopenharmony_ci &property_string_data_method); 235e1051a39Sopenharmony_ci 236e1051a39Sopenharmony_ci if (propdata == NULL) 237e1051a39Sopenharmony_ci return 0; 238e1051a39Sopenharmony_ci return ossl_property_string(propdata->lock, propdata->prop_values, 239e1051a39Sopenharmony_ci create ? &propdata->prop_value_idx : NULL, 240e1051a39Sopenharmony_ci s); 241e1051a39Sopenharmony_ci} 242e1051a39Sopenharmony_ci 243e1051a39Sopenharmony_ciconst char *ossl_property_value_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx) 244e1051a39Sopenharmony_ci{ 245e1051a39Sopenharmony_ci return ossl_property_str(0, ctx, idx); 246e1051a39Sopenharmony_ci} 247