@ -22,12 +22,9 @@
# include <openssl/thread.h>
# include "../internal.h"
# include "../lhash/internal.h"
# include "internal.h"
DEFINE_LHASH_OF ( CRYPTO_BUFFER )
static uint32_t CRYPTO_BUFFER_hash ( const CRYPTO_BUFFER * buf ) {
return OPENSSL_hash32 ( buf - > data , buf - > len ) ;
}
@ -73,16 +70,28 @@ void CRYPTO_BUFFER_POOL_free(CRYPTO_BUFFER_POOL *pool) {
OPENSSL_free ( pool ) ;
}
CRYPTO_BUFFER * CRYPTO_BUFFER_new ( const uint8_t * data , size_t len ,
CRYPTO_BUFFER_POOL * pool ) {
static void crypto_buffer_free_object ( CRYPTO_BUFFER * buf ) {
if ( ! buf - > data_is_static ) {
OPENSSL_free ( buf - > data ) ;
}
OPENSSL_free ( buf ) ;
}
static CRYPTO_BUFFER * crypto_buffer_new ( const uint8_t * data , size_t len ,
int data_is_static ,
CRYPTO_BUFFER_POOL * pool ) {
if ( pool ! = NULL ) {
CRYPTO_BUFFER tmp ;
tmp . data = ( uint8_t * ) data ;
tmp . len = len ;
CRYPTO_MUTEX_lock_read ( & pool - > lock ) ;
CRYPTO_BUFFER * const duplicate =
lh_CRYPTO_BUFFER_retrieve ( pool - > bufs , & tmp ) ;
CRYPTO_BUFFER * duplicate = lh_CRYPTO_BUFFER_retrieve ( pool - > bufs , & tmp ) ;
if ( data_is_static & & duplicate ! = NULL & & ! duplicate - > data_is_static ) {
// If the new |CRYPTO_BUFFER| would have static data, but the duplicate
// does not, we replace the old one with the new static version.
duplicate = NULL ;
}
if ( duplicate ! = NULL ) {
CRYPTO_refcount_inc ( & duplicate - > references ) ;
}
@ -99,10 +108,15 @@ CRYPTO_BUFFER *CRYPTO_BUFFER_new(const uint8_t *data, size_t len,
}
OPENSSL_memset ( buf , 0 , sizeof ( CRYPTO_BUFFER ) ) ;
buf - > data = OPENSSL_memdup ( data , len ) ;
if ( len ! = 0 & & buf - > data = = NULL ) {
OPENSSL_free ( buf ) ;
return NULL ;
if ( data_is_static ) {
buf - > data = ( uint8_t * ) data ;
buf - > data_is_static = 1 ;
} else {
buf - > data = OPENSSL_memdup ( data , len ) ;
if ( len ! = 0 & & buf - > data = = NULL ) {
OPENSSL_free ( buf ) ;
return NULL ;
}
}
buf - > len = len ;
@ -116,11 +130,18 @@ CRYPTO_BUFFER *CRYPTO_BUFFER_new(const uint8_t *data, size_t len,
CRYPTO_MUTEX_lock_write ( & pool - > lock ) ;
CRYPTO_BUFFER * duplicate = lh_CRYPTO_BUFFER_retrieve ( pool - > bufs , buf ) ;
if ( data_is_static & & duplicate ! = NULL & & ! duplicate - > data_is_static ) {
// If the new |CRYPTO_BUFFER| would have static data, but the duplicate does
// not, we replace the old one with the new static version.
duplicate = NULL ;
}
int inserted = 0 ;
if ( duplicate = = NULL ) {
CRYPTO_BUFFER * old = NULL ;
inserted = lh_CRYPTO_BUFFER_insert ( pool - > bufs , & old , buf ) ;
assert ( old = = NULL ) ;
// |old| may be non-NULL if a match was found but ignored. |pool->bufs| does
// not increment refcounts, so there is no need to clean up after the
// replacement.
} else {
CRYPTO_refcount_inc ( & duplicate - > references ) ;
}
@ -129,14 +150,18 @@ CRYPTO_BUFFER *CRYPTO_BUFFER_new(const uint8_t *data, size_t len,
if ( ! inserted ) {
// We raced to insert |buf| into the pool and lost, or else there was an
// error inserting.
OPENSSL_free ( buf - > data ) ;
OPENSSL_free ( buf ) ;
crypto_buffer_free_object ( buf ) ;
return duplicate ;
}
return buf ;
}
CRYPTO_BUFFER * CRYPTO_BUFFER_new ( const uint8_t * data , size_t len ,
CRYPTO_BUFFER_POOL * pool ) {
return crypto_buffer_new ( data , len , /*data_is_static=*/ 0 , pool ) ;
}
CRYPTO_BUFFER * CRYPTO_BUFFER_alloc ( uint8_t * * out_data , size_t len ) {
CRYPTO_BUFFER * const buf = OPENSSL_malloc ( sizeof ( CRYPTO_BUFFER ) ) ;
if ( buf = = NULL ) {
@ -156,10 +181,16 @@ CRYPTO_BUFFER *CRYPTO_BUFFER_alloc(uint8_t **out_data, size_t len) {
return buf ;
}
CRYPTO_BUFFER * CRYPTO_BUFFER_new_from_CBS ( CBS * cbs , CRYPTO_BUFFER_POOL * pool ) {
CRYPTO_BUFFER * CRYPTO_BUFFER_new_from_CBS ( const CBS * cbs ,
CRYPTO_BUFFER_POOL * pool ) {
return CRYPTO_BUFFER_new ( CBS_data ( cbs ) , CBS_len ( cbs ) , pool ) ;
}
CRYPTO_BUFFER * CRYPTO_BUFFER_new_from_static_data_unsafe (
const uint8_t * data , size_t len , CRYPTO_BUFFER_POOL * pool ) {
return crypto_buffer_new ( data , len , /*data_is_static=*/ 1 , pool ) ;
}
void CRYPTO_BUFFER_free ( CRYPTO_BUFFER * buf ) {
if ( buf = = NULL ) {
return ;
@ -171,8 +202,7 @@ void CRYPTO_BUFFER_free(CRYPTO_BUFFER *buf) {
// If a reference count of zero is observed, there cannot be a reference
// from any pool to this buffer and thus we are able to free this
// buffer.
OPENSSL_free ( buf - > data ) ;
OPENSSL_free ( buf ) ;
crypto_buffer_free_object ( buf ) ;
}
return ;
@ -188,13 +218,19 @@ void CRYPTO_BUFFER_free(CRYPTO_BUFFER *buf) {
// find this buffer and increment the reference count. Thus, if the count is
// zero there are and can never be any more references and thus we can free
// this buffer.
void * found = lh_CRYPTO_BUFFER_delete ( pool - > bufs , buf ) ;
assert ( found ! = NULL ) ;
assert ( found = = buf ) ;
( void ) found ;
//
// Note it is possible |buf| is no longer in the pool, if it was replaced by a
// static version. If that static version was since removed, it is even
// possible for |found| to be NULL.
CRYPTO_BUFFER * found = lh_CRYPTO_BUFFER_retrieve ( pool - > bufs , buf ) ;
if ( found = = buf ) {
found = lh_CRYPTO_BUFFER_delete ( pool - > bufs , buf ) ;
assert ( found = = buf ) ;
( void ) found ;
}
CRYPTO_MUTEX_unlock_write ( & buf - > pool - > lock ) ;
OPENSSL_free ( buf - > data ) ;
OPENSSL_free ( buf ) ;
crypto_buffer_free_object ( buf ) ;
}
int CRYPTO_BUFFER_up_ref ( CRYPTO_BUFFER * buf ) {