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