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_malloc(sizeof(CRYPTO_BUFFER_POOL));
46 if (pool == NULL) {
47 return NULL;
48 }
49
50 OPENSSL_memset(pool, 0, sizeof(CRYPTO_BUFFER_POOL));
51 pool->bufs = lh_CRYPTO_BUFFER_new(CRYPTO_BUFFER_hash, CRYPTO_BUFFER_cmp);
52 if (pool->bufs == NULL) {
53 OPENSSL_free(pool);
54 return NULL;
55 }
56
57 CRYPTO_MUTEX_init(&pool->lock);
58 RAND_bytes((uint8_t *)&pool->hash_key, sizeof(pool->hash_key));
59
60 return pool;
61 }
62
CRYPTO_BUFFER_POOL_free(CRYPTO_BUFFER_POOL * pool)63 void CRYPTO_BUFFER_POOL_free(CRYPTO_BUFFER_POOL *pool) {
64 if (pool == NULL) {
65 return;
66 }
67
68 #if !defined(NDEBUG)
69 CRYPTO_MUTEX_lock_write(&pool->lock);
70 assert(lh_CRYPTO_BUFFER_num_items(pool->bufs) == 0);
71 CRYPTO_MUTEX_unlock_write(&pool->lock);
72 #endif
73
74 lh_CRYPTO_BUFFER_free(pool->bufs);
75 CRYPTO_MUTEX_cleanup(&pool->lock);
76 OPENSSL_free(pool);
77 }
78
crypto_buffer_free_object(CRYPTO_BUFFER * buf)79 static void crypto_buffer_free_object(CRYPTO_BUFFER *buf) {
80 if (!buf->data_is_static) {
81 OPENSSL_free(buf->data);
82 }
83 OPENSSL_free(buf);
84 }
85
crypto_buffer_new(const uint8_t * data,size_t len,int data_is_static,CRYPTO_BUFFER_POOL * pool)86 static CRYPTO_BUFFER *crypto_buffer_new(const uint8_t *data, size_t len,
87 int data_is_static,
88 CRYPTO_BUFFER_POOL *pool) {
89 if (pool != NULL) {
90 CRYPTO_BUFFER tmp;
91 tmp.data = (uint8_t *) data;
92 tmp.len = len;
93 tmp.pool = pool;
94
95 CRYPTO_MUTEX_lock_read(&pool->lock);
96 CRYPTO_BUFFER *duplicate = lh_CRYPTO_BUFFER_retrieve(pool->bufs, &tmp);
97 if (data_is_static && duplicate != NULL && !duplicate->data_is_static) {
98 // If the new |CRYPTO_BUFFER| would have static data, but the duplicate
99 // does not, we replace the old one with the new static version.
100 duplicate = NULL;
101 }
102 if (duplicate != NULL) {
103 CRYPTO_refcount_inc(&duplicate->references);
104 }
105 CRYPTO_MUTEX_unlock_read(&pool->lock);
106
107 if (duplicate != NULL) {
108 return duplicate;
109 }
110 }
111
112 CRYPTO_BUFFER *const buf = OPENSSL_malloc(sizeof(CRYPTO_BUFFER));
113 if (buf == NULL) {
114 return NULL;
115 }
116 OPENSSL_memset(buf, 0, sizeof(CRYPTO_BUFFER));
117
118 if (data_is_static) {
119 buf->data = (uint8_t *)data;
120 buf->data_is_static = 1;
121 } else {
122 buf->data = OPENSSL_memdup(data, len);
123 if (len != 0 && buf->data == NULL) {
124 OPENSSL_free(buf);
125 return NULL;
126 }
127 }
128
129 buf->len = len;
130 buf->references = 1;
131
132 if (pool == NULL) {
133 return buf;
134 }
135
136 buf->pool = pool;
137
138 CRYPTO_MUTEX_lock_write(&pool->lock);
139 CRYPTO_BUFFER *duplicate = lh_CRYPTO_BUFFER_retrieve(pool->bufs, buf);
140 if (data_is_static && duplicate != NULL && !duplicate->data_is_static) {
141 // If the new |CRYPTO_BUFFER| would have static data, but the duplicate does
142 // not, we replace the old one with the new static version.
143 duplicate = NULL;
144 }
145 int inserted = 0;
146 if (duplicate == NULL) {
147 CRYPTO_BUFFER *old = NULL;
148 inserted = lh_CRYPTO_BUFFER_insert(pool->bufs, &old, buf);
149 // |old| may be non-NULL if a match was found but ignored. |pool->bufs| does
150 // not increment refcounts, so there is no need to clean up after the
151 // replacement.
152 } else {
153 CRYPTO_refcount_inc(&duplicate->references);
154 }
155 CRYPTO_MUTEX_unlock_write(&pool->lock);
156
157 if (!inserted) {
158 // We raced to insert |buf| into the pool and lost, or else there was an
159 // error inserting.
160 crypto_buffer_free_object(buf);
161 return duplicate;
162 }
163
164 return buf;
165 }
166
CRYPTO_BUFFER_new(const uint8_t * data,size_t len,CRYPTO_BUFFER_POOL * pool)167 CRYPTO_BUFFER *CRYPTO_BUFFER_new(const uint8_t *data, size_t len,
168 CRYPTO_BUFFER_POOL *pool) {
169 return crypto_buffer_new(data, len, /*data_is_static=*/0, pool);
170 }
171
CRYPTO_BUFFER_alloc(uint8_t ** out_data,size_t len)172 CRYPTO_BUFFER *CRYPTO_BUFFER_alloc(uint8_t **out_data, size_t len) {
173 CRYPTO_BUFFER *const buf = OPENSSL_malloc(sizeof(CRYPTO_BUFFER));
174 if (buf == NULL) {
175 return NULL;
176 }
177 OPENSSL_memset(buf, 0, sizeof(CRYPTO_BUFFER));
178
179 buf->data = OPENSSL_malloc(len);
180 if (len != 0 && buf->data == NULL) {
181 OPENSSL_free(buf);
182 return NULL;
183 }
184 buf->len = len;
185 buf->references = 1;
186
187 *out_data = buf->data;
188 return buf;
189 }
190
CRYPTO_BUFFER_new_from_CBS(const CBS * cbs,CRYPTO_BUFFER_POOL * pool)191 CRYPTO_BUFFER *CRYPTO_BUFFER_new_from_CBS(const CBS *cbs,
192 CRYPTO_BUFFER_POOL *pool) {
193 return CRYPTO_BUFFER_new(CBS_data(cbs), CBS_len(cbs), pool);
194 }
195
CRYPTO_BUFFER_new_from_static_data_unsafe(const uint8_t * data,size_t len,CRYPTO_BUFFER_POOL * pool)196 CRYPTO_BUFFER *CRYPTO_BUFFER_new_from_static_data_unsafe(
197 const uint8_t *data, size_t len, CRYPTO_BUFFER_POOL *pool) {
198 return crypto_buffer_new(data, len, /*data_is_static=*/1, pool);
199 }
200
CRYPTO_BUFFER_free(CRYPTO_BUFFER * buf)201 void CRYPTO_BUFFER_free(CRYPTO_BUFFER *buf) {
202 if (buf == NULL) {
203 return;
204 }
205
206 CRYPTO_BUFFER_POOL *const pool = buf->pool;
207 if (pool == NULL) {
208 if (CRYPTO_refcount_dec_and_test_zero(&buf->references)) {
209 // If a reference count of zero is observed, there cannot be a reference
210 // from any pool to this buffer and thus we are able to free this
211 // buffer.
212 crypto_buffer_free_object(buf);
213 }
214
215 return;
216 }
217
218 CRYPTO_MUTEX_lock_write(&pool->lock);
219 if (!CRYPTO_refcount_dec_and_test_zero(&buf->references)) {
220 CRYPTO_MUTEX_unlock_write(&buf->pool->lock);
221 return;
222 }
223
224 // We have an exclusive lock on the pool, therefore no concurrent lookups can
225 // find this buffer and increment the reference count. Thus, if the count is
226 // zero there are and can never be any more references and thus we can free
227 // this buffer.
228 //
229 // Note it is possible |buf| is no longer in the pool, if it was replaced by a
230 // static version. If that static version was since removed, it is even
231 // possible for |found| to be NULL.
232 CRYPTO_BUFFER *found = lh_CRYPTO_BUFFER_retrieve(pool->bufs, buf);
233 if (found == buf) {
234 found = lh_CRYPTO_BUFFER_delete(pool->bufs, buf);
235 assert(found == buf);
236 (void)found;
237 }
238
239 CRYPTO_MUTEX_unlock_write(&buf->pool->lock);
240 crypto_buffer_free_object(buf);
241 }
242
CRYPTO_BUFFER_up_ref(CRYPTO_BUFFER * buf)243 int CRYPTO_BUFFER_up_ref(CRYPTO_BUFFER *buf) {
244 // This is safe in the case that |buf->pool| is NULL because it's just
245 // standard reference counting in that case.
246 //
247 // This is also safe if |buf->pool| is non-NULL because, if it were racing
248 // with |CRYPTO_BUFFER_free| then the two callers must have independent
249 // references already and so the reference count will never hit zero.
250 CRYPTO_refcount_inc(&buf->references);
251 return 1;
252 }
253
CRYPTO_BUFFER_data(const CRYPTO_BUFFER * buf)254 const uint8_t *CRYPTO_BUFFER_data(const CRYPTO_BUFFER *buf) {
255 return buf->data;
256 }
257
CRYPTO_BUFFER_len(const CRYPTO_BUFFER * buf)258 size_t CRYPTO_BUFFER_len(const CRYPTO_BUFFER *buf) {
259 return buf->len;
260 }
261
CRYPTO_BUFFER_init_CBS(const CRYPTO_BUFFER * buf,CBS * out)262 void CRYPTO_BUFFER_init_CBS(const CRYPTO_BUFFER *buf, CBS *out) {
263 CBS_init(out, buf->data, buf->len);
264 }
265