Coverage Report

Created: 2025-06-13 06:58

/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
15.2M
{
47
15.2M
    return OPENSSL_LH_strhash(a->s);
48
15.2M
}
49
50
static int property_cmp(const PROPERTY_STRING *a, const PROPERTY_STRING *b)
51
12.1M
{
52
12.1M
    return strcmp(a->s, b->s);
53
12.1M
}
54
55
static void property_free(PROPERTY_STRING *ps)
56
1.51k
{
57
1.51k
    OPENSSL_free(ps);
58
1.51k
}
59
60
static void property_table_free(PROP_TABLE **pt)
61
246
{
62
246
    PROP_TABLE *t = *pt;
63
64
246
    if (t != NULL) {
65
246
        lh_PROPERTY_STRING_doall(t, &property_free);
66
246
        lh_PROPERTY_STRING_free(t);
67
246
        *pt = NULL;
68
246
    }
69
246
}
70
71
static void property_string_data_free(void *vpropdata)
72
24
{
73
24
    PROPERTY_STRING_DATA *propdata = vpropdata;
74
75
24
    if (propdata == NULL)
76
0
        return;
77
78
24
    CRYPTO_THREAD_lock_free(propdata->lock);
79
24
    property_table_free(&propdata->prop_names);
80
24
    property_table_free(&propdata->prop_values);
81
24
    propdata->prop_name_idx = propdata->prop_value_idx = 0;
82
83
24
    OPENSSL_free(propdata);
84
24
}
85
86
34
static void *property_string_data_new(OSSL_LIB_CTX *ctx) {
87
34
    PROPERTY_STRING_DATA *propdata = OPENSSL_zalloc(sizeof(*propdata));
88
89
34
    if (propdata == NULL)
90
0
        return NULL;
91
92
34
    propdata->lock = CRYPTO_THREAD_lock_new();
93
34
    if (propdata->lock == NULL)
94
0
        goto err;
95
96
34
    propdata->prop_names = lh_PROPERTY_STRING_new(&property_hash,
97
34
                                                  &property_cmp);
98
34
    if (propdata->prop_names == NULL)
99
0
        goto err;
100
101
34
    propdata->prop_values = lh_PROPERTY_STRING_new(&property_hash,
102
34
                                                   &property_cmp);
103
34
    if (propdata->prop_values == NULL)
104
0
        goto err;
105
106
34
    return propdata;
107
108
0
err:
109
0
    property_string_data_free(propdata);
110
0
    return NULL;
111
34
}
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
2.08k
{
122
2.08k
    const size_t l = strlen(s);
123
2.08k
    PROPERTY_STRING *ps = OPENSSL_malloc(sizeof(*ps) + l);
124
125
2.08k
    if (ps != NULL) {
126
2.08k
        memcpy(ps->body, s, l + 1);
127
2.08k
        ps->s = ps->body;
128
2.08k
        ps->idx = ++*pidx;
129
2.08k
        if (ps->idx == 0) {
130
0
            OPENSSL_free(ps);
131
0
            return NULL;
132
0
        }
133
2.08k
    }
134
2.08k
    return ps;
135
2.08k
}
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
6.83M
{
142
6.83M
    PROPERTY_STRING p, *ps, *ps_new;
143
144
6.83M
    p.s = s;
145
6.83M
    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
6.83M
    ps = lh_PROPERTY_STRING_retrieve(t, &p);
150
6.83M
    if (ps == NULL && pidx != NULL) {
151
374
        CRYPTO_THREAD_unlock(lock);
152
374
        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
374
        ps = lh_PROPERTY_STRING_retrieve(t, &p);
157
374
        if (ps == NULL && (ps_new = new_property_string(s, pidx)) != NULL) {
158
374
            lh_PROPERTY_STRING_insert(t, ps_new);
159
374
            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
374
            ps = ps_new;
165
374
        }
166
374
    }
167
6.83M
    CRYPTO_THREAD_unlock(lock);
168
6.83M
    return ps != NULL ? ps->idx : 0;
169
6.83M
}
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
100M
{
178
100M
    struct find_str_st *findstr = vfindstr;
179
180
100M
    if (prop->idx == findstr->idx)
181
5.14M
        findstr->str = prop->s;
182
100M
}
183
184
static const char *ossl_property_str(int name, OSSL_LIB_CTX *ctx,
185
                                     OSSL_PROPERTY_IDX idx)
186
9.25M
{
187
9.25M
    struct find_str_st findstr;
188
9.25M
    PROPERTY_STRING_DATA *propdata
189
9.25M
        = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX,
190
9.25M
                                &property_string_data_method);
191
192
9.25M
    if (propdata == NULL)
193
0
        return NULL;
194
195
9.25M
    findstr.str = NULL;
196
9.25M
    findstr.idx = idx;
197
198
9.25M
    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
9.25M
    lh_PROPERTY_STRING_doall_arg(name ? propdata->prop_names
203
9.25M
                                      : propdata->prop_values,
204
9.25M
                                 find_str_fn, &findstr);
205
9.25M
    CRYPTO_THREAD_unlock(propdata->lock);
206
207
9.25M
    return findstr.str;
208
9.25M
}
209
210
OSSL_PROPERTY_IDX ossl_property_name(OSSL_LIB_CTX *ctx, const char *s,
211
                                     int create)
212
6.83M
{
213
6.83M
    PROPERTY_STRING_DATA *propdata
214
6.83M
        = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX,
215
6.83M
                                &property_string_data_method);
216
217
6.83M
    if (propdata == NULL)
218
0
        return 0;
219
6.83M
    return ossl_property_string(propdata->lock, propdata->prop_names,
220
6.83M
                                create ? &propdata->prop_name_idx : NULL,
221
6.83M
                                s);
222
6.83M
}
223
224
const char *ossl_property_name_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx)
225
412
{
226
412
    return ossl_property_str(1, ctx, idx);
227
412
}
228
229
OSSL_PROPERTY_IDX ossl_property_value(OSSL_LIB_CTX *ctx, const char *s,
230
                                      int create)
231
2.49k
{
232
2.49k
    PROPERTY_STRING_DATA *propdata
233
2.49k
        = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX,
234
2.49k
                                &property_string_data_method);
235
236
2.49k
    if (propdata == NULL)
237
0
        return 0;
238
2.49k
    return ossl_property_string(propdata->lock, propdata->prop_values,
239
2.49k
                                create ? &propdata->prop_value_idx : NULL,
240
2.49k
                                s);
241
2.49k
}
242
243
const char *ossl_property_value_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx)
244
9.25M
{
245
9.25M
    return ossl_property_str(0, ctx, idx);
246
9.25M
}