/src/openssl30/crypto/property/defn_cache.c
Line | Count | Source |
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 | | |
11 | | #include <string.h> |
12 | | #include <openssl/err.h> |
13 | | #include <openssl/lhash.h> |
14 | | #include "internal/propertyerr.h" |
15 | | #include "internal/property.h" |
16 | | #include "internal/core.h" |
17 | | #include "property_local.h" |
18 | | |
19 | | /* |
20 | | * Implement a property definition cache. |
21 | | * These functions assume that they are called under a write lock. |
22 | | * No attempt is made to clean out the cache, except when it is shut down. |
23 | | */ |
24 | | |
25 | | typedef struct { |
26 | | const char *prop; |
27 | | OSSL_PROPERTY_LIST *defn; |
28 | | char body[1]; |
29 | | } PROPERTY_DEFN_ELEM; |
30 | | |
31 | | DEFINE_LHASH_OF(PROPERTY_DEFN_ELEM); |
32 | | |
33 | | static unsigned long property_defn_hash(const PROPERTY_DEFN_ELEM *a) |
34 | 28.0k | { |
35 | 28.0k | return OPENSSL_LH_strhash(a->prop); |
36 | 28.0k | } |
37 | | |
38 | | static int property_defn_cmp(const PROPERTY_DEFN_ELEM *a, |
39 | | const PROPERTY_DEFN_ELEM *b) |
40 | 22.8k | { |
41 | 22.8k | return strcmp(a->prop, b->prop); |
42 | 22.8k | } |
43 | | |
44 | | static void property_defn_free(PROPERTY_DEFN_ELEM *elem) |
45 | 1.41k | { |
46 | 1.41k | ossl_property_free(elem->defn); |
47 | 1.41k | OPENSSL_free(elem); |
48 | 1.41k | } |
49 | | |
50 | | static void property_defns_free(void *vproperty_defns) |
51 | 7 | { |
52 | 7 | LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns = vproperty_defns; |
53 | | |
54 | 7 | if (property_defns != NULL) { |
55 | 7 | lh_PROPERTY_DEFN_ELEM_doall(property_defns, |
56 | 7 | &property_defn_free); |
57 | 7 | lh_PROPERTY_DEFN_ELEM_free(property_defns); |
58 | 7 | } |
59 | 7 | } |
60 | | |
61 | | static void *property_defns_new(OSSL_LIB_CTX *ctx) |
62 | 7 | { |
63 | 7 | return lh_PROPERTY_DEFN_ELEM_new(&property_defn_hash, &property_defn_cmp); |
64 | 7 | } |
65 | | |
66 | | static const OSSL_LIB_CTX_METHOD property_defns_method = { |
67 | | OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY, |
68 | | property_defns_new, |
69 | | property_defns_free, |
70 | | }; |
71 | | |
72 | | OSSL_PROPERTY_LIST *ossl_prop_defn_get(OSSL_LIB_CTX *ctx, const char *prop) |
73 | 1.24k | { |
74 | 1.24k | PROPERTY_DEFN_ELEM elem, *r; |
75 | 1.24k | LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns; |
76 | | |
77 | 1.24k | property_defns = ossl_lib_ctx_get_data(ctx, |
78 | 1.24k | OSSL_LIB_CTX_PROPERTY_DEFN_INDEX, |
79 | 1.24k | &property_defns_method); |
80 | 1.24k | if (property_defns == NULL || !ossl_lib_ctx_read_lock(ctx)) |
81 | 0 | return NULL; |
82 | | |
83 | 1.24k | elem.prop = prop; |
84 | 1.24k | r = lh_PROPERTY_DEFN_ELEM_retrieve(property_defns, &elem); |
85 | 1.24k | ossl_lib_ctx_unlock(ctx); |
86 | 1.24k | if (r == NULL || !ossl_assert(r->defn != NULL)) |
87 | 182 | return NULL; |
88 | 1.06k | return r->defn; |
89 | 1.24k | } |
90 | | |
91 | | /* |
92 | | * Cache the property list for a given property string *pl. |
93 | | * If an entry already exists in the cache *pl is freed and |
94 | | * overwritten with the existing entry from the cache. |
95 | | */ |
96 | | int ossl_prop_defn_set(OSSL_LIB_CTX *ctx, const char *prop, |
97 | | OSSL_PROPERTY_LIST **pl) |
98 | 1.74k | { |
99 | 1.74k | PROPERTY_DEFN_ELEM elem, *old, *p = NULL; |
100 | 1.74k | size_t len; |
101 | 1.74k | LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns; |
102 | 1.74k | int res = 1; |
103 | | |
104 | 1.74k | property_defns = ossl_lib_ctx_get_data(ctx, |
105 | 1.74k | OSSL_LIB_CTX_PROPERTY_DEFN_INDEX, |
106 | 1.74k | &property_defns_method); |
107 | 1.74k | if (property_defns == NULL) |
108 | 0 | return 0; |
109 | | |
110 | 1.74k | if (prop == NULL) |
111 | 0 | return 1; |
112 | | |
113 | 1.74k | if (!ossl_lib_ctx_write_lock(ctx)) |
114 | 0 | return 0; |
115 | 1.74k | elem.prop = prop; |
116 | 1.74k | if (pl == NULL) { |
117 | 0 | lh_PROPERTY_DEFN_ELEM_delete(property_defns, &elem); |
118 | 0 | goto end; |
119 | 0 | } |
120 | | /* check if property definition is in the cache already */ |
121 | 1.74k | if ((p = lh_PROPERTY_DEFN_ELEM_retrieve(property_defns, &elem)) != NULL) { |
122 | 0 | ossl_property_free(*pl); |
123 | 0 | *pl = p->defn; |
124 | 0 | goto end; |
125 | 0 | } |
126 | 1.74k | len = strlen(prop); |
127 | 1.74k | p = OPENSSL_malloc(sizeof(*p) + len); |
128 | 1.74k | if (p != NULL) { |
129 | 1.74k | p->prop = p->body; |
130 | 1.74k | p->defn = *pl; |
131 | 1.74k | memcpy(p->body, prop, len + 1); |
132 | 1.74k | old = lh_PROPERTY_DEFN_ELEM_insert(property_defns, p); |
133 | 1.74k | if (!ossl_assert(old == NULL)) |
134 | | /* This should not happen. An existing entry is handled above. */ |
135 | 0 | goto end; |
136 | 1.74k | if (!lh_PROPERTY_DEFN_ELEM_error(property_defns)) |
137 | 1.74k | goto end; |
138 | 1.74k | } |
139 | 0 | OPENSSL_free(p); |
140 | 0 | res = 0; |
141 | 1.74k | end: |
142 | 1.74k | ossl_lib_ctx_unlock(ctx); |
143 | 1.74k | return res; |
144 | 0 | } |