1 /* Copyright (c) 2016, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15 #include <openssl/pool.h>
16
17 #include <assert.h>
18 #include <string.h>
19
20 #include <openssl/bytestring.h>
21 #include <openssl/mem.h>
22 #include <openssl/rand.h>
23 #include <openssl/siphash.h>
24 #include <openssl/thread.h>
25
26 #include "../internal.h"
27 #include "internal.h"
28
29
CRYPTO_BUFFER_hash(const CRYPTO_BUFFER * buf)30 static uint32_t CRYPTO_BUFFER_hash(const CRYPTO_BUFFER *buf) {
31 return (uint32_t)SIPHASH_24(buf->pool->hash_key, buf->data, buf->len);
32 }
33
CRYPTO_BUFFER_cmp(const CRYPTO_BUFFER * a,const CRYPTO_BUFFER * b)34 static int CRYPTO_BUFFER_cmp(const CRYPTO_BUFFER *a, const CRYPTO_BUFFER *b) {
35 // Only |CRYPTO_BUFFER|s from the same pool have compatible hashes.
36 assert(a->pool != NULL);
37 assert(a->pool == b->pool);
38 if (a->len != b->len) {
39 return 1;
40 }
41 return OPENSSL_memcmp(a->data, b->data, a->len);
42 }
43
CRYPTO_BUFFER_POOL_new(void)44 CRYPTO_BUFFER_POOL* CRYPTO_BUFFER_POOL_new(void) {
45 CRYPTO_BUFFER_POOL *pool = OPENSSL_zalloc(sizeof(CRYPTO_BUFFER_POOL));
46 if (pool == NULL) {
47 return NULL;
48 }
49
50 pool->bufs = lh_CRYPTO_BUFFER_new(CRYPTO_BUFFER_hash, CRYPTO_BUFFER_cmp);
51 if (pool->bufs == NULL) {
52 OPENSSL_free(pool);
53 return NULL;
54 }
55
56 CRYPTO_MUTEX_init(&pool->lock);
57 RAND_bytes((uint8_t *)&pool->hash_key, sizeof(pool->hash_key));
58
59 return pool;
60 }
61
CRYPTO_BUFFER_POOL_free(CRYPTO_BUFFER_POOL * pool)62 void CRYPTO_BUFFER_POOL_free(CRYPTO_BUFFER_POOL *pool) {
63 if (pool == NULL) {
64 return;
65 }
66
67 #if !defined(NDEBUG)
68 CRYPTO_MUTEX_lock_write(&pool->lock);
69 assert(lh_CRYPTO_BUFFER_num_items(pool->bufs) == 0);
70 CRYPTO_MUTEX_unlock_write(&pool->lock);
71 #endif
72
73 lh_CRYPTO_BUFFER_free(pool->bufs);
74 CRYPTO_MUTEX_cleanup(&pool->lock);
75 OPENSSL_free(pool);
76 }
77
crypto_buffer_free_object(CRYPTO_BUFFER * buf)78 static void crypto_buffer_free_object(CRYPTO_BUFFER *buf) {
79 if (!buf->data_is_static) {
80 OPENSSL_free(buf->data);
81 }
82 OPENSSL_free(buf);
83 }
84
crypto_buffer_new(const uint8_t * data,size_t len,int data_is_static,CRYPTO_BUFFER_POOL * pool)85 static CRYPTO_BUFFER *crypto_buffer_new(const uint8_t *data, size_t len,
86 int data_is_static,
87 CRYPTO_BUFFER_POOL *pool) {
88 if (pool != NULL) {
89 CRYPTO_BUFFER tmp;
90 tmp.data = (uint8_t *) data;
91 tmp.len = len;
92 tmp.pool = pool;
93
94 CRYPTO_MUTEX_lock_read(&pool->lock);
95 CRYPTO_BUFFER *duplicate = lh_CRYPTO_BUFFER_retrieve(pool->bufs, &tmp);
96 if (data_is_static && duplicate != NULL && !duplicate->data_is_static) {
97 // If the new |CRYPTO_BUFFER| would have static data, but the duplicate
98 // does not, we replace the old one with the new static version.
99 duplicate = NULL;
100 }
101 if (duplicate != NULL) {
102 CRYPTO_refcount_inc(&duplicate->references);
103 }
104 CRYPTO_MUTEX_unlock_read(&pool->lock);
105
106 if (duplicate != NULL) {
107 return duplicate;
108 }
109 }
110
111 CRYPTO_BUFFER *const buf = OPENSSL_zalloc(sizeof(CRYPTO_BUFFER));
112 if (buf == NULL) {
113 return NULL;
114 }
115
116 if (data_is_static) {
117 buf->data = (uint8_t *)data;
118 buf->data_is_static = 1;
119 } else {
120 buf->data = OPENSSL_memdup(data, len);
121 if (len != 0 && buf->data == NULL) {
122 OPENSSL_free(buf);
123 return NULL;
124 }
125 }
126
127 buf->len = len;
128 buf->references = 1;
129
130 if (pool == NULL) {
131 return buf;
132 }
133
134 buf->pool = pool;
135
136 CRYPTO_MUTEX_lock_write(&pool->lock);
137 CRYPTO_BUFFER *duplicate = lh_CRYPTO_BUFFER_retrieve(pool->bufs, buf);
138 if (data_is_static && duplicate != NULL && !duplicate->data_is_static) {
139 // If the new |CRYPTO_BUFFER| would have static data, but the duplicate does
140 // not, we replace the old one with the new static version.
141 duplicate = NULL;
142 }
143 int inserted = 0;
144 if (duplicate == NULL) {
145 CRYPTO_BUFFER *old = NULL;
146 inserted = lh_CRYPTO_BUFFER_insert(pool->bufs, &old, buf);
147 // |old| may be non-NULL if a match was found but ignored. |pool->bufs| does
148 // not increment refcounts, so there is no need to clean up after the
149 // replacement.
150 } else {
151 CRYPTO_refcount_inc(&duplicate->references);
152 }
153 CRYPTO_MUTEX_unlock_write(&pool->lock);
154
155 if (!inserted) {
156 // We raced to insert |buf| into the pool and lost, or else there was an
157 // error inserting.
158 crypto_buffer_free_object(buf);
159 return duplicate;
160 }
161
162 return buf;
163 }
164
CRYPTO_BUFFER_new(const uint8_t * data,size_t len,CRYPTO_BUFFER_POOL * pool)165 CRYPTO_BUFFER *CRYPTO_BUFFER_new(const uint8_t *data, size_t len,
166 CRYPTO_BUFFER_POOL *pool) {
167 return crypto_buffer_new(data, len, /*data_is_static=*/0, pool);
168 }
169
CRYPTO_BUFFER_alloc(uint8_t ** out_data,size_t len)170 CRYPTO_BUFFER *CRYPTO_BUFFER_alloc(uint8_t **out_data, size_t len) {
171 CRYPTO_BUFFER *const buf = OPENSSL_zalloc(sizeof(CRYPTO_BUFFER));
172 if (buf == NULL) {
173 return NULL;
174 }
175
176 buf->data = OPENSSL_malloc(len);
177 if (len != 0 && buf->data == NULL) {
178 OPENSSL_free(buf);
179 return NULL;
180 }
181 buf->len = len;
182 buf->references = 1;
183
184 *out_data = buf->data;
185 return buf;
186 }
187
CRYPTO_BUFFER_new_from_CBS(const CBS * cbs,CRYPTO_BUFFER_POOL * pool)188 CRYPTO_BUFFER *CRYPTO_BUFFER_new_from_CBS(const CBS *cbs,
189 CRYPTO_BUFFER_POOL *pool) {
190 return CRYPTO_BUFFER_new(CBS_data(cbs), CBS_len(cbs), pool);
191 }
192
CRYPTO_BUFFER_new_from_static_data_unsafe(const uint8_t * data,size_t len,CRYPTO_BUFFER_POOL * pool)193 CRYPTO_BUFFER *CRYPTO_BUFFER_new_from_static_data_unsafe(
194 const uint8_t *data, size_t len, CRYPTO_BUFFER_POOL *pool) {
195 return crypto_buffer_new(data, len, /*data_is_static=*/1, pool);
196 }
197
CRYPTO_BUFFER_free(CRYPTO_BUFFER * buf)198 void CRYPTO_BUFFER_free(CRYPTO_BUFFER *buf) {
199 if (buf == NULL) {
200 return;
201 }
202
203 CRYPTO_BUFFER_POOL *const pool = buf->pool;
204 if (pool == NULL) {
205 if (CRYPTO_refcount_dec_and_test_zero(&buf->references)) {
206 // If a reference count of zero is observed, there cannot be a reference
207 // from any pool to this buffer and thus we are able to free this
208 // buffer.
209 crypto_buffer_free_object(buf);
210 }
211
212 return;
213 }
214
215 CRYPTO_MUTEX_lock_write(&pool->lock);
216 if (!CRYPTO_refcount_dec_and_test_zero(&buf->references)) {
217 CRYPTO_MUTEX_unlock_write(&buf->pool->lock);
218 return;
219 }
220
221 // We have an exclusive lock on the pool, therefore no concurrent lookups can
222 // find this buffer and increment the reference count. Thus, if the count is
223 // zero there are and can never be any more references and thus we can free
224 // this buffer.
225 //
226 // Note it is possible |buf| is no longer in the pool, if it was replaced by a
227 // static version. If that static version was since removed, it is even
228 // possible for |found| to be NULL.
229 CRYPTO_BUFFER *found = lh_CRYPTO_BUFFER_retrieve(pool->bufs, buf);
230 if (found == buf) {
231 found = lh_CRYPTO_BUFFER_delete(pool->bufs, buf);
232 assert(found == buf);
233 (void)found;
234 }
235
236 CRYPTO_MUTEX_unlock_write(&buf->pool->lock);
237 crypto_buffer_free_object(buf);
238 }
239
CRYPTO_BUFFER_up_ref(CRYPTO_BUFFER * buf)240 int CRYPTO_BUFFER_up_ref(CRYPTO_BUFFER *buf) {
241 // This is safe in the case that |buf->pool| is NULL because it's just
242 // standard reference counting in that case.
243 //
244 // This is also safe if |buf->pool| is non-NULL because, if it were racing
245 // with |CRYPTO_BUFFER_free| then the two callers must have independent
246 // references already and so the reference count will never hit zero.
247 CRYPTO_refcount_inc(&buf->references);
248 return 1;
249 }
250
CRYPTO_BUFFER_data(const CRYPTO_BUFFER * buf)251 const uint8_t *CRYPTO_BUFFER_data(const CRYPTO_BUFFER *buf) {
252 return buf->data;
253 }
254
CRYPTO_BUFFER_len(const CRYPTO_BUFFER * buf)255 size_t CRYPTO_BUFFER_len(const CRYPTO_BUFFER *buf) {
256 return buf->len;
257 }
258
CRYPTO_BUFFER_init_CBS(const CRYPTO_BUFFER * buf,CBS * out)259 void CRYPTO_BUFFER_init_CBS(const CRYPTO_BUFFER *buf, CBS *out) {
260 CBS_init(out, buf->data, buf->len);
261 }
262