Coverage Report

Created: 2023-09-25 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
1.08M
{
47
1.08M
    return OPENSSL_LH_strhash(a->s);
48
1.08M
}
49
50
static int property_cmp(const PROPERTY_STRING *a, const PROPERTY_STRING *b)
51
1.08M
{
52
1.08M
    return strcmp(a->s, b->s);
53
1.08M
}
54
55
static void property_free(PROPERTY_STRING *ps)
56
31
{
57
31
    OPENSSL_free(ps);
58
31
}
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
4
static void *property_string_data_new(OSSL_LIB_CTX *ctx) {
87
4
    PROPERTY_STRING_DATA *propdata = OPENSSL_zalloc(sizeof(*propdata));
88
89
4
    if (propdata == NULL)
90
0
        return NULL;
91
92
4
    propdata->lock = CRYPTO_THREAD_lock_new();
93
4
    if (propdata->lock == NULL)
94
0
        goto err;
95
96
4
    propdata->prop_names = lh_PROPERTY_STRING_new(&property_hash,
97
4
                                                  &property_cmp);
98
4
    if (propdata->prop_names == NULL)
99
0
        goto err;
100
101
4
    propdata->prop_values = lh_PROPERTY_STRING_new(&property_hash,
102
4
                                                   &property_cmp);
103
4
    if (propdata->prop_values == NULL)
104
0
        goto err;
105
106
4
    return propdata;
107
108
0
err:
109
0
    property_string_data_free(propdata);
110
0
    return NULL;
111
4
}
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
47
{
122
47
    const size_t l = strlen(s);
123
47
    PROPERTY_STRING *ps = OPENSSL_malloc(sizeof(*ps) + l);
124
125
47
    if (ps != NULL) {
126
47
        memcpy(ps->body, s, l + 1);
127
47
        ps->s = ps->body;
128
47
        ps->idx = ++*pidx;
129
47
        if (ps->idx == 0) {
130
0
            OPENSSL_free(ps);
131
0
            return NULL;
132
0
        }
133
47
    }
134
47
    return ps;
135
47
}
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
1.08M
{
142
1.08M
    PROPERTY_STRING p, *ps, *ps_new;
143
144
1.08M
    p.s = s;
145
1.08M
    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
1.08M
    ps = lh_PROPERTY_STRING_retrieve(t, &p);
150
1.08M
    if (ps == NULL && pidx != NULL) {
151
47
        CRYPTO_THREAD_unlock(lock);
152
47
        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
47
        ps = lh_PROPERTY_STRING_retrieve(t, &p);
157
47
        if (ps == NULL && (ps_new = new_property_string(s, pidx)) != NULL) {
158
47
            lh_PROPERTY_STRING_insert(t, ps_new);
159
47
            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
47
            ps = ps_new;
165
47
        }
166
47
    }
167
1.08M
    CRYPTO_THREAD_unlock(lock);
168
1.08M
    return ps != NULL ? ps->idx : 0;
169
1.08M
}
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
14.0M
{
178
14.0M
    struct find_str_st *findstr = vfindstr;
179
180
14.0M
    if (prop->idx == findstr->idx)
181
828k
        findstr->str = prop->s;
182
14.0M
}
183
184
static const char *ossl_property_str(int name, OSSL_LIB_CTX *ctx,
185
                                     OSSL_PROPERTY_IDX idx)
186
828k
{
187
828k
    struct find_str_st findstr;
188
828k
    PROPERTY_STRING_DATA *propdata
189
828k
        = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX,
190
828k
                                &property_string_data_method);
191
192
828k
    if (propdata == NULL)
193
0
        return NULL;
194
195
828k
    findstr.str = NULL;
196
828k
    findstr.idx = idx;
197
198
828k
    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
828k
    lh_PROPERTY_STRING_doall_arg(name ? propdata->prop_names
203
828k
                                      : propdata->prop_values,
204
828k
                                 find_str_fn, &findstr);
205
828k
    CRYPTO_THREAD_unlock(propdata->lock);
206
207
828k
    return findstr.str;
208
828k
}
209
210
OSSL_PROPERTY_IDX ossl_property_name(OSSL_LIB_CTX *ctx, const char *s,
211
                                     int create)
212
1.08M
{
213
1.08M
    PROPERTY_STRING_DATA *propdata
214
1.08M
        = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX,
215
1.08M
                                &property_string_data_method);
216
217
1.08M
    if (propdata == NULL)
218
0
        return 0;
219
1.08M
    return ossl_property_string(propdata->lock, propdata->prop_names,
220
1.08M
                                create ? &propdata->prop_name_idx : NULL,
221
1.08M
                                s);
222
1.08M
}
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
214
{
232
214
    PROPERTY_STRING_DATA *propdata
233
214
        = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX,
234
214
                                &property_string_data_method);
235
236
214
    if (propdata == NULL)
237
0
        return 0;
238
214
    return ossl_property_string(propdata->lock, propdata->prop_values,
239
214
                                create ? &propdata->prop_value_idx : NULL,
240
214
                                s);
241
214
}
242
243
const char *ossl_property_value_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx)
244
828k
{
245
828k
    return ossl_property_str(0, ctx, idx);
246
828k
}