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; }
/* * create an "oct" symmetric JWK */ oidc_jwk_t *oidc_jwk_create_symmetric_key(apr_pool_t *pool, const char *skid, const unsigned char *key, unsigned int key_len, apr_byte_t set_kid, oidc_jose_error_t *err) { cjose_err cjose_err; cjose_jwk_t *cjose_jwk = cjose_jwk_create_oct_spec(key, key_len, &cjose_err); if (cjose_jwk == NULL) { oidc_jose_error(err, "cjose_jwk_create_oct_spec failed: %s", oidc_cjose_e2s(pool, cjose_err)); return FALSE; } if (set_kid == TRUE) { if (oidc_jwk_set_or_generate_kid(pool, cjose_jwk, skid, (const char *) key, key_len, err) == FALSE) { cjose_jwk_release(cjose_jwk); return FALSE; } } oidc_jwk_t *jwk = oidc_jwk_new(pool); jwk->cjose_jwk = cjose_jwk; jwk->kid = apr_pstrdup(pool, cjose_jwk_get_kid(jwk->cjose_jwk, &cjose_err)); jwk->kty = cjose_jwk_get_kty(jwk->cjose_jwk, &cjose_err); return jwk; }
cjose_jwk_t *cjose_jwk_derive_ecdh_ephemeral_key( cjose_jwk_t *jwk_self, cjose_jwk_t *jwk_peer, cjose_err *err) { EVP_PKEY_CTX *ctx = NULL; EVP_PKEY *pkey_self = NULL; EVP_PKEY *pkey_peer = NULL; uint8_t *secret = NULL; size_t secret_len = 0; uint8_t *ephemeral_key = NULL; size_t ephemeral_key_len = 0; cjose_jwk_t *jwk_ephemeral_key = NULL; // get EVP_KEY from jwk_self if (!_cjose_jwk_evp_key_from_ec_key(jwk_self, &pkey_self, err)) { goto _cjose_jwk_derive_shared_secret_fail; } // get EVP_KEY from jwk_peer if (!_cjose_jwk_evp_key_from_ec_key(jwk_peer, &pkey_peer, err)) { goto _cjose_jwk_derive_shared_secret_fail; } // create derivation context based on local key pair ctx = EVP_PKEY_CTX_new(pkey_self, NULL); if (NULL == ctx) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jwk_derive_shared_secret_fail; } // initialize derivation context if (1 != EVP_PKEY_derive_init(ctx)) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jwk_derive_shared_secret_fail; } // provide the peer public key if (1 != EVP_PKEY_derive_set_peer(ctx, pkey_peer)) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jwk_derive_shared_secret_fail; } // determine buffer length for shared secret if(1 != EVP_PKEY_derive(ctx, NULL, &secret_len)) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jwk_derive_shared_secret_fail; } // allocate buffer for shared secret secret = (uint8_t *)cjose_get_alloc()(secret_len); if (NULL == secret) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); goto _cjose_jwk_derive_shared_secret_fail; } memset(secret, 0, secret_len); // derive the shared secret if (1 != (EVP_PKEY_derive(ctx, secret, &secret_len))) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); goto _cjose_jwk_derive_shared_secret_fail; } // HKDF of the DH shared secret (SHA256, no salt, no info, 256 bit expand) ephemeral_key_len = 32; 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)) { goto _cjose_jwk_derive_shared_secret_fail; } // create a JWK of the shared secret jwk_ephemeral_key = cjose_jwk_create_oct_spec( ephemeral_key, ephemeral_key_len, err); if (NULL == jwk_ephemeral_key) { goto _cjose_jwk_derive_shared_secret_fail; } // happy path EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey_self); EVP_PKEY_free(pkey_peer); cjose_get_dealloc()(secret); cjose_get_dealloc()(ephemeral_key); return jwk_ephemeral_key; // fail path _cjose_jwk_derive_shared_secret_fail: if (NULL != ctx) { EVP_PKEY_CTX_free(ctx); } if (NULL != pkey_self) { EVP_PKEY_free(pkey_self); } if (NULL != pkey_peer) { EVP_PKEY_free(pkey_peer); } if (NULL != jwk_ephemeral_key) { cjose_jwk_release(jwk_ephemeral_key); } cjose_get_dealloc()(secret); cjose_get_dealloc()(ephemeral_key); return NULL; }