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 { 35 return OPENSSL_LH_strhash(a->prop); 36 } 37 38 static int property_defn_cmp(const PROPERTY_DEFN_ELEM *a, 39 const PROPERTY_DEFN_ELEM *b) 40 { 41 return strcmp(a->prop, b->prop); 42 } 43 44 static void property_defn_free(PROPERTY_DEFN_ELEM *elem) 45 { 46 ossl_property_free(elem->defn); 47 OPENSSL_free(elem); 48 } 49 50 static void property_defns_free(void *vproperty_defns) 51 { 52 LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns = vproperty_defns; 53 54 if (property_defns != NULL) { 55 lh_PROPERTY_DEFN_ELEM_doall(property_defns, 56 &property_defn_free); 57 lh_PROPERTY_DEFN_ELEM_free(property_defns); 58 } 59 } 60 61 static void *property_defns_new(OSSL_LIB_CTX *ctx) { 62 return lh_PROPERTY_DEFN_ELEM_new(&property_defn_hash, &property_defn_cmp); 63 } 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 { 73 PROPERTY_DEFN_ELEM elem, *r; 74 LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns; 75 76 property_defns = ossl_lib_ctx_get_data(ctx, 77 OSSL_LIB_CTX_PROPERTY_DEFN_INDEX, 78 &property_defns_method); 79 if (property_defns == NULL || !ossl_lib_ctx_read_lock(ctx)) 80 return NULL; 81 82 elem.prop = prop; 83 r = lh_PROPERTY_DEFN_ELEM_retrieve(property_defns, &elem); 84 ossl_lib_ctx_unlock(ctx); 85 if (r == NULL || !ossl_assert(r->defn != NULL)) 86 return NULL; 87 return r->defn; 88 } 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 { 98 PROPERTY_DEFN_ELEM elem, *old, *p = NULL; 99 size_t len; 100 LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns; 101 int res = 1; 102 103 property_defns = ossl_lib_ctx_get_data(ctx, 104 OSSL_LIB_CTX_PROPERTY_DEFN_INDEX, 105 &property_defns_method); 106 if (property_defns == NULL) 107 return 0; 108 109 if (prop == NULL) 110 return 1; 111 112 if (!ossl_lib_ctx_write_lock(ctx)) 113 return 0; 114 elem.prop = prop; 115 if (pl == NULL) { 116 lh_PROPERTY_DEFN_ELEM_delete(property_defns, &elem); 117 goto end; 118 } 119 /* check if property definition is in the cache already */ 120 if ((p = lh_PROPERTY_DEFN_ELEM_retrieve(property_defns, &elem)) != NULL) { 121 ossl_property_free(*pl); 122 *pl = p->defn; 123 goto end; 124 } 125 len = strlen(prop); 126 p = OPENSSL_malloc(sizeof(*p) + len); 127 if (p != NULL) { 128 p->prop = p->body; 129 p->defn = *pl; 130 memcpy(p->body, prop, len + 1); 131 old = lh_PROPERTY_DEFN_ELEM_insert(property_defns, p); 132 if (!ossl_assert(old == NULL)) 133 /* This should not happen. An existing entry is handled above. */ 134 goto end; 135 if (!lh_PROPERTY_DEFN_ELEM_error(property_defns)) 136 goto end; 137 } 138 OPENSSL_free(p); 139 res = 0; 140 end: 141 ossl_lib_ctx_unlock(ctx); 142 return res; 143 } 144