From c77d0333c6e6b47ae5dc4d70c3d2b966ff206f6b Mon Sep 17 00:00:00 2001 From: "Matthew A. Miller" Date: Sun, 3 Apr 2016 11:01:52 -0300 Subject: [PATCH] Support custom memory allocation --- include/Makefile.am | 1 + include/Makefile.in | 1 + include/cjose/util.h | 87 +++++++++++++++++++++++++++++++++++++ src/Makefile.am | 1 + src/Makefile.in | 15 +++++-- src/base64.c | 13 +++--- src/jwe.c | 41 ++++++++++-------- src/jwk.c | 101 ++++++++++++++++++++++--------------------- src/jws.c | 36 ++++++++------- src/util.c | 50 +++++++++++++++++++++ test/Makefile.am | 1 + test/Makefile.in | 21 ++++++++- test/check_cjose.c | 1 + test/check_cjose.h | 2 +- test/check_util.c | 50 +++++++++++++++++++++ 15 files changed, 324 insertions(+), 97 deletions(-) create mode 100644 include/cjose/util.h create mode 100644 src/util.c create mode 100644 test/check_util.c diff --git a/include/Makefile.am b/include/Makefile.am index 5edccd7..77bb691 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -5,4 +5,5 @@ nobase_include_HEADERS = cjose/cjose.h \ cjose/jws.h \ cjose/header.h \ cjose/error.h \ + cjose/util.h \ cjose/version.h diff --git a/include/Makefile.in b/include/Makefile.in index 06d07fa..83f366e 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -321,6 +321,7 @@ nobase_include_HEADERS = cjose/cjose.h \ cjose/jws.h \ cjose/header.h \ cjose/error.h \ + cjose/util.h \ cjose/version.h all: all-am diff --git a/include/cjose/util.h b/include/cjose/util.h new file mode 100644 index 0000000..4749dd6 --- /dev/null +++ b/include/cjose/util.h @@ -0,0 +1,87 @@ +/* + * Copyrights + * + * Portions created or assigned to Cisco Systems, Inc. are + * Copyright (c) 2014-2016 Cisco Systems, Inc. All Rights Reserved. + */ + +/** + * \file util.h + * \brief Utility functions and data structures for CJOSE. + * + */ + +#ifndef CJOSE_UTIL_H +#define CJOSE_UTIL_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * Typedef for memory allocator function. + */ +typedef void *(* cjose_alloc_fn_t)(size_t); + +/** + * Typedef for memory reallocator function. + */ +typedef void *(* cjose_realloc_fn_t)(void *, size_t); + +/** + * Typedef for memory deallocator function. + */ +typedef void (* cjose_dealloc_fn_t)(void *); + +/** + * Sets the allocator and deallocator functions. + * + * If alloc is NULL, any previously set allocator function is clared + * and the the default allocator malloc() + * is used. + * + * If dealloc is NULL, the default dallocator free() + * is used. + * + * \param alloc [in] The custom allocator function to use. + * \param realloc [in] The custom reallocator function to use. + * \param dealloc [in] The custom deallocator function to use. + */ +void cjose_set_alloc_funcs(cjose_alloc_fn_t alloc, + cjose_realloc_fn_t realloc, + cjose_dealloc_fn_t dealloc); + + +/** + * Retrieves the configured allocator function. If an allocator function is + * not set, this function returns a pointer to malloc(). + * + * \returns The configured allocator function + */ +cjose_alloc_fn_t cjose_get_alloc(); + +/** + * Retrieve the configured reallocator function. If a reallocator function is + * not set, this function retursn a pointer to realloc. + * + * \returns The configured reallocator function + */ +cjose_realloc_fn_t cjose_get_realloc(); + +/** + * Retrieves the configured deallocator function. If a deallocator function is + * not set, this function returns a pointer to free(). + * + * \returns The configured deallocator function + */ +cjose_dealloc_fn_t cjose_get_dealloc(); + +#ifdef __cplusplus +} +#endif + +#endif // CJOSE_UTIL_H diff --git a/src/Makefile.am b/src/Makefile.am index b25e673..000b906 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,6 +3,7 @@ AM_CFLAGS =-std=gnu99 --pedantic -Wall -Werror -g -O2 -I$(top_builddir)/include lib_LTLIBRARIES=libcjose.la libcjose_la_CPPFLAGS= -I$(topdir)/include libcjose_la_SOURCES=version.c \ + util.c \ base64.c \ jwk.c \ jwe.c \ diff --git a/src/Makefile.in b/src/Makefile.in index b717e77..ce601da 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -130,9 +130,9 @@ am__uninstall_files_from_dir = { \ am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libcjose_la_LIBADD = -am_libcjose_la_OBJECTS = libcjose_la-version.lo libcjose_la-base64.lo \ - libcjose_la-jwk.lo libcjose_la-jwe.lo libcjose_la-jws.lo \ - libcjose_la-header.lo libcjose_la-error.lo +am_libcjose_la_OBJECTS = libcjose_la-version.lo libcjose_la-util.lo \ + libcjose_la-base64.lo libcjose_la-jwk.lo libcjose_la-jwe.lo \ + libcjose_la-jws.lo libcjose_la-header.lo libcjose_la-error.lo libcjose_la_OBJECTS = $(am_libcjose_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -348,6 +348,7 @@ AM_CFLAGS = -std=gnu99 --pedantic -Wall -Werror -g -O2 -I$(top_builddir)/include lib_LTLIBRARIES = libcjose.la libcjose_la_CPPFLAGS = -I$(topdir)/include libcjose_la_SOURCES = version.c \ + util.c \ base64.c \ jwk.c \ jwe.c \ @@ -443,6 +444,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcjose_la-jwe.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcjose_la-jwk.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcjose_la-jws.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcjose_la-util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcjose_la-version.Plo@am__quote@ .c.o: @@ -473,6 +475,13 @@ libcjose_la-version.lo: version.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcjose_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcjose_la-version.lo `test -f 'version.c' || echo '$(srcdir)/'`version.c +libcjose_la-util.lo: util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcjose_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcjose_la-util.lo -MD -MP -MF $(DEPDIR)/libcjose_la-util.Tpo -c -o libcjose_la-util.lo `test -f 'util.c' || echo '$(srcdir)/'`util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcjose_la-util.Tpo $(DEPDIR)/libcjose_la-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util.c' object='libcjose_la-util.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcjose_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcjose_la-util.lo `test -f 'util.c' || echo '$(srcdir)/'`util.c + libcjose_la-base64.lo: base64.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcjose_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcjose_la-base64.lo -MD -MP -MF $(DEPDIR)/libcjose_la-base64.Tpo -c -o libcjose_la-base64.lo `test -f 'base64.c' || echo '$(srcdir)/'`base64.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcjose_la-base64.Tpo $(DEPDIR)/libcjose_la-base64.Plo diff --git a/src/base64.c b/src/base64.c index ca3ced0..fbedea8 100644 --- a/src/base64.c +++ b/src/base64.c @@ -6,6 +6,7 @@ */ #include +#include #include #include @@ -73,7 +74,7 @@ static inline bool _decode(const char *input, size_t inlen, // return empty string on 0 length input if (0 == inlen) { - uint8_t *retVal = (uint8_t *)malloc(sizeof(uint8_t)); + uint8_t *retVal = (uint8_t *)cjose_get_alloc()(sizeof(uint8_t)); if (NULL == retVal) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -96,7 +97,7 @@ static inline bool _decode(const char *input, size_t inlen, // rlen takes a best guess on size; // might be too large for base64url, but never too small. size_t rlen = ((inlen * 3) >> 2) + 3; - uint8_t *buffer = malloc(sizeof(uint8_t) * rlen); + uint8_t *buffer = cjose_get_alloc()(sizeof(uint8_t) * rlen); if (NULL == buffer) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -130,7 +131,7 @@ static inline bool _decode(const char *input, size_t inlen, if (0xff == val) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); - free(buffer); + cjose_get_dealloc()(buffer); return false; } idx++; @@ -168,7 +169,7 @@ static inline bool _decode(const char *input, size_t inlen, b64_decode_failed: if (NULL != buffer) { - free(buffer); + cjose_get_dealloc()(buffer); } return false; } @@ -186,7 +187,7 @@ static inline bool _encode(const uint8_t *input, size_t inlen, // return empty string on 0 length input if (!inlen) { - char * retVal = (char *)malloc(sizeof(char)); + char * retVal = (char *)cjose_get_alloc()(sizeof(char)); if (!retVal) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -202,7 +203,7 @@ static inline bool _encode(const uint8_t *input, size_t inlen, size_t rlen = (((inlen + 2) / 3) << 2); char *base; - base = (char *)malloc(sizeof(char) * (rlen+1)); + base = (char *)cjose_get_alloc()(sizeof(char) * (rlen+1)); if (NULL == base) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); diff --git a/src/jwe.c b/src/jwe.c index c238578..fe44822 100644 --- a/src/jwe.c +++ b/src/jwe.c @@ -5,15 +5,18 @@ * Copyright (c) 2014-2016 Cisco Systems, Inc. All Rights Reserved. */ +#include +#include +#include +#include + #include #include #include #include #include #include -#include "cjose/jwe.h" -#include "cjose/header.h" -#include "cjose/base64.h" + #include "include/header_int.h" #include "include/jwk_int.h" #include "include/jwe_int.h" @@ -66,7 +69,7 @@ static bool _cjose_jwe_malloc( uint8_t **buffer, cjose_err *err) { - *buffer = (uint8_t *)malloc(bytes); + *buffer = (uint8_t *)cjose_get_alloc()(bytes); if (NULL == *buffer) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -108,11 +111,11 @@ static bool _cjose_jwe_build_hdr( if (NULL == jwe->part[0].raw) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); - free(hdr_str); + cjose_get_dealloc()(hdr_str); return false; } jwe->part[0].raw_len = strlen(hdr_str); - free(hdr_str); + cjose_get_dealloc()(hdr_str); return true; } @@ -189,7 +192,7 @@ static bool _cjose_jwe_set_cek_a256gcm( // if no JWK is provided, generate a random key if (NULL == jwk) { - free(jwe->cek); + cjose_get_dealloc()(jwe->cek); if (!_cjose_jwe_malloc(keysize, true, &jwe->cek, err)) { return false; @@ -208,7 +211,7 @@ static bool _cjose_jwe_set_cek_a256gcm( } // copy the key material directly from jwk to the jwe->cek - free(jwe->cek); + cjose_get_dealloc()(jwe->cek); if (!_cjose_jwe_malloc(keysize, false, &jwe->cek, err)) { return false; @@ -286,7 +289,7 @@ static bool _cjose_jwe_encrypt_ek_rsa_oaep( } // allocate memory for RSA encryption - free(jwe->part[1].raw); + cjose_get_dealloc()(jwe->part[1].raw); if (!_cjose_jwe_malloc(jwe->part[1].raw_len, false, &jwe->part[1].raw, err)) { return false; @@ -325,7 +328,7 @@ static bool _cjose_jwe_decrypt_ek_rsa_oaep( } // we don't know the size of the key to expect, but must be < RSA_size - free(jwe->cek); + cjose_get_dealloc()(jwe->cek); size_t buflen = RSA_size((RSA *)jwk->keydata); if (!_cjose_jwe_malloc(buflen, false, &jwe->cek, err)) { @@ -352,7 +355,7 @@ static bool _cjose_jwe_set_iv_a256gcm( cjose_err *err) { // generate IV as random 96 bit value - free(jwe->part[2].raw); + cjose_get_dealloc()(jwe->part[2].raw); jwe->part[2].raw_len = 12; if (!_cjose_jwe_malloc(jwe->part[2].raw_len, true, &jwe->part[2].raw, err)) { @@ -423,7 +426,7 @@ static bool _cjose_jwe_encrypt_dat_a256gcm( } // allocate buffer for the ciphertext - free(jwe->part[3].raw); + cjose_get_dealloc()(jwe->part[3].raw); jwe->part[3].raw_len = plaintext_len; if (!_cjose_jwe_malloc(jwe->part[3].raw_len, false, &jwe->part[3].raw, err)) { @@ -448,7 +451,7 @@ static bool _cjose_jwe_encrypt_dat_a256gcm( } // allocate buffer for the authentication tag - free(jwe->part[4].raw); + cjose_get_dealloc()(jwe->part[4].raw); jwe->part[4].raw_len = 16; if (!_cjose_jwe_malloc(jwe->part[4].raw_len, false, &jwe->part[4].raw, err)) { @@ -527,7 +530,7 @@ static bool _cjose_jwe_decrypt_dat_a256gcm( } // allocate buffer for the plaintext - free(jwe->dat); + cjose_get_dealloc()(jwe->dat); jwe->dat_len = jwe->part[3].raw_len; if (!_cjose_jwe_malloc(jwe->dat_len, false, &jwe->dat, err)) { @@ -644,12 +647,12 @@ void cjose_jwe_release( } for (int i = 0; i < 5; ++i) { - free(jwe->part[i].raw); - free(jwe->part[i].b64u); + cjose_get_dealloc()(jwe->part[i].raw); + cjose_get_dealloc()(jwe->part[i].b64u); } - free(jwe->cek); - free(jwe->dat); - free(jwe); + cjose_get_dealloc()(jwe->cek); + cjose_get_dealloc()(jwe->dat); + cjose_get_dealloc()(jwe); } diff --git a/src/jwk.c b/src/jwk.c index ac46704..d97457c 100644 --- a/src/jwk.c +++ b/src/jwk.c @@ -8,6 +8,7 @@ #include "include/jwk_int.h" #include +#include #include #include @@ -91,7 +92,7 @@ bool cjose_jwk_release(cjose_jwk_t *jwk) --(jwk->retained); if (0 == jwk->retained) { - free(jwk->kid); + cjose_get_dealloc()(jwk->kid); jwk->kid = NULL; // assumes freefunc is set @@ -138,9 +139,9 @@ bool cjose_jwk_set_kid( } if (jwk->kid) { - free(jwk->kid); + cjose_get_dealloc()(jwk->kid); } - jwk->kid = (char *)malloc(len+1); + jwk->kid = (char *)cjose_get_alloc()(len+1); if (!jwk->kid) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -216,7 +217,7 @@ char *cjose_jwk_to_json(const cjose_jwk_t *jwk, bool priv, cjose_err *err) goto to_json_cleanup; } result = strdup(str_jwk); - free(str_jwk); + cjose_get_dealloc()(str_jwk); to_json_cleanup: if (json) @@ -250,7 +251,7 @@ static const key_fntable OCT_FNTABLE = { static cjose_jwk_t *_oct_new(uint8_t *buffer, size_t keysize, cjose_err *err) { - cjose_jwk_t *jwk = (cjose_jwk_t *)malloc(sizeof(cjose_jwk_t)); + cjose_jwk_t *jwk = (cjose_jwk_t *)cjose_get_alloc()(sizeof(cjose_jwk_t)); if (NULL == jwk) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -274,9 +275,9 @@ static void _oct_free(cjose_jwk_t *jwk) jwk->keydata = NULL; if (buffer) { - free(buffer); + cjose_get_dealloc()(buffer); } - free(jwk); + cjose_get_dealloc()(jwk); } static bool _oct_public_fields( @@ -300,7 +301,7 @@ static bool _oct_private_fields( } field = json_stringn(k, klen); - free(k); + cjose_get_dealloc()(k); k = NULL; if (!field) { @@ -328,7 +329,7 @@ cjose_jwk_t *cjose_jwk_create_oct_random(size_t keysize, cjose_err *err) // resize to bytes size_t buffersize = sizeof(uint8_t) * (keysize / 8); - buffer = (uint8_t *)malloc(buffersize); + buffer = (uint8_t *)cjose_get_alloc()(buffersize); if (NULL == buffer) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -349,7 +350,7 @@ cjose_jwk_t *cjose_jwk_create_oct_random(size_t keysize, cjose_err *err) create_oct_failed: if (buffer) { - free(buffer); + cjose_get_dealloc()(buffer); buffer = NULL; } @@ -368,7 +369,7 @@ cjose_jwk_t * cjose_jwk_create_oct_spec( goto create_oct_failed; } - buffer = (uint8_t *)malloc(len); + buffer = (uint8_t *)cjose_get_alloc()(len); if (!buffer) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -387,7 +388,7 @@ cjose_jwk_t * cjose_jwk_create_oct_spec( create_oct_failed: if (buffer) { - free(buffer); + cjose_get_dealloc()(buffer); buffer = NULL; } @@ -489,7 +490,7 @@ static inline bool _kty_from_name( static cjose_jwk_t *_EC_new(cjose_jwk_ec_curve crv, EC_KEY *ec, cjose_err *err) { - ec_keydata *keydata = malloc(sizeof(ec_keydata)); + ec_keydata *keydata = cjose_get_alloc()(sizeof(ec_keydata)); if (!keydata) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -498,11 +499,11 @@ static cjose_jwk_t *_EC_new(cjose_jwk_ec_curve crv, EC_KEY *ec, cjose_err *err) keydata->crv = crv; keydata->key = ec; - cjose_jwk_t *jwk = malloc(sizeof(cjose_jwk_t)); + cjose_jwk_t *jwk = cjose_get_alloc()(sizeof(cjose_jwk_t)); if (!jwk) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); - free(keydata); + cjose_get_dealloc()(keydata); return NULL; } memset(jwk, 0, sizeof(cjose_jwk_t)); @@ -538,9 +539,9 @@ static void _EC_free(cjose_jwk_t *jwk) { EC_KEY_free(ec); } - free(keydata); + cjose_get_dealloc()(keydata); } - free(jwk); + cjose_get_dealloc()(jwk); } static bool _EC_public_fields( @@ -581,7 +582,7 @@ static bool _EC_public_fields( goto _ec_to_string_cleanup; } - buffer = malloc(numsize); + buffer = cjose_get_alloc()(numsize); bnX = BN_new(); bnY = BN_new(); if (!buffer || !bnX || !bnY) @@ -612,7 +613,7 @@ static bool _EC_public_fields( json_object_set(json, "x", field); json_decref(field); field = NULL; - free(b64u); + cjose_get_dealloc()(b64u); b64u = NULL; // output the y coordinate @@ -632,7 +633,7 @@ static bool _EC_public_fields( json_object_set(json, "y", field); json_decref(field); field = NULL; - free(b64u); + cjose_get_dealloc()(b64u); b64u = NULL; result = true; @@ -652,11 +653,11 @@ static bool _EC_public_fields( } if (buffer) { - free(buffer); + cjose_get_dealloc()(buffer); } if (b64u) { - free(b64u); + cjose_get_dealloc()(b64u); } return result; @@ -682,7 +683,7 @@ static bool _EC_private_fields( return true; } - buffer = malloc(numsize); + buffer = cjose_get_alloc()(numsize); if (!buffer) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -705,7 +706,7 @@ static bool _EC_private_fields( json_object_set(json, "d", field); json_decref(field); field = NULL; - free(b64u); + cjose_get_dealloc()(b64u); b64u = NULL; result = true; @@ -713,7 +714,7 @@ static bool _EC_private_fields( _ec_to_string_cleanup: if (buffer) { - free(buffer); + cjose_get_dealloc()(buffer); } return result; @@ -750,7 +751,7 @@ cjose_jwk_t *cjose_jwk_create_EC_random(cjose_jwk_ec_curve crv, cjose_err *err) create_EC_failed: if (jwk) { - free(jwk); + cjose_get_dealloc()(jwk); jwk = NULL; } if (ec) @@ -877,7 +878,7 @@ cjose_jwk_t *cjose_jwk_create_EC_spec( create_EC_failed: if (jwk) { - free(jwk); + cjose_get_dealloc()(jwk); jwk = NULL; } if (ec) @@ -928,7 +929,7 @@ static const key_fntable RSA_FNTABLE = { static inline cjose_jwk_t *_RSA_new(RSA *rsa, cjose_err *err) { - cjose_jwk_t *jwk = malloc(sizeof(cjose_jwk_t)); + cjose_jwk_t *jwk = cjose_get_alloc()(sizeof(cjose_jwk_t)); if (!jwk) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -952,7 +953,7 @@ static void _RSA_free(cjose_jwk_t *jwk) { RSA_free(rsa); } - free(jwk); + cjose_get_dealloc()(jwk); } static inline bool _RSA_json_field( @@ -971,7 +972,7 @@ static inline bool _RSA_json_field( } datalen = BN_num_bytes(param); - data = malloc(sizeof(uint8_t) * datalen); + data = cjose_get_alloc()(sizeof(uint8_t) * datalen); if (!data) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -996,12 +997,12 @@ static inline bool _RSA_json_field( RSA_json_field_cleanup: if (b64u) { - free(b64u); + cjose_get_dealloc()(b64u); b64u = NULL; } if (data) { - free(data); + cjose_get_dealloc()(data); data = NULL; } @@ -1355,15 +1356,15 @@ static cjose_jwk_t *_cjose_jwk_import_EC(json_t *jwk_json, cjose_err *err) import_EC_cleanup: if (NULL != x_buffer) { - free(x_buffer); + cjose_get_dealloc()(x_buffer); } if (NULL != y_buffer) { - free(y_buffer); + cjose_get_dealloc()(y_buffer); } if (NULL != d_buffer) { - free(d_buffer); + cjose_get_dealloc()(d_buffer); } return jwk; @@ -1477,14 +1478,14 @@ static cjose_jwk_t *_cjose_jwk_import_RSA(json_t *jwk_json, cjose_err *err) jwk = cjose_jwk_create_RSA_spec(&rsa_keyspec, err); import_RSA_cleanup: - free(n_buffer); - free(e_buffer); - free(d_buffer); - free(p_buffer); - free(q_buffer); - free(dp_buffer); - free(dq_buffer); - free(qi_buffer); + cjose_get_dealloc()(n_buffer); + cjose_get_dealloc()(e_buffer); + cjose_get_dealloc()(d_buffer); + cjose_get_dealloc()(p_buffer); + cjose_get_dealloc()(q_buffer); + cjose_get_dealloc()(dp_buffer); + cjose_get_dealloc()(dq_buffer); + cjose_get_dealloc()(qi_buffer); return jwk; } @@ -1509,7 +1510,7 @@ static cjose_jwk_t *_cjose_jwk_import_oct(json_t *jwk_json, cjose_err *err) import_oct_cleanup: if (NULL != k_buffer) { - free(k_buffer); + cjose_get_dealloc()(k_buffer); } return jwk; @@ -1704,7 +1705,7 @@ cjose_jwk_t *cjose_jwk_derive_ecdh_ephemeral_key( } // allocate buffer for shared secret - secret = (uint8_t *)malloc(secret_len); + secret = (uint8_t *)cjose_get_alloc()(secret_len); if (NULL == secret) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -1721,7 +1722,7 @@ cjose_jwk_t *cjose_jwk_derive_ecdh_ephemeral_key( // HKDF of the DH shared secret (SHA256, no salt, no info, 256 bit expand) ephemeral_key_len = 32; - ephemeral_key = (uint8_t *)malloc(ephemeral_key_len); + ephemeral_key = (uint8_t *)cjose_get_alloc()(ephemeral_key_len); if (!cjose_jwk_hkdf(EVP_sha256(), (uint8_t *)"", 0, (uint8_t *)"", 0, secret, secret_len, ephemeral_key, ephemeral_key_len, err)) { @@ -1740,8 +1741,8 @@ cjose_jwk_t *cjose_jwk_derive_ecdh_ephemeral_key( EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey_self); EVP_PKEY_free(pkey_peer); - free(secret); - free(ephemeral_key); + cjose_get_dealloc()(secret); + cjose_get_dealloc()(ephemeral_key); return jwk_ephemeral_key; @@ -1764,8 +1765,8 @@ cjose_jwk_t *cjose_jwk_derive_ecdh_ephemeral_key( { cjose_jwk_release(jwk_ephemeral_key); } - free(secret); - free(ephemeral_key); + cjose_get_dealloc()(secret); + cjose_get_dealloc()(ephemeral_key); return NULL; } diff --git a/src/jws.c b/src/jws.c index 976ffb5..31d7a14 100644 --- a/src/jws.c +++ b/src/jws.c @@ -5,18 +5,22 @@ * Copyright (c) 2014-2016 Cisco Systems, Inc. All Rights Reserved. */ + +#include +#include +#include +#include +#include + #include #include #include #include #include -#include "cjose/base64.h" -#include "cjose/jws.h" -#include "include/jws_int.h" -#include "cjose/jwk.h" + #include "include/jwk_int.h" -#include "cjose/header.h" #include "include/header_int.h" +#include "include/jws_int.h" //////////////////////////////////////////////////////////////////////////////// @@ -120,7 +124,7 @@ static bool _cjose_jws_build_dat( { // copy plaintext data jws->dat_len = plaintext_len; - jws->dat = (uint8_t *)malloc(jws->dat_len); + jws->dat = (uint8_t *)cjose_get_alloc()(jws->dat_len); if (NULL == jws->dat) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -158,7 +162,7 @@ static bool _cjose_jws_build_dig_sha256( // allocate buffer for digest jws->dig_len = digest_alg->md_size; - jws->dig = (uint8_t *)malloc(jws->dig_len); + jws->dig = (uint8_t *)cjose_get_alloc()(jws->dig_len); if (NULL == jws->dig) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -242,7 +246,7 @@ static bool _cjose_jws_build_sig_ps256( // apply EMSA-PSS encoding (RFC-3447, 8.1.1, step 1) // (RSA_padding_add_PKCS1_PSS includes PKCS1_MGF1, -1 => saltlen = hashlen) em_len = RSA_size((RSA *)jwk->keydata); - em = (uint8_t *)malloc(em_len); + em = (uint8_t *)cjose_get_alloc()(em_len); if (NULL == em) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -257,7 +261,7 @@ static bool _cjose_jws_build_sig_ps256( // sign the digest (RFC-3447, 8.1.1, step 2) jws->sig_len = em_len; - jws->sig = (uint8_t *)malloc(jws->sig_len); + jws->sig = (uint8_t *)cjose_get_alloc()(jws->sig_len); if (NULL == jws->sig) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -303,7 +307,7 @@ static bool _cjose_jws_build_sig_rs256( // allocate buffer for signature jws->sig_len = RSA_size((RSA *)jwk->keydata); - jws->sig = (uint8_t *)malloc(jws->sig_len); + jws->sig = (uint8_t *)cjose_get_alloc()(jws->sig_len); if (NULL == jws->sig) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -349,7 +353,7 @@ static bool _cjose_jws_build_cser( // allocate buffer for compact serialization assert(NULL == jws->cser); - jws->cser = (char *)malloc(jws->cser_len); + jws->cser = (char *)cjose_get_alloc()(jws->cser_len); if (NULL == jws->cser) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -381,7 +385,7 @@ cjose_jws_t *cjose_jws_sign( } // allocate and initialize JWS - jws = (cjose_jws_t *)malloc(sizeof(cjose_jws_t)); + jws = (cjose_jws_t *)cjose_get_alloc()(sizeof(cjose_jws_t)); if (NULL == jws) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -488,7 +492,7 @@ static bool _cjose_jws_strcpy( int len, cjose_err *err) { - *dst = (char *)malloc(len + 1); + *dst = (char *)cjose_get_alloc()(len + 1); if (NULL == dst) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); @@ -518,7 +522,7 @@ cjose_jws_t *cjose_jws_import( } // allocate and initialize a new JWS object - jws = (cjose_jws_t *)malloc(sizeof(cjose_jws_t)); + jws = (cjose_jws_t *)cjose_get_alloc()(sizeof(cjose_jws_t)); if (NULL == jws) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); @@ -626,7 +630,7 @@ static bool _cjose_jws_verify_sig_ps256( // allocate buffer for encoded message em_len = RSA_size((RSA *)jwk->keydata); - em = (uint8_t *)malloc(em_len); + em = (uint8_t *)cjose_get_alloc()(em_len); if (NULL == em) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); @@ -691,7 +695,7 @@ static bool _cjose_jws_verify_sig_rs256( // allocate buffer for decrypted digest dig_len = RSA_size((RSA *)jwk->keydata); - dig = (uint8_t *)malloc(dig_len); + dig = (uint8_t *)cjose_get_alloc()(dig_len); if (NULL == dig) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..19920b1 --- /dev/null +++ b/src/util.c @@ -0,0 +1,50 @@ + /*! + * Copyrights + * + * Portions created or assigned to Cisco Systems, Inc. are + * Copyright (c) 2014-2016 Cisco Systems, Inc. All Rights Reserved. + */ + +#include + +#include +#include +#include + +static cjose_alloc_fn_t _alloc; +static cjose_realloc_fn_t _realloc; +static cjose_dealloc_fn_t _dealloc; + +void cjose_set_alloc_funcs(cjose_alloc_fn_t alloc, + cjose_realloc_fn_t realloc, + cjose_dealloc_fn_t dealloc) +{ + // save "locally" + _alloc = alloc; + _realloc = realloc; + _dealloc = dealloc; + // set upstream + json_set_alloc_funcs(_alloc, _dealloc); + CRYPTO_set_mem_functions(_alloc, _realloc, _dealloc); +} + +cjose_alloc_fn_t cjose_get_alloc() +{ + return (!_alloc) ? + malloc : + _alloc; +} + +cjose_realloc_fn_t cjose_get_realloc() +{ + return (!_realloc) ? + realloc : + _realloc; +} + +cjose_dealloc_fn_t cjose_get_dealloc() +{ + return (!_dealloc) ? + free : + _dealloc; +} diff --git a/test/Makefile.am b/test/Makefile.am index cb31fbc..5b6c28e 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -11,6 +11,7 @@ check_cjose_CFLAGS = @CHECK_CFLAGS@ -I$(top_builddir)/include \ check_cjose_LDADD = $(top_builddir)/src/libcjose.la @CHECK_LIBS@ check_cjose_SOURCES = check_cjose.c \ check_version.c \ + check_util.c \ check_base64.c \ check_jwk.c \ check_jwe.c \ diff --git a/test/Makefile.in b/test/Makefile.in index 957fc14..da6ddb8 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -103,11 +103,12 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @HAVE_CHECK_TRUE@am__EXEEXT_1 = check_cjose$(EXEEXT) am__check_cjose_SOURCES_DIST = check_cjose.c check_version.c \ - check_base64.c check_jwk.c check_jwe.c check_jws.c \ - check_header.c + check_util.c check_base64.c check_jwk.c check_jwe.c \ + check_jws.c check_header.c @HAVE_CHECK_TRUE@am_check_cjose_OBJECTS = \ @HAVE_CHECK_TRUE@ check_cjose-check_cjose.$(OBJEXT) \ @HAVE_CHECK_TRUE@ check_cjose-check_version.$(OBJEXT) \ +@HAVE_CHECK_TRUE@ check_cjose-check_util.$(OBJEXT) \ @HAVE_CHECK_TRUE@ check_cjose-check_base64.$(OBJEXT) \ @HAVE_CHECK_TRUE@ check_cjose-check_jwk.$(OBJEXT) \ @HAVE_CHECK_TRUE@ check_cjose-check_jwe.$(OBJEXT) \ @@ -542,6 +543,7 @@ top_srcdir = @top_srcdir@ @HAVE_CHECK_TRUE@check_cjose_LDADD = $(top_builddir)/src/libcjose.la @CHECK_LIBS@ @HAVE_CHECK_TRUE@check_cjose_SOURCES = check_cjose.c \ @HAVE_CHECK_TRUE@ check_version.c \ +@HAVE_CHECK_TRUE@ check_util.c \ @HAVE_CHECK_TRUE@ check_base64.c \ @HAVE_CHECK_TRUE@ check_jwk.c \ @HAVE_CHECK_TRUE@ check_jwe.c \ @@ -607,6 +609,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_cjose-check_jwe.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_cjose-check_jwk.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_cjose-check_jws.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_cjose-check_util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_cjose-check_version.Po@am__quote@ .c.o: @@ -658,6 +661,20 @@ check_cjose-check_version.obj: check_version.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(check_cjose_CFLAGS) $(CFLAGS) -c -o check_cjose-check_version.obj `if test -f 'check_version.c'; then $(CYGPATH_W) 'check_version.c'; else $(CYGPATH_W) '$(srcdir)/check_version.c'; fi` +check_cjose-check_util.o: check_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(check_cjose_CFLAGS) $(CFLAGS) -MT check_cjose-check_util.o -MD -MP -MF $(DEPDIR)/check_cjose-check_util.Tpo -c -o check_cjose-check_util.o `test -f 'check_util.c' || echo '$(srcdir)/'`check_util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/check_cjose-check_util.Tpo $(DEPDIR)/check_cjose-check_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='check_util.c' object='check_cjose-check_util.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(check_cjose_CFLAGS) $(CFLAGS) -c -o check_cjose-check_util.o `test -f 'check_util.c' || echo '$(srcdir)/'`check_util.c + +check_cjose-check_util.obj: check_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(check_cjose_CFLAGS) $(CFLAGS) -MT check_cjose-check_util.obj -MD -MP -MF $(DEPDIR)/check_cjose-check_util.Tpo -c -o check_cjose-check_util.obj `if test -f 'check_util.c'; then $(CYGPATH_W) 'check_util.c'; else $(CYGPATH_W) '$(srcdir)/check_util.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/check_cjose-check_util.Tpo $(DEPDIR)/check_cjose-check_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='check_util.c' object='check_cjose-check_util.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(check_cjose_CFLAGS) $(CFLAGS) -c -o check_cjose-check_util.obj `if test -f 'check_util.c'; then $(CYGPATH_W) 'check_util.c'; else $(CYGPATH_W) '$(srcdir)/check_util.c'; fi` + check_cjose-check_base64.o: check_base64.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(check_cjose_CFLAGS) $(CFLAGS) -MT check_cjose-check_base64.o -MD -MP -MF $(DEPDIR)/check_cjose-check_base64.Tpo -c -o check_cjose-check_base64.o `test -f 'check_base64.c' || echo '$(srcdir)/'`check_base64.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/check_cjose-check_base64.Tpo $(DEPDIR)/check_cjose-check_base64.Po diff --git a/test/check_cjose.c b/test/check_cjose.c index f4c0cd7..79c21a6 100644 --- a/test/check_cjose.c +++ b/test/check_cjose.c @@ -24,6 +24,7 @@ int main() // setup suites SRunner *runner = srunner_create(cjose_suite()); srunner_add_suite(runner, cjose_version_suite()); + srunner_add_suite(runner, cjose_util_suite()); srunner_add_suite(runner, cjose_base64_suite()); srunner_add_suite(runner, cjose_jwk_suite()); srunner_add_suite(runner, cjose_jwe_suite()); diff --git a/test/check_cjose.h b/test/check_cjose.h index 13331d3..780eed0 100644 --- a/test/check_cjose.h +++ b/test/check_cjose.h @@ -10,6 +10,7 @@ #include Suite *cjose_version_suite(); +Suite *cjose_util_suite(); Suite *cjose_base64_suite(); Suite *cjose_jwk_suite(); Suite *cjose_jwe_suite(); @@ -26,4 +27,3 @@ Suite *cjose_utils_suite(); } while (0); #define ck_assert_bin_eq(X, Y, LEN) _ck_assert_bin(X, ==, Y, LEN) - diff --git a/test/check_util.c b/test/check_util.c new file mode 100644 index 0000000..3774c31 --- /dev/null +++ b/test/check_util.c @@ -0,0 +1,50 @@ + +#include "check_cjose.h" +#include +#include +#include + +static void *test_alloc(size_t amt) +{ + // TODO: verify amount requested + return malloc(amt); +} +static void *test_realloc(void *ptr, size_t amt) +{ + // TODO: verify pointer to change & amount requested + return realloc(ptr, amt); +} +static void test_dealloc(void *ptr) +{ + // TODO: verify pointer requested + free(ptr); +} + +START_TEST(test_cjose_set_allocators) +{ + ck_assert(malloc == cjose_get_alloc()); + ck_assert(realloc == cjose_get_realloc()); + ck_assert(free == cjose_get_dealloc()); + + cjose_set_alloc_funcs(test_alloc, test_realloc, test_dealloc); + ck_assert(test_alloc == cjose_get_alloc()); + ck_assert(test_realloc == cjose_get_realloc()); + ck_assert(test_dealloc == cjose_get_dealloc()); + + cjose_set_alloc_funcs(NULL, NULL, NULL); + ck_assert(malloc == cjose_get_alloc()); + ck_assert(realloc == cjose_get_realloc()); + ck_assert(free == cjose_get_dealloc()); +} +END_TEST + +Suite *cjose_util_suite() +{ + Suite *suite = suite_create("util"); + + TCase *tc_util = tcase_create("core"); + tcase_add_test(tc_util, test_cjose_set_allocators); + suite_add_tcase(suite, tc_util); + + return suite; +}