From 9bc8a801a5160952787d4ed2fdc225eb57d471a5 Mon Sep 17 00:00:00 2001 From: "Matthew A. Miller" Date: Tue, 2 Aug 2016 11:03:34 -0600 Subject: [PATCH] Update: support OpenSSL 1.1.x (#26) In collaboration with @zandbelt --- include/cjose/util.h | 91 +++++++++++++++++++- src/include/jwk_int.h | 2 + src/include/util_int.h | 8 ++ src/jwe.c | 32 ++++--- src/jwk.c | 187 ++++++++++++++++++++++++++++------------- src/jws.c | 50 +++++++++-- src/util.c | 92 +++++++++++++++++++- test/check_jwe.c | 6 +- test/check_jwk.c | 25 +++--- test/check_jws.c | 1 + test/check_util.c | 58 +++++++++++++ 11 files changed, 448 insertions(+), 104 deletions(-) diff --git a/include/cjose/util.h b/include/cjose/util.h index 98b5aa6..ec32567 100644 --- a/include/cjose/util.h +++ b/include/cjose/util.h @@ -16,32 +16,57 @@ #include #include +#include + +#include #ifdef __cplusplus extern "C" { #endif +#define CJOSE_OPENSSL_11X OPENSSL_VERSION_NUMBER >= 0x10100005L /** - * Typedef for memory allocator function. + * Macro to explicitly mark a parameter unused, and usable across multiple + * compiler/platform environments. + */ +#define CJOSE_UNUSED_PARAM(x) (void)(x) + +/** + * Typedef for the basic memory allocator function. */ typedef void *(* cjose_alloc_fn_t)(size_t); +/** + * Typedef for the enhanced memory allocator function. + */ +typedef void *(* cjose_alloc3_fn_t)(size_t, const char *, int); /** - * Typedef for memory reallocator function. + * Typedef for the basic memory reallocator function. */ typedef void *(* cjose_realloc_fn_t)(void *, size_t); +/** + * Typedef for the enhanced memory reallocator function. + */ +typedef void *(* cjose_realloc3_fn_t)(void *, size_t, const char *, int); /** - * Typedef for memory deallocator function. + * Typedef for the basic memory deallocator function. */ typedef void (* cjose_dealloc_fn_t)(void *); +/** + * Typedef for the enhanced memory deallocator function. + */ +typedef void (* cjose_dealloc3_fn_t)(void *, const char *, int); /** * Sets the allocator and deallocator functions. * - * If alloc is NULL, any previously set allocator function is clared + * **NOTE:** This function is mutually exclusive from + * cjose_set_alloc_ex_funcs(). Both SHOULD NOT be called. + * + * If alloc is NULL, any previously set allocator function is cleared * and the the default allocator malloc() * is used. * @@ -57,6 +82,31 @@ void cjose_set_alloc_funcs(cjose_alloc_fn_t alloc, cjose_dealloc_fn_t dealloc); +/** + * Sets the enhanced allocator and deallocator functions. This function provides + * improved support for OpenSSL >= 1.1.x. + * + * **NOTE:** This function is mutually exclusive from + * cjose_set_alloc_funcs(). Both SHOULD NOT be called. + * + * If alloc3 is NULL, any previously set allocator function is cleared + * and the the default allocator malloc() + * is used. + * + * If dealloc3 is NULL, the default dallocator free() + * is used. + * + * \param alloc3 [in] The custom allocator function to use for + * OpenSSL >= 1.1.0, called with extra file/line params. + * \param realloc3 [in] The custom reallocator function to use for + * OpenSSL >= 1.1.0, called with extra file/line params. + * \param dealloc3 [in] The custom deallocator function to use for + * OpenSSL >= 1.1.0, called with extra file/line params. + */ +void cjose_set_alloc_ex_funcs(cjose_alloc3_fn_t alloc3, + cjose_realloc3_fn_t realloc3, + cjose_dealloc3_fn_t dealloc3); + /** * Retrieves the configured allocator function. If an allocator function is * not set, this function returns a pointer to malloc(). @@ -65,6 +115,16 @@ void cjose_set_alloc_funcs(cjose_alloc_fn_t alloc, */ cjose_alloc_fn_t cjose_get_alloc(); +/** + * Retrieves the configured enhanced allocator function. If an enhanced + * allocator function is not set, this function returns a pointer to an + * internally defined variant that wraps the basic allocator returned by + * cjose_get_alloc(). + * + * \returns The configured enhanced allocator function + */ +cjose_alloc3_fn_t cjose_get_alloc3(); + /** * Retrieve the configured reallocator function. If a reallocator function is * not set, this function retursn a pointer to realloc. @@ -73,6 +133,16 @@ cjose_alloc_fn_t cjose_get_alloc(); */ cjose_realloc_fn_t cjose_get_realloc(); +/** + * Retrieves the configured enhanced reallocator function. If an enhanced + * reallocator function is not set, this function returns a pointer to an + * internally defined variant that wraps the basic allocator returned by + * cjose_get_realloc(). + * + * \returns The configured enhanced allocator function + */ +cjose_realloc3_fn_t cjose_get_realloc3(); + /** * Retrieves the configured deallocator function. If a deallocator function is * not set, this function returns a pointer to free(). @@ -81,9 +151,22 @@ cjose_realloc_fn_t cjose_get_realloc(); */ cjose_dealloc_fn_t cjose_get_dealloc(); +/** + * Retrieves the configured enhanced deallocator function. If an enhanced + * deallocator function is not set, this function returns a pointer to an + * internally defined variant that wraps the basic allocator returned by + * cjose_get_dealloc(). + * + * \returns The configured enhanced allocator function + */ +cjose_dealloc3_fn_t cjose_get_dealloc3(); + /** * Compares the first n bytes of the memory areas s1 and s2 in constant time. * + * \param a [in] The first octet string to compare + * \param b [in] The second octet string to compare + * \param size [in] The length to compare * \returns an integer less than, equal to, or * greater than zero if the first n bytes of s1 is found, respectively, to * be less than, to match, or be greater than the first n bytes of s2 diff --git a/src/include/jwk_int.h b/src/include/jwk_int.h index ed62200..1171678 100644 --- a/src/include/jwk_int.h +++ b/src/include/jwk_int.h @@ -69,4 +69,6 @@ bool cjose_jwk_hkdf( unsigned int okm_len, cjose_err *err); +void _cjose_jwk_rsa_get(RSA *rsa, BIGNUM **n, BIGNUM **e, BIGNUM **d); + #endif // SRC_JWK_INT_H diff --git a/src/include/util_int.h b/src/include/util_int.h index c2815c3..c8d059c 100644 --- a/src/include/util_int.h +++ b/src/include/util_int.h @@ -16,4 +16,12 @@ char *_cjose_strndup(const char *str, ssize_t len, cjose_err *err); json_t *_cjose_json_stringn(const char *value, size_t len, cjose_err *err); +void *cjose_alloc3_default(size_t n, const char *file, int line); +void *cjose_realloc3_default(void *p, size_t n, const char *file, int line); +void cjose_dealloc3_default(void *p, const char *file, int line); + +void *cjose_alloc_wrapped(size_t n); +void *cjose_realloc_wrapped(void *p, size_t n); +void cjose_dealloc_wrapped(void *p); + #endif // SRC_UTIL_INT_H diff --git a/src/jwe.c b/src/jwe.c index bd8ef93..f00a16b 100644 --- a/src/jwe.c +++ b/src/jwe.c @@ -458,11 +458,17 @@ static bool _cjose_jwe_encrypt_ek_rsa_padding( int padding, cjose_err *err) { - // jwk must be RSA and have the necessary public parts set - if (jwk->kty != CJOSE_JWK_KTY_RSA || - NULL == jwk->keydata || - NULL == ((RSA *)jwk->keydata)->e || - NULL == ((RSA *)jwk->keydata)->n) + // jwk must be RSA + if (jwk->kty != CJOSE_JWK_KTY_RSA || NULL == jwk->keydata) + { + CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); + return false; + } + + // jwk must have the necessary public parts set + BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL; + _cjose_jwk_rsa_get((RSA *)jwk->keydata, &rsa_n, &rsa_e, &rsa_d); + if (NULL == rsa_e || NULL == rsa_n) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; @@ -642,6 +648,14 @@ static bool _cjose_jwe_set_iv_aes_cbc( } +#if (CJOSE_OPENSSL_11X) + #define CJOSE_EVP_CTRL_GCM_GET_TAG EVP_CTRL_AEAD_GET_TAG + #define CJOSE_EVP_CTRL_GCM_SET_TAG EVP_CTRL_AEAD_SET_TAG +#else + #define CJOSE_EVP_CTRL_GCM_GET_TAG EVP_CTRL_GCM_GET_TAG + #define CJOSE_EVP_CTRL_GCM_SET_TAG EVP_CTRL_GCM_SET_TAG +#endif + //////////////////////////////////////////////////////////////////////////////// static bool _cjose_jwe_encrypt_dat_a256gcm( cjose_jwe_t *jwe, @@ -735,8 +749,7 @@ static bool _cjose_jwe_encrypt_dat_a256gcm( } // get the GCM-mode authentication tag - if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, - jwe->part[4].raw_len, jwe->part[4].raw) != 1) + if (EVP_CIPHER_CTX_ctrl(ctx, CJOSE_EVP_CTRL_GCM_GET_TAG, jwe->part[4].raw_len, jwe->part[4].raw) != 1) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jwe_encrypt_dat_fail; @@ -890,7 +903,7 @@ static bool _cjose_jwe_encrypt_dat_aes_cbc( // allocate buffer for the ciphertext (plaintext + block size) cjose_get_dealloc()(jwe->part[3].raw); - jwe->part[3].raw_len = plaintext_len + cipher->block_size; + jwe->part[3].raw_len = plaintext_len + EVP_CIPHER_block_size(cipher); if (!_cjose_jwe_malloc(jwe->part[3].raw_len, false, &jwe->part[3].raw, err)) { goto _cjose_jwe_encrypt_dat_aes_cbc_fail; @@ -976,8 +989,7 @@ static bool _cjose_jwe_decrypt_dat_a256gcm( } // set the expected GCM-mode authentication tag - if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, - jwe->part[4].raw_len, jwe->part[4].raw) != 1) + if (EVP_CIPHER_CTX_ctrl(ctx, CJOSE_EVP_CTRL_GCM_SET_TAG, jwe->part[4].raw_len, jwe->part[4].raw) != 1) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jwe_decrypt_dat_a256gcm_fail; diff --git a/src/jwk.c b/src/jwk.c index 85169c1..b3a9777 100644 --- a/src/jwk.c +++ b/src/jwk.c @@ -54,6 +54,103 @@ static const char * JWK_KTY_NAMES[] = { CJOSE_JWK_KTY_OCT_STR }; +void _cjose_jwk_rsa_get(RSA *rsa, BIGNUM **rsa_n, BIGNUM **rsa_e, BIGNUM **rsa_d) +{ + if (rsa == NULL) return; +#if (CJOSE_OPENSSL_11X) + RSA_get0_key(rsa, (const BIGNUM **)rsa_n, (const BIGNUM **)rsa_e, (const BIGNUM **)rsa_d); +#else + *rsa_n=rsa->n; + *rsa_e=rsa->e; + *rsa_d=rsa->d; +#endif +} + +bool _cjose_jwk_rsa_set(RSA *rsa, uint8_t *n, size_t n_len, uint8_t *e, size_t e_len, uint8_t *d, size_t d_len) +{ + BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL; + + // RSA_set0_key doesn't work without each of those on the first call! + if ((n == NULL) || (n_len <= 0) || (e == NULL) || (e_len <= 0)) + return false; + + if (n && n_len > 0) + rsa_n = BN_bin2bn(n, n_len, NULL); + if (e && e_len > 0) + rsa_e = BN_bin2bn(e, e_len, NULL); + if (d && d_len > 0) + rsa_d = BN_bin2bn(d, d_len, NULL); + +#if (CJOSE_OPENSSL_11X) + return RSA_set0_key(rsa, rsa_n, rsa_e, rsa_d) == 1; +#else + rsa->n = rsa_n; + rsa->e = rsa_e; + rsa->d = rsa_d; + return true; +#endif +} + +void _cjose_jwk_rsa_get_factors(RSA *rsa, BIGNUM **p, BIGNUM **q) +{ +#if (CJOSE_OPENSSL_11X) + RSA_get0_factors(rsa, (const BIGNUM **)p, (const BIGNUM **)q); +#else + *p=rsa->p; + *q=rsa->q; +#endif +} + +void _cjose_jwk_rsa_set_factors(RSA *rsa, uint8_t *p, size_t p_len, uint8_t *q, size_t q_len) +{ + BIGNUM *rsa_p = NULL, *rsa_q = NULL; + + if (p && p_len > 0) + rsa_p = BN_bin2bn(p, p_len, NULL); + if (q && q_len > 0) + rsa_q = BN_bin2bn(q, q_len, NULL); + +#if (CJOSE_OPENSSL_11X) + RSA_set0_factors(rsa, rsa_p, rsa_q); +#else + rsa->p = rsa_p; + rsa->q = rsa_q; +#endif +} + +void _cjose_jwk_rsa_get_crt(RSA *rsa, BIGNUM **dmp1, BIGNUM **dmq1, BIGNUM **iqmp) +{ +#if (CJOSE_OPENSSL_11X) + RSA_get0_crt_params(rsa, (const BIGNUM **)dmp1, (const BIGNUM **)dmq1, (const BIGNUM **)iqmp); +#else + *dmp1=rsa->dmp1; + *dmq1=rsa->dmq1; + *iqmp=rsa->iqmp; +#endif +} + +void _cjose_jwk_rsa_set_crt(RSA *rsa, uint8_t *dmp1, size_t dmp1_len, uint8_t *dmq1, size_t dmq1_len, uint8_t *iqmp, size_t iqmp_len) +{ + BIGNUM *rsa_dmp1 = NULL, *rsa_dmq1 = NULL, *rsa_iqmp = NULL; + + if (dmp1 && dmp1_len > 0) + rsa_dmp1 = BN_bin2bn(dmp1, dmp1_len, NULL); + if (dmq1 && dmq1_len > 0) + rsa_dmq1 = BN_bin2bn(dmq1, dmq1_len, NULL); + if (iqmp && iqmp_len > 0) + rsa_iqmp = BN_bin2bn(iqmp, iqmp_len, NULL); + +#if (CJOSE_OPENSSL_11X) + RSA_set0_crt_params(rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp); +#else + rsa->dmp1 = rsa_dmp1; + rsa->dmq1 = rsa_dmq1; + rsa->iqmp = rsa_iqmp; +#endif +} + + + // interface functions -- Generic const char * cjose_jwk_name_for_kty(cjose_jwk_kty_t kty, cjose_err *err) @@ -1033,11 +1130,15 @@ static bool _RSA_public_fields( const cjose_jwk_t *jwk, json_t *json, cjose_err *err) { RSA *rsa = (RSA *)jwk->keydata; - if (!_RSA_json_field(rsa->e, "e", json, err)) + + BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL; + _cjose_jwk_rsa_get(rsa, &rsa_n, &rsa_e, &rsa_d); + + if (!_RSA_json_field(rsa_e, "e", json, err)) { return false; } - if (!_RSA_json_field(rsa->n, "n", json, err)) + if (!_RSA_json_field(rsa_n, "n", json, err)) { return false; } @@ -1049,27 +1150,37 @@ static bool _RSA_private_fields( const cjose_jwk_t *jwk, json_t *json, cjose_err *err) { RSA *rsa = (RSA *)jwk->keydata; - if (!_RSA_json_field(rsa->d, "d", json, err)) + + BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL; + _cjose_jwk_rsa_get(rsa, &rsa_n, &rsa_e, &rsa_d); + + BIGNUM *rsa_p = NULL, *rsa_q; + _cjose_jwk_rsa_get_factors(rsa, &rsa_p, &rsa_q); + + BIGNUM *rsa_dmp1 = NULL, *rsa_dmq1 = NULL, *rsa_iqmp = NULL; + _cjose_jwk_rsa_get_crt(rsa, &rsa_dmp1, &rsa_dmq1, &rsa_iqmp); + + if (!_RSA_json_field(rsa_d, "d", json, err)) { return false; } - if (!_RSA_json_field(rsa->p, "p", json, err)) + if (!_RSA_json_field(rsa_p, "p", json, err)) { return false; } - if (!_RSA_json_field(rsa->q, "q", json, err)) + if (!_RSA_json_field(rsa_q, "q", json, err)) { return false; } - if (!_RSA_json_field(rsa->dmp1, "dp", json, err)) + if (!_RSA_json_field(rsa_dmp1, "dp", json, err)) { return false; } - if (!_RSA_json_field(rsa->dmq1, "dq", json, err)) + if (!_RSA_json_field(rsa_dmq1, "dq", json, err)) { return false; } - if (!_RSA_json_field(rsa->iqmp, "qi", json, err)) + if (!_RSA_json_field(rsa_iqmp, "qi", json, err)) { return false; } @@ -1118,6 +1229,7 @@ cjose_jwk_t *cjose_jwk_create_RSA_random( goto create_RSA_random_failed; } + BN_free(bn); return _RSA_new(rsa, err); create_RSA_random_failed: @@ -1132,24 +1244,6 @@ cjose_jwk_t *cjose_jwk_create_RSA_random( return NULL; } -static inline bool _RSA_set_param( - BIGNUM **param, const uint8_t *data, size_t len, cjose_err *err) -{ - BIGNUM *bn = NULL; - if (NULL != data && 0 < len) - { - bn = BN_bin2bn(data, len, NULL); - if (!bn) - { - CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); - return false; - } - *param = bn; - } - - return true; -} - cjose_jwk_t *cjose_jwk_create_RSA_spec( const cjose_jwk_rsa_keyspec *spec, cjose_err *err) { @@ -1179,43 +1273,20 @@ cjose_jwk_t *cjose_jwk_create_RSA_spec( if (hasPriv) { - if (!_RSA_set_param(&rsa->n, spec->n, spec->nlen, err)) - { - goto create_RSA_spec_failed; - } - if (!_RSA_set_param(&rsa->d, spec->d, spec->dlen, err)) - { - goto create_RSA_spec_failed; - } - if (!_RSA_set_param(&rsa->p, spec->p, spec->plen, err)) - { - goto create_RSA_spec_failed; - } - if (!_RSA_set_param(&rsa->q, spec->q, spec->qlen, err)) - { - goto create_RSA_spec_failed; - } - if (!_RSA_set_param(&rsa->dmp1, spec->dp, spec->dplen, err)) - { - goto create_RSA_spec_failed; - } - if (!_RSA_set_param(&rsa->dmq1, spec->dq, spec->dqlen, err)) - { - goto create_RSA_spec_failed; - } - if (!_RSA_set_param(&rsa->iqmp, spec->qi, spec->qilen, err)) + if (!_cjose_jwk_rsa_set(rsa, spec->n, spec->nlen, spec->e, spec->elen, spec->d, spec->dlen)) { + CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); goto create_RSA_spec_failed; } + _cjose_jwk_rsa_set_factors(rsa, spec->p, spec->plen, spec->q, spec->qlen); + _cjose_jwk_rsa_set_crt(rsa, spec->dp, spec->dplen, spec->dq, spec->dqlen, spec->qi, spec->qilen); + } - if (hasPub) + else if (hasPub) { - if (!_RSA_set_param(&rsa->e, spec->e, spec->elen, err)) - { - goto create_RSA_spec_failed; - } - if (!hasPriv && !_RSA_set_param(&rsa->n, spec->n, spec->nlen, err)) + if (!_cjose_jwk_rsa_set(rsa, spec->n, spec->nlen, spec->e, spec->elen, NULL, 0)) { + CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); goto create_RSA_spec_failed; } } @@ -1563,7 +1634,7 @@ cjose_jwk_t *cjose_jwk_import(const char *jwk_str, size_t len, cjose_err *err) goto import_cleanup; } - // get kty cooresponding to kty_str (kty is required) + // get kty corresponding to kty_str (kty is required) cjose_jwk_kty_t kty; if (!_kty_from_name(kty_str, &kty, err)) { diff --git a/src/jws.c b/src/jws.c index 9dda454..4f884ee 100644 --- a/src/jws.c +++ b/src/jws.c @@ -214,7 +214,7 @@ static bool _cjose_jws_build_dig_sha( } // allocate buffer for digest - jws->dig_len = digest_alg->md_size; + jws->dig_len = EVP_MD_size(digest_alg); jws->dig = (uint8_t *)cjose_get_alloc()(jws->dig_len); if (NULL == jws->dig) { @@ -304,7 +304,7 @@ static bool _cjose_jws_build_dig_hmac_sha( } // allocate buffer for digest - jws->dig_len = digest_alg->md_size; + jws->dig_len = EVP_MD_size(digest_alg); jws->dig = (uint8_t *)cjose_get_alloc()(jws->dig_len); if (NULL == jws->dig) { @@ -313,13 +313,20 @@ static bool _cjose_jws_build_dig_hmac_sha( } // instantiate and initialize a new mac digest context +#if (CJOSE_OPENSSL_11X) + ctx = HMAC_CTX_new(); +#else ctx = cjose_get_alloc()(sizeof(HMAC_CTX)); +#endif if (NULL == ctx) { - CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); + CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); goto _cjose_jws_build_dig_hmac_sha_cleanup; } + +#if !(CJOSE_OPENSSL_11X) HMAC_CTX_init(ctx); +#endif // create digest as DIGEST(B64U(HEADER).B64U(DATA)) if (HMAC_Init_ex(ctx, jwk->keydata, jwk->keysize / 8, digest_alg, NULL) != 1) @@ -354,8 +361,12 @@ static bool _cjose_jws_build_dig_hmac_sha( _cjose_jws_build_dig_hmac_sha_cleanup: if (NULL != ctx) { +#if (CJOSE_OPENSSL_11X) + HMAC_CTX_free(ctx); +#else HMAC_CTX_cleanup(ctx); cjose_get_dealloc()(ctx); +#endif } return retval; @@ -378,7 +389,9 @@ static bool _cjose_jws_build_sig_ps( goto _cjose_jws_build_sig_ps_cleanup; } RSA *rsa = (RSA *)jwk->keydata; - if (!rsa || !rsa->e || !rsa->n || !rsa->d) + BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL; + _cjose_jwk_rsa_get(rsa, &rsa_n, &rsa_e, &rsa_d); + if (!rsa || !rsa_e || !rsa_n || !rsa_d) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; @@ -470,7 +483,9 @@ static bool _cjose_jws_build_sig_rs( return false; } RSA *rsa = (RSA *)jwk->keydata; - if (!rsa || !rsa->e || !rsa->n || !rsa->d) + BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL; + _cjose_jwk_rsa_get(rsa, &rsa_n, &rsa_e, &rsa_d); + if (!rsa || !rsa_e || !rsa_n || !rsa_d) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; @@ -605,10 +620,19 @@ static bool _cjose_jws_build_sig_ec( } memset(jws->sig, 0, jws->sig_len); - int rlen = BN_num_bytes(ecdsa_sig->r); - int slen = BN_num_bytes(ecdsa_sig->s); - BN_bn2bin(ecdsa_sig->r, jws->sig + jws->sig_len / 2 - rlen); - BN_bn2bin(ecdsa_sig->s, jws->sig + jws->sig_len - slen); + + const BIGNUM *pr, *ps; +#if (CJOSE_OPENSSL_11X) + ECDSA_SIG_get0(ecdsa_sig, &pr, &ps); +#else + pr = ecdsa_sig->r; + ps = ecdsa_sig->s; +#endif + + int rlen = BN_num_bytes(pr); + int slen = BN_num_bytes(ps); + BN_bn2bin(pr, jws->sig + jws->sig_len / 2 - rlen); + BN_bn2bin(ps, jws->sig + jws->sig_len - slen); // base64url encode signed digest if (!cjose_base64url_encode((const uint8_t *)jws->sig, jws->sig_len, @@ -1086,8 +1110,16 @@ static bool _cjose_jws_verify_sig_ec( ECDSA_SIG *ecdsa_sig = ECDSA_SIG_new(); int key_len = jws->sig_len / 2; + +#if (CJOSE_OPENSSL_11X) + BIGNUM *pr = BN_new(), *ps = BN_new(); + BN_bin2bn(jws->sig, key_len, pr); + BN_bin2bn(jws->sig + key_len, key_len, ps); + ECDSA_SIG_set0(ecdsa_sig, pr, ps); +#else BN_bin2bn(jws->sig, key_len, ecdsa_sig->r); BN_bin2bn(jws->sig + key_len, key_len, ecdsa_sig->s); +#endif if (ECDSA_do_verify(jws->dig, jws->dig_len, ecdsa_sig, ec) != 1) { diff --git a/src/util.c b/src/util.c index b782a1c..e60245b 100644 --- a/src/util.c +++ b/src/util.c @@ -17,6 +17,54 @@ static cjose_alloc_fn_t _alloc; static cjose_realloc_fn_t _realloc; static cjose_dealloc_fn_t _dealloc; +static cjose_alloc3_fn_t _alloc3; +static cjose_realloc3_fn_t _realloc3; +static cjose_dealloc3_fn_t _dealloc3; + +void *cjose_alloc_wrapped(size_t n) +{ + return cjose_get_alloc3()(n, __FILE__, __LINE__); +} +void *cjose_realloc_wrapped(void *p, size_t n) +{ + return cjose_get_realloc3()(p, n, __FILE__, __LINE__); +} +void cjose_dealloc_wrapped(void *p) +{ + cjose_get_dealloc3()(p, __FILE__, __LINE__); +} + +void *cjose_alloc3_default(size_t n, const char *file, int line) +{ + CJOSE_UNUSED_PARAM(file); + CJOSE_UNUSED_PARAM(line); + return cjose_get_alloc()(n); +} + +void *cjose_realloc3_default(void *p, size_t n, const char *file, int line) +{ + CJOSE_UNUSED_PARAM(file); + CJOSE_UNUSED_PARAM(line); + return cjose_get_realloc()(p, n); +} + +void cjose_dealloc3_default(void *p, const char *file, int line) +{ + CJOSE_UNUSED_PARAM(file); + CJOSE_UNUSED_PARAM(line); + cjose_get_dealloc()(p); +} + +static void cjose_apply_allocs() +{ + // set upstream + json_set_alloc_funcs(cjose_get_alloc(), cjose_get_dealloc()); +#if (CJOSE_OPENSSL_11X) + CRYPTO_set_mem_functions(cjose_get_alloc3(), cjose_get_realloc3(), cjose_get_dealloc3()); +#else + CRYPTO_set_mem_functions(cjose_get_alloc(), cjose_get_realloc(), cjose_get_dealloc()); +#endif +} void cjose_set_alloc_funcs(cjose_alloc_fn_t alloc, cjose_realloc_fn_t realloc, @@ -26,9 +74,29 @@ void cjose_set_alloc_funcs(cjose_alloc_fn_t alloc, _alloc = alloc; _realloc = realloc; _dealloc = dealloc; - // set upstream - json_set_alloc_funcs(_alloc, _dealloc); - CRYPTO_set_mem_functions(_alloc, _realloc, _dealloc); + _alloc3 = cjose_alloc3_default; + _realloc3 = cjose_realloc3_default; + _dealloc3 = cjose_dealloc3_default; + + cjose_apply_allocs(); +} + +void cjose_set_alloc_ex_funcs(cjose_alloc3_fn_t alloc3, + cjose_realloc3_fn_t realloc3, + cjose_dealloc3_fn_t dealloc3) +{ + // save "locally" + _alloc3 = alloc3; + _realloc3 = realloc3; + _dealloc3 = dealloc3; + _alloc = (NULL != alloc3) ? cjose_alloc_wrapped : + NULL; + _realloc = (NULL != realloc3) ? cjose_realloc_wrapped : + NULL; + _dealloc = (NULL != dealloc3) ? cjose_dealloc_wrapped : + NULL; + + cjose_apply_allocs(); } cjose_alloc_fn_t cjose_get_alloc() @@ -37,6 +105,12 @@ cjose_alloc_fn_t cjose_get_alloc() malloc : _alloc; } +cjose_alloc3_fn_t cjose_get_alloc3() +{ + return (!_alloc3) ? + cjose_alloc3_default : + _alloc3; +} cjose_realloc_fn_t cjose_get_realloc() { @@ -44,6 +118,12 @@ cjose_realloc_fn_t cjose_get_realloc() realloc : _realloc; } +cjose_realloc3_fn_t cjose_get_realloc3() +{ + return (!_realloc3) ? + cjose_realloc3_default : + _realloc3; +} cjose_dealloc_fn_t cjose_get_dealloc() { @@ -51,6 +131,12 @@ cjose_dealloc_fn_t cjose_get_dealloc() free : _dealloc; } +cjose_dealloc3_fn_t cjose_get_dealloc3() +{ + return (!_dealloc3) ? + cjose_dealloc3_default : + _dealloc3; +} int cjose_const_memcmp( const uint8_t *a, diff --git a/test/check_jwe.c b/test/check_jwe.c index b28d084..67fd653 100644 --- a/test/check_jwe.c +++ b/test/check_jwe.c @@ -341,11 +341,7 @@ START_TEST(test_cjose_jwe_encrypt_with_bad_key) // some bad keys to test with static const char *JWK_BAD[] = { - // missing public part 'e' needed for encryption - "{ \"kty\": \"RSA\", " - "\"kid\": \"9ebf9edb-3a24-48b4-b2cb-21f0cf747ea7\", " - "\"n\": \"0a5nKJLjaB1xdebYWfhvlhYhgfzkw49HAUIjyvb6fNPKhwlBQMoAS5jM3kI17_OMGrHxL7ZP00OE-24__VWDCAhOQsSvlgCvw2XOOCtSWWLpb03dTrCMFeemqS4S9jrKd3NbUk3UJ2dVb_EIbQEC_BVjZStr_HcCrKsj4AluaQUn09H7TuK0yZFBzZMhJ1J8Yi3nAPkxzdGah0XuWhLObMAvANSVmHzRXwnTDw9Dh_bJ4G1xd1DE7W94uoUlcSDx59aSdzTpQzJh1l3lXc6JRUrXTESYgHpMv0O1n0gbIxX8X1ityBlMiccDjfZIKLnwz6hQObvRtRIpxEdq4SYS-w\", " - "\"d\": \"B1vTivz8th6yaKzdUusBH4dPTbyOWr6gg07K6siYKeFU7kBI5fkw4XZPWk2AjxdBB37PNBl127g25owL-twRaSrBdF5quxzzDix4fEgo77Ik9x8IcUaI5AvpMW7Ig5O0n1SRE-ZfV7KssO0Imqq6bBZkEpzfgVC760tmSuqJ0W2on8eWzi36zuKru9qA5uo7L8w9I5rzqY7XEaak0PYFi5zB1BkpI83tN2bBP2jPsym9lMP4fbf-duHgu0s9H4mDeQFyb7OuI_P7AyH3V3qhUAvk37w-HNL-17g7OBYsZK5jMwa7LobO8Tw0ZdPk5u6dWKdmiWOUUScQVAqtaDjRIQ\" }", + // importing private key with a missing public part 'e' fails at cjose_jwk_import // currently unsupported key type (EC) "{ \"kty\": \"EC\", \"crv\": \"P-256\", " diff --git a/test/check_jwk.c b/test/check_jwk.c index 2e1b4e7..9462289 100644 --- a/test/check_jwk.c +++ b/test/check_jwk.c @@ -100,18 +100,7 @@ START_TEST (test_cjose_jwk_create_RSA_spec) ck_assert(cjose_jwk_get_keydata(jwk, &err) == jwk->keydata); cjose_jwk_release(jwk); - // only private - cjose_get_dealloc()(specPriv.e); - specPriv.e = NULL; - jwk = cjose_jwk_create_RSA_spec(&specPriv, &err); - ck_assert(NULL != jwk); - ck_assert(1 == jwk->retained); - ck_assert(CJOSE_JWK_KTY_RSA == jwk->kty); - ck_assert(2048 == jwk->keysize); - ck_assert(cjose_jwk_get_keysize(jwk, &err) == jwk->keysize); - ck_assert(NULL != jwk->keydata); - ck_assert(cjose_jwk_get_keydata(jwk, &err) == jwk->keydata); - cjose_jwk_release(jwk); + // only private is not possible after the OpenSSL 1.1.x changes because e & n always need to be set // minimal private cjose_get_dealloc()(specPriv.p); @@ -138,6 +127,8 @@ START_TEST (test_cjose_jwk_create_RSA_spec) specPriv.n = NULL; cjose_get_dealloc()(specPriv.d); specPriv.d = NULL; + cjose_get_dealloc()(specPriv.e); + specPriv.e = NULL; // public only memset(&specPub, 0, sizeof(cjose_jwk_rsa_keyspec)); @@ -617,8 +608,8 @@ START_TEST(test_cjose_jwk_import_valid) // EC P-521 "{ \"kty\": \"EC\", \"crv\": \"P-521\", " - "\"x\": \"AVq9Y0jEvSINQJzcExSIUWYjo73cJcVTz_QHXCU7p9rbmC8chFdACiGLKDKlzdgW6lhZzA5qnp8mkpS2qJO_EVxU\", " - "\"y\": \"AQHcQF8s_dhS_84CKLll0vkr0xCqWLp5XXdb79coYWI7Ev9SwZ4UZZVPxgu7ZGyp_2WdtaWw68uYeUVU4WiyKfPm\", " + "\"x\": \"AC8xogZa6uKAPU8086yAlG_inL3BaRyTB0pQUIJMENsPV_4S32DxIEEellMzQ_ts1Egp6OyS3ewjCUKHv5CTF7IV\", " + "\"y\": \"AIR1I2rUew5WyetOHYC-arEDDk2R30Yto6TTot92l4aY0DL8pSYxPVwv9beFUJEl95o_1Vv5y1453nFZW1Ca0uUj\", " "\"kid\": \"A3EAB438-EBF8-4FEC-B605-A67C3A0D2313\" }", // RSA 2048 public params only @@ -671,7 +662,11 @@ START_TEST(test_cjose_jwk_import_valid) { // do import jwk = cjose_jwk_import( JWK[i], strlen(JWK[i]), &err); - ck_assert_msg(NULL != jwk, "expected a cjose_jwk_t, but got NULL"); + ck_assert_msg( + NULL != jwk, + "expected a cjose_jwk_t, but got NULL (%s) : " + "%s, file: %s, function: %s, line: %ld", + JWK[i], err.message, err.file, err.function, err.line); // get json representation of "before" json_t *left_json = json_loads(JWK[i], 0, NULL); diff --git a/test/check_jws.c b/test/check_jws.c index 59ad21b..2960988 100644 --- a/test/check_jws.c +++ b/test/check_jws.c @@ -932,6 +932,7 @@ START_TEST(test_cjose_jws_none) ck_assert_msg(!cjose_jws_sign(jwk, jws->hdr, PLAINTEXT, strlen(PLAINTEXT), &err), "cjose_jws_sign succeeded for unsecured JWT"); + cjose_jws_release(jws); cjose_jwk_release(jwk); } END_TEST diff --git a/test/check_util.c b/test/check_util.c index 8eb6c6c..704638c 100644 --- a/test/check_util.c +++ b/test/check_util.c @@ -4,17 +4,20 @@ #include #include #include +#include "include/util_int.h" 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 @@ -26,16 +29,70 @@ START_TEST(test_cjose_set_allocators) ck_assert(malloc == cjose_get_alloc()); ck_assert(realloc == cjose_get_realloc()); ck_assert(free == cjose_get_dealloc()); + ck_assert(cjose_alloc3_default == cjose_get_alloc3()); + ck_assert(cjose_realloc3_default == cjose_get_realloc3()); + ck_assert(cjose_dealloc3_default == cjose_get_dealloc3()); 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()); + ck_assert(cjose_alloc3_default == cjose_get_alloc3()); + ck_assert(cjose_realloc3_default == cjose_get_realloc3()); + ck_assert(cjose_dealloc3_default == cjose_get_dealloc3()); 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()); + ck_assert(cjose_alloc3_default == cjose_get_alloc3()); + ck_assert(cjose_realloc3_default == cjose_get_realloc3()); + ck_assert(cjose_dealloc3_default == cjose_get_dealloc3()); +} +END_TEST + +static void *test_alloc3(size_t amt, const char *file, int line) +{ + // TODO: verify amount requested + return malloc(amt); +} + +static void *test_realloc3(void *ptr, size_t amt, const char *file, int line) +{ + // TODO: verify pointer to change & amount requested + return realloc(ptr, amt); +} + +static void test_dealloc3(void *ptr, const char *file, int line) +{ + // TODO: verify pointer requested + free(ptr); +} + +START_TEST(test_cjose_set_allocators_ex) +{ + ck_assert(malloc == cjose_get_alloc()); + ck_assert(realloc == cjose_get_realloc()); + ck_assert(free == cjose_get_dealloc()); + ck_assert(cjose_alloc3_default == cjose_get_alloc3()); + ck_assert(cjose_realloc3_default == cjose_get_realloc3()); + ck_assert(cjose_dealloc3_default == cjose_get_dealloc3()); + + cjose_set_alloc_ex_funcs(test_alloc3, test_realloc3, test_dealloc3); + ck_assert(cjose_alloc_wrapped == cjose_get_alloc()); + ck_assert(cjose_realloc_wrapped == cjose_get_realloc()); + ck_assert(cjose_dealloc_wrapped == cjose_get_dealloc()); + ck_assert(test_alloc3 == cjose_get_alloc3()); + ck_assert(test_realloc3 == cjose_get_realloc3()); + ck_assert(test_dealloc3 == cjose_get_dealloc3()); + + cjose_set_alloc_ex_funcs(NULL, NULL, NULL); + ck_assert(malloc == cjose_get_alloc()); + ck_assert(realloc == cjose_get_realloc()); + ck_assert(free == cjose_get_dealloc()); + ck_assert(cjose_alloc3_default == cjose_get_alloc3()); + ck_assert(cjose_realloc3_default == cjose_get_realloc3()); + ck_assert(cjose_dealloc3_default == cjose_get_dealloc3()); } END_TEST @@ -45,6 +102,7 @@ Suite *cjose_util_suite() TCase *tc_util = tcase_create("core"); tcase_add_test(tc_util, test_cjose_set_allocators); + tcase_add_test(tc_util, test_cjose_set_allocators_ex); suite_add_tcase(suite, tc_util); return suite;