/src/openssl30/crypto/property/defn_cache.c
Line | Count | Source (jump to first uncovered line) |
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 | 11.9k | { |
35 | 11.9k | return OPENSSL_LH_strhash(a->prop); |
36 | 11.9k | } |
37 | | |
38 | | static int property_defn_cmp(const PROPERTY_DEFN_ELEM *a, |
39 | | const PROPERTY_DEFN_ELEM *b) |
40 | 9.18k | { |
41 | 9.18k | return strcmp(a->prop, b->prop); |
42 | 9.18k | } |
43 | | |
44 | | static void property_defn_free(PROPERTY_DEFN_ELEM *elem) |
45 | 925 | { |
46 | 925 | ossl_property_free(elem->defn); |
47 | 925 | OPENSSL_free(elem); |
48 | 925 | } |
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 | 7 | static void *property_defns_new(OSSL_LIB_CTX *ctx) { |
62 | 7 | return lh_PROPERTY_DEFN_ELEM_new(&property_defn_hash, &property_defn_cmp); |
63 | 7 | } |
64 | | |
65 | | static const OSSL_LIB_CTX_METHOD property_defns_method = { |
66 | | OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY, |
67 | | property_defns_new, |
68 | | property_defns_free, |
69 | | }; |
70 | | |
71 | | OSSL_PROPERTY_LIST *ossl_prop_defn_get(OSSL_LIB_CTX *ctx, const char *prop) |
72 | 1.24k | { |
73 | 1.24k | PROPERTY_DEFN_ELEM elem, *r; |
74 | 1.24k | LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns; |
75 | | |
76 | 1.24k | property_defns = ossl_lib_ctx_get_data(ctx, |
77 | 1.24k | OSSL_LIB_CTX_PROPERTY_DEFN_INDEX, |
78 | 1.24k | &property_defns_method); |
79 | 1.24k | if (property_defns == NULL || !ossl_lib_ctx_read_lock(ctx)) |
80 | 0 | return NULL; |
81 | | |
82 | 1.24k | elem.prop = prop; |
83 | 1.24k | r = lh_PROPERTY_DEFN_ELEM_retrieve(property_defns, &elem); |
84 | 1.24k | ossl_lib_ctx_unlock(ctx); |
85 | 1.24k | if (r == NULL || !ossl_assert(r->defn != NULL)) |
86 | 176 | return NULL; |
87 | 1.06k | return r->defn; |
88 | 1.24k | } |
89 | | |
90 | | /* |
91 | | * Cache the property list for a given property string *pl. |
92 | | * If an entry already exists in the cache *pl is freed and |
93 | | * overwritten with the existing entry from the cache. |
94 | | */ |
95 | | int ossl_prop_defn_set(OSSL_LIB_CTX *ctx, const char *prop, |
96 | | OSSL_PROPERTY_LIST **pl) |
97 | 927 | { |
98 | 927 | PROPERTY_DEFN_ELEM elem, *old, *p = NULL; |
99 | 927 | size_t len; |
100 | 927 | LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns; |
101 | 927 | int res = 1; |
102 | | |
103 | 927 | property_defns = ossl_lib_ctx_get_data(ctx, |
104 | 927 | OSSL_LIB_CTX_PROPERTY_DEFN_INDEX, |
105 | 927 | &property_defns_method); |
106 | 927 | if (property_defns == NULL) |
107 | 0 | return 0; |
108 | | |
109 | 927 | if (prop == NULL) |
110 | 0 | return 1; |
111 | | |
112 | 927 | if (!ossl_lib_ctx_write_lock(ctx)) |
113 | 0 | return 0; |
114 | 927 | elem.prop = prop; |
115 | 927 | if (pl == NULL) { |
116 | 0 | lh_PROPERTY_DEFN_ELEM_delete(property_defns, &elem); |
117 | 0 | goto end; |
118 | 0 | } |
119 | | /* check if property definition is in the cache already */ |
120 | 927 | if ((p = lh_PROPERTY_DEFN_ELEM_retrieve(property_defns, &elem)) != NULL) { |
121 | 0 | ossl_property_free(*pl); |
122 | 0 | *pl = p->defn; |
123 | 0 | goto end; |
124 | 0 | } |
125 | 927 | len = strlen(prop); |
126 | 927 | p = OPENSSL_malloc(sizeof(*p) + len); |
127 | 927 | if (p != NULL) { |
128 | 927 | p->prop = p->body; |
129 | 927 | p->defn = *pl; |
130 | 927 | memcpy(p->body, prop, len + 1); |
131 | 927 | old = lh_PROPERTY_DEFN_ELEM_insert(property_defns, p); |
132 | 927 | if (!ossl_assert(old == NULL)) |
133 | | /* This should not happen. An existing entry is handled above. */ |
134 | 0 | goto end; |
135 | 927 | if (!lh_PROPERTY_DEFN_ELEM_error(property_defns)) |
136 | 927 | goto end; |
137 | 927 | } |
138 | 0 | OPENSSL_free(p); |
139 | 0 | res = 0; |
140 | 927 | end: |
141 | 927 | ossl_lib_ctx_unlock(ctx); |
142 | 927 | return res; |
143 | 0 | } |