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 { 36 return OPENSSL_LH_strhash(a->prop); 37 } 38 39 static int property_defn_cmp(const PROPERTY_DEFN_ELEM *a, 40 const PROPERTY_DEFN_ELEM *b) 41 { 42 return strcmp(a->prop, b->prop); 43 } 44 45 static void property_defn_free(PROPERTY_DEFN_ELEM *elem) 46 { 47 ossl_property_free(elem->defn); 48 OPENSSL_free(elem); 49 } 50 51 void ossl_property_defns_free(void *vproperty_defns) 52 { 53 LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns = vproperty_defns; 54 55 if (property_defns != NULL) { 56 lh_PROPERTY_DEFN_ELEM_doall(property_defns, 57 &property_defn_free); 58 lh_PROPERTY_DEFN_ELEM_free(property_defns); 59 } 60 } 61 62 void *ossl_property_defns_new(OSSL_LIB_CTX *ctx) 63 { 64 return lh_PROPERTY_DEFN_ELEM_new(&property_defn_hash, &property_defn_cmp); 65 } 66 67 OSSL_PROPERTY_LIST *ossl_prop_defn_get(OSSL_LIB_CTX *ctx, const char *prop) 68 { 69 PROPERTY_DEFN_ELEM elem, *r; 70 LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns; 71 72 property_defns = ossl_lib_ctx_get_data(ctx, 73 OSSL_LIB_CTX_PROPERTY_DEFN_INDEX); 74 if (!ossl_assert(property_defns != NULL) || !ossl_lib_ctx_read_lock(ctx)) 75 return NULL; 76 77 elem.prop = prop; 78 r = lh_PROPERTY_DEFN_ELEM_retrieve(property_defns, &elem); 79 ossl_lib_ctx_unlock(ctx); 80 if (r == NULL || !ossl_assert(r->defn != NULL)) 81 return NULL; 82 return r->defn; 83 } 84 85 /* 86 * Cache the property list for a given property string *pl. 87 * If an entry already exists in the cache *pl is freed and 88 * overwritten with the existing entry from the cache. 89 */ 90 int ossl_prop_defn_set(OSSL_LIB_CTX *ctx, const char *prop, 91 OSSL_PROPERTY_LIST **pl) 92 { 93 PROPERTY_DEFN_ELEM elem, *old, *p = NULL; 94 size_t len; 95 LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns; 96 int res = 1; 97 98 property_defns = ossl_lib_ctx_get_data(ctx, 99 OSSL_LIB_CTX_PROPERTY_DEFN_INDEX); 100 if (property_defns == NULL) 101 return 0; 102 103 if (prop == NULL) 104 return 1; 105 106 if (!ossl_lib_ctx_write_lock(ctx)) 107 return 0; 108 elem.prop = prop; 109 if (pl == NULL) { 110 lh_PROPERTY_DEFN_ELEM_delete(property_defns, &elem); 111 goto end; 112 } 113 /* check if property definition is in the cache already */ 114 if ((p = lh_PROPERTY_DEFN_ELEM_retrieve(property_defns, &elem)) != NULL) { 115 ossl_property_free(*pl); 116 *pl = p->defn; 117 goto end; 118 } 119 len = strlen(prop); 120 p = OPENSSL_malloc(sizeof(*p) + len); 121 if (p != NULL) { 122 p->prop = p->body; 123 p->defn = *pl; 124 memcpy(p->body, prop, len + 1); 125 old = lh_PROPERTY_DEFN_ELEM_insert(property_defns, p); 126 if (!ossl_assert(old == NULL)) 127 /* This should not happen. An existing entry is handled above. */ 128 goto end; 129 if (!lh_PROPERTY_DEFN_ELEM_error(property_defns)) 130 goto end; 131 } 132 OPENSSL_free(p); 133 res = 0; 134 end: 135 ossl_lib_ctx_unlock(ctx); 136 return res; 137 } 138