Coverage Report

Created: 2025-12-31 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl30/crypto/property/property_string.c
Line
Count
Source
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
11.4M
{
47
11.4M
    return OPENSSL_LH_strhash(a->s);
48
11.4M
}
49
50
static int property_cmp(const PROPERTY_STRING *a, const PROPERTY_STRING *b)
51
8.38M
{
52
8.38M
    return strcmp(a->s, b->s);
53
8.38M
}
54
55
static void property_free(PROPERTY_STRING *ps)
56
2.60k
{
57
2.60k
    OPENSSL_free(ps);
58
2.60k
}
59
60
static void property_table_free(PROP_TABLE **pt)
61
440
{
62
440
    PROP_TABLE *t = *pt;
63
64
440
    if (t != NULL) {
65
440
        lh_PROPERTY_STRING_doall(t, &property_free);
66
440
        lh_PROPERTY_STRING_free(t);
67
440
        *pt = NULL;
68
440
    }
69
440
}
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
static void *property_string_data_new(OSSL_LIB_CTX *ctx)
87
34
{
88
34
    PROPERTY_STRING_DATA *propdata = OPENSSL_zalloc(sizeof(*propdata));
89
90
34
    if (propdata == NULL)
91
0
        return NULL;
92
93
34
    propdata->lock = CRYPTO_THREAD_lock_new();
94
34
    if (propdata->lock == NULL)
95
0
        goto err;
96
97
34
    propdata->prop_names = lh_PROPERTY_STRING_new(&property_hash,
98
34
        &property_cmp);
99
34
    if (propdata->prop_names == NULL)
100
0
        goto err;
101
102
34
    propdata->prop_values = lh_PROPERTY_STRING_new(&property_hash,
103
34
        &property_cmp);
104
34
    if (propdata->prop_values == NULL)
105
0
        goto err;
106
107
34
    return propdata;
108
109
0
err:
110
0
    property_string_data_free(propdata);
111
0
    return NULL;
112
34
}
113
114
static const OSSL_LIB_CTX_METHOD property_string_data_method = {
115
    OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
116
    property_string_data_new,
117
    property_string_data_free,
118
};
119
120
static PROPERTY_STRING *new_property_string(const char *s,
121
    OSSL_PROPERTY_IDX *pidx)
122
4.72k
{
123
4.72k
    const size_t l = strlen(s);
124
4.72k
    PROPERTY_STRING *ps = OPENSSL_malloc(sizeof(*ps) + l);
125
126
4.72k
    if (ps != NULL) {
127
4.72k
        memcpy(ps->body, s, l + 1);
128
4.72k
        ps->s = ps->body;
129
4.72k
        ps->idx = ++*pidx;
130
4.72k
        if (ps->idx == 0) {
131
0
            OPENSSL_free(ps);
132
0
            return NULL;
133
0
        }
134
4.72k
    }
135
4.72k
    return ps;
136
4.72k
}
137
138
static OSSL_PROPERTY_IDX ossl_property_string(CRYPTO_RWLOCK *lock,
139
    PROP_TABLE *t,
140
    OSSL_PROPERTY_IDX *pidx,
141
    const char *s)
142
6.94M
{
143
6.94M
    PROPERTY_STRING p, *ps, *ps_new;
144
145
6.94M
    p.s = s;
146
6.94M
    if (!CRYPTO_THREAD_read_lock(lock)) {
147
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_READ_LOCK);
148
0
        return 0;
149
0
    }
150
6.94M
    ps = lh_PROPERTY_STRING_retrieve(t, &p);
151
6.94M
    if (ps == NULL && pidx != NULL) {
152
374
        CRYPTO_THREAD_unlock(lock);
153
374
        if (!CRYPTO_THREAD_write_lock(lock)) {
154
0
            ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
155
0
            return 0;
156
0
        }
157
374
        ps = lh_PROPERTY_STRING_retrieve(t, &p);
158
374
        if (ps == NULL && (ps_new = new_property_string(s, pidx)) != NULL) {
159
374
            lh_PROPERTY_STRING_insert(t, ps_new);
160
374
            if (lh_PROPERTY_STRING_error(t)) {
161
0
                property_free(ps_new);
162
0
                CRYPTO_THREAD_unlock(lock);
163
0
                return 0;
164
0
            }
165
374
            ps = ps_new;
166
374
        }
167
374
    }
168
6.94M
    CRYPTO_THREAD_unlock(lock);
169
6.94M
    return ps != NULL ? ps->idx : 0;
170
6.94M
}
171
172
struct find_str_st {
173
    const char *str;
174
    OSSL_PROPERTY_IDX idx;
175
};
176
177
static void find_str_fn(PROPERTY_STRING *prop, void *vfindstr)
178
102M
{
179
102M
    struct find_str_st *findstr = vfindstr;
180
181
102M
    if (prop->idx == findstr->idx)
182
5.22M
        findstr->str = prop->s;
183
102M
}
184
185
static const char *ossl_property_str(int name, OSSL_LIB_CTX *ctx,
186
    OSSL_PROPERTY_IDX idx)
187
6.43M
{
188
6.43M
    struct find_str_st findstr;
189
6.43M
    PROPERTY_STRING_DATA *propdata
190
6.43M
        = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX,
191
6.43M
            &property_string_data_method);
192
193
6.43M
    if (propdata == NULL)
194
0
        return NULL;
195
196
6.43M
    findstr.str = NULL;
197
6.43M
    findstr.idx = idx;
198
199
6.43M
    if (!CRYPTO_THREAD_read_lock(propdata->lock)) {
200
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_READ_LOCK);
201
0
        return NULL;
202
0
    }
203
6.43M
    lh_PROPERTY_STRING_doall_arg(name ? propdata->prop_names
204
6.43M
                                      : propdata->prop_values,
205
6.43M
        find_str_fn, &findstr);
206
6.43M
    CRYPTO_THREAD_unlock(propdata->lock);
207
208
6.43M
    return findstr.str;
209
6.43M
}
210
211
OSSL_PROPERTY_IDX ossl_property_name(OSSL_LIB_CTX *ctx, const char *s,
212
    int create)
213
6.94M
{
214
6.94M
    PROPERTY_STRING_DATA *propdata
215
6.94M
        = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX,
216
6.94M
            &property_string_data_method);
217
218
6.94M
    if (propdata == NULL)
219
0
        return 0;
220
6.94M
    return ossl_property_string(propdata->lock, propdata->prop_names,
221
6.94M
        create ? &propdata->prop_name_idx : NULL,
222
6.94M
        s);
223
6.94M
}
224
225
const char *ossl_property_name_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx)
226
495
{
227
495
    return ossl_property_str(1, ctx, idx);
228
495
}
229
230
OSSL_PROPERTY_IDX ossl_property_value(OSSL_LIB_CTX *ctx, const char *s,
231
    int create)
232
2.54k
{
233
2.54k
    PROPERTY_STRING_DATA *propdata
234
2.54k
        = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX,
235
2.54k
            &property_string_data_method);
236
237
2.54k
    if (propdata == NULL)
238
0
        return 0;
239
2.54k
    return ossl_property_string(propdata->lock, propdata->prop_values,
240
2.54k
        create ? &propdata->prop_value_idx : NULL,
241
2.54k
        s);
242
2.54k
}
243
244
const char *ossl_property_value_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx)
245
6.43M
{
246
6.43M
    return ossl_property_str(0, ctx, idx);
247
6.43M
}