You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

201 lines
5.5 KiB

  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. #include <openssl/pool.h>
  15. #include <assert.h>
  16. #include <string.h>
  17. #include <openssl/buf.h>
  18. #include <openssl/bytestring.h>
  19. #include <openssl/mem.h>
  20. #include <openssl/thread.h>
  21. #include "../internal.h"
  22. #include "internal.h"
  23. static uint32_t CRYPTO_BUFFER_hash(const CRYPTO_BUFFER *buf) {
  24. return OPENSSL_hash32(buf->data, buf->len);
  25. }
  26. static int CRYPTO_BUFFER_cmp(const CRYPTO_BUFFER *a, const CRYPTO_BUFFER *b) {
  27. if (a->len != b->len) {
  28. return 1;
  29. }
  30. return OPENSSL_memcmp(a->data, b->data, a->len);
  31. }
  32. CRYPTO_BUFFER_POOL* CRYPTO_BUFFER_POOL_new(void) {
  33. CRYPTO_BUFFER_POOL *pool = OPENSSL_malloc(sizeof(CRYPTO_BUFFER_POOL));
  34. if (pool == NULL) {
  35. return NULL;
  36. }
  37. OPENSSL_memset(pool, 0, sizeof(CRYPTO_BUFFER_POOL));
  38. pool->bufs = lh_CRYPTO_BUFFER_new(CRYPTO_BUFFER_hash, CRYPTO_BUFFER_cmp);
  39. if (pool->bufs == NULL) {
  40. OPENSSL_free(pool);
  41. return NULL;
  42. }
  43. CRYPTO_MUTEX_init(&pool->lock);
  44. return pool;
  45. }
  46. void CRYPTO_BUFFER_POOL_free(CRYPTO_BUFFER_POOL *pool) {
  47. if (pool == NULL) {
  48. return;
  49. }
  50. #if !defined(NDEBUG)
  51. CRYPTO_MUTEX_lock_write(&pool->lock);
  52. assert(lh_CRYPTO_BUFFER_num_items(pool->bufs) == 0);
  53. CRYPTO_MUTEX_unlock_write(&pool->lock);
  54. #endif
  55. lh_CRYPTO_BUFFER_free(pool->bufs);
  56. CRYPTO_MUTEX_cleanup(&pool->lock);
  57. OPENSSL_free(pool);
  58. }
  59. CRYPTO_BUFFER *CRYPTO_BUFFER_new(const uint8_t *data, size_t len,
  60. CRYPTO_BUFFER_POOL *pool) {
  61. if (pool != NULL) {
  62. CRYPTO_BUFFER tmp;
  63. tmp.data = (uint8_t *) data;
  64. tmp.len = len;
  65. CRYPTO_MUTEX_lock_read(&pool->lock);
  66. CRYPTO_BUFFER *const duplicate =
  67. lh_CRYPTO_BUFFER_retrieve(pool->bufs, &tmp);
  68. if (duplicate != NULL) {
  69. CRYPTO_refcount_inc(&duplicate->references);
  70. }
  71. CRYPTO_MUTEX_unlock_read(&pool->lock);
  72. if (duplicate != NULL) {
  73. return duplicate;
  74. }
  75. }
  76. CRYPTO_BUFFER *const buf = OPENSSL_malloc(sizeof(CRYPTO_BUFFER));
  77. if (buf == NULL) {
  78. return NULL;
  79. }
  80. OPENSSL_memset(buf, 0, sizeof(CRYPTO_BUFFER));
  81. buf->data = BUF_memdup(data, len);
  82. if (len != 0 && buf->data == NULL) {
  83. OPENSSL_free(buf);
  84. return NULL;
  85. }
  86. buf->len = len;
  87. buf->references = 1;
  88. if (pool == NULL) {
  89. return buf;
  90. }
  91. buf->pool = pool;
  92. CRYPTO_MUTEX_lock_write(&pool->lock);
  93. CRYPTO_BUFFER *duplicate = lh_CRYPTO_BUFFER_retrieve(pool->bufs, buf);
  94. int inserted = 0;
  95. if (duplicate == NULL) {
  96. CRYPTO_BUFFER *old = NULL;
  97. inserted = lh_CRYPTO_BUFFER_insert(pool->bufs, &old, buf);
  98. assert(old == NULL);
  99. } else {
  100. CRYPTO_refcount_inc(&duplicate->references);
  101. }
  102. CRYPTO_MUTEX_unlock_write(&pool->lock);
  103. if (!inserted) {
  104. // We raced to insert |buf| into the pool and lost, or else there was an
  105. // error inserting.
  106. OPENSSL_free(buf->data);
  107. OPENSSL_free(buf);
  108. return duplicate;
  109. }
  110. return buf;
  111. }
  112. CRYPTO_BUFFER* CRYPTO_BUFFER_new_from_CBS(CBS *cbs, CRYPTO_BUFFER_POOL *pool) {
  113. return CRYPTO_BUFFER_new(CBS_data(cbs), CBS_len(cbs), pool);
  114. }
  115. void CRYPTO_BUFFER_free(CRYPTO_BUFFER *buf) {
  116. if (buf == NULL) {
  117. return;
  118. }
  119. CRYPTO_BUFFER_POOL *const pool = buf->pool;
  120. if (pool == NULL) {
  121. if (CRYPTO_refcount_dec_and_test_zero(&buf->references)) {
  122. // If a reference count of zero is observed, there cannot be a reference
  123. // from any pool to this buffer and thus we are able to free this
  124. // buffer.
  125. OPENSSL_free(buf->data);
  126. OPENSSL_free(buf);
  127. }
  128. return;
  129. }
  130. CRYPTO_MUTEX_lock_write(&pool->lock);
  131. if (!CRYPTO_refcount_dec_and_test_zero(&buf->references)) {
  132. CRYPTO_MUTEX_unlock_write(&buf->pool->lock);
  133. return;
  134. }
  135. // We have an exclusive lock on the pool, therefore no concurrent lookups can
  136. // find this buffer and increment the reference count. Thus, if the count is
  137. // zero there are and can never be any more references and thus we can free
  138. // this buffer.
  139. void *found = lh_CRYPTO_BUFFER_delete(pool->bufs, buf);
  140. assert(found != NULL);
  141. assert(found == buf);
  142. (void)found;
  143. CRYPTO_MUTEX_unlock_write(&buf->pool->lock);
  144. OPENSSL_free(buf->data);
  145. OPENSSL_free(buf);
  146. }
  147. int CRYPTO_BUFFER_up_ref(CRYPTO_BUFFER *buf) {
  148. // This is safe in the case that |buf->pool| is NULL because it's just
  149. // standard reference counting in that case.
  150. //
  151. // This is also safe if |buf->pool| is non-NULL because, if it were racing
  152. // with |CRYPTO_BUFFER_free| then the two callers must have independent
  153. // references already and so the reference count will never hit zero.
  154. CRYPTO_refcount_inc(&buf->references);
  155. return 1;
  156. }
  157. const uint8_t *CRYPTO_BUFFER_data(const CRYPTO_BUFFER *buf) {
  158. return buf->data;
  159. }
  160. size_t CRYPTO_BUFFER_len(const CRYPTO_BUFFER *buf) {
  161. return buf->len;
  162. }
  163. void CRYPTO_BUFFER_init_CBS(const CRYPTO_BUFFER *buf, CBS *out) {
  164. CBS_init(out, buf->data, buf->len);
  165. }