Coverage Report

Created: 2023-06-08 06:41

/src/openssl30/crypto/property/property_string.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/crypto.h>
13
#include <openssl/lhash.h>
14
#include "crypto/lhash.h"
15
#include "property_local.h"
16
17
/*
18
 * Property strings are a consolidation of all strings seen by the property
19
 * subsystem.  There are two name spaces to keep property names separate from
20
 * property values (numeric values are not expected to be cached however).
21
 * They allow a rapid conversion from a string to a unique index and any
22
 * subsequent string comparison can be done via an integer compare.
23
 *
24
 * This implementation uses OpenSSL's standard hash table.  There are more
25
 * space and time efficient algorithms if this becomes a bottleneck.
26
 */
27
28
typedef struct {
29
    const char *s;
30
    OSSL_PROPERTY_IDX idx;
31
    char body[1];
32
} PROPERTY_STRING;
33
34
DEFINE_LHASH_OF(PROPERTY_STRING);
35
typedef LHASH_OF(PROPERTY_STRING) PROP_TABLE;
36
37
typedef struct {
38
    CRYPTO_RWLOCK *lock;
39
    PROP_TABLE *prop_names;
40
    PROP_TABLE *prop_values;
41
    OSSL_PROPERTY_IDX prop_name_idx;
42
    OSSL_PROPERTY_IDX prop_value_idx;
43
} PROPERTY_STRING_DATA;
44
45
static unsigned long property_hash(const PROPERTY_STRING *a)
46
48
{
47
48
    return OPENSSL_LH_strhash(a->s);
48
48
}
49
50
static int property_cmp(const PROPERTY_STRING *a, const PROPERTY_STRING *b)
51
0
{
52
0
    return strcmp(a->s, b->s);
53
0
}
54
55
static void property_free(PROPERTY_STRING *ps)
56
16
{
57
16
    OPENSSL_free(ps);
58
16
}
59
60
static void property_table_free(PROP_TABLE **pt)
61
4
{
62
4
    PROP_TABLE *t = *pt;
63
64
4
    if (t != NULL) {
65
4
        lh_PROPERTY_STRING_doall(t, &property_free);
66
4
        lh_PROPERTY_STRING_free(t);
67
4
        *pt = NULL;
68
4
    }
69
4
}
70
71
static void property_string_data_free(void *vpropdata)
72
2
{
73
2
    PROPERTY_STRING_DATA *propdata = vpropdata;
74
75
2
    if (propdata == NULL)
76
0
        return;
77
78
2
    CRYPTO_THREAD_lock_free(propdata->lock);
79
2
    property_table_free(&propdata->prop_names);
80
2
    property_table_free(&propdata->prop_values);
81
2
    propdata->prop_name_idx = propdata->prop_value_idx = 0;
82
83
2
    OPENSSL_free(propdata);
84
2
}
85
86
2
static void *property_string_data_new(OSSL_LIB_CTX *ctx) {
87
2
    PROPERTY_STRING_DATA *propdata = OPENSSL_zalloc(sizeof(*propdata));
88
89
2
    if (propdata == NULL)
90
0
        return NULL;
91
92
2
    propdata->lock = CRYPTO_THREAD_lock_new();
93
2
    if (propdata->lock == NULL)
94
0
        goto err;
95
96
2
    propdata->prop_names = lh_PROPERTY_STRING_new(&property_hash,
97
2
                                                  &property_cmp);
98
2
    if (propdata->prop_names == NULL)
99
0
        goto err;
100
101
2
    propdata->prop_values = lh_PROPERTY_STRING_new(&property_hash,
102
2
                                                   &property_cmp);
103
2
    if (propdata->prop_values == NULL)
104
0
        goto err;
105
106
2
    return propdata;
107
108
0
err:
109
0
    property_string_data_free(propdata);
110
0
    return NULL;
111
2
}
112
113
static const OSSL_LIB_CTX_METHOD property_string_data_method = {
114
    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
115
    property_string_data_new,
116
    property_string_data_free,
117
};
118
119
static PROPERTY_STRING *new_property_string(const char *s,
120
                                            OSSL_PROPERTY_IDX *pidx)
121
16
{
122
16
    const size_t l = strlen(s);
123
16
    PROPERTY_STRING *ps = OPENSSL_malloc(sizeof(*ps) + l);
124
125
16
    if (ps != NULL) {
126
16
        memcpy(ps->body, s, l + 1);
127
16
        ps->s = ps->body;
128
16
        ps->idx = ++*pidx;
129
16
        if (ps->idx == 0) {
130
0
            OPENSSL_free(ps);
131
0
            return NULL;
132
0
        }
133
16
    }
134
16
    return ps;
135
16
}
136
137
static OSSL_PROPERTY_IDX ossl_property_string(CRYPTO_RWLOCK *lock,
138
                                              PROP_TABLE *t,
139
                                              OSSL_PROPERTY_IDX *pidx,
140
                                              const char *s)
141
16
{
142
16
    PROPERTY_STRING p, *ps, *ps_new;
143
144
16
    p.s = s;
145
16
    if (!CRYPTO_THREAD_read_lock(lock)) {
146
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_READ_LOCK);
147
0
        return 0;
148
0
    }
149
16
    ps = lh_PROPERTY_STRING_retrieve(t, &p);
150
16
    if (ps == NULL && pidx != NULL) {
151
16
        CRYPTO_THREAD_unlock(lock);
152
16
        if (!CRYPTO_THREAD_write_lock(lock)) {
153
0
            ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
154
0
            return 0;
155
0
        }
156
16
        ps = lh_PROPERTY_STRING_retrieve(t, &p);
157
16
        if (ps == NULL && (ps_new = new_property_string(s, pidx)) != NULL) {
158
16
            lh_PROPERTY_STRING_insert(t, ps_new);
159
16
            if (lh_PROPERTY_STRING_error(t)) {
160
0
                property_free(ps_new);
161
0
                CRYPTO_THREAD_unlock(lock);
162
0
                return 0;
163
0
            }
164
16
            ps = ps_new;
165
16
        }
166
16
    }
167
16
    CRYPTO_THREAD_unlock(lock);
168
16
    return ps != NULL ? ps->idx : 0;
169
16
}
170
171
struct find_str_st {
172
    const char *str;
173
    OSSL_PROPERTY_IDX idx;
174
};
175
176
static void find_str_fn(PROPERTY_STRING *prop, void *vfindstr)
177
0
{
178
0
    struct find_str_st *findstr = vfindstr;
179
180
0
    if (prop->idx == findstr->idx)
181
0
        findstr->str = prop->s;
182
0
}
183
184
static const char *ossl_property_str(int name, OSSL_LIB_CTX *ctx,
185
                                     OSSL_PROPERTY_IDX idx)
186
0
{
187
0
    struct find_str_st findstr;
188
0
    PROPERTY_STRING_DATA *propdata
189
0
        = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX,
190
0
                                &property_string_data_method);
191
192
0
    if (propdata == NULL)
193
0
        return NULL;
194
195
0
    findstr.str = NULL;
196
0
    findstr.idx = idx;
197
198
0
    if (!CRYPTO_THREAD_read_lock(propdata->lock)) {
199
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_READ_LOCK);
200
0
        return NULL;
201
0
    }
202
0
    lh_PROPERTY_STRING_doall_arg(name ? propdata->prop_names
203
0
                                      : propdata->prop_values,
204
0
                                 find_str_fn, &findstr);
205
0
    CRYPTO_THREAD_unlock(propdata->lock);
206
207
0
    return findstr.str;
208
0
}
209
210
OSSL_PROPERTY_IDX ossl_property_name(OSSL_LIB_CTX *ctx, const char *s,
211
                                     int create)
212
12
{
213
12
    PROPERTY_STRING_DATA *propdata
214
12
        = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX,
215
12
                                &property_string_data_method);
216
217
12
    if (propdata == NULL)
218
0
        return 0;
219
12
    return ossl_property_string(propdata->lock, propdata->prop_names,
220
12
                                create ? &propdata->prop_name_idx : NULL,
221
12
                                s);
222
12
}
223
224
const char *ossl_property_name_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx)
225
0
{
226
0
    return ossl_property_str(1, ctx, idx);
227
0
}
228
229
OSSL_PROPERTY_IDX ossl_property_value(OSSL_LIB_CTX *ctx, const char *s,
230
                                      int create)
231
4
{
232
4
    PROPERTY_STRING_DATA *propdata
233
4
        = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX,
234
4
                                &property_string_data_method);
235
236
4
    if (propdata == NULL)
237
0
        return 0;
238
4
    return ossl_property_string(propdata->lock, propdata->prop_values,
239
4
                                create ? &propdata->prop_value_idx : NULL,
240
4
                                s);
241
4
}
242
243
const char *ossl_property_value_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx)
244
0
{
245
0
    return ossl_property_str(0, ctx, idx);
246
0
}