static bool _cjose_jws_build_sig_hmac_sha(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err) { // ensure jwk is OCT if (jwk->kty != CJOSE_JWK_KTY_OCT) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } // allocate buffer for signature jws->sig_len = jws->dig_len; jws->sig = (uint8_t *)cjose_get_alloc()(jws->sig_len); if (NULL == jws->sig) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); return false; } memcpy(jws->sig, jws->dig, jws->sig_len); // base64url encode signed digest if (!cjose_base64url_encode((const uint8_t *)jws->sig, jws->sig_len, &jws->sig_b64u, &jws->sig_b64u_len, err)) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); return false; } return true; }
static bool _cjose_jws_verify_sig_hmac_sha(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err) { bool retval = false; // ensure jwk is OCT if (jwk->kty != CJOSE_JWK_KTY_OCT) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); goto _cjose_jws_verify_sig_hmac_sha_cleanup; } // verify decrypted digest matches computed digest if ((cjose_const_memcmp(jws->dig, jws->sig, jws->dig_len) != 0) || (jws->sig_len != jws->dig_len)) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jws_verify_sig_hmac_sha_cleanup; } // if we got this far - success retval = true; _cjose_jws_verify_sig_hmac_sha_cleanup: return retval; }
static bool _cjose_jwe_malloc( size_t bytes, bool random, uint8_t **buffer, cjose_err *err) { *buffer = (uint8_t *)cjose_get_alloc()(bytes); if (NULL == *buffer) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); return false; } if (random) { if (RAND_bytes((unsigned char *)*buffer, bytes) != 1) { cjose_get_dealloc()(*buffer); CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); return false; } } else { memset(*buffer, 0, bytes); } return true; }
bool _cjose_jwe_import_part( cjose_jwe_t *jwe, size_t p, const char *b64u, size_t b64u_len, cjose_err *err) { // only the ek and the data parts may be of zero length if (b64u_len == 0 && p != 1 && p != 3) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } // copy the b64u part to the jwe jwe->part[p].b64u = strdup(b64u); if (NULL == jwe->part[p].b64u) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); return false; } jwe->part[p].b64u_len = b64u_len; // b64u decode the part if (!cjose_base64url_decode( jwe->part[p].b64u, jwe->part[p].b64u_len, (uint8_t **)&jwe->part[p].raw, &jwe->part[p].raw_len, err) || NULL == jwe->part[p].raw) { return false; } return true; }
static bool _cjose_jwe_build_hdr( cjose_jwe_t *jwe, cjose_header_t *header, cjose_err *err) { // save header object as part of the JWE (and incr. refcount) jwe->hdr = header; json_incref(jwe->hdr); // serialize the header char *hdr_str = json_dumps(header, JSON_ENCODE_ANY | JSON_PRESERVE_ORDER); if (NULL == hdr_str) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); return false; } // copy the serialized header to JWE (hdr_str is owned by header object) jwe->part[0].raw = (uint8_t *)strdup(hdr_str); if (NULL == jwe->part[0].raw) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); cjose_get_dealloc()(hdr_str); return false; } jwe->part[0].raw_len = strlen(hdr_str); cjose_get_dealloc()(hdr_str); return true; }
static bool _EC_private_fields( const cjose_jwk_t *jwk, json_t *json, cjose_err *err) { ec_keydata *keydata = (ec_keydata *)jwk->keydata; const BIGNUM *bnD = EC_KEY_get0_private_key(keydata->key); uint8_t *buffer = NULL; char *b64u = NULL; size_t len = 0, offset = 0; json_t *field = NULL; bool result = false; // track expected binary data size uint8_t numsize = _ec_size_for_curve(keydata->crv, err); // short circuit if 'd' is NULL or 0 if (!bnD || BN_is_zero(bnD)) { return true; } buffer = cjose_get_alloc()(numsize); if (!buffer) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); goto _ec_to_string_cleanup; } offset = numsize - BN_num_bytes(bnD); memset(buffer, 0, numsize); BN_bn2bin(bnD, (buffer + offset)); if (!cjose_base64url_encode(buffer, numsize, &b64u, &len, err)) { goto _ec_to_string_cleanup; } field = json_stringn(b64u, len); if (!field) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); goto _ec_to_string_cleanup; } json_object_set(json, "d", field); json_decref(field); field = NULL; cjose_get_dealloc()(b64u); b64u = NULL; result = true; _ec_to_string_cleanup: if (buffer) { cjose_get_dealloc()(buffer); } return result; }
cjose_jwk_t *cjose_jwk_create_RSA_spec( const cjose_jwk_rsa_keyspec *spec, cjose_err *err) { if (NULL == spec) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return NULL; } bool hasPub = (NULL != spec->n && 0 < spec->nlen) && (NULL != spec->e && 0 < spec->elen); bool hasPriv = (NULL != spec->n && 0 < spec->nlen) && (NULL != spec->d && 0 < spec->dlen); if (!hasPub && !hasPriv) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return NULL; } RSA *rsa = NULL; rsa = RSA_new(); if (!rsa) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); return NULL; } if (hasPriv) { 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); } else if (hasPub) { 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; } } return _RSA_new(rsa, err); create_RSA_spec_failed: if (rsa) { RSA_free(rsa); } return NULL; }
static bool _cjose_jwe_validate_hdr( cjose_jwe_t *jwe, cjose_header_t *header, cjose_err *err) { // make sure we have an alg header json_t *alg_obj = json_object_get(header, CJOSE_HDR_ALG); if (NULL == alg_obj) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } const char *alg = json_string_value(alg_obj); // make sure we have an enc header json_t *enc_obj = json_object_get(header, CJOSE_HDR_ENC); if (NULL == enc_obj) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } const char *enc = json_string_value(enc_obj); // set JWE build functions based on header contents if (strcmp(alg, CJOSE_HDR_ALG_RSA_OAEP) == 0) { jwe->fns.encrypt_ek = _cjose_jwe_encrypt_ek_rsa_oaep; jwe->fns.decrypt_ek = _cjose_jwe_decrypt_ek_rsa_oaep; } if (strcmp(alg, CJOSE_HDR_ALG_DIR) == 0) { jwe->fns.encrypt_ek = _cjose_jwe_encrypt_ek_dir; jwe->fns.decrypt_ek = _cjose_jwe_decrypt_ek_dir; } if (strcmp(enc, CJOSE_HDR_ENC_A256GCM) == 0) { jwe->fns.set_cek = _cjose_jwe_set_cek_a256gcm; jwe->fns.set_iv = _cjose_jwe_set_iv_a256gcm; jwe->fns.encrypt_dat = _cjose_jwe_encrypt_dat_a256gcm; jwe->fns.decrypt_dat = _cjose_jwe_decrypt_dat_a256gcm; } // ensure required builders have been assigned if (NULL == jwe->fns.set_cek || NULL == jwe->fns.encrypt_ek || NULL == jwe->fns.decrypt_ek || NULL == jwe->fns.set_iv || NULL == jwe->fns.encrypt_dat || NULL == jwe->fns.decrypt_dat) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } return true; }
static inline bool _RSA_json_field( BIGNUM *param, const char *name, json_t *json, cjose_err *err) { json_t *field = NULL; uint8_t *data = NULL; char *b64u = NULL; size_t datalen = 0, b64ulen = 0; bool result = false; if (!param) { return true; } datalen = BN_num_bytes(param); data = cjose_get_alloc()(sizeof(uint8_t) * datalen); if (!data) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); goto RSA_json_field_cleanup; } BN_bn2bin(param, data); if (!cjose_base64url_encode(data, datalen, &b64u, &b64ulen, err)) { goto RSA_json_field_cleanup; } field = json_stringn(b64u, b64ulen); if (!field) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); goto RSA_json_field_cleanup; } json_object_set(json, name, field); json_decref(field); field = NULL; result = true; RSA_json_field_cleanup: if (b64u) { cjose_get_dealloc()(b64u); b64u = NULL; } if (data) { cjose_get_dealloc()(data); data = NULL; } return result; }
cjose_jwk_t *cjose_jwk_create_RSA_random( size_t keysize, const uint8_t *e, size_t elen, cjose_err *err) { if (0 == keysize) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return NULL; } if (NULL == e || 0 >= elen) { e = DEFAULT_E_DAT; elen = DEFAULT_E_LEN; } RSA *rsa = NULL; BIGNUM *bn = NULL; rsa = RSA_new(); if (!rsa) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); goto create_RSA_random_failed; } bn = BN_bin2bn(e, elen, NULL); if (!bn) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); goto create_RSA_random_failed; } if (0 == RSA_generate_key_ex(rsa, keysize, bn, NULL)) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); goto create_RSA_random_failed; } BN_free(bn); return _RSA_new(rsa, err); create_RSA_random_failed: if (bn) { BN_free(bn); } if (rsa) { RSA_free(rsa); } return NULL; }
static bool _cjose_jwe_encrypt_ek_rsa_oaep( cjose_jwe_t *jwe, const cjose_jwk_t *jwk, 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) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } // generate random cek if (!jwe->fns.set_cek(jwe, NULL, err)) { return false; } // the size of the ek will match the size of the RSA key jwe->part[1].raw_len = RSA_size((RSA *)jwk->keydata); // for OAEP padding - the RSA size - 41 must be greater than input if (jwe->cek_len >= jwe->part[1].raw_len - 41) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } // allocate memory for RSA encryption cjose_get_dealloc()(jwe->part[1].raw); if (!_cjose_jwe_malloc(jwe->part[1].raw_len, false, &jwe->part[1].raw, err)) { return false; } // encrypt the CEK using RSAES-OAEP if (RSA_public_encrypt(jwe->cek_len, jwe->cek, jwe->part[1].raw, (RSA *)jwk->keydata, RSA_PKCS1_OAEP_PADDING) != jwe->part[1].raw_len) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); return false; } return true; }
static bool _cjose_jws_build_cser(cjose_jws_t *jws, cjose_err *err) { // both sign and import should be setting these - but check just in case if (NULL == jws->hdr_b64u || NULL == jws->dat_b64u || NULL == jws->sig_b64u) { return false; } // compute length of compact serialization jws->cser_len = jws->hdr_b64u_len + jws->dat_b64u_len + jws->sig_b64u_len + 3; // allocate buffer for compact serialization assert(NULL == jws->cser); jws->cser = (char *)cjose_get_alloc()(jws->cser_len); if (NULL == jws->cser) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); return false; } // build the compact serialization snprintf(jws->cser, jws->cser_len, "%s.%s.%s", jws->hdr_b64u, jws->dat_b64u, jws->sig_b64u); return true; }
bool cjose_jws_verify(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err) { if (NULL == jws || NULL == jwk) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } // validate JWS header if (!_cjose_jws_validate_hdr(jws, err)) { return false; } // build JWS digest from header and payload (hashed signing input value) if (!jws->fns.digest(jws, jwk, err)) { return false; } // verify JWS signature if (!jws->fns.verify(jws, jwk, err)) { return false; } return true; }
uint8_t *cjose_jwe_decrypt( cjose_jwe_t *jwe, const cjose_jwk_t *jwk, size_t *content_len, cjose_err *err) { if (NULL == jwe || NULL == jwk || NULL == content_len) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return NULL; } // decrypt JWE content-encryption key from encrypted key if (!jwe->fns.decrypt_ek(jwe, jwk, err)) { return NULL; } // decrypt JWE encrypted data if (!jwe->fns.decrypt_dat(jwe, err)) { return NULL; } // take the plaintext data from the jwe object uint8_t *content = jwe->dat; *content_len = jwe->dat_len; jwe->dat = NULL; jwe->dat_len = 0; return content; }
bool cjose_jwk_hkdf( const EVP_MD *md, const uint8_t *salt, size_t salt_len, const uint8_t *info, size_t info_len, const uint8_t *ikm, size_t ikm_len, uint8_t *okm, unsigned int okm_len, cjose_err *err) { // current impl. is very limited: SHA256, 256 bit output, and no info if ((EVP_sha256() != md) || (0 != info_len) || (32 != okm_len)) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } // HKDF-Extract, HMAC-SHA256(salt, IKM) -> PRK unsigned int prk_len; unsigned char prk[EVP_MAX_MD_SIZE]; HMAC(md, salt, salt_len, ikm, ikm_len, prk, &prk_len); // HKDF-Expand, HMAC-SHA256(PRK,0x01) -> OKM const unsigned char t[] = { 0x01 }; HMAC(md, prk, prk_len, t, sizeof(t), okm, NULL); return true; }
static cjose_jwk_t *_cjose_jwk_import_oct(json_t *jwk_json, cjose_err *err) { cjose_jwk_t *jwk = NULL; uint8_t *k_buffer = NULL; // get the decoded value of k (buflen = 0 means no particular expected len) size_t k_buflen = 0; if (!_decode_json_object_base64url_attribute( jwk_json, CJOSE_JWK_K_STR, &k_buffer, &k_buflen, err)) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); goto import_oct_cleanup; } // create the jwk jwk = cjose_jwk_create_oct_spec(k_buffer, k_buflen, err); import_oct_cleanup: if (NULL != k_buffer) { cjose_get_dealloc()(k_buffer); } return jwk; }
static bool _cjose_jws_validate_hdr(cjose_jws_t *jws, cjose_err *err) { // make sure we have an alg header json_t *alg_obj = json_object_get(jws->hdr, CJOSE_HDR_ALG); if ((NULL == alg_obj) || (!json_is_string(alg_obj))) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } const char *alg = json_string_value(alg_obj); if ((strcmp(alg, CJOSE_HDR_ALG_PS256) == 0) || (strcmp(alg, CJOSE_HDR_ALG_PS384) == 0) || (strcmp(alg, CJOSE_HDR_ALG_PS512) == 0)) { jws->fns.digest = _cjose_jws_build_dig_sha; jws->fns.sign = _cjose_jws_build_sig_ps; jws->fns.verify = _cjose_jws_verify_sig_ps; } else if ((strcmp(alg, CJOSE_HDR_ALG_RS256) == 0) || (strcmp(alg, CJOSE_HDR_ALG_RS384) == 0) || (strcmp(alg, CJOSE_HDR_ALG_RS512) == 0)) { jws->fns.digest = _cjose_jws_build_dig_sha; jws->fns.sign = _cjose_jws_build_sig_rs; jws->fns.verify = _cjose_jws_verify_sig_rs; } else if ((strcmp(alg, CJOSE_HDR_ALG_HS256) == 0) || (strcmp(alg, CJOSE_HDR_ALG_HS384) == 0) || (strcmp(alg, CJOSE_HDR_ALG_HS512) == 0)) { jws->fns.digest = _cjose_jws_build_dig_hmac_sha; jws->fns.sign = _cjose_jws_build_sig_hmac_sha; jws->fns.verify = _cjose_jws_verify_sig_hmac_sha; } else if ((strcmp(alg, CJOSE_HDR_ALG_ES256) == 0) || (strcmp(alg, CJOSE_HDR_ALG_ES384) == 0) || (strcmp(alg, CJOSE_HDR_ALG_ES512) == 0)) { jws->fns.digest = _cjose_jws_build_dig_sha; jws->fns.sign = _cjose_jws_build_sig_ec; jws->fns.verify = _cjose_jws_verify_sig_ec; } else { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } return true; }
static bool _cjose_jws_verify_sig_rs(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err) { bool retval = false; // ensure jwk is RSA if (jwk->kty != CJOSE_JWK_KTY_RSA) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); goto _cjose_jws_verify_sig_rs_cleanup; } // make sure we have an alg header json_t *alg_obj = json_object_get(jws->hdr, CJOSE_HDR_ALG); if (NULL == alg_obj) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } const char *alg = json_string_value(alg_obj); // build digest using SHA-256/384/512 digest algorithm int digest_alg = -1; if (strcmp(alg, CJOSE_HDR_ALG_RS256) == 0) digest_alg = NID_sha256; else if (strcmp(alg, CJOSE_HDR_ALG_RS384) == 0) digest_alg = NID_sha384; else if (strcmp(alg, CJOSE_HDR_ALG_RS512) == 0) digest_alg = NID_sha512; if (-1 == digest_alg) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jws_verify_sig_rs_cleanup; } if (RSA_verify(digest_alg, jws->dig, jws->dig_len, jws->sig, jws->sig_len, (RSA *)jwk->keydata) != 1) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jws_verify_sig_rs_cleanup; } // if we got this far - success retval = true; _cjose_jws_verify_sig_rs_cleanup: return retval; }
size_t cjose_jwk_get_keysize(const cjose_jwk_t *jwk, cjose_err *err) { if (!jwk) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return 0; } return jwk->keysize; }
void *cjose_jwk_get_keydata(const cjose_jwk_t *jwk, cjose_err *err) { if (!jwk) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return NULL; } return jwk->keydata; }
const char * cjose_jwk_name_for_kty(cjose_jwk_kty_t kty, cjose_err *err) { if (0 == kty || CJOSE_JWK_KTY_OCT < kty) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return NULL; } return JWK_KTY_NAMES[kty - CJOSE_JWK_KTY_RSA]; }
const char *cjose_jwk_get_kid(const cjose_jwk_t *jwk, cjose_err *err) { if (!jwk) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return NULL; } return jwk->kid; }
cjose_jwk_kty_t cjose_jwk_get_kty(const cjose_jwk_t *jwk, cjose_err *err) { if (!jwk) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return -1; } return jwk->kty; }
static bool _cjose_jws_verify_sig_ec(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err) { bool retval = false; // ensure jwk is EC if (jwk->kty != CJOSE_JWK_KTY_EC) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } ec_keydata *keydata = (ec_keydata *)jwk->keydata; EC_KEY *ec = keydata->key; ECDSA_SIG *ecdsa_sig = ECDSA_SIG_new(); int key_len = jws->sig_len / 2; #if defined(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) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jws_verify_sig_ec_cleanup; } // if we got this far - success retval = true; _cjose_jws_verify_sig_ec_cleanup: if (ecdsa_sig) ECDSA_SIG_free(ecdsa_sig); return retval; }
static bool _cjose_jwk_evp_key_from_ec_key( cjose_jwk_t *jwk, EVP_PKEY **key, cjose_err *err) { // validate that the jwk is of type EC and we have a valid out-param if (NULL == jwk || CJOSE_JWK_KTY_EC != jwk->kty || NULL == jwk->keydata || NULL == key || NULL != *key) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); goto _cjose_jwk_evp_key_from_ec_key_fail; } // create a blank EVP_PKEY *key = EVP_PKEY_new(); if (NULL == key) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jwk_evp_key_from_ec_key_fail; } // assign the EVP_PKEY to reference the jwk's internal EC_KEY structure if (1 != EVP_PKEY_set1_EC_KEY( *key, ((struct _ec_keydata_int *)(jwk->keydata))->key)) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jwk_evp_key_from_ec_key_fail; } // happy path return true; // fail path _cjose_jwk_evp_key_from_ec_key_fail: EVP_PKEY_free(*key); *key = NULL; return false; }
cjose_jwk_t *cjose_jwk_create_oct_random(size_t keysize, cjose_err *err) { cjose_jwk_t * jwk = NULL; uint8_t * buffer = NULL; if (0 == keysize) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); goto create_oct_failed; } // resize to bytes size_t buffersize = sizeof(uint8_t) * (keysize / 8); buffer = (uint8_t *)cjose_get_alloc()(buffersize); if (NULL == buffer) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); goto create_oct_failed; } if (1 != RAND_bytes(buffer, buffersize)) { goto create_oct_failed; } jwk = _oct_new(buffer, keysize, err); if (NULL == jwk) { goto create_oct_failed; } return jwk; create_oct_failed: if (buffer) { cjose_get_dealloc()(buffer); buffer = NULL; } return NULL; }
cjose_jwk_t *cjose_jwk_create_EC_random(cjose_jwk_ec_curve crv, cjose_err *err) { cjose_jwk_t * jwk = NULL; EC_KEY * ec = NULL; ec = EC_KEY_new_by_curve_name(crv); if (!ec) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); goto create_EC_failed; } if (1 != EC_KEY_generate_key(ec)) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); goto create_EC_failed; } jwk = _EC_new(crv, ec, err); if (!jwk) { goto create_EC_failed; } return jwk; create_EC_failed: if (jwk) { cjose_get_dealloc()(jwk); jwk = NULL; } if (ec) { EC_KEY_free(ec); ec = NULL; } return NULL; }
bool cjose_jws_get_plaintext(const cjose_jws_t *jws, uint8_t **plaintext, size_t *plaintext_len, cjose_err *err) { if (NULL == jws || NULL == plaintext || NULL == jws->dat) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } *plaintext = jws->dat; *plaintext_len = jws->dat_len; return true; }
cjose_jwk_t * cjose_jwk_retain(cjose_jwk_t *jwk, cjose_err *err) { if (!jwk) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return NULL; } ++(jwk->retained); // TODO: check for overflow return jwk; }
static bool _cjose_jwe_decrypt_ek_rsa_oaep( cjose_jwe_t *jwe, const cjose_jwk_t *jwk, cjose_err *err) { if (NULL == jwe || NULL == jwk) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } // jwk must be RSA if (jwk->kty != CJOSE_JWK_KTY_RSA) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } // we don't know the size of the key to expect, but must be < RSA_size cjose_get_dealloc()(jwe->cek); size_t buflen = RSA_size((RSA *)jwk->keydata); if (!_cjose_jwe_malloc(buflen, false, &jwe->cek, err)) { return false; } // decrypt the CEK using RSAES-OAEP jwe->cek_len = RSA_private_decrypt( jwe->part[1].raw_len, jwe->part[1].raw, jwe->cek, (RSA *)jwk->keydata, RSA_PKCS1_OAEP_PADDING); if (-1 == jwe->cek_len) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); return false; } return true; }