property_string.c 8.0 KB

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