/* * encrypt JWT */ apr_byte_t oidc_jwt_encrypt(apr_pool_t *pool, oidc_jwt_t *jwe, oidc_jwk_t *jwk, const char *payload, char **serialized, oidc_jose_error_t *err) { cjose_header_t *hdr = (cjose_header_t *)jwe->header.value.json; if (jwe->header.alg) oidc_jwt_hdr_set(jwe, CJOSE_HDR_ALG, jwe->header.alg); if (jwe->header.kid) oidc_jwt_hdr_set(jwe, CJOSE_HDR_KID, jwe->header.kid); if (jwe->header.enc) oidc_jwt_hdr_set(jwe, CJOSE_HDR_ENC, jwe->header.enc); cjose_err cjose_err; cjose_jwe_t *cjose_jwe = cjose_jwe_encrypt(jwk->cjose_jwk, hdr, (const uint8_t *) payload, strlen(payload), &cjose_err); if (cjose_jwe == NULL) { oidc_jose_error(err, "cjose_jwe_encrypt failed: %s", oidc_cjose_e2s(pool, cjose_err)); return FALSE; } char *cser = cjose_jwe_export(cjose_jwe, &cjose_err); if (cser == NULL) { oidc_jose_error(err, "cjose_jwe_export failed: %s", oidc_cjose_e2s(pool, cjose_err)); return FALSE; } *serialized = apr_pstrdup(pool, cser); cjose_get_dealloc()(cser); cjose_jwe_release(cjose_jwe); return TRUE; }
/* * decrypt a JSON Web Token */ apr_byte_t oidc_jwe_decrypt(apr_pool_t *pool, const char *input_json, apr_hash_t *keys, char **s_json, oidc_jose_error_t *err, apr_byte_t import_must_succeed) { cjose_err cjose_err; cjose_jwe_t *jwe = cjose_jwe_import(input_json, strlen(input_json), &cjose_err); if (jwe != NULL) { size_t content_len = 0; uint8_t *decrypted = oidc_jwe_decrypt_impl(pool, jwe, keys, &content_len, err); if (decrypted != NULL) { decrypted[content_len] = '\0'; *s_json = apr_pstrdup(pool, (const char *) decrypted); cjose_get_dealloc()(decrypted); } cjose_jwe_release(jwe); } else if (import_must_succeed == FALSE) { *s_json = apr_pstrdup(pool, input_json); } else { oidc_jose_error(err, "cjose_jwe_import failed: %s", oidc_cjose_e2s(pool, cjose_err)); } return (*s_json != NULL); }
cjose_jwe_t *cjose_jwe_import( const char *cser, size_t cser_len, cjose_err *err) { cjose_jwe_t *jwe = NULL; if (NULL == cser) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return NULL; } // allocate and initialize a new JWE object if (!_cjose_jwe_malloc(sizeof(cjose_jwe_t), false, (uint8_t **)&jwe, err)) { return NULL; } // import each part of the compact serialization int part = 0; int idx = 0; int start_idx = 0; while (idx <= cser_len && part < 5) { if ((idx == cser_len) || (cser[idx] == '.')) { if (!_cjose_jwe_import_part( jwe, part++, cser + start_idx, idx - start_idx, err)) { cjose_jwe_release(jwe); return NULL; } start_idx = idx + 1; } if (part < 5) ++idx; } // fail if we didn't find enough parts if (part != 5) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); cjose_jwe_release(jwe); return NULL; } // fail if we finished early (e.g. more than 5 parts) if (idx != cser_len) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); cjose_jwe_release(jwe); return NULL; } // deserialize JSON header jwe->hdr = json_loadb( (const char *)jwe->part[0].raw, jwe->part[0].raw_len, 0, NULL); if (NULL == jwe->hdr) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); cjose_jwe_release(jwe); return NULL; } // validate the JSON header if (!_cjose_jwe_validate_hdr(jwe, jwe->hdr, err)) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); cjose_jwe_release(jwe); return NULL; } return jwe; }
cjose_jwe_t *cjose_jwe_encrypt( const cjose_jwk_t *jwk, cjose_header_t *protected_header, const uint8_t *plaintext, size_t plaintext_len, cjose_err *err) { cjose_jwe_t *jwe = NULL; if (NULL == jwk || NULL == protected_header) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return NULL; } // if not already set, add kid header to JWE to match that of JWK const char *kid = cjose_jwk_get_kid(jwk, err); if (NULL != kid) { if (!cjose_header_set(protected_header, CJOSE_HDR_KID, kid, err)) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_STATE); return false; } } // allocate and initialize a new JWE object if (!_cjose_jwe_malloc(sizeof(cjose_jwe_t), false, (uint8_t **)&jwe, err)) { return NULL; } // validate JWE header if (!_cjose_jwe_validate_hdr(jwe, protected_header, err)) { cjose_jwe_release(jwe); return NULL; } // build JWE header if (!_cjose_jwe_build_hdr(jwe, protected_header, err)) { cjose_jwe_release(jwe); return NULL; } // build JWE content-encryption key and encrypted key if (!jwe->fns.encrypt_ek(jwe, jwk, err)) { cjose_jwe_release(jwe); return NULL; } // build JWE initialization vector if (!jwe->fns.set_iv(jwe, err)) { cjose_jwe_release(jwe); return NULL; } // build JWE encrypted data and authentication tag if (!jwe->fns.encrypt_dat(jwe, plaintext, plaintext_len, err)) { cjose_jwe_release(jwe); return NULL; } return jwe; }