From 357fe0b964903e8c84ab49f0f27ddf0447d44c84 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Mon, 2 Nov 2020 18:39:08 +0100 Subject: [PATCH 1/2] feat: Revised API, No dependencies, Browser Support, Promises MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BREAKING CHANGE: Revised, Promise-based API BREAKING CHANGE: No dependencies BREAKING CHANGE: Browser support (using [Web Cryptography API](https://www.w3.org/TR/WebCryptoAPI/)) BREAKING CHANGE: Support for verification using a remote JWKS endpoint BREAKING CHANGE: Experimental Node.js libuv thread pool based runtime (non-blocking 🎉) --- .c8rc.json | 3 - .codecov.yml | 14 - .github/ISSUE_TEMPLATE/bug-report.md | 25 +- .github/ISSUE_TEMPLATE/config.yml | 3 +- .github/ISSUE_TEMPLATE/feature-request.md | 4 +- .github/workflows/codeql-analysis.yml | 83 +- .github/workflows/lock.yml | 12 +- .github/workflows/test.yml | 105 +- .gitignore | 65 +- .prettierignore | 4 + LICENSE_THIRD_PARTY | 209 -- README.md | 461 ++--- docs/README.md | 1739 +---------------- .../_jwe_compact_encrypt_.compactencrypt.md | 164 ++ ...jwe_flattened_encrypt_.flattenedencrypt.md | 223 +++ .../classes/_jws_compact_sign_.compactsign.md | 100 + .../_jws_flattened_sign_.flattenedsign.md | 118 ++ docs/classes/_jwt_encrypt_.encryptjwt.md | 340 ++++ docs/classes/_jwt_sign_.signjwt.md | 236 +++ docs/classes/_jwt_unsecured_.unsecuredjwt.md | 246 +++ .../_util_errors_.josealgnotallowed.md | 66 + docs/classes/_util_errors_.joseerror.md | 76 + .../classes/_util_errors_.josenotsupported.md | 67 + .../_util_errors_.jwedecryptionfailed.md | 68 + docs/classes/_util_errors_.jweinvalid.md | 66 + docs/classes/_util_errors_.jwkinvalid.md | 66 + docs/classes/_util_errors_.jwksinvalid.md | 66 + .../_util_errors_.jwksmultiplematchingkeys.md | 68 + .../_util_errors_.jwksnomatchingkey.md | 68 + docs/classes/_util_errors_.jwsinvalid.md | 66 + ..._errors_.jwssignatureverificationfailed.md | 68 + .../_util_errors_.jwtclaimvalidationfailed.md | 92 + docs/classes/_util_errors_.jwtexpired.md | 92 + docs/classes/_util_errors_.jwtinvalid.md | 66 + .../_jwe_compact_decrypt_.compactdecrypt.md | 54 + ...jwe_flattened_decrypt_.flatteneddecrypt.md | 66 + docs/functions/_jwk_embedded_.embeddedjwk.md | 48 + docs/functions/_jwk_parse_.parsejwk.md | 51 + .../_jwk_thumbprint_.calculatethumbprint.md | 41 + .../_jwks_remote_.createremotejwkset.md | 46 + .../_jws_compact_verify_.compactverify.md | 50 + .../_jws_flattened_verify_.flattenedverify.md | 54 + docs/functions/_jwt_decrypt_.jwtdecrypt.md | 49 + docs/functions/_jwt_verify_.jwtverify.md | 51 + ...util_generate_key_pair_.generatekeypair.md | 38 + .../_util_generate_secret_.generatesecret.md | 34 + ...e_compact_decrypt_.compactdecryptgetkey.md | 22 + ...attened_decrypt_.flatteneddecryptgetkey.md | 22 + .../_jwks_remote_.remotejwksetoptions.md | 32 + ...jws_compact_verify_.compactverifygetkey.md | 22 + ...flattened_verify_.flattenedverifygetkey.md | 22 + .../_jwt_decrypt_.jwtdecryptgetkey.md | 22 + .../_jwt_decrypt_.jwtdecryptoptions.md | 121 ++ .../_jwt_verify_.jwtverifygetkey.md | 22 + .../_jwt_verify_.jwtverifyoptions.md | 98 + .../_types_d_.compactdecryptresult.md | 28 + .../_types_d_.compactverifyresult.md | 28 + docs/interfaces/_types_d_.decryptoptions.md | 42 + docs/interfaces/_types_d_.deflatefunction.md | 19 + docs/interfaces/_types_d_.encryptoptions.md | 20 + .../_types_d_.flatteneddecryptresult.md | 61 + docs/interfaces/_types_d_.flattenedjwe.md | 119 ++ docs/interfaces/_types_d_.flattenedjws.md | 28 + .../interfaces/_types_d_.flattenedjwsinput.md | 63 + .../_types_d_.flattenedverifyresult.md | 39 + docs/interfaces/_types_d_.getkeyfunction.md | 29 + docs/interfaces/_types_d_.inflatefunction.md | 19 + .../_types_d_.joseheaderparameters.md | 83 + .../_types_d_.jweheaderparameters.md | 136 ++ ...pes_d_.jwekeymanagementheaderparameters.md | 62 + docs/interfaces/_types_d_.jwk.md | 236 +++ .../_types_d_.jwsheaderparameters.md | 127 ++ .../_types_d_.jwtclaimverificationoptions.md | 87 + docs/interfaces/_types_d_.jwtdecryptresult.md | 28 + docs/interfaces/_types_d_.jwtpayload.md | 92 + docs/interfaces/_types_d_.jwtverifyresult.md | 28 + docs/interfaces/_types_d_.verifyoptions.md | 19 + ...nerate_key_pair_.generatekeypairoptions.md | 19 + docs/modules/_jwe_compact_decrypt_.md | 11 + docs/modules/_jwe_compact_encrypt_.md | 7 + docs/modules/_jwe_flattened_decrypt_.md | 11 + docs/modules/_jwe_flattened_encrypt_.md | 7 + docs/modules/_jwk_embedded_.md | 7 + docs/modules/_jwk_parse_.md | 7 + docs/modules/_jwk_thumbprint_.md | 7 + docs/modules/_jwks_remote_.md | 11 + docs/modules/_jws_compact_sign_.md | 7 + docs/modules/_jws_compact_verify_.md | 11 + docs/modules/_jws_flattened_sign_.md | 7 + docs/modules/_jws_flattened_verify_.md | 11 + docs/modules/_jwt_decrypt_.md | 12 + docs/modules/_jwt_encrypt_.md | 7 + docs/modules/_jwt_sign_.md | 7 + docs/modules/_jwt_unsecured_.md | 7 + docs/modules/_jwt_verify_.md | 12 + docs/modules/_types_d_.md | 32 + docs/modules/_util_base64url_.md | 1 + docs/modules/_util_errors_.md | 20 + docs/modules/_util_generate_key_pair_.md | 11 + docs/modules/_util_generate_secret_.md | 7 + docs/modules/_util_random_.md | 1 + docs/types/_types_d_.keylike.md | 17 + img/demo.gif | Bin 1890101 -> 0 bytes karma.conf.js | 115 ++ lib/errors.js | 86 - lib/help/asn1/algorithm_identifier.js | 8 - lib/help/asn1/ec_private_key.js | 10 - lib/help/asn1/index.js | 29 - lib/help/asn1/oids.js | 14 - lib/help/asn1/one_asymmetric_key.js | 7 - lib/help/asn1/private_key.js | 5 - lib/help/asn1/private_key_info.js | 7 - lib/help/asn1/public_key_info.js | 6 - lib/help/asn1/rsa_private_key.js | 13 - lib/help/asn1/rsa_public_key.js | 6 - lib/help/base64url.js | 65 - lib/help/consts.js | 18 - lib/help/deep_clone.js | 1 - lib/help/ecdsa_signatures.js | 180 -- lib/help/epoch.js | 1 - lib/help/generate_iv.js | 5 - lib/help/get_key.js | 35 - lib/help/is_disjoint.js | 5 - lib/help/is_object.js | 1 - lib/help/key_object.js | 435 ----- lib/help/key_utils.js | 300 --- lib/help/node_alg.js | 1 - lib/help/rsa_primes.js | 170 -- lib/help/runtime_support.js | 11 - lib/help/timing_safe_equal.js | 18 - lib/help/uint64be.js | 10 - lib/help/validate_crit.js | 41 - lib/index.js | 8 - lib/index.mjs | 9 - lib/jwa/aes_cbc_hmac_sha2.js | 70 - lib/jwa/aes_gcm.js | 55 - lib/jwa/aes_gcm_kw.js | 24 - lib/jwa/aes_kw.js | 37 - lib/jwa/ecdh/compute_secret.js | 43 - lib/jwa/ecdh/derive.js | 40 - lib/jwa/ecdh/dir.js | 31 - lib/jwa/ecdh/kw.js | 47 - lib/jwa/ecdsa.js | 77 - lib/jwa/eddsa.js | 24 - lib/jwa/hmac.js | 28 - lib/jwa/index.js | 88 - lib/jwa/none.js | 7 - lib/jwa/pbes2.js | 56 - lib/jwa/rsaes.js | 67 - lib/jwa/rsassa.js | 29 - lib/jwa/rsassa_pss.js | 43 - lib/jwe/decrypt.js | 229 --- lib/jwe/encrypt.js | 214 -- lib/jwe/generate_cek.js | 15 - lib/jwe/index.js | 15 - lib/jwe/serializers.js | 121 -- lib/jwe/validate_headers.js | 70 - lib/jwk/generate.js | 53 - lib/jwk/import.js | 134 -- lib/jwk/index.js | 15 - lib/jwk/key/base.js | 339 ---- lib/jwk/key/ec.js | 110 -- lib/jwk/key/embedded.jwk.js | 27 - lib/jwk/key/embedded.x5c.js | 27 - lib/jwk/key/none.js | 34 - lib/jwk/key/oct.js | 103 - lib/jwk/key/okp.js | 86 - lib/jwk/key/rsa.js | 117 -- lib/jwk/thumbprint.js | 9 - lib/jwks/index.js | 3 - lib/jwks/keystore.js | 183 -- lib/jws/index.js | 15 - lib/jws/serializers.js | 104 - lib/jws/sign.js | 130 -- lib/jws/verify.js | 202 -- lib/jwt/decode.js | 30 - lib/jwt/index.js | 16 - lib/jwt/profiles.js | 168 -- lib/jwt/shared_validations.js | 45 - lib/jwt/sign.js | 94 - lib/jwt/verify.js | 186 -- lib/registry/ec_curves.js | 21 - lib/registry/ecdh_derive_lengths.js | 1 - lib/registry/index.js | 17 - lib/registry/iv_lengths.js | 11 - lib/registry/jwa.js | 8 - lib/registry/jwk.js | 38 - lib/registry/key_lengths.js | 8 - lib/registry/okp_curves.js | 9 - package.json | 500 ++++- src/.eslintrc.json | 38 + src/.prettierrc.json | 6 + src/jwe/compact/decrypt.ts | 93 + src/jwe/compact/encrypt.ts | 115 ++ src/jwe/flattened/decrypt.ts | 255 +++ src/jwe/flattened/encrypt.ts | 324 +++ src/jwk/embedded.ts | 64 + src/jwk/parse.ts | 95 + src/jwk/thumbprint.ts | 85 + src/jwks/remote.ts | 239 +++ src/jws/compact/sign.ts | 79 + src/jws/compact/verify.ts | 82 + src/jws/flattened/sign.ts | 170 ++ src/jws/flattened/verify.ts | 193 ++ src/jwt/decrypt.ts | 105 + src/jwt/encrypt.ts | 185 ++ src/jwt/sign.ts | 77 + src/jwt/unsecured.ts | 104 + src/jwt/verify.ts | 76 + src/lib/buffer_utils.ts | 66 + src/lib/cek.ts | 24 + src/lib/check_iv_length.ts | 10 + src/lib/check_key_type.ts | 30 + src/lib/check_p2s.ts | 7 + src/lib/decrypt_key_management.ts | 119 ++ src/lib/encrypt_key_management.ts | 115 ++ src/lib/epoch.ts | 1 + src/lib/is_disjoint.ts | 29 + src/lib/is_object.ts | 3 + src/lib/iv.ts | 28 + src/lib/jwt_claims_set.ts | 143 ++ src/lib/jwt_producer.ts | 108 + lib/help/secs.js => src/lib/secs.ts | 11 +- src/lib/validate_algorithms.ts | 16 + src/lib/validate_crit.ts | 52 + src/runtime/browser/aesgcmkw.ts | 40 + src/runtime/browser/aeskw.ts | 58 + src/runtime/browser/base64url.ts | 25 + src/runtime/browser/bogus.ts | 7 + src/runtime/browser/check_cek_length.ts | 43 + src/runtime/browser/check_key_length.ts | 17 + src/runtime/browser/decrypt.ts | 112 ++ src/runtime/browser/digest.ts | 10 + src/runtime/browser/ecdhes.ts | 82 + src/runtime/browser/encrypt.ts | 96 + src/runtime/browser/fetch.ts | 28 + src/runtime/browser/generate.ts | 112 ++ src/runtime/browser/jwk_to_key.ts | 121 ++ src/runtime/browser/pbes2kw.ts | 93 + src/runtime/browser/random.ts | 6 + src/runtime/browser/rsaes.ts | 59 + src/runtime/browser/sign.ts | 30 + src/runtime/browser/subtle_dsa.ts | 46 + src/runtime/browser/subtle_rsaes.ts | 15 + src/runtime/browser/timing_safe_equal.ts | 23 + src/runtime/browser/verify.ts | 29 + src/runtime/browser/webcrypto.ts | 12 + src/runtime/browser/zlib.ts | 13 + src/runtime/interfaces.d.ts | 111 ++ src/runtime/node/aesgcmkw.ts | 50 + src/runtime/node/aeskw.ts | 48 + src/runtime/node/asn1_sequence_encoder.ts | 104 + src/runtime/node/base64url.ts | 13 + src/runtime/node/cbc_tag.ts | 16 + src/runtime/node/check_cek_length.ts | 40 + src/runtime/node/check_modulus_length.ts | 70 + src/runtime/node/decrypt.ts | 102 + src/runtime/node/digest.ts | 5 + src/runtime/node/dsa_digest.ts | 29 + src/runtime/node/ecdhes.ts | 138 ++ src/runtime/node/encrypt.ts | 72 + src/runtime/node/fetch.ts | 43 + src/runtime/node/generate.ts | 99 + src/runtime/node/get_named_curve.ts | 55 + src/runtime/node/hmac_digest.ts | 19 + src/runtime/node/jwk_to_key.ts | 121 ++ src/runtime/node/node_key.ts | 67 + src/runtime/node/pbes2kw.ts | 44 + src/runtime/node/random.ts | 6 + src/runtime/node/rsaes.ts | 62 + src/runtime/node/secret_key.ts | 13 + src/runtime/node/sign.ts | 32 + src/runtime/node/timing_safe_equal.ts | 7 + src/runtime/node/verify.ts | 29 + src/runtime/node/webcrypto.ts | 13 + src/runtime/node/zlib.ts | 15 + src/types.d.ts | 550 ++++++ src/types.i.d.ts | 31 + src/util/base64url.ts | 1 + src/util/errors.ts | 136 ++ src/util/generate_key_pair.ts | 46 + src/util/generate_secret.ts | 30 + src/util/random.ts | 3 + test-browser/.eslintrc.json | 12 + test-browser/.prettierrc.json | 6 + test-browser/generate_keys.js | 83 + test-browser/generate_secrets.js | 85 + test-browser/jwe_asymmetric.js | 59 + test-browser/jwe_symmetric.js | 185 ++ test-browser/jwks.js | 18 + test-browser/jws.js | 50 + test/.eslintrc.json | 7 + test/.prettierrc.json | 6 + test/cookbook/4_1.rsa_v15_signature.test.js | 88 - test/cookbook/4_2.rsa-pss_signature.test.js | 95 - test/cookbook/4_3.ecdsa_signature.test.js | 95 - ...4_4.hmac-sha2_integrity_protection.test.js | 88 - ....protecting_specific_header_fields.test.js | 64 - .../4_7.protecting_content_only.test.js | 64 - test/cookbook/4_8.multiple_signatures.test.js | 59 - ...on_using_rsa_v15_and_aes-hmac-sha2.test.js | 98 - ...ing_additional_authentication_data.test.js | 74 - ....protecting_specific_header_fields.test.js | 74 - .../5_12.protecting_content_only.test.js | 74 - ....encrypting_to_multiple_recipients.test.js | 58 - ...yption_using_rsa-oaep_with_aes-gcm.test.js | 98 - ...aes-keywrap_with-aes-cbc-hmac-sha2.test.js | 100 - ...dh-es_and_aes-keywrap_with_aes-gcm.test.js | 100 - ...ing_ecdh-es_with_aes-cbc-hmac-sha2.test.js | 98 - ..._6.direct_encryption_using_aes-gcm.test.js | 98 - ...gcm_keywrap_with_aes-cbc-hmac-sha2.test.js | 98 - ...rap_using_aes-keywrap_with_aes-gcm.test.js | 100 - test/cookbook/5_9.compressed_content.test.js | 100 - test/cookbook/jwk.test.js | 125 -- ...ng_rsa-oaep-256_with_a128cbc-hs256.test.js | 102 - test/cookbook/recipes/3_1.ec_public_key.js | 8 - test/cookbook/recipes/3_2.ec_private_key.js | 9 - test/cookbook/recipes/3_3.rsa_public_key.js | 7 - test/cookbook/recipes/3_4.rsa_private_key.js | 13 - .../3_5.symmetric_key_mac_computation.js | 7 - .../recipes/3_6.symmetric_key_encryption.js | 7 - .../cookbook/recipes/4_1.rsa_v15_signature.js | 43 - .../cookbook/recipes/4_2.rsa-pss_signature.js | 43 - test/cookbook/recipes/4_3.ecdsa_signature.js | 39 - .../4_4.hmac-sha2_integrity_protection.js | 37 - .../4_6.protecting_specific_header_fields.js | 44 - .../recipes/4_7.protecting_content_only.js | 45 - .../recipes/4_8.multiple_signatures.js | 89 - ...ryption_using_rsa_v15_and_aes-hmac-sha2.js | 49 - ...ncluding_additional_authentication_data.js | 46 - .../5_11.protecting_specific_header_fields.js | 53 - .../recipes/5_12.protecting_content_only.js | 60 - .../5_13.encrypting_to_multiple_recipients.js | 113 -- ..._encryption_using_rsa-oaep_with_aes-gcm.js | 50 - ...bes2-aes-keywrap_with-aes-cbc-hmac-sha2.js | 37 - ...ng_ecdh-es_and_aes-keywrap_with_aes-gcm.js | 45 - ...nt_using_ecdh-es_with_aes-cbc-hmac-sha2.js | 39 - .../5_6.direct_encryption_using_aes-gcm.js | 37 - ..._aes-gcm_keywrap_with_aes-cbc-hmac-sha2.js | 45 - ...key_wrap_using_aes-keywrap_with_aes-gcm.js | 43 - .../recipes/5_9.compressed_content.js | 46 - test/cookbook/recipes/index.js | 32 - ...n_using_rsa-oaep-256_with_a128cbc-hs256.js | 46 - .../rfc7797.4_1.hmac-sha2_b64_false.js | 37 - .../rfc7797.4_2.hmac-sha2_b64_false.js | 36 - test/cookbook/recipes/rfc8037.a4.ed25519.js | 35 - .../rfc7797.4_1.hmac-sha2_b64_false.test.js | 88 - .../rfc7797.4_2.hmac-sha2_b64_false.test.js | 64 - test/cookbook/rfc8037.a4.ed25519.test.js | 96 - test/cookbook/rfc8037.ecdhes.test.js | 42 - test/cookbook/verifiers.js | 136 -- test/electron/electron.test.js | 29 - test/electron/index.js | 3 - test/fixtures/Ed25519.key | 3 - test/fixtures/Ed25519.pem | 3 - test/fixtures/Ed448.key | 4 - test/fixtures/Ed448.pem | 4 - test/fixtures/P-256.key | 5 - test/fixtures/P-256.pem | 4 - test/fixtures/P-384.key | 6 - test/fixtures/P-384.pem | 5 - test/fixtures/P-521.key | 8 - test/fixtures/P-521.pem | 6 - test/fixtures/X25519.key | 3 - test/fixtures/X25519.pem | 3 - test/fixtures/X448.key | 4 - test/fixtures/X448.pem | 4 - test/fixtures/index.js | 127 -- test/fixtures/rsa.key | 28 - test/fixtures/rsa.pem | 9 - test/fixtures/secp256k1.key | 5 - test/fixtures/secp256k1.pem | 4 - test/help/base64url.test.js | 42 - test/help/ecdsa_signatures.test.js | 216 -- test/help/get_key.test.js | 78 - test/help/key_utils.test.js | 165 -- test/help/multi_error.test.js | 24 - test/help/secs.test.js | 58 - test/help/timing_safe_equal.test.js | 12 - test/jwa/sanity.test.js | 17 - test/jwe/compact.decrypt.test.mjs | 24 + test/jwe/compact.encrypt.test.mjs | 112 ++ test/jwe/complete.test.js | 71 - test/jwe/cookbook.test.mjs | 943 +++++++++ test/jwe/crit.test.js | 84 - test/jwe/ecdh_derive.test.js | 33 - test/jwe/flattened.decrypt.test.mjs | 227 +++ test/jwe/flattened.encrypt.test.mjs | 209 ++ test/jwe/sanity.test.js | 608 ------ test/jwe/smoke.oct.test.js | 52 - test/jwe/smoke.p256.test.js | 1 - test/jwe/smoke.p384.test.js | 1 - test/jwe/smoke.p521.test.js | 1 - test/jwe/smoke.rsa.test.js | 1 - test/jwe/smoke.rsamin.test.js | 20 - test/jwe/smoke.test.js | 15 - test/jwe/smoke.test.mjs | 296 +++ test/jwe/smoke.x25519.test.js | 1 - test/jwe/smoke.x448.test.js | 1 - test/jwk/ec.test.js | 332 ---- test/jwk/embedded.test.js | 189 -- test/jwk/embedded.test.mjs | 85 + test/jwk/general.test.js | 46 - test/jwk/generate.test.js | 254 --- test/jwk/import.test.js | 203 -- test/jwk/jwk2key.test.mjs | 206 ++ test/jwk/key_ops.test.js | 107 - test/jwk/keyobject.test.js | 135 -- test/jwk/none.test.js | 20 - test/jwk/oct.test.js | 214 -- test/jwk/okp_enc.test.js | 172 -- test/jwk/okp_enc_no_dh.js | 164 -- test/jwk/okp_sig.test.js | 267 --- test/jwk/rsa.test.js | 405 ---- test/jwk/thumbprint.test.mjs | 132 ++ test/jwk/x5c_thumbprints.test.js | 69 - test/jwks/keystore.test.js | 287 --- test/jwks/remote.test.mjs | 262 +++ test/jws/b64.test.js | 131 -- test/jws/compact.sign.test.mjs | 56 + test/jws/compact.verify.test.mjs | 24 + test/jws/complete.test.js | 39 - test/jws/cookbook.test.mjs | 520 +++++ test/jws/crit.test.js | 84 - test/jws/flattened.sign.test.mjs | 134 ++ test/jws/flattened.verify.test.mjs | 131 ++ test/jws/restrictions.test.mjs | 161 ++ test/jws/sanity.test.js | 281 --- test/jws/smoke.test.js | 60 - test/jws/smoke.test.mjs | 229 +++ test/jws/unsecured.test.js | 111 -- test/jwt/decode.test.js | 49 - test/jwt/decrypt.test.mjs | 399 ++++ test/jwt/encrypt.test.mjs | 135 ++ test/jwt/sign.test.js | 189 -- test/jwt/sign.test.mjs | 83 + test/jwt/unsecured.test.js | 46 - test/jwt/unsecured.test.mjs | 77 + test/jwt/verify.test.js | 937 --------- test/jwt/verify.test.mjs | 363 ++++ test/macros/generate.js | 20 - test/macros/index.js | 194 -- test/macros/test_asymm_enc.js | 36 - test/util/generators.test.mjs | 136 ++ tools/docs.postbump.js | 30 + tools/explode-exports.js | 48 + tools/member.sources.hbs | 33 + tools/reflection.hbs | 83 + tsconfig/base.json | 39 + tsconfig/browser.json | 8 + tsconfig/node-cjs.json | 8 + tsconfig/node-esm.json | 8 + tsconfig/node-webcrypto-cjs.json | 7 + tsconfig/node-webcrypto-esm.json | 7 + types/index.d.ts | 543 ----- types/jose-tests.ts | 120 -- types/tsconfig.json | 23 - webpack.config.js | 14 + 458 files changed, 18104 insertions(+), 18848 deletions(-) delete mode 100644 .c8rc.json delete mode 100644 .codecov.yml create mode 100644 .prettierignore delete mode 100644 LICENSE_THIRD_PARTY create mode 100644 docs/classes/_jwe_compact_encrypt_.compactencrypt.md create mode 100644 docs/classes/_jwe_flattened_encrypt_.flattenedencrypt.md create mode 100644 docs/classes/_jws_compact_sign_.compactsign.md create mode 100644 docs/classes/_jws_flattened_sign_.flattenedsign.md create mode 100644 docs/classes/_jwt_encrypt_.encryptjwt.md create mode 100644 docs/classes/_jwt_sign_.signjwt.md create mode 100644 docs/classes/_jwt_unsecured_.unsecuredjwt.md create mode 100644 docs/classes/_util_errors_.josealgnotallowed.md create mode 100644 docs/classes/_util_errors_.joseerror.md create mode 100644 docs/classes/_util_errors_.josenotsupported.md create mode 100644 docs/classes/_util_errors_.jwedecryptionfailed.md create mode 100644 docs/classes/_util_errors_.jweinvalid.md create mode 100644 docs/classes/_util_errors_.jwkinvalid.md create mode 100644 docs/classes/_util_errors_.jwksinvalid.md create mode 100644 docs/classes/_util_errors_.jwksmultiplematchingkeys.md create mode 100644 docs/classes/_util_errors_.jwksnomatchingkey.md create mode 100644 docs/classes/_util_errors_.jwsinvalid.md create mode 100644 docs/classes/_util_errors_.jwssignatureverificationfailed.md create mode 100644 docs/classes/_util_errors_.jwtclaimvalidationfailed.md create mode 100644 docs/classes/_util_errors_.jwtexpired.md create mode 100644 docs/classes/_util_errors_.jwtinvalid.md create mode 100644 docs/functions/_jwe_compact_decrypt_.compactdecrypt.md create mode 100644 docs/functions/_jwe_flattened_decrypt_.flatteneddecrypt.md create mode 100644 docs/functions/_jwk_embedded_.embeddedjwk.md create mode 100644 docs/functions/_jwk_parse_.parsejwk.md create mode 100644 docs/functions/_jwk_thumbprint_.calculatethumbprint.md create mode 100644 docs/functions/_jwks_remote_.createremotejwkset.md create mode 100644 docs/functions/_jws_compact_verify_.compactverify.md create mode 100644 docs/functions/_jws_flattened_verify_.flattenedverify.md create mode 100644 docs/functions/_jwt_decrypt_.jwtdecrypt.md create mode 100644 docs/functions/_jwt_verify_.jwtverify.md create mode 100644 docs/functions/_util_generate_key_pair_.generatekeypair.md create mode 100644 docs/functions/_util_generate_secret_.generatesecret.md create mode 100644 docs/interfaces/_jwe_compact_decrypt_.compactdecryptgetkey.md create mode 100644 docs/interfaces/_jwe_flattened_decrypt_.flatteneddecryptgetkey.md create mode 100644 docs/interfaces/_jwks_remote_.remotejwksetoptions.md create mode 100644 docs/interfaces/_jws_compact_verify_.compactverifygetkey.md create mode 100644 docs/interfaces/_jws_flattened_verify_.flattenedverifygetkey.md create mode 100644 docs/interfaces/_jwt_decrypt_.jwtdecryptgetkey.md create mode 100644 docs/interfaces/_jwt_decrypt_.jwtdecryptoptions.md create mode 100644 docs/interfaces/_jwt_verify_.jwtverifygetkey.md create mode 100644 docs/interfaces/_jwt_verify_.jwtverifyoptions.md create mode 100644 docs/interfaces/_types_d_.compactdecryptresult.md create mode 100644 docs/interfaces/_types_d_.compactverifyresult.md create mode 100644 docs/interfaces/_types_d_.decryptoptions.md create mode 100644 docs/interfaces/_types_d_.deflatefunction.md create mode 100644 docs/interfaces/_types_d_.encryptoptions.md create mode 100644 docs/interfaces/_types_d_.flatteneddecryptresult.md create mode 100644 docs/interfaces/_types_d_.flattenedjwe.md create mode 100644 docs/interfaces/_types_d_.flattenedjws.md create mode 100644 docs/interfaces/_types_d_.flattenedjwsinput.md create mode 100644 docs/interfaces/_types_d_.flattenedverifyresult.md create mode 100644 docs/interfaces/_types_d_.getkeyfunction.md create mode 100644 docs/interfaces/_types_d_.inflatefunction.md create mode 100644 docs/interfaces/_types_d_.joseheaderparameters.md create mode 100644 docs/interfaces/_types_d_.jweheaderparameters.md create mode 100644 docs/interfaces/_types_d_.jwekeymanagementheaderparameters.md create mode 100644 docs/interfaces/_types_d_.jwk.md create mode 100644 docs/interfaces/_types_d_.jwsheaderparameters.md create mode 100644 docs/interfaces/_types_d_.jwtclaimverificationoptions.md create mode 100644 docs/interfaces/_types_d_.jwtdecryptresult.md create mode 100644 docs/interfaces/_types_d_.jwtpayload.md create mode 100644 docs/interfaces/_types_d_.jwtverifyresult.md create mode 100644 docs/interfaces/_types_d_.verifyoptions.md create mode 100644 docs/interfaces/_util_generate_key_pair_.generatekeypairoptions.md create mode 100644 docs/modules/_jwe_compact_decrypt_.md create mode 100644 docs/modules/_jwe_compact_encrypt_.md create mode 100644 docs/modules/_jwe_flattened_decrypt_.md create mode 100644 docs/modules/_jwe_flattened_encrypt_.md create mode 100644 docs/modules/_jwk_embedded_.md create mode 100644 docs/modules/_jwk_parse_.md create mode 100644 docs/modules/_jwk_thumbprint_.md create mode 100644 docs/modules/_jwks_remote_.md create mode 100644 docs/modules/_jws_compact_sign_.md create mode 100644 docs/modules/_jws_compact_verify_.md create mode 100644 docs/modules/_jws_flattened_sign_.md create mode 100644 docs/modules/_jws_flattened_verify_.md create mode 100644 docs/modules/_jwt_decrypt_.md create mode 100644 docs/modules/_jwt_encrypt_.md create mode 100644 docs/modules/_jwt_sign_.md create mode 100644 docs/modules/_jwt_unsecured_.md create mode 100644 docs/modules/_jwt_verify_.md create mode 100644 docs/modules/_types_d_.md create mode 100644 docs/modules/_util_base64url_.md create mode 100644 docs/modules/_util_errors_.md create mode 100644 docs/modules/_util_generate_key_pair_.md create mode 100644 docs/modules/_util_generate_secret_.md create mode 100644 docs/modules/_util_random_.md create mode 100644 docs/types/_types_d_.keylike.md delete mode 100644 img/demo.gif create mode 100644 karma.conf.js delete mode 100644 lib/errors.js delete mode 100644 lib/help/asn1/algorithm_identifier.js delete mode 100644 lib/help/asn1/ec_private_key.js delete mode 100644 lib/help/asn1/index.js delete mode 100644 lib/help/asn1/oids.js delete mode 100644 lib/help/asn1/one_asymmetric_key.js delete mode 100644 lib/help/asn1/private_key.js delete mode 100644 lib/help/asn1/private_key_info.js delete mode 100644 lib/help/asn1/public_key_info.js delete mode 100644 lib/help/asn1/rsa_private_key.js delete mode 100644 lib/help/asn1/rsa_public_key.js delete mode 100644 lib/help/base64url.js delete mode 100644 lib/help/consts.js delete mode 100644 lib/help/deep_clone.js delete mode 100644 lib/help/ecdsa_signatures.js delete mode 100644 lib/help/epoch.js delete mode 100644 lib/help/generate_iv.js delete mode 100644 lib/help/get_key.js delete mode 100644 lib/help/is_disjoint.js delete mode 100644 lib/help/is_object.js delete mode 100644 lib/help/key_object.js delete mode 100644 lib/help/key_utils.js delete mode 100644 lib/help/node_alg.js delete mode 100644 lib/help/rsa_primes.js delete mode 100644 lib/help/runtime_support.js delete mode 100644 lib/help/timing_safe_equal.js delete mode 100644 lib/help/uint64be.js delete mode 100644 lib/help/validate_crit.js delete mode 100644 lib/index.js delete mode 100644 lib/index.mjs delete mode 100644 lib/jwa/aes_cbc_hmac_sha2.js delete mode 100644 lib/jwa/aes_gcm.js delete mode 100644 lib/jwa/aes_gcm_kw.js delete mode 100644 lib/jwa/aes_kw.js delete mode 100644 lib/jwa/ecdh/compute_secret.js delete mode 100644 lib/jwa/ecdh/derive.js delete mode 100644 lib/jwa/ecdh/dir.js delete mode 100644 lib/jwa/ecdh/kw.js delete mode 100644 lib/jwa/ecdsa.js delete mode 100644 lib/jwa/eddsa.js delete mode 100644 lib/jwa/hmac.js delete mode 100644 lib/jwa/index.js delete mode 100644 lib/jwa/none.js delete mode 100644 lib/jwa/pbes2.js delete mode 100644 lib/jwa/rsaes.js delete mode 100644 lib/jwa/rsassa.js delete mode 100644 lib/jwa/rsassa_pss.js delete mode 100644 lib/jwe/decrypt.js delete mode 100644 lib/jwe/encrypt.js delete mode 100644 lib/jwe/generate_cek.js delete mode 100644 lib/jwe/index.js delete mode 100644 lib/jwe/serializers.js delete mode 100644 lib/jwe/validate_headers.js delete mode 100644 lib/jwk/generate.js delete mode 100644 lib/jwk/import.js delete mode 100644 lib/jwk/index.js delete mode 100644 lib/jwk/key/base.js delete mode 100644 lib/jwk/key/ec.js delete mode 100644 lib/jwk/key/embedded.jwk.js delete mode 100644 lib/jwk/key/embedded.x5c.js delete mode 100644 lib/jwk/key/none.js delete mode 100644 lib/jwk/key/oct.js delete mode 100644 lib/jwk/key/okp.js delete mode 100644 lib/jwk/key/rsa.js delete mode 100644 lib/jwk/thumbprint.js delete mode 100644 lib/jwks/index.js delete mode 100644 lib/jwks/keystore.js delete mode 100644 lib/jws/index.js delete mode 100644 lib/jws/serializers.js delete mode 100644 lib/jws/sign.js delete mode 100644 lib/jws/verify.js delete mode 100644 lib/jwt/decode.js delete mode 100644 lib/jwt/index.js delete mode 100644 lib/jwt/profiles.js delete mode 100644 lib/jwt/shared_validations.js delete mode 100644 lib/jwt/sign.js delete mode 100644 lib/jwt/verify.js delete mode 100644 lib/registry/ec_curves.js delete mode 100644 lib/registry/ecdh_derive_lengths.js delete mode 100644 lib/registry/index.js delete mode 100644 lib/registry/iv_lengths.js delete mode 100644 lib/registry/jwa.js delete mode 100644 lib/registry/jwk.js delete mode 100644 lib/registry/key_lengths.js delete mode 100644 lib/registry/okp_curves.js create mode 100644 src/.eslintrc.json create mode 100644 src/.prettierrc.json create mode 100644 src/jwe/compact/decrypt.ts create mode 100644 src/jwe/compact/encrypt.ts create mode 100644 src/jwe/flattened/decrypt.ts create mode 100644 src/jwe/flattened/encrypt.ts create mode 100644 src/jwk/embedded.ts create mode 100644 src/jwk/parse.ts create mode 100644 src/jwk/thumbprint.ts create mode 100644 src/jwks/remote.ts create mode 100644 src/jws/compact/sign.ts create mode 100644 src/jws/compact/verify.ts create mode 100644 src/jws/flattened/sign.ts create mode 100644 src/jws/flattened/verify.ts create mode 100644 src/jwt/decrypt.ts create mode 100644 src/jwt/encrypt.ts create mode 100644 src/jwt/sign.ts create mode 100644 src/jwt/unsecured.ts create mode 100644 src/jwt/verify.ts create mode 100644 src/lib/buffer_utils.ts create mode 100644 src/lib/cek.ts create mode 100644 src/lib/check_iv_length.ts create mode 100644 src/lib/check_key_type.ts create mode 100644 src/lib/check_p2s.ts create mode 100644 src/lib/decrypt_key_management.ts create mode 100644 src/lib/encrypt_key_management.ts create mode 100644 src/lib/epoch.ts create mode 100644 src/lib/is_disjoint.ts create mode 100644 src/lib/is_object.ts create mode 100644 src/lib/iv.ts create mode 100644 src/lib/jwt_claims_set.ts create mode 100644 src/lib/jwt_producer.ts rename lib/help/secs.js => src/lib/secs.ts (86%) create mode 100644 src/lib/validate_algorithms.ts create mode 100644 src/lib/validate_crit.ts create mode 100644 src/runtime/browser/aesgcmkw.ts create mode 100644 src/runtime/browser/aeskw.ts create mode 100644 src/runtime/browser/base64url.ts create mode 100644 src/runtime/browser/bogus.ts create mode 100644 src/runtime/browser/check_cek_length.ts create mode 100644 src/runtime/browser/check_key_length.ts create mode 100644 src/runtime/browser/decrypt.ts create mode 100644 src/runtime/browser/digest.ts create mode 100644 src/runtime/browser/ecdhes.ts create mode 100644 src/runtime/browser/encrypt.ts create mode 100644 src/runtime/browser/fetch.ts create mode 100644 src/runtime/browser/generate.ts create mode 100644 src/runtime/browser/jwk_to_key.ts create mode 100644 src/runtime/browser/pbes2kw.ts create mode 100644 src/runtime/browser/random.ts create mode 100644 src/runtime/browser/rsaes.ts create mode 100644 src/runtime/browser/sign.ts create mode 100644 src/runtime/browser/subtle_dsa.ts create mode 100644 src/runtime/browser/subtle_rsaes.ts create mode 100644 src/runtime/browser/timing_safe_equal.ts create mode 100644 src/runtime/browser/verify.ts create mode 100644 src/runtime/browser/webcrypto.ts create mode 100644 src/runtime/browser/zlib.ts create mode 100644 src/runtime/interfaces.d.ts create mode 100644 src/runtime/node/aesgcmkw.ts create mode 100644 src/runtime/node/aeskw.ts create mode 100644 src/runtime/node/asn1_sequence_encoder.ts create mode 100644 src/runtime/node/base64url.ts create mode 100644 src/runtime/node/cbc_tag.ts create mode 100644 src/runtime/node/check_cek_length.ts create mode 100644 src/runtime/node/check_modulus_length.ts create mode 100644 src/runtime/node/decrypt.ts create mode 100644 src/runtime/node/digest.ts create mode 100644 src/runtime/node/dsa_digest.ts create mode 100644 src/runtime/node/ecdhes.ts create mode 100644 src/runtime/node/encrypt.ts create mode 100644 src/runtime/node/fetch.ts create mode 100644 src/runtime/node/generate.ts create mode 100644 src/runtime/node/get_named_curve.ts create mode 100644 src/runtime/node/hmac_digest.ts create mode 100644 src/runtime/node/jwk_to_key.ts create mode 100644 src/runtime/node/node_key.ts create mode 100644 src/runtime/node/pbes2kw.ts create mode 100644 src/runtime/node/random.ts create mode 100644 src/runtime/node/rsaes.ts create mode 100644 src/runtime/node/secret_key.ts create mode 100644 src/runtime/node/sign.ts create mode 100644 src/runtime/node/timing_safe_equal.ts create mode 100644 src/runtime/node/verify.ts create mode 100644 src/runtime/node/webcrypto.ts create mode 100644 src/runtime/node/zlib.ts create mode 100644 src/types.d.ts create mode 100644 src/types.i.d.ts create mode 100644 src/util/base64url.ts create mode 100644 src/util/errors.ts create mode 100644 src/util/generate_key_pair.ts create mode 100644 src/util/generate_secret.ts create mode 100644 src/util/random.ts create mode 100644 test-browser/.eslintrc.json create mode 100644 test-browser/.prettierrc.json create mode 100644 test-browser/generate_keys.js create mode 100644 test-browser/generate_secrets.js create mode 100644 test-browser/jwe_asymmetric.js create mode 100644 test-browser/jwe_symmetric.js create mode 100644 test-browser/jwks.js create mode 100644 test-browser/jws.js create mode 100644 test/.eslintrc.json create mode 100644 test/.prettierrc.json delete mode 100644 test/cookbook/4_1.rsa_v15_signature.test.js delete mode 100644 test/cookbook/4_2.rsa-pss_signature.test.js delete mode 100644 test/cookbook/4_3.ecdsa_signature.test.js delete mode 100644 test/cookbook/4_4.hmac-sha2_integrity_protection.test.js delete mode 100644 test/cookbook/4_6.protecting_specific_header_fields.test.js delete mode 100644 test/cookbook/4_7.protecting_content_only.test.js delete mode 100644 test/cookbook/4_8.multiple_signatures.test.js delete mode 100644 test/cookbook/5_1.key_encryption_using_rsa_v15_and_aes-hmac-sha2.test.js delete mode 100644 test/cookbook/5_10.including_additional_authentication_data.test.js delete mode 100644 test/cookbook/5_11.protecting_specific_header_fields.test.js delete mode 100644 test/cookbook/5_12.protecting_content_only.test.js delete mode 100644 test/cookbook/5_13.encrypting_to_multiple_recipients.test.js delete mode 100644 test/cookbook/5_2.key_encryption_using_rsa-oaep_with_aes-gcm.test.js delete mode 100644 test/cookbook/5_3.key_wrap_using_pbes2-aes-keywrap_with-aes-cbc-hmac-sha2.test.js delete mode 100644 test/cookbook/5_4.key_agreement_with_key_wrapping_using_ecdh-es_and_aes-keywrap_with_aes-gcm.test.js delete mode 100644 test/cookbook/5_5.key_agreement_using_ecdh-es_with_aes-cbc-hmac-sha2.test.js delete mode 100644 test/cookbook/5_6.direct_encryption_using_aes-gcm.test.js delete mode 100644 test/cookbook/5_7.key_wrap_using_aes-gcm_keywrap_with_aes-cbc-hmac-sha2.test.js delete mode 100644 test/cookbook/5_8.key_wrap_using_aes-keywrap_with_aes-gcm.test.js delete mode 100644 test/cookbook/5_9.compressed_content.test.js delete mode 100644 test/cookbook/jwk.test.js delete mode 100644 test/cookbook/ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256.test.js delete mode 100644 test/cookbook/recipes/3_1.ec_public_key.js delete mode 100644 test/cookbook/recipes/3_2.ec_private_key.js delete mode 100644 test/cookbook/recipes/3_3.rsa_public_key.js delete mode 100644 test/cookbook/recipes/3_4.rsa_private_key.js delete mode 100644 test/cookbook/recipes/3_5.symmetric_key_mac_computation.js delete mode 100644 test/cookbook/recipes/3_6.symmetric_key_encryption.js delete mode 100644 test/cookbook/recipes/4_1.rsa_v15_signature.js delete mode 100644 test/cookbook/recipes/4_2.rsa-pss_signature.js delete mode 100644 test/cookbook/recipes/4_3.ecdsa_signature.js delete mode 100644 test/cookbook/recipes/4_4.hmac-sha2_integrity_protection.js delete mode 100644 test/cookbook/recipes/4_6.protecting_specific_header_fields.js delete mode 100644 test/cookbook/recipes/4_7.protecting_content_only.js delete mode 100644 test/cookbook/recipes/4_8.multiple_signatures.js delete mode 100644 test/cookbook/recipes/5_1.key_encryption_using_rsa_v15_and_aes-hmac-sha2.js delete mode 100644 test/cookbook/recipes/5_10.including_additional_authentication_data.js delete mode 100644 test/cookbook/recipes/5_11.protecting_specific_header_fields.js delete mode 100644 test/cookbook/recipes/5_12.protecting_content_only.js delete mode 100644 test/cookbook/recipes/5_13.encrypting_to_multiple_recipients.js delete mode 100644 test/cookbook/recipes/5_2.key_encryption_using_rsa-oaep_with_aes-gcm.js delete mode 100644 test/cookbook/recipes/5_3.key_wrap_using_pbes2-aes-keywrap_with-aes-cbc-hmac-sha2.js delete mode 100644 test/cookbook/recipes/5_4.key_agreement_with_key_wrapping_using_ecdh-es_and_aes-keywrap_with_aes-gcm.js delete mode 100644 test/cookbook/recipes/5_5.key_agreement_using_ecdh-es_with_aes-cbc-hmac-sha2.js delete mode 100644 test/cookbook/recipes/5_6.direct_encryption_using_aes-gcm.js delete mode 100644 test/cookbook/recipes/5_7.key_wrap_using_aes-gcm_keywrap_with_aes-cbc-hmac-sha2.js delete mode 100644 test/cookbook/recipes/5_8.key_wrap_using_aes-keywrap_with_aes-gcm.js delete mode 100644 test/cookbook/recipes/5_9.compressed_content.js delete mode 100644 test/cookbook/recipes/index.js delete mode 100644 test/cookbook/recipes/ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256.js delete mode 100644 test/cookbook/recipes/rfc7797.4_1.hmac-sha2_b64_false.js delete mode 100644 test/cookbook/recipes/rfc7797.4_2.hmac-sha2_b64_false.js delete mode 100644 test/cookbook/recipes/rfc8037.a4.ed25519.js delete mode 100644 test/cookbook/rfc7797.4_1.hmac-sha2_b64_false.test.js delete mode 100644 test/cookbook/rfc7797.4_2.hmac-sha2_b64_false.test.js delete mode 100644 test/cookbook/rfc8037.a4.ed25519.test.js delete mode 100644 test/cookbook/rfc8037.ecdhes.test.js delete mode 100644 test/cookbook/verifiers.js delete mode 100644 test/electron/electron.test.js delete mode 100644 test/electron/index.js delete mode 100644 test/fixtures/Ed25519.key delete mode 100644 test/fixtures/Ed25519.pem delete mode 100644 test/fixtures/Ed448.key delete mode 100644 test/fixtures/Ed448.pem delete mode 100644 test/fixtures/P-256.key delete mode 100644 test/fixtures/P-256.pem delete mode 100644 test/fixtures/P-384.key delete mode 100644 test/fixtures/P-384.pem delete mode 100644 test/fixtures/P-521.key delete mode 100644 test/fixtures/P-521.pem delete mode 100644 test/fixtures/X25519.key delete mode 100644 test/fixtures/X25519.pem delete mode 100644 test/fixtures/X448.key delete mode 100644 test/fixtures/X448.pem delete mode 100644 test/fixtures/index.js delete mode 100644 test/fixtures/rsa.key delete mode 100644 test/fixtures/rsa.pem delete mode 100644 test/fixtures/secp256k1.key delete mode 100644 test/fixtures/secp256k1.pem delete mode 100644 test/help/base64url.test.js delete mode 100644 test/help/ecdsa_signatures.test.js delete mode 100644 test/help/get_key.test.js delete mode 100644 test/help/key_utils.test.js delete mode 100644 test/help/multi_error.test.js delete mode 100644 test/help/secs.test.js delete mode 100644 test/help/timing_safe_equal.test.js delete mode 100644 test/jwa/sanity.test.js create mode 100644 test/jwe/compact.decrypt.test.mjs create mode 100644 test/jwe/compact.encrypt.test.mjs delete mode 100644 test/jwe/complete.test.js create mode 100644 test/jwe/cookbook.test.mjs delete mode 100644 test/jwe/crit.test.js delete mode 100644 test/jwe/ecdh_derive.test.js create mode 100644 test/jwe/flattened.decrypt.test.mjs create mode 100644 test/jwe/flattened.encrypt.test.mjs delete mode 100644 test/jwe/sanity.test.js delete mode 100644 test/jwe/smoke.oct.test.js delete mode 100644 test/jwe/smoke.p256.test.js delete mode 100644 test/jwe/smoke.p384.test.js delete mode 100644 test/jwe/smoke.p521.test.js delete mode 100644 test/jwe/smoke.rsa.test.js delete mode 100644 test/jwe/smoke.rsamin.test.js delete mode 100644 test/jwe/smoke.test.js create mode 100644 test/jwe/smoke.test.mjs delete mode 100644 test/jwe/smoke.x25519.test.js delete mode 100644 test/jwe/smoke.x448.test.js delete mode 100644 test/jwk/ec.test.js delete mode 100644 test/jwk/embedded.test.js create mode 100644 test/jwk/embedded.test.mjs delete mode 100644 test/jwk/general.test.js delete mode 100644 test/jwk/generate.test.js delete mode 100644 test/jwk/import.test.js create mode 100644 test/jwk/jwk2key.test.mjs delete mode 100644 test/jwk/key_ops.test.js delete mode 100644 test/jwk/keyobject.test.js delete mode 100644 test/jwk/none.test.js delete mode 100644 test/jwk/oct.test.js delete mode 100644 test/jwk/okp_enc.test.js delete mode 100644 test/jwk/okp_enc_no_dh.js delete mode 100644 test/jwk/okp_sig.test.js delete mode 100644 test/jwk/rsa.test.js create mode 100644 test/jwk/thumbprint.test.mjs delete mode 100644 test/jwk/x5c_thumbprints.test.js delete mode 100644 test/jwks/keystore.test.js create mode 100644 test/jwks/remote.test.mjs delete mode 100644 test/jws/b64.test.js create mode 100644 test/jws/compact.sign.test.mjs create mode 100644 test/jws/compact.verify.test.mjs delete mode 100644 test/jws/complete.test.js create mode 100644 test/jws/cookbook.test.mjs delete mode 100644 test/jws/crit.test.js create mode 100644 test/jws/flattened.sign.test.mjs create mode 100644 test/jws/flattened.verify.test.mjs create mode 100644 test/jws/restrictions.test.mjs delete mode 100644 test/jws/sanity.test.js delete mode 100644 test/jws/smoke.test.js create mode 100644 test/jws/smoke.test.mjs delete mode 100644 test/jws/unsecured.test.js delete mode 100644 test/jwt/decode.test.js create mode 100644 test/jwt/decrypt.test.mjs create mode 100644 test/jwt/encrypt.test.mjs delete mode 100644 test/jwt/sign.test.js create mode 100644 test/jwt/sign.test.mjs delete mode 100644 test/jwt/unsecured.test.js create mode 100644 test/jwt/unsecured.test.mjs delete mode 100644 test/jwt/verify.test.js create mode 100644 test/jwt/verify.test.mjs delete mode 100644 test/macros/generate.js delete mode 100644 test/macros/index.js delete mode 100644 test/macros/test_asymm_enc.js create mode 100644 test/util/generators.test.mjs create mode 100755 tools/docs.postbump.js create mode 100755 tools/explode-exports.js create mode 100644 tools/member.sources.hbs create mode 100644 tools/reflection.hbs create mode 100644 tsconfig/base.json create mode 100644 tsconfig/browser.json create mode 100644 tsconfig/node-cjs.json create mode 100644 tsconfig/node-esm.json create mode 100644 tsconfig/node-webcrypto-cjs.json create mode 100644 tsconfig/node-webcrypto-esm.json delete mode 100644 types/index.d.ts delete mode 100644 types/jose-tests.ts delete mode 100644 types/tsconfig.json create mode 100644 webpack.config.js diff --git a/.c8rc.json b/.c8rc.json deleted file mode 100644 index 7cb7d759b6..0000000000 --- a/.c8rc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "reporter": ["lcov", "text-summary"] -} diff --git a/.codecov.yml b/.codecov.yml deleted file mode 100644 index e6779cb506..0000000000 --- a/.codecov.yml +++ /dev/null @@ -1,14 +0,0 @@ -coverage: - status: - project: off - patch: off - changes: off - -comment: - layout: diff - behavior: once - -ignore: - - package.json - - **/*.md - - **/*.yml diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index a10fe2040e..a2577039b4 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -5,26 +5,33 @@ labels: triage --- **Describe the bug** - + **To Reproduce** -Steps to reproduce the behaviour: + -1. -2. -3. +Code to reproduce the behaviour: + +```js +// formatted code snippet that reproduces the behaviour +``` **Expected behaviour** A clear and concise description of what you expected to happen. **Environment:** - - `jose` version: [e.g. v1.0.0] - - node version: [e.g. v12.0.0] + +- `jose` version: [e.g. v3.0.0] +- affected runtime is: [e.g. Node.js 14.15.0, Chrome 86, or iOS 14 Safari] **Additional context** Add any other context about the problem here. - - [ ] the bug is happening on latest `jose` too. - - [ ] i have searched the issues tracker on github for similar issues and couldn't find anything related. +- [ ] the bug is happening on latest `jose` too. +- [ ] i have searched the issues tracker on github for similar issues and couldn't find anything related. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index bdb43775a1..d75c6434af 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -5,6 +5,7 @@ contact_links: about: Are you asking your nth question? Consider supporting the project before opening another. - name: Report a security vulnerability url: https://en.wikipedia.org/wiki/Responsible_disclosure - about: Do not disclose vulnerabilities via issues. Reach out to the project team via e.g. email, + about: + Do not disclose vulnerabilities via issues. Reach out to the project team via e.g. email, we'll work together on patching the vulnerability and follow some form of Responsible disclosure once fixed. Thank you. diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md index dc44b0846c..87ce03f52e 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -16,5 +16,5 @@ A clear and concise description of any alternative solutions or features you've **Additional context** Add any other context about the problem here. - - [ ] i have searched the configuration section for this feature and couldn't find it - - [ ] i have searched the issues tracker on github for similar requests and couldn't find anything related. +- [ ] i have searched the configuration section for this feature and couldn't find it +- [ ] i have searched the issues tracker on github for similar requests and couldn't find anything related. diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 850ec51dcf..13b3b6c607 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,55 +1,48 @@ name: "Code scanning - action" on: - push: - paths-ignore: - - '**.md' - pull_request: - paths-ignore: - - '**.md' schedule: - - cron: '0 6 * * 0' + - cron: "0 6 * * 0" jobs: CodeQL-Build: - runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v2 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 - - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - # Override language selection by uncommenting this and choosing your languages - # with: - # languages: go, javascript, csharp, python, cpp, java - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + - name: Checkout repository + uses: actions/checkout@v2 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 + + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + # Override language selection by uncommenting this and choosing your languages + # with: + # languages: go, javascript, csharp, python, cpp, java + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index 44399fc304..9fc487850c 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -1,8 +1,8 @@ -name: 'Lock threads' +name: "Lock threads" on: schedule: - - cron: '0 9 * * *' + - cron: "0 9 * * *" jobs: lock: @@ -11,7 +11,7 @@ jobs: - uses: dessant/lock-threads@v2 with: github-token: ${{ github.token }} - issue-lock-inactive-days: '90' - issue-lock-reason: '' - pr-lock-inactive-days: '90' - pr-lock-reason: '' + issue-lock-inactive-days: "90" + issue-lock-reason: "" + pr-lock-inactive-days: "90" + pr-lock-reason: "" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1955e18042..5ea9a0fdc2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,16 +3,15 @@ name: Continuous Integration on: push: paths-ignore: - - '**.md' + - "**.md" pull_request: paths-ignore: - - '**.md' + - "**.md" schedule: - - cron: 0 11 * * 1-5 + - cron: 0 11 * * 1-5 jobs: - lint: - name: Lint + build: runs-on: ubuntu-latest steps: - name: Checkout @@ -20,7 +19,7 @@ jobs: - name: Setup node uses: actions/setup-node@v2-beta with: - node-version: 12 + node-version: 14 - name: Store node version variable id: node run: | @@ -30,35 +29,37 @@ jobs: id: node_modules with: path: node_modules - key: ${{ runner.os }}-node_modules-${{ hashFiles('**/package.json') }}-${{ steps.node.outputs.version }} + key: ${{ runner.os }}-node_modules-${{ hashFiles('package.json') }}-${{ steps.node.outputs.version }} - name: Install dependencies run: npx panva/npm-install-retry if: ${{ steps.node_modules.outputs.cache-hit != 'true' }} - - run: npm run lint - - run: npm run lint-ts + - name: Cache dist + uses: actions/cache@v2 + id: dist + with: + path: dist + key: dist-${{ hashFiles('src/**/*.ts') }}-${{ hashFiles('tsconfig/*.json') }} + - run: sed -i -e "s/-i ''/-i/g" package.json + - name: Build + run: npm run build-all + if: ${{ steps.dist.outputs.cache-hit != 'true' }} + - run: git reset HEAD --hard test: env: - NODE_NO_WARNINGS: 1 - runs-on: ${{ matrix.os }} + NODE_OPTIONS: --enable-source-maps + needs: + - build strategy: matrix: node-version: - - 10.13.0 - - 10 - - 11.0.0 - - 11 - - 12.0.0 + - 12.19.0 - 12 - - 13.7.0 - - 13 - - 14.0.0 + - 14.15.0 - 14 - 15.0.1 - 15 - os: - - ubuntu-latest - - windows-latest + runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@master @@ -75,42 +76,40 @@ jobs: id: node_modules with: path: node_modules - key: ${{ runner.os }}-node_modules-${{ hashFiles('**/package.json') }}-${{ steps.node.outputs.version }} + key: ${{ runner.os }}-node_modules-${{ hashFiles('package.json') }}-${{ steps.node.outputs.version }} - name: Install dependencies run: npx panva/npm-install-retry if: ${{ steps.node_modules.outputs.cache-hit != 'true' }} - - run: npm run coverage - - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - run: npx codecov + - name: Load cached dist + uses: actions/cache@v2 + id: dist + with: + path: dist + key: dist-${{ hashFiles('src/**/*.ts') }}-${{ hashFiles('tsconfig/*.json') }} + - run: npm install + working-directory: ./test + - name: Test Node.js crypto + run: npm run test + - name: Test Web Cryptography API + run: npm run test-webcrypto + if: ${{ !startsWith(matrix.node-version, '14') && !startsWith(matrix.node-version, '12') }} + - run: git reset HEAD --hard - test-electron: + browserstack: env: - NODE_NO_WARNINGS: 1 - runs-on: ${{ matrix.os }} - strategy: - matrix: - electron-version: - - 6.0.0 - - 6 - - 7.0.0 - - 7 - - 8.0.0 - - 8 - - 9.0.0 - - 9 - - 10.0.0 - - 10 - os: - - ubuntu-latest - - windows-latest + NODE_OPTIONS: --enable-source-maps + BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }} + BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }} + needs: + - build + runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@master - name: Setup node uses: actions/setup-node@v2-beta with: - node-version: 12 + node-version: 14 - name: Store node version variable id: node run: | @@ -120,9 +119,15 @@ jobs: id: node_modules with: path: node_modules - key: ${{ runner.os }}-node_modules-${{ hashFiles('**/package.json') }}-${{ steps.node.outputs.version }} + key: ${{ runner.os }}-node_modules-${{ hashFiles('package.json') }}-${{ steps.node.outputs.version }} - name: Install dependencies run: npx panva/npm-install-retry if: ${{ steps.node_modules.outputs.cache-hit != 'true' }} - - run: npm install --global xvfb-maybe electron@${{ matrix.electron-version }} - - run: xvfb-maybe electron ./test/electron + - name: Load cached dist + uses: actions/cache@v2 + id: dist + with: + path: dist + key: dist-${{ hashFiles('src/**/*.ts') }}-${{ hashFiles('tsconfig/*.json') }} + - run: npm run test-browser + - run: git reset HEAD --hard diff --git a/.gitignore b/.gitignore index b39b8bfc82..8e8c1e8b06 100644 --- a/.gitignore +++ b/.gitignore @@ -1,45 +1,10 @@ -# Logs -logs -*.log -npm-debug.log* +# crypto runtime copies +src/runtime/*.ts ++src/runtime/interfaces.d.ts -# Runtime data -pids -*.pid -*.seed +# cjs clone of the test suite +test/cjs -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -.nyc_output - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (http://nodejs.org/api/addons.html) -node -build/Release - -# Dependency directory and lockfiles -node_modules -yarn.lock -npm-shrinkwrap.json -package-lock.json - -# Optional npm cache directory -.npm - -# Optional REPL history -.node_repl_history - -# TODOs -TODO*.md -.nvmrc # Logs logs *.log @@ -79,12 +44,15 @@ bower_components # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release -# Dependency directories +# Dependency directory and lockfiles node_modules/ jspm_packages/ +yarn.lock +npm-shrinkwrap.json +package-lock.json -# TypeScript v1 declaration files -typings/ +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ # TypeScript cache *.tsbuildinfo @@ -116,13 +84,16 @@ typings/ # parcel-bundler cache (https://parceljs.org/) .cache +.parcel-cache # Next.js build output .next +out # Nuxt.js build / generate output .nuxt dist +dist-browser-tests # Gatsby files .cache/ @@ -148,5 +119,9 @@ dist # Stores VSCode versions used for testing VSCode extensions .vscode-test -# TS test -types/*.js +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..330fc8a1f8 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +# Ignore artifacts: +build +dist +coverage diff --git a/LICENSE_THIRD_PARTY b/LICENSE_THIRD_PARTY deleted file mode 100644 index 2df8e111e8..0000000000 --- a/LICENSE_THIRD_PARTY +++ /dev/null @@ -1,209 +0,0 @@ -https://github.com/Brightspace/node-ecdsa-sig-formatter - -// CHANGES MADE -// - code style -// - uses new ECMAScript syntax -// - removed dependencies -// - only accepts and produces Buffers to avoid type conversion - -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2015 D2L Corporation - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/README.md b/README.md index 67a5e6361c..ff568668c1 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # jose -> "JSON Web Almost Everything" - JWA, JWS, JWE, JWT, JWK, JWKS for Node.js with minimal dependencies - -

+> Universal "JSON Web Almost Everything" - JWA, JWS, JWE, JWT, JWK with no dependencies using native crypto runtimes ## Implemented specs & features @@ -21,354 +19,198 @@ The following specifications are implemented by `jose` The test suite utilizes examples defined in [RFC7520][spec-cookbook] to confirm its JOSE implementation is correct. -Available JWT validation profiles - -- Generic JWT -- OIDC ID Token - [OpenID Connect Core 1.0][spec-oidc-id_token] -- (draft 04) OIDC Logout Token - [OpenID Connect Back-Channel Logout 1.0][spec-oidc-logout_token] -- (draft 06) OAuth 2.0 JWT Access Tokens - [JWT Profile for OAuth 2.0 Access Tokens][draft-ietf-oauth-access-token-jwt] - ## Support If you or your business use `jose`, please consider becoming a [sponsor][support-sponsor] so I can continue maintaining it and adding new features carefree. -## Documentation - -- [jose API Documentation][documentation] - - [JWK (JSON Web Key)][documentation-jwk] - - [JWKS (JSON Web Key Set)][documentation-jwks] - - [JWT (JSON Web Token)][documentation-jwt] - - [JWS (JSON Web Signature)][documentation-jws] - - [JWE (JSON Web Encryption)][documentation-jwe] - -## Usage - -For the best performance Node.js version **>=12.0.0** is recommended, but **^10.13.0** lts/dubnium -is also supported. - -Installing `jose` +## Install ```console -npm install jose -``` - -Usage -```js -const jose = require('jose') -const { - JWE, // JSON Web Encryption (JWE) - JWK, // JSON Web Key (JWK) - JWKS, // JSON Web Key Set (JWKS) - JWS, // JSON Web Signature (JWS) - JWT, // JSON Web Token (JWT) - errors // errors utilized by jose -} = jose -``` - -#### Keys and KeyStores - -Prepare your Keys and KeyStores. See the [documentation][documentation-jwk] for more. - -```js -const key = jose.JWK.asKey(fs.readFileSync('path/to/key/file')) - -const jwk = { kty: 'EC', - kid: 'dl4M_fcI7XoFCsQ22PYrQBkuxZ2pDcbDimcdFmmXM98', - crv: 'P-256', - x: 'v37avifcL-xgh8cy6IFzcINqqmFLc2JF20XUpn4Y2uQ', - y: 'QTwy27XgP7ZMOdGOSopAHB-FU1JMQn3J9GEWGtUXreQ' } -const anotherKey = jose.JWK.asKey(jwk) - -const keystore = new jose.JWKS.KeyStore(key, anotherKey) -``` - -### JWT vs JWS - -The JWT module provides IANA registered claim type and format validations on top of JWS as well as -convenience options for verifying UNIX timestamps, setting maximum allowed JWT age, verifying -audiences, and more. - -The JWS module on the other hand handles the other JWS Serialization Syntaxes with all their -additional available features and allows signing of any payload, i.e. not just serialized JSON -objects. - -#### JWT Signing - -Sign with a private or symmetric key with plethora of convenience options. See the -[documentation][documentation-jwt] for more. - -```js -jose.JWT.sign( - { 'urn:example:claim': 'foo' }, - privateKey, - { - algorithm: 'PS256', - audience: 'urn:example:client_id', - expiresIn: '1 hour', - header: { - typ: 'JWT' - }, - issuer: 'https://op.example.com' - } -) -``` - -#### JWT Verifying - -Verify with a public or symmetric key with plethora of convenience options. See the -[documentation][documentation-jwt] for more. - -```js -jose.JWT.verify( - 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzI1NiIsImtpZCI6IjRQQXBsVkJIN0toS1ZqN0xob0RFM0VVQnNGc0hvaTRhSmxBZGstM3JuME0ifQ.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6ImZvbyIsImF1ZCI6InVybjpleGFtcGxlOmNsaWVudF9pZCIsImlzcyI6Imh0dHBzOi8vb3AuZXhhbXBsZS5jb20iLCJpYXQiOjE1NTEyOTI2MjksImV4cCI6MTU1MTI5NjIyOX0.nE5fgRL8gvlStf_wB4mJ0TSXVmhJRnUVQuZ0ts6a1nWnnk0Rv69bEJ12BoMdpyPrGa_W6dxU4HFj89F4pQwW0kqBK2-TZ_n9lq-iqupj46w_lpKOfPC3clVc7ZmqYF81bEA-nX93cSKqVV-qPNPEFenb8XHKszYhBFu_uiRg9rXj2qXVU7PXGJAGTzhVgVxB-3XDB1bQ_6KiDCwzVPftrHxEYLydRCaHzggDg6sAFUhQqhPguKuE2gs6jVUh_gIL2RXeoLoinx6gZ72rfovaOmud-yzNIUN8Tvo0pqBmx0s_lEhTlfrQCzN7hZNmV1eG0GDDE-S_CfZhPePnVJZoRA', - publicKey, - { - issuer: 'https://op.example.com', - audience: 'urn:example:client_id', - algorithms: ['PS256'] - } -) -``` - -
- Verifying OIDC ID Tokens (Click to expand)
- -ID Token is a JWT, but profiled, there are additional requirements to a JWT to be accepted as an -ID Token and it is pretty easy to omit some, use the -`JWT.IdToken.verify` API to make sure what you're accepting is really an ID Token meant to -your Client. This will then perform all doable validations given the input. See the -[documentation][documentation-jwt] for more. - -```js -jose.JWT.IdToken.verify( - 'eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJzdWIiOiJmb28iLCJub25jZSI6ImE1MWNjZjA4ZjRiYmIwNmU4ODcxNWRkYzRiYmI0MWQ4IiwiYXVkIjoidXJuOmV4YW1wbGU6Y2xpZW50X2lkIiwiZXhwIjoxNTYzODg4ODMwLCJpYXQiOjE1NjM4ODUyMzAsImlzcyI6Imh0dHBzOi8vb3AuZXhhbXBsZS5jb20ifQ.RKCZczgICF5G9XdNDSwe4dolGauQHptpFKPzahA2wYGG2HKrKhyC8ZzqpeVc8cbntuqFBgABJVv6_9YICRx_dgwPYydTpZfZYjHnxrdWF9QsIPEGs672mrnhqIXUnXoseZ0TF6GOq6P7Qbf6gk1ru7TAbr_ieyJnNWcJhh5iHpz1k3mFz0TyTh7UNXshtQXftPUipqz4OBni5r9UaZXHw8B3QYOnms8__GJ3owOxaqkr1jgRs_EWqMlBNjPaj7ElVaeBWljDKuoK673tH0heSpgzUmUX_W8IDUVqs33uglpZwAQC7cAA5mGEg2odcRpvpP5M-WaP4RE9dl9jzcYmrw', - keyOrStore, - { - issuer: 'https://op.example.com', - audience: 'urn:example:client_id', - nonce: 'a51ccf08f4bbb06e88715ddc4bbb41d8', - algorithms: ['PS256'] - } -) -``` - -Note: Depending on the channel you receive an ID Token from the following claims may be required -and must also be checked: `at_hash`, `c_hash` or `s_hash`. Use e.g. [`oidc-token-hash`][oidc-token-hash] -to validate those hashes after getting the ID Token payload and signature validated by `jose` - -
- -
- Verifying OAuth 2.0 JWT Access Tokens (Click to expand)
- -Draft specification profiles are updated as minor versions of the library, therefore, -since they may have breaking changes use the `~` semver operator when using these and pay close -attention to changelog and the drafts themselves. - -When accepting a JWT-formatted OAuth 2.0 Access Token there are additional requirements for the JWT -to be accepted as an Access Token according to the [specification][draft-ietf-oauth-access-token-jwt] -and it is pretty easy to omit some. Use the -`JWT.AccessToken.verify` API to make sure what you're accepting is really a JWT Access Token -meant for your Resource Server. This will then perform all doable validations given the input. See -the [documentation][documentation-jwt] for more. - -```js -jose.JWT.AccessToken.verify( - 'eyJhbGciOiJQUzI1NiIsInR5cCI6ImF0K0pXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJzdWIiOiJmb28iLCJjbGllbnRfaWQiOiJ1cm46ZXhhbXBsZTpjbGllbnRfaWQiLCJhdWQiOiJ1cm46ZXhhbXBsZTpyZXNvdXJjZS1zZXJ2ZXIiLCJleHAiOjE1NjM4ODg4MzAsImlzcyI6Imh0dHBzOi8vb3AuZXhhbXBsZS5jb20iLCJzY29wZSI6ImFwaTpyZWFkIn0.UYy8vEGWS0cS24giCYobMMy9-bqI45p807yV1l-2WXX2J4UO-eohV_R58LE2oM88gl414c6XydO6QSYXul5roNPoOs41jpEvreQIP-HmegjbWGutktWJKfvoOblE5FjYwjrwStjLQGUzkq6KWcnDLPGmpFy7n6gZ4LF8YVz4dLEaO335hMNVNrmSPSXYqr7bAWybnLVpLxjDYwNfCO1g0_TlFx8fHh2OftHoOOmJFltFwb8JypkSB-JXVVSEh43IOEjeeMJIG_ylWIOxfLLi5Q7vPWgub83ZTkuGNe4KmlQJKIsH5k0yZSshsLYUOOH0RiXqQ-SA4Ubh3Fowigdu-g', - keyOrStore, - { - issuer: 'https://op.example.com', - audience: 'urn:example:resource-server', - algorithms: ['PS256'] - } -) -``` - -
- -
- Verifying OIDC Logout Token (Click to expand)
- -Draft specification profiles are updated as minor versions of the library, therefore, -since they may have breaking changes use the `~` semver operator when using these and pay close -attention to changelog and the drafts themselves. - -Logout Token is a JWT, but profiled, there are additional requirements to a JWT to be accepted as an -Logout Token and it is pretty easy to omit some, use the -`JWT.LogoutToken.verify` API to make sure what you're accepting is really an Logout Token meant to your -Client. This will then perform all doable validations given the input. See the -[documentation][documentation-jwt] for more. - -```js -jose.JWT.LogoutToken.verify( - 'eyJhbGciOiJQUzI1NiJ9.eyJzdWIiOiJmb28iLCJhdWQiOiJ1cm46ZXhhbXBsZTpjbGllbnRfaWQiLCJpYXQiOjE1NjM4ODg4MzAsImp0aSI6ImhqazMyN2RzYSIsImlzcyI6Imh0dHBzOi8vb3AuZXhhbXBsZS5jb20iLCJldmVudHMiOnsiaHR0cDovL3NjaGVtYXMub3BlbmlkLm5ldC9ldmVudC9iYWNrY2hhbm5lbC1sb2dvdXQiOnt9fX0.SBi7uNUvjHL9TFoFzautGgTQ1MjyeGUNYHL7inpgq3XgTv6xc9EAKuPRtpixmhdNhmInGwUvAeqDSJxomwv1KK1cTndrC9zAMZ7h657BGQAwGhu7nTm41fWMpKQdiLa9sqp3yit5_FNBmqUNeOoMPrYT_Vl9ytsoNO89MUQy2aqCd-Z7BrNJZH0QycdW6dmYlrmZL7w3t3TaAXoJDJ4Hgl2Itkkkb6_6gO-VoPIdVD8sDuf1zQzGhIkmcFrk0fXczVYOkeF2hNYBuvsM8LuO-EPA3oyE2In9djai3M7yceTQetRa1vwlqWkg_xmYS59ry-6wT44aN7-Y6p0TdXm-Zg', - keyOrStore, - { - issuer: 'https://op.example.com', - audience: 'urn:example:client_id', - algorithms: ['PS256'] - } -) -``` - -
- -#### JWS Signing - -Sign with a private or symmetric key using compact serialization. See the -[documentation][documentation-jws] for more. - -```js -jose.JWS.sign( - { sub: 'johndoe' }, - privateKey, - { kid: privateKey.kid } -) -``` - -#### JWS Verifying - -Verify with a public or symmetric key. See the [documentation][documentation-jws] for more. - -```js -jose.JWS.verify( - 'eyJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJqb2huZG9lIn0.T_SYLQV3A5_kFDDVNuoadoURSEtuSOR-dG2CMmrP-ULK9xbIf2vYeiHOkvTrnqGlWEGBGxYtsP1VkXmNsi1uOw', - publicKey -) +npm install jose@3 ``` -#### JWE Encrypting - -Encrypt using the recipient's public key or a shared symmetrical secret. See the -[documentation][documentation-jwe] for more. - -```js -jose.JWE.encrypt( - 'eyJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJqb2huZG9lIn0.T_SYLQV3A5_kFDDVNuoadoURSEtuSOR-dG2CMmrP-ULK9xbIf2vYeiHOkvTrnqGlWEGBGxYtsP1VkXmNsi1uOw', - publicKey, - { kid: publicKey.kid } -) -``` - -#### JWE Decrypting - -Decrypt using the private key or a shared symmetrical secret. See the -[documentation][documentation-jwe] for more. - -```js -jose.JWE.decrypt( - 'eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiRUNESC1FUyIsImVwayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6IkVsUGhsN1ljTVZsWkhHM0daSkRoOVJhemNYYlN2VFNheUF6aTBINFFtRUEiLCJ5IjoiM0hDREJTRy12emd6cGtLWmJqMU05UzVuUEJrTDBBdFM4U29ORUxMWE1SayJ9fQ..FhmidRo0twvFA7jcfKFNJw.o112vgiG_qUL1JR5WHpsErcxxgaK_FAa7vCWJ--WulndLpdwdRXHd9k3aL_k8K67xoAThrt10d7dSY2TlPpHdYkw979u0V-C4TNrpzNkv5jpBjU6hHyKpoGZfEsiTD1ivHaFy3ZLCTS69kN_eVKsZGLVf_dkq6Sz6bWE4-ln_fuwukPyMvjTyaTreLjPLBZW.ocKwptCm4Zn437L5hWFnHg', - privateKey -) -``` - -## Detailed Support Matrix +## Documentation -| JWK Key Types | Supported | `kty` value | `crv` values | +- JSON Web Tokens (JWT) + - [Signing](docs/classes/_jwt_sign_.signjwt.md#readme) + - [Verification & Claims Set Validation](docs/functions/_jwt_verify_.jwtverify.md#readme) + - Encrypted JSON Web Tokens + - [Encryption](docs/classes/_jwt_encrypt_.encryptjwt.md#readme) + - [Decryption & Claims Set Validation](docs/functions/_jwt_decrypt_.jwtdecrypt.md#readme) +- JSON Web Encryption (JWE) + - Encryption - [Compact](docs/classes/_jwe_compact_encrypt_.compactencrypt.md#readme), [Flattened](docs/classes/_jwe_flattened_encrypt_.flattenedencrypt.md#readme) + - Decryption - [Compact](docs/functions/_jwe_compact_decrypt_.compactdecrypt.md#readme), [Flattened](docs/functions/_jwe_flattened_decrypt_.flatteneddecrypt.md#readme) +- JSON Web Signature (JWS) + - Signing - [Compact](docs/classes/_jws_compact_sign_.compactsign.md#readme), [Flattened](docs/classes/_jws_flattened_sign_.flattenedsign.md#readme) + - Verification - [Compact](docs/functions/_jws_compact_verify_.compactverify.md#readme), [Flattened](docs/functions/_jws_flattened_verify_.flattenedverify.md#readme) +- JSON Web Key (JWK) + - [Parsing & Conversion](docs/functions/_jwk_parse_.parsejwk.md#readme) + - [Thumbprints](docs/functions/_jwk_thumbprint_.calculatethumbprint.md#readme) + - [EmbeddedJWK](docs/functions/_jwk_embedded_.embeddedjwk.md#readme) +- JSON Web Key Set (JWKS) + - [Verify using a remote JWKSet](docs/functions/_jwks_remote_.createremotejwkset.md#readme) +- Key Pair or Secret Generation + - [Asymmetric Key Pair Generation](docs/functions/_util_generate_key_pair_.generatekeypair.md#readme) + - [Symmetric Secret Generation](docs/functions/_util_generate_secret_.generatesecret.md#readme) +- [Unsecured JWT](docs/classes/_jwt_unsecured_.unsecuredjwt.md#readme) +- [JOSE Errors](docs/modules/_util_errors_.md) + +## JOSE Support Matrix + +| JWK Key Types | Supported | `kty` value | | | -- | -- | -- | -- | -| RSA | ✓ | RSA || -| Elliptic Curve | ✓ | EC | P-256, secp256k1[1], P-384, P-521 | -| Octet Key Pair | ✓ | OKP | Ed25519, Ed448[1], X25519[1], X448[1] | -| Octet sequence | ✓ | oct || +| RSA | ✓ | RSA | | +| Elliptic Curve | ✓ | EC | supported curves: P-256, secp256k1, P-384, P-521 | +| Octet Key Pair | ✓ | OKP | supported subtypes: Ed25519, Ed448, X25519, X448 | +| Octet sequence | ✓ | oct | | | Serialization | JWS Sign | JWS Verify | JWE Encrypt | JWE Decrypt | | -- | -- | -- | -- | -- | | Compact | ✓ | ✓ | ✓ | ✓ | -| General JSON | ✓ | ✓ | ✓ | ✓ | -| Flattened JSON | ✓ | ✓ | ✓ | ✓ | +| General JSON | ✕ | ✕ | ✕ | ✕ | +| Flattened JSON | ✓ | ✓ | ✓ | ✓ | -| JWS Algorithms | Supported || +| JWT Sign | JWT Verify | JWT Encrypt | JWT Decrypt | +| -- | -- | -- | -- | +| ✓ | ✓ | ✓ | ✓ | + +| JWS Algorithms | Supported | | | -- | -- | -- | | RSASSA-PKCS1-v1_5 | ✓ | RS256, RS384, RS512 | | RSASSA-PSS | ✓ | PS256, PS384, PS512 | -| ECDSA | ✓ | ES256, ES256K[1], ES384, ES512 | +| ECDSA | ✓ | ES256, ES256K, ES384, ES512 | | Edwards-curve DSA | ✓ | EdDSA | | HMAC with SHA-2 | ✓ | HS256, HS384, HS512 | -| Unsecured JWS | ✓ | none[2] | +| Unsecured JWS | ✓ | none | -| JWE Key Management Algorithms | Supported || +| JWE Key Management Algorithms | Supported | | | -- | -- | -- | -| AES | ✓ | A128KW[1], A192KW[1], A256KW[1] | +| AES | ✓ | A128KW, A192KW, A256KW | | AES GCM | ✓ | A128GCMKW, A192GCMKW, A256GCMKW | | Direct Key Agreement | ✓ | dir | -| RSAES OAEP | ✓ | RSA-OAEP, RSA-OAEP-256[3], RSA-OAEP-384[3], RSA-OAEP-512[3] | +| RSAES OAEP | ✓ | RSA-OAEP, RSA-OAEP-256, RSA-OAEP-384, RSA-OAEP-512 | | RSAES-PKCS1-v1_5 | ✓ | RSA1_5 | -| PBES2 | ✓ | PBES2-HS256+A128KW[1], PBES2-HS384+A192KW[1], PBES2-HS512+A256KW[1] | -| ECDH-ES | ✓[4] | ECDH-ES, ECDH-ES+A128KW[1], ECDH-ES+A192KW[1], ECDH-ES+A256KW[1] | +| PBES2 | ✓ | PBES2-HS256+A128KW, PBES2-HS384+A192KW, PBES2-HS512+A256KW | +| ECDH-ES | ✓ | ECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW | -| JWE Content Encryption Algorithms | Supported || +| JWE Content Encryption Algorithms | Supported | | | -- | -- | -- | | AES GCM | ✓ | A128GCM, A192GCM, A256GCM | -| AES_CBC_HMAC_SHA2 | ✓ | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 | - -| JWT profile validation | Supported | Stable profile | | -| -- | -- | -- | -- | -| JWT Access Tokens - [JWT Profile for OAuth 2.0 Access Tokens][draft-ietf-oauth-access-token-jwt] | ✓ | ✕5 | see [`JWT.AccessToken.verify`](/docs/README.md#jwtaccesstokenverifytoken-keyorstore-options) | -| ID Token - [OpenID Connect Core 1.0][spec-oidc-id_token] | ✓ | ✓ | see [`JWT.IdToken.verify`](/docs/README.md#jwtidtokenverifytoken-keyorstore-options) | -| Logout Token - [OpenID Connect Back-Channel Logout 1.0][spec-oidc-logout_token] | ✓ | ✕5 | see [`JWT.LogoutToken.verify`](/docs/README.md#jwtlogouttokenverifytoken-keyorstore-options) | -| JARM - [JWT Secured Authorization Response Mode for OAuth 2.0][draft-jarm] | ◯ ||| -| [JWT Response for OAuth Token Introspection][draft-jwtintrospection] | ◯ ||| -| [OAuth 2.0 DPoP][draft-dpop] | ◯ ||| +| AES CBC w/ HMAC | ✓ | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 | Legend: - **✓** Implemented -- **✕** Missing node crypto support / won't implement -- **◯** TBD - -1 Not supported in Electron due to Electron's use of BoringSSL -2 Unsecured JWS is [supported][documentation-none] for the JWS and JWT sign and verify -operations but it is an entirely opt-in behaviour, downgrade attacks are prevented by the required -use of a special `JWK.Key`-like object that cannot be instantiated through the key import API -3 RSAES OAEP using SHA-2 and MGF1 with SHA-2 is only supported when Node.js `>=12.9.0` runtime is detected -4 ECDH-ES with X25519 and X448 keys is only supported when Node.js `^12.17.0 || >=13.9.0` runtime is detected -5 Draft specification profiles are updated as minor versions of the library, therefore, -since they may have breaking changes use the `~` semver operator when using these and pay close -attention to changelog and the drafts themselves. +- **✕** Not Considered + +## Runtime Support Matrix + +| Platform | supported versions | caveats | +| -- | -- | -- | +| Node.js | LTS ^12.19.0 || ^14.15.0 | | +| Electron | `process.version` must match
the Node.js supported versions. So 12+ | see [1] | +| Deno | ✕ | needs [Web Cryptography API integration](https://github.com/denoland/deno/issues/1891) first | +| React Native | ✕ | has no available and usable crypto runtime | +| IE | ✕ | implements old version of the Web Cryptography API specification | +| Browsers | see [caniuse.com][caniuse] | | +| --- | | | +| Edge | 79+ | see [2], [4] | +| Firefox | 57+ | see [2] | +| Chrome | 63+ | see [2], [4] | +| Safari | 11+ | see [2], [3] | +| Opera | 50+ | see [2], [4] | +| iOS Safari | 12+ | see [2], [3] | + +1 Due to its use of BoringSSL the following is not supported in Electron + - A128KW, A192KW, A256KW, and all composite algorithms utilizing those + - secp256k1 EC curves + - Ed448, X25519, and X448 OKP Sub Types + +2 RSA1_5, OKP JWK Key Type, and secp256k1 EC curve is not supported in [Web Cryptography API][webcrypto]. + +3 P-521 EC curve is not supported in Safari + +4 192 bit AES keys are not supported in Chromium ## FAQ -#### Semver? +#### Supported Versions + +| Version | Bug Fixes 🐞 | New Features ⭐ | +| ------- | --------- | -------- | +| [3.x.x](https://github.com/panva/jose) | ✅ | ✅ | +| [2.x.x](https://github.com/panva/jose/tree/v2.x) | ✅ until 2022-04-30 | ❌ | -**Yes.** Everything that's either exported in the TypeScript definitions file or -[documented][documentation] is subject to -[Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html). The rest is to be considered -private API and is subject to change between any versions. +#### What is new in v3.x? -**Although.** Draft specification profiles are updated as minor versions of the library, therefore, -since they may have breaking changes use the `~` semver operator when using these and pay close -attention to changelog and the drafts themselves. +- Revised API +- No dependencies +- Browser support (using [Web Cryptography API][webcrypto]) +- Promise-based API +- experimental (non-blocking 🎉) Node.js libuv thread pool based runtime -#### How do I use it outside of Node.js +#### v2.x docs? -It is **only built for >=10.13.0 Node.js** environment - including `jose` in transpiled -browser-environment targeted projects is not supported and may result in unexpected results. +[Here.](https://github.com/panva/jose/blob/v2.x/docs/README.md) + +#### Semver? + +**Yes.** All module's public API is subject to [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html). #### How is it different from [`jws`](https://github.com/brianloveswords/node-jws), [`jwa`](https://github.com/brianloveswords/node-jwa) or [`jsonwebtoken`](https://github.com/auth0/node-jsonwebtoken)? +- it supports browser runtime +- it supports encrypted JWTs (i.e. in JWE format) +- supports secp256k1, Ed25519, Ed448, X25519, and X448 - it supports JWK Key Format for all four key types (oct, RSA, EC and OKP) -- it is providing Key and KeyStore abstractions +- it is exclusively using native platform Key object representations (CryptoKey and KeyObject) - there is JSON Web Encryption support -- it supports all JWS / JWE Serialization Syntaxes +- it supports the flattened JWS / JWE Serialization Syntaxes - it supports the "crit" member validations to make sure extensions are handled correctly -- it is not only validating the signatures, it is making sure the JWE/JWS is syntactically correct, - e.g. not having duplicated header parameters between protected/unprotected or per-recipient - headers -#### How is it different from [`node-jose`][node-jose] +#### How is it different from [`node-jose`](https://github.com/cisco/node-jose)? -`node-jose` is built to work in any javascript runtime, to be able to do that it packs a lot of -backfill and javascript implementation code in the form of +`node-jose` is also built to work in any javascript runtime, to be able to do that it packs a lot of +polyfills and javascript implementation code in the form of [`node-forge`](https://github.com/digitalbazaar/forge), this significantly increases the footprint -of the module with dependencies that either aren't ever used or have native implementation available -in Node.js already, those are often times faster and more reliable. +of the modules with dependencies that either aren't ever used or have native implementation available +in the runtime already, those are often times faster and more reliable. + +- it has smaller module footprints as it does not bundle unnecessary polyfills +- it does not bundle [`node-forge`](https://github.com/digitalbazaar/forge) fallbacks when crypto runtime is unavailable +- supports secp256k1, Ed25519, Ed448, X25519, and X448 + +#### Uint8Array?! + +- Whenever `Uint8Array` is a valid input, so is [`Buffer`](https://nodejs.org/api/buffer.html#buffer_buffer) since buffers are instances of Uint8Array. +- Whenever `Uint8Array` is returned and you want a `Buffer` instead, use `Buffer.from(uint8array)`. + +#### Bundle Size, Package Size, Tree Shaking + +Yes the bundle size is on the larger side, that is because each module is actually published +5 times so that it can remain truly without dependencies and be universal / isomorphic. +The source TS files are also published with inline docs so that your IDE's Intelligent code +completion works and has the exact same documentation as published. + +Nevertheless, since each module can be required independently and is fully tree-shakeable, the +install size should not be a cause for concern. -#### What is the ultimate goal? +#### Most types are "any" -- **No dependencies**, the moment JWK formatted keys are supported by node's `crypto` the direct -dependency count will go down from 1 to 0. 🚀 -- Just the API one needs, having used other jose modules for 3+ years I only include what's useful +Install @types/node as your project's development dependency + +``` +npm install --save-dev @types/node +``` + +#### "Cannot find module '...' or its corresponding type declarations." + +Install @types/node as your project's development dependency + +``` +npm install --save-dev @types/node +``` -#### Why? Just, why? +#### Why? Just. Why? I was using [`node-jose`][node-jose] for [`openid-client`](https://github.com/panva/node-openid-client) and @@ -377,12 +219,6 @@ in terms of performance and API (not having well defined errors). + this was an amazing opportunity to learn JOSE as a whole -[documentation-jwe]: /docs/README.md#jwe-json-web-encryption -[documentation-jwk]: /docs/README.md#jwk-json-web-key -[documentation-jwks]: /docs/README.md#jwks-json-web-key-set -[documentation-jws]: /docs/README.md#jws-json-web-signature -[documentation-jwt]: /docs/README.md#jwt-json-web-token -[documentation-none]: /docs/README.md#jwknone [documentation]: /docs/README.md [node-jose]: https://github.com/cisco/node-jose [spec-b64]: https://tools.ietf.org/html/rfc7797 @@ -394,12 +230,9 @@ in terms of performance and API (not having well defined errors). [spec-jwt]: https://tools.ietf.org/html/rfc7519 [spec-okp]: https://tools.ietf.org/html/rfc8037 [spec-secp256k1]: https://tools.ietf.org/html/rfc8812 -[draft-ietf-oauth-access-token-jwt]: https://tools.ietf.org/html/draft-ietf-oauth-access-token-jwt-06 -[draft-jarm]: https://openid.net/specs/openid-financial-api-jarm.html -[draft-jwtintrospection]: https://tools.ietf.org/html/draft-ietf-oauth-jwt-introspection-response -[draft-dpop]: https://tools.ietf.org/html/draft-ietf-oauth-dpop [spec-thumbprint]: https://tools.ietf.org/html/rfc7638 -[spec-oidc-id_token]: https://openid.net/specs/openid-connect-core-1_0.html#IDToken -[spec-oidc-logout_token]: https://openid.net/specs/openid-connect-backchannel-1_0-04.html#LogoutToken -[oidc-token-hash]: https://www.npmjs.com/package/oidc-token-hash [support-sponsor]: https://github.com/sponsors/panva +[conditional-exports]: https://nodejs.org/api/packages.html#packages_conditional_exports +[webcrypto]: https://www.w3.org/TR/WebCryptoAPI/ +[nodewebcrypto]: https://nodejs.org/docs/latest-v15.x/api/webcrypto.html +[caniuse]: https://caniuse.com/mdn-javascript_operators_await,async-functions,mdn-javascript_statements_for_await_of,cryptography,textencoder diff --git a/docs/README.md b/docs/README.md index ed1a78c11c..81753ef887 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,1720 +1,35 @@ -# `jose` API Documentation +# `jose` Modules API Documentation -> "JSON Web Almost Everything" - JWA, JWS, JWE, JWT, JWK, JWKS for Node.js with minimal dependencies - -**Table of Contents** - -- [JWK (JSON Web Key)](#jwk-json-web-key) -- [JWKS (JSON Web Key Set)](#jwks-json-web-key-set) -- [JWT (JSON Web Token)](#jwt-json-web-token) -- [JWS (JSON Web Signature)](#jws-json-web-signature) -- [JWE (JSON Web Encryption)](#jwe-json-web-encryption) -- [errors](#errors) +> "JSON Web Almost Everything" - JWA, JWS, JWE, JWT, JWK with no dependencies using native crypto runtimes ## Support If you or your business use `jose`, please consider becoming a [sponsor][support-sponsor] so I can continue maintaining it and adding new features carefree. -
- ---- - -## JWK (JSON Web Key) - - -- [Class: <JWK.Key> and <JWK.RSAKey> | <JWK.ECKey> | <JWK.OKPKey> | <JWK.OctKey>](#class-jwkkey-and-jwkrsakey--jwkeckey--jwkokpkey--jwkoctkey) - - [key.kty](#keykty) - - [key.alg](#keyalg) - - [key.use](#keyuse) - - [key.kid](#keykid) - - [key.x5c](#keyx5c) - - [key.x5t](#keyx5t) - - [key['x5t#S256']](#keyx5ts256) - - [key.key_ops](#keykey_ops) - - [key.thumbprint](#keythumbprint) - - [key.type](#keytype) - - [key.public](#keypublic) - - [key.private](#keyprivate) - - [key.secret](#keysecret) - - [key.keyObject](#keykeyobject) - - [key.algorithms([operation])](#keyalgorithmsoperation) - - [key.toJWK([private])](#keytojwkprivate) - - [key.toPEM([private[, encoding]])](#keytopemprivate-encoding) -- JWK.asKey - - [JWK.asKey(key[, options]) asymmetric key import](#jwkaskeykey-options-asymmetric-key-import) - - [JWK.asKey(secret[, options]) secret key import](#jwkaskeysecret-options-secret-key-import) - - [JWK.asKey(jwk[, options]) JWK-formatted key import](#jwkaskeyjwk-options-jwk-formatted-key-import) -- [JWK.generate(kty[, crvOrSize[, options[, private]]]) generating new keys](#jwkgeneratekty-crvorsize-options-private-generating-new-keys) -- [JWK.generateSync(kty[, crvOrSize[, options[, private]]])](#jwkgeneratesynckty-crvorsize-options-private) -- [JWK.isKey(object)](#jwkiskeyobject) -- [JWK.None](#jwknone) -- [JWK.EmbeddedJWK](#jwkembeddedjwk) -- [JWK.EmbeddedX5C](#jwkembeddedx5c) - - -All sign and encrypt operations require `` or `JWK.asKey()` compatible input. -All verify and decrypt operations require ``, ``, or `JWK.asKey()` compatible input. - -Whenever you're re-using the same key input for an operation it is recommended that you instantiate -the `` instance. Here's how to get a `` instances generated or instantiated from existing key material. - - -```js -const { JWK } = require('jose') -// { asKey: [Function: asKey], -// generate: [AsyncFunction: generate], -// generateSync: [Function: generateSync] } -``` - ---- - -#### Class: `` and `` | `` | `` | `` - -``, ``, `` and `` represent a key usable for JWS and JWE operations. -The `JWK.asKey()` method is used to retrieve a key representation of an existing key or secret. -`JWK.generate()` method is used to generate a new random key. - -``, ``, `` and `` inherit methods from `` and in addition -to the properties documented below have the respective key component properties exported as -`` in their format defined by the specifications. - -- `e, n` for Public RSA Keys -- `e, n, d, p, q, dp, dq, qi` for Private RSA Keys -- `crv, x, y` for Public EC Keys -- `crv, x, y, n` for Private EC Keys -- `crv, x` for Public OKP Keys -- `crv, x, n` for Private OKP Keys -- `k` for Symmetric keys - ---- - -#### `key.kty` - -Returns the key's JWK Key Type Parameter. 'EC', 'RSA', 'OKP' or 'oct' for the respective supported -key types. - -- `` - ---- - -#### `key.alg` - -Returns the key's JWK Algorithm Parameter if set, undefined otherwise. If set the key is only usable -for that one algorithm and will fail when used with others. - -- `` - ---- - -#### `key.use` - -Returns the key's JWK Key Use Parameter if set, undefined otherwise. Only 'sig' and 'enc' values -are supported. If set the key can only be used for either signing / verification or encryption -related operations (key management or encryption). - -- `` - ---- - -#### `key.kid` - -Returns the key's JWK Key ID Parameter if set, if not set it will be calculated using the method -defined in [RFC7638][spec-thumbprint]. - -- `` - ---- - -#### `key.x5c` - -Returns the key's X.509 Certificate Chain Parameter if set - -- `string[]` - ---- - -#### `key.x5t` - -Returns the key's X.509 Certificate SHA-1 Thumbprint Parameter if set. This -property can be either set manually by the JWK producer or left to the library to compute based -on the first certificate in the key's `x5c`, the latter is preferred. - -- `` - ---- - -#### `key['x5t#S256']` - -Returns the key's X.509 Certificate SHA-256 Thumbprint Parameter if set. This -property can be either set manually by the JWK producer or left to the library to compute based -on the first certificate in the key's `x5c`, the latter is preferred. - -- `` - ---- - -#### `key.key_ops` - -Returns the key's JWK Key Operations Parameter if set. If set the key can only be used for the -specified operations. Supported values are 'sign', 'verify', 'encrypt', 'decrypt', 'wrapKey', -'unwrapKey' and 'deriveKey'. - -- `string[]` - ---- - -#### `key.thumbprint` - -Returns the key's JWK Key thumbprint calculated using the method defined in [RFC7638][spec-thumbprint]. - -- `` - ---- - -#### `key.type` - -Returns the type of key. One of 'private', 'public' or 'secret' - -- `` - ---- - -#### `key.public` - -Returns true/false if the key is asymmetric and public. Returns false for symmetric keys. - -- `` - ---- - -#### `key.private` - -Returns true/false if the key is asymmetric and private. Returns false for symmetric keys. - -- `` - -#### `key.secret` - -Returns true/false if the key is symmetric. Returns false for asymmetric keys. - -- `` - ---- - -#### `key.keyObject` - -Returns the underlying [`KeyObject`](https://nodejs.org/api/crypto.html#crypto_class_keyobject) -instance. Throws `JOSENotSupported` when KeyObject API is not supported in the Node.js runtime. - -- `` - ---- - -#### `key.algorithms([operation])` - -Returns a [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) -of algorithms the key may perform. - -- `operation`: `` Must be one of 'encrypt', 'decrypt', 'sign', 'verify', 'wrapKey', - 'unwrapKey' -- Returns: `Set` - -
- Example (Click to expand) - -```js -const { JWK: { generateSync } } = require('jose') - -const privateKey = generateSync('RSA') -privateKey.algorithms() -// Set { -// 'PS256', -// 'RS256', -// 'PS384', -// 'RS384', -// 'PS512', -// 'RS512', -// 'RSA-OAEP', -// 'RSA-OAEP-256', -// 'RSA1_5' } -privateKey.algorithms('wrapKey') -// Set { -// 'RSA-OAEP', -// 'RSA-OAEP-256', -// 'RSA1_5' } - -const publicKey = generateSync('RSA', 2048, { use: 'enc' }, false) -publicKey.algorithms('sign') -// Set {} -publicKey.algorithms('unwrapKey') -// Set {} -publicKey.algorithms('wrapKey') -// Set { -// 'RSA-OAEP', -// 'RSA-OAEP-256', -// 'RSA1_5' } -``` -
- ---- - -#### `key.toJWK([private])` - -Exports the key to a JSON Web Key formatted object. - -- `private`: `` When true exports keys with its private components. **Default:** 'false' -- Returns: `` - -
- Example (Click to expand) - -```js -const { JWK: { generateSync } } = require('jose') - -const key = generateSync('RSA', 2048, { use: 'sig', alg: 'PS256' }) -key.toJWK() -// { kty: 'RSA', -// kid: 'UFldqYiAzlc1aGj5SoqxqYnWcv2Nc4us2ryQe3-FsUA', -// e: 'AQAB', -// n: -// 'uKEKEJUrnfBdXr6zmzq91fQHhW_8GFFUAYtvt5Uvj9wzsWDbspfL9MorhJgkPioo9T6QQvyyEJBaAQOLZxLsPORk83vmB9OACQT3PEM2LbSFK7XUoZGwqlf8Anvs7M1GwvypYbc1v1WrCqcsjrbmYF9TZkV8nNsy2cweh9gFNR-lIiZCHWDgnP6PifoeGvC9RxKdusFa66vtUJGUcoVmMoiOM7EDVdYOP91qJtbDBx7NPPywwD-8pt3UVBW0bYvOqHGF6XXky5JiB8AZQ2NdZHWxklaM2fd8Mxu9CT3xSYg51nS0KV7wO9lAh_ynBpxE2Qmr-7nvKkkDMOL1FSoEQw', -// alg: 'PS256', -// use: 'sig' } -key.toJWK(true) -// { kty: 'RSA', -// kid: 'UFldqYiAzlc1aGj5SoqxqYnWcv2Nc4us2ryQe3-FsUA', -// e: 'AQAB', -// n: -// 'uKEKEJUrnfBdXr6zmzq91fQHhW_8GFFUAYtvt5Uvj9wzsWDbspfL9MorhJgkPioo9T6QQvyyEJBaAQOLZxLsPORk83vmB9OACQT3PEM2LbSFK7XUoZGwqlf8Anvs7M1GwvypYbc1v1WrCqcsjrbmYF9TZkV8nNsy2cweh9gFNR-lIiZCHWDgnP6PifoeGvC9RxKdusFa66vtUJGUcoVmMoiOM7EDVdYOP91qJtbDBx7NPPywwD-8pt3UVBW0bYvOqHGF6XXky5JiB8AZQ2NdZHWxklaM2fd8Mxu9CT3xSYg51nS0KV7wO9lAh_ynBpxE2Qmr-7nvKkkDMOL1FSoEQw', -// d: -// 'F9G24bLNAMBM23dQ5prqeNrVyZJL_LspUlWx4QZfL3kiNiUf0uegiYE3ohCaxGZeCF288Nd3BYoKAo15g5--WJDCsWLvp1zS7Nb2KpElQTpD4ALCXuHT3_Yf7hYc1-QX1_oOxCuFxJyBx4sPxY21JQPHV69pRzdEVTLvUWk-Kr8k-kgu8xFOsyqLK0g0IBAtwOX2ksIPLuHT-nGh_VQwfpJowq1MoUZD-y_6Ai5HWAZy9t6gARpG3K4yBcmAQBRIQgoFiGw41BqVB5fJyjVZDsMbvT_iEFKkrHRjifUI6QTNtt1k9xOFIL_Ojzn6aLylm58AGD8oORWZvfpmJJ03yQ', -// p: -// '8lvcv5Ov9rJsa_kaCJBRijeOdz3La11_26o2QDpkINFKKoDNWRpIT0KZNF4P16Z5OXOK6rSezuN2vACAPg3riUHVdbRyFhMI6FvQhlx7unyv07xBBqbnp8dV2NiQv3-rFeNPV_5RqZHJyqQga-VUXvwics3eUzm_2CbrMQG3Klc', -// q: -// 'wwVZ6d5uZm9kj3tWICF1FqCWHwSWMt1wgFZ3DOp2LPuqBHjYPas4zwXd3V4wolaCi8irbTfbL0F6c51yN72-enAjgm6r5yzxedkV9GWk5U0y8VrNwYm55qz1o88LB6PX6RG5Lp2rYZp_34dgCrllQc8T-5YY4KIHy7TaLkKkGfU', -// dp: -// 'sPZseCIxcPOVAT3xSWF_eGnah6zCVJH_4vglBr7cD65h9ij4R-BN_jnFvhwUe0Ud7No2C-x4rN4f-2RuP2FQo3dDkt-AEigx79_iocjzuxaCGBu0a1QBgFunjl-LSZjB5oiEjd6v6B4AdwtidQYNlhGKYcN6W9CmCQFZ5_21rZ8', -// dq: -// 'sokKmGSuUw61U_mIjh-zDoTzCfBsBKLepE8D7AoVJ_c43aE37bT7a-MmCst44JUsLAYIkhMpkKh0DrXb45XMdFCG4ZipvRhS9Ma9J6GKBPXYpkYHyZ9pVfmPY2he456mQdOc4UUsqU0EtcE8NnUlcsq9s3vkyHjthBrMBr-xdaU', -// qi: -// 'jbZrzP8f3y0-ZAjqSQAPbKnQI0Vli952nQTUgffF2Bh2q0dB719PHjmIV7NjwCFOMcNx-2usJFwI9VikgN9GTGauakvG7SFzXD8yHiRzFwcjYvXDuJ-4Q1Yjo1m4JUIW_BLVnzauSg0P9qnxT1dxvchEQRIIfF72FW80BsJD4LQ', -// alg: 'PS256', -// use: 'sig' } -``` -
- ---- - -#### `key.toPEM([private[, encoding]])` - -Exports an asymmetric key as a PEM string with specified encoding and optional encryption for private keys. - -- `private`: `` When true exports keys as private. **Default:** 'false' -- `encoding`: `` See below -- Returns: `` - -For public key export, the following encoding options can be used: - -- `type`: `` Must be one of 'pkcs1' (RSA only) or 'spki'. **Default:** 'spki' - - -For private key export, the following encoding options can be used: - -- `type`: `` Must be one of 'pkcs1' (RSA only), 'pkcs8' or 'sec1' (EC only). **Default:** 'pkcs8' -- `cipher`: `` If specified, the private key will be encrypted with the given cipher and - passphrase using PKCS#5 v2.0 password based encryption. **Default**: 'undefined' (no encryption) -- `passphrase`: `` | `` The passphrase to use for encryption. **Default**: 'undefined' (no encryption) - -
- Example (Click to expand) - -```js -const { JWK: { generateSync } } = require('jose') - -const key = generateSync('RSA', 2048) -key.toPEM() -// -----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEATPpxgDY7XU8cYX9Rb44xxXDO6zP\nzELVOHTcutCiXS9HZvUrZsnG7U/SPj0AT1hsH6lTUK4uFr7GG7KWgsf1Aw==\n-----END PUBLIC KEY-----\n -key.toPEM(true) -// -----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgUdAzlvX4i+RJS2BL\nQrqRj/ndTbpqugX61Ih9X+rvAcShRANCAAQBM+nGANjtdTxxhf1FvjjHFcM7rM/M\nQtU4dNy60KJdL0dm9StmycbtT9I+PQBPWGwfqVNQri4WvsYbspaCx/UD\n-----END PRIVATE KEY-----\n -key.toPEM(true, { passphrase: 'super-strong', cipher: 'aes-256-cbc' }) -// -----BEGIN ENCRYPTED PRIVATE KEY-----\nMIHsMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAjjeqsgorjSqwICCAAw\nDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEJFcyG1ZBe2FZuvXIqiRFUcEgZD5\nWzt2XIUGIEZQIUUpJ1naaIFKiZvBcFAXhqG5KJ6PgaohgcmRUK8OZTA9Ome+uXB+\n9PLLfKscOsyr0gkd45gYYNRDLYwbQSqDQ4g8pHrCVjR+R3mh1nk8jIkOxSppwzmF\n7aoCmnQo7oXRy1+kRZL7OfwAD5gAXnsIA42D9RgOG1XIiBYTvAITcFVX0UPh0zM=\n-----END ENCRYPTED PRIVATE KEY-----\n -``` -
- ---- - -#### `JWK.asKey(key[, options])` asymmetric key import - -Imports an asymmetric private or public key. Supports importing JWK formatted keys (private, public, -secrets), `pem` and `der` formatted private and public keys, `pem` formatted X.509 certificates. -Private keys may also be passphrase protected. - - -- `key`: `` | `` | `` | `` - - `key`: `` | `` - - `format`: `` Must be 'pem' or 'der'. **Default:** 'pem'. - - `type`: `` Must be 'pkcs1', 'pkcs8', or 'sec1' for private keys, 'pkcs1', 'spki' for - public keys. This option is required only if the format is 'der' and ignored if it is 'pem'. - - `passphrase`: `` | `` The passphrase to use for decryption. -- `options`: `` - - `alg`: `` option identifies the algorithm intended for use with the key. - - `kid`: `` Key ID Parameter. When not provided is computed using the method defined in - [RFC7638][spec-thumbprint] - - `use`: `` option indicates whether the key is to be used for encrypting & decrypting - data or signing & verifying data. Must be 'sig' or 'enc'. -- Returns: `` | `` | `` - -See the underlying Node.js API for details on importing private and public keys in the different -formats - -- [crypto.createPrivateKey(key)](https://nodejs.org/api/crypto.html#crypto_crypto_createprivatekey_key) -- [crypto.createPublicKey(key)](https://nodejs.org/api/crypto.html#crypto_crypto_createpublickey_key) - -
- Example (Click to expand) - -```js -const { readFileSync } = require('fs') -const { JWK: { asKey } } = require('jose') - -const key = asKey(readFileSync('path/to/key/file')) -// ECKey { -// kty: 'EC', -// public: true, -// kid: [Getter], -// crv: [Getter], -// x: [Getter], -// y: [Getter] } -``` -
- ---- - -#### `JWK.asKey(secret[, options])` secret key import - -Imports a symmetric key. - -- `secret`: `` | `` | `` -- `options`: `` - - `alg`: `` option identifies the algorithm intended for use with the key. - - `kid`: `` Key ID Parameter. When not provided is computed using the method defined in - [RFC7638][spec-thumbprint] - - `use`: `` option indicates whether the key is to be used for encrypting & decrypting - data or signing & verifying data. Must be 'sig' or 'enc'. -- Returns: `` - -
- Example (Click to expand) - -```js -const { JWK: { asKey } } = require('jose') - -const key = asKey(Buffer.from('8yHym6h5CG5FylbzrCn8fhxEbp3kOaTsgLaawaaJ')) -// OctKey { -// kty: 'oct', -// kid: [Getter], -// k: [Getter] } -``` -
- ---- - -#### `JWK.asKey(jwk[, options])` JWK-formatted key import - -Imports a JWK formatted key. This supports JWK formatted RSA, EC, OKP and oct keys. Asymmetrical -keys may be both private and public. - -- `jwk`: `` - - `kty`: `` Key type. Must be 'RSA', 'EC', 'OKP' or 'oct'. - - `alg`: `` option identifies the algorithm intended for use with the key. - - `use`: `` option indicates whether the key is to be used for encrypting & decrypting - data or signing & verifying data. Must be 'sig' or 'enc'. - - `kid`: `` Key ID Parameter. When not provided is computed using the method defined in - [RFC7638][spec-thumbprint] - - `e`, `n` properties as `` for RSA public keys - - `e`, `n`, `d`, `p`, `q`, `dp`, `dq`, `qi` properties as `` for RSA private keys - - `e`, `n`, `d` properties as `` for RSA private keys without optimization parametes (only - with `calculateMissingRSAPrimes` option, see below) - - `crv`, `x`, `y` properties as `` for EC public keys - - `crv`, `x`, `y`, `d` properties as `` for EC private keys - - `crv`, `x`, properties as `` for OKP public keys - - `crv`, `x`, `d` properties as `` for OKP private keys - - `k` properties as `` for secret oct keys -- `options`: `` - - `calculateMissingRSAPrimes`: `` **Default** 'false'. This option is really only in - effect when importing private RSA JWK keys, by default, keys without the optimization private - key parameters (p, q, dp, dq, qi) won't be imported because their calculation is heavy and prone - to blocking the process. Setting this option to true will enable these keys to be imported, - albeit at your own risk. Depending on the key size the calculation takes long and it should - only be used for JWK keys from trusted sources. -- Returns: `` | `` | `` | `` - - -
-Example (Click to expand) - -```js -const { JWK: { asKey } } = require('jose') -const jwk = { - kty: 'RSA', - kid: 'r1LkbBo3925Rb2ZFFrKyU3MVex9T2817Kx0vbi6i_Kc', - use: 'sig', - e: 'AQAB', - n: 'xwQ72P9z9OYshiQ-ntDYaPnnfwG6u9JAdLMZ5o0dmjlcyrvwQRdoFIKPnO65Q8mh6F_LDSxjxa2Yzo_wdjhbPZLjfUJXgCzm54cClXzT5twzo7lzoAfaJlkTsoZc2HFWqmcri0BuzmTFLZx2Q7wYBm0pXHmQKF0V-C1O6NWfd4mfBhbM-I1tHYSpAMgarSm22WDMDx-WWI7TEzy2QhaBVaENW9BKaKkJklocAZCxk18WhR0fckIGiWiSM5FcU1PY2jfGsTmX505Ub7P5Dz75Ygqrutd5tFrcqyPAtPTFDk8X1InxkkUwpP3nFU5o50DGhwQolGYKPGtQ-ZtmbOfcWQ' -} - -const key = asKey(jwk) -// RSAKey { -// kty: 'RSA', -// public: true, -// use: 'sig', -// kid: 'r1LkbBo3925Rb2ZFFrKyU3MVex9T2817Kx0vbi6i_Kc', -// e: [Getter], -// n: [Getter] } -``` -
- ---- - -#### `JWK.generate(kty[, crvOrSize[, options[, private]]])` generating new keys - -Securely generates a new RSA, EC, OKP or oct key. - -- `kty`: `` Key type. Must be 'RSA', 'EC', 'OKP' or 'oct'. -- `crvOrSize`: `` | `` key's bit size or in case of OKP and EC keys the curve - **Default:** 2048 for RSA, 'P-256' for EC, 'Ed25519' for OKP and 256 for oct. -- `options`: `` - - `alg`: `` Key Algorithm Parameter. It identifies the algorithm intended for use with the - key. - - `kid`: `` Key ID Parameter. When not provided is computed using the method defined in - [RFC7638][spec-thumbprint]. - - `use`: `` Public Key Use Parameter. Indicates whether the key is to be used for - encrypting & decrypting data or signing & verifying data. Must be 'sig' or 'enc'. - - `key_ops`: `string[]` Key Operations Parameter. If set, the key can only be used for the - specified operations. Supported values are 'sign', 'verify', 'encrypt', 'decrypt', 'wrapKey', - 'unwrapKey' and 'deriveKey'. -- `private`: `` **Default** 'true'. Is the resulting key private or public (when - asymmetrical) -- Returns: `Promise` | `Promise` | `Promise` | `Promise` - -
-Example (Click to expand) - -```js -const { JWK: { generate } } = require('jose') -(async () => { - const key = await generate('EC', 'P-384', { use: 'sig' }) - // ECKey { - // kty: 'EC', - // private: true, - // use: 'sig', - // kid: [Getter], - // crv: [Getter], - // x: [Getter], - // y: [Getter], - // d: [Getter] } -})() -``` -
- ---- - -#### `JWK.generateSync(kty[, crvOrSize[, options[, private]]])` - -Synchronous version of `JWK.generate()` - -- `kty`: `` Key type. Must be 'RSA', 'EC', 'OKP' or 'oct'. -- `crvOrSize`: `` | `` key's bit size or in case of OKP and EC keys the curve. - **Default:** 2048 for RSA, 'P-256' for EC, 'Ed25519' for OKP and 256 for oct. -- `options`: `` - - `alg`: `` Key Algorithm Parameter. It identifies the algorithm intended for use with the - key. - - `kid`: `` Key ID Parameter. When not provided is computed using the method defined in - [RFC7638][spec-thumbprint]. - - `use`: `` Public Key Use Parameter. Indicates whether the key is to be used for - encrypting & decrypting data or signing & verifying data. Must be 'sig' or 'enc'. - - `key_ops`: `string[]` Key Operations Parameter. If set, the key can only be used for the - specified operations. Supported values are 'sign', 'verify', 'encrypt', 'decrypt', 'wrapKey', - 'unwrapKey' and 'deriveKey'. -- `private`: `` **Default** 'true'. Is the resulting key private or public (when - asymmetrical) -- Returns: `` | `` | `` | `` - -
-Example (Click to expand) - -```js -const { JWK: { generateSync } } = require('jose') -const key = generateSync('RSA', 2048, { use: 'enc' }) -// RSAKey { -// kty: 'RSA', -// private: true, -// use: 'enc', -// kid: [Getter], -// e: [Getter], -// n: [Getter], -// d: [Getter], -// p: [Getter], -// q: [Getter], -// dp: [Getter], -// dq: [Getter], -// qi: [Getter] } -``` -
- ---- - -#### `JWK.isKey(object)` - -Returns 'true' if the value is an instance of ``. - -- `object`: `` -- Returns: `` - ---- - -#### `JWK.None` - -`JWK.None` is a special key object that can be used with JWS/JWT sign and verify whenever you want -to opt-in for the `none` Unsecured JWS algorithm. Using this key fulfills the requirements given by -the [specification](https://tools.ietf.org/html/rfc7518#section-3.6), namely: - -- Implementations MUST NOT accept Unsecured JWSs by default. -- Implementations that support Unsecured JWSs MUST NOT accept such objects as valid unless the -application specifies that it is acceptable for a specific object to not be integrity protected. - -```js -const { JWK: { None, generateSync }, JWT, JWS } = require('jose') -const anActualKey = generateSync('RSA') - -const signedJWT = JWT.sign({ sub: 'John Doe' }, anActualKey) -JWT.verify(signedJWT, None) -// Thrown: -// JWKKeySupport: the key does not support PS256 verify algorithm -// name: 'JWKKeySupport', -// code: 'ERR_JWK_KEY_SUPPORT' - -const unsecuredJWT = JWT.sign({ sub: 'John Doe' }, None) -// eyJhbGciOiJub25lIn0.eyJzdWIiOiJKb2huIERvZSIsImlhdCI6MTU3OTc5NDM2Mn0. - -JWT.verify(unsecuredJWT, anActualKey) -// Thrown: -// JWKKeySupport: the key does not support none verify algorithm -// name: 'JWKKeySupport', -// code: 'ERR_JWK_KEY_SUPPORT' - -JWT.verify(unsecuredJWT, None) -// { sub: 'John Doe', iat: 1579794362 } - -const unsecuredJWS = JWS.sign('foobar', None) -// eyJhbGciOiJub25lIn0.Zm9vYmFy. - -JWS.verify(unsecuredJWS, anActualKey) -// Thrown: -// JWKKeySupport: the key does not support none verify algorithm -// name: 'JWKKeySupport', -// code: 'ERR_JWK_KEY_SUPPORT' - -JWS.verify(unsecuredJWS, None) -// => verifies -``` - ---- - -#### `JWK.EmbeddedJWK` - -`JWK.EmbeddedJWK` is a special key object that can be used with the JWS/JWT verify operations -whenever you want to opt-in to verify signatures with a public key embedded in the JWS Header `jwk` -parameter. It is recommended to combine this with the verify `algorithms` option to whitelist -JWS algorithms to accept as well as the `complete` option set to `true` if you need to work with the -instantiated `JWK.Key` from the token. - ---- - -#### `JWK.EmbeddedX5C` - -`JWK.EmbeddedX5C` is a special key object that can be used with the JWS/JWT verify operations -whenever you want to opt-in to verify signatures with a public key embedded in the first JWS Header -`x5c` parameter member. It is recommended to combine this with the verify `algorithms` option to whitelist -JWS algorithms to accept as well as the `complete` option set to `true` if you need to work with -the instantiated `JWK.Key` from the token. ⚠️ the x5c members are all validated to be certificates -but their chain or trust is not validated. Unfortunately Node.js does not have any good tools to do -that reliably. - ---- - -## JWKS (JSON Web Key Set) - - -- [Class: ](#class-jwkskeystore) - - [new JWKS.KeyStore([keys])](#new-jwkskeystorekeys) - - [keystore.size](#keystoresize) - - [keystore.all([parameters])](#keystoreallparameters) - - [keystore.get([parameters])](#keystoregetparameters) - - [keystore.add(key)](#keystoreaddkey) - - [keystore.remove(key)](#keystoreremovekey) - - [keystore.generate(...)](#keystoregenerate) - - [keystore.generateSync(...)](#keystoregeneratesync) - - [keystore.toJWKS([private])](#keystoretojwksprivate) - - [JWKS.asKeyStore(jwks[, options])](#jwksaskeystorejwks-options) - - -```js -const { JWKS } = require('jose') -// { KeyStore: [Function: KeyStore] } -``` - -#### Class: `` - -`JWKS.KeyStore` is an abstraction representing a set of JWKs, a keystore instance may be queried for -keys matching specific parameters. Keystores may be instantiated either populated, or empty and -there are lifecycle `keystore.remove()` and `keystore.add()` methods for adding/removing keys from -an existing store. - ---- - -#### `new JWKS.KeyStore([keys])` - -Creates a new KeyStore, either empty or populated. - -- `keys`: `` Array of key keys instantiated by `JWK.asKey()` -- Returns: `` - ---- - -#### `keystore.size` - -Returns the number of keys in the keystore. - -- `` ---- - -#### `keystore.all([parameters])` - -Retrieves an array of keys matching the provided parameters, returns all if none are provided. The -returned array is sorted by relevance based on the parameters. Keys with the exact algorithm or use -specified by the parameters are first. - -- `parameters`: `` - - `kty`: `` Key Type to filter for. - - `crv`: `` Key Curve to filter for. (for EC and OKP keys) - - `alg`: `` Key supported algorithm to filter for. - - `kid`: `` Key ID to filter for. - - `thumbprint`: `` JWK Key thumbprint to filter for. - - `use`: `` Filter keys with the specified use defined. Keys missing "use" parameter will - be matched but rank lower then ones with an exact match. - - `key_ops`: `string[]` Filter keys with specified key_ops defined (if key_ops is defined on the - key). Keys missing "key_ops" parameter will be matched but rank lower then ones with matching - entries. - - `x5t`: `` Key X.509 Certificate SHA-1 Thumbprint to filter for. - - `x5t#S256`: `` Key X.509 Certificate SHA-256 Thumbprint to filter for. -- Returns: `` Array of key instances or an empty array when none are matching the parameters. - ---- - -#### `keystore.get([parameters])` - -Retrieves a single key matching the provided parameters. The most relevant Key based on the -parameters is returned. - -- `parameters`: `` - - `kty`: `` Key Type to filter for. - - `crv`: `` Key Curve to filter for. (for EC and OKP keys) - - `alg`: `` Key supported algorithm to filter for. - - `kid`: `` Key ID to filter for. - - `thumbprint`: `` JWK Key thumbprint to filter for. - - `use`: `` Filter keys with the specified use defined. Keys missing "use" parameter will - be matched but rank lower then ones with an exact match. - - `key_ops`: `string[]` Filter keys with specified key_ops defined (if key_ops is defined on the - key). Keys missing "key_ops" parameter will be matched but rank lower then ones with matching - entries. - - `x5t`: `` Key X.509 Certificate SHA-1 Thumbprint to filter for. - - `x5t#S256`: `` Key X.509 Certificate SHA-256 Thumbprint to filter for. -- Returns: `` | `` | `` | `` | `undefined` - ---- - -#### `keystore.add(key)` - -Adds a key instance to the store unless it is already included. - -- `key`: `` | `` | `` | `` - ---- - -#### `keystore.remove(key)` - -Ensures a key is removed from a store. - -- `key`: `` | `` | `` | `` - ---- - -#### `keystore.generate(...)` - -Asynchronously generates new random key and automatically adds it to the store. See `JWK.generate()` -for the API. - ---- - -#### `keystore.generateSync(...)` - -Synchronous version of `keystore.generate()`. - ---- - -#### `keystore.toJWKS([private])` - -Exports the keystore to a JSON Web Key Set formatted object. - -- `private`: `` When true exports private keys with their private components. **Default:** 'false' -- Returns: `` - ---- - -#### `JWKS.asKeyStore(jwks[, options])` - -Creates a new KeyStore from a JSON Web Key Set. - -- `jwks`: `` JWKS formatted object (`{ keys: [{ kty: '...', ... }, ...] }`) -- `options`: `` - - `ignoreErrors`: `` **Default** 'false'. This will make it so that keys - unsupported by your Node.js runtime version (or otherwise faulty keys) get swallowed. - - `calculateMissingRSAPrimes`: `` **Default** 'false'. This option is really only in - effect when the JWKS contains private RSA JWK keys, by default, keys without the optimization - private key parameters (p, q, dp, dq, qi) won't be imported because their calculation is heavy and - prone to blocking the process. Setting this option to true will enable these keys to be - imported, albeit at your own risk. Depending on the key size the calculation takes long and it - should only be used for JWKS from trusted sources. -- Returns: `` - -
-Example (Click to expand) - -```js -const { JWKS: { KeyStore, asKeyStore } } = require('jose') -const jwks = { - keys: [ - { kty: 'RSA', - kid: 'gqUcZ2TjhmNrVOd1d27tedkabhOTs9WghMHIyjIBn7Y', - e: 'AQAB', - n: - 'vi1Aui6R0rUL_7pdcFKKMhBF25h4x8WiTZ4w66eNZhwIp48lz-vBuyUUrSR-RwcuvnxlXdjBdSaN-PZkNRDv2bXE3mVtjZgoYyzQlGLJ1wduQaBXIkrQWxc7yzL91MvtP1kWwFHHrQHZRlpiFQQm9gNCy2wXCTbWGT9kjrR1W1bkwhmOKK4rF-hMgaCNDrtEQ6xWknxV8aXW4itouJ0pJv8xplc6J14f_SNq6arVUcAZ26EzJYC2fcvqwsrnKzvW7QxQGQzh-u9Tn82Tl14Omh1KDV8C7Vb_m8XClv_9zOrKBGdaTl1zgINyMEaa_IMophnBgK_kAXvtVvEThQ93GQ', - use: 'enc' } - ] -} -const ks = asKeyStore(jwks) -// KeyStore {} -ks.size -// 1 -ks instanceof KeyStore -// true -``` -
- ------- - -## JWT (JSON Web Token) - - -- [JWT.sign(payload, key[, options])](#jwtsignpayload-key-options) -- [JWT.verify(token, keyOrStore[, options])](#jwtverifytoken-keyorstore-options) -- [JWT.AccessToken.verify(token, keyOrStore, options)](#jwtaccesstokenverifytoken-keyorstore-options) -- [JWT.IdToken.verify(token, keyOrStore, options)](#jwtidtokenverifytoken-keyorstore-options) -- [JWT.LogoutToken.verify(token, keyOrStore, options)](#jwtlogouttokenverifytoken-keyorstore-options) - - -```js -const { JWT } = require('jose') -// { sign: [Function], verify: [Function] } -``` - -#### `JWT.sign(payload, key[, options])` - -Serializes and signs the payload as JWT using the provided private or symmetrical key. The Algorithm -that will be used to sign with is either provided as part of the 'options.algorithm', -'options.header.alg' or inferred from the provided `` instance. - -- `payload`: `` JWT Claims Set -- `key`: `` The key to sign with. Any `JWK.asKey()` compatible input also works. - `` instances are recommended for performance purposes when re-using the same key for - every operation. -- `options`: `` - - `algorithm`: `` The algorithm to use - - `audience`: `` | `string[]` JWT Audience, "aud" claim value, if provided it will replace - "aud" found in the payload - - `expiresIn`: `` JWT Expiration Time, "exp" claim value, specified as string which is - added to the current unix epoch timestamp e.g. `24 hours`, `20 m`, `60s`, etc., if provided it - will replace Expiration Time found in the payload - - `header`: `` JWT Header object - - `iat`: `` When true it pushes the "iat" to the JWT Header. **Default:** 'true' - - `issuer`: `` JWT Issuer, "iss" claim value, if provided it will replace "iss" found in - the payload - - `jti`: `` JWT ID, "jti" claim value, if provided it will replace "jti" found in the - payload - - `kid`: `` When true it pushes the key's "kid" to the JWT Header. **Default:** 'true' for asymmetric keys, 'false' for symmetric keys. - - `notBefore`: `` JWT Not Before, "nbf" claim value, specified as string which is added to - the current unix epoch timestamp e.g. `24 hours`, `20 m`, `60s`, etc., if provided it will - replace Not Before found in the payload - - `now`: `` Date object to be used instead of the current unix epoch timestamp. - **Default:** 'new Date()' - - `subject`: `` JWT subject, "sub" claim value, if provided it will replace "sub" found in - the payload -- Returns: `` - -
-Example (Click to expand) - -```js -const { JWT, JWK } = require('jose') -const key = JWK.asKey({ - kty: 'oct', - k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg' -}) - -const payload = { - 'urn:example:claim': 'foo' -} - -const token = JWT.sign(payload, key, { - audience: ['urn:example:client'], - issuer: 'https://op.example.com', - expiresIn: '2 hours', - header: { - typ: 'JWT' - } -}) -// eyJ0eXAiOiJKV1QiLCJraWQiOiJSdG9SdXJfMURpcjVNNHd1T2ZxTmtEWU9mOU9fNFJKLWFIa1RBNzVSTEE4IiwiYWxnIjoiSFMyNTYifQ.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6ImZvbyIsImF1ZCI6WyJ1cm46ZXhhbXBsZTpjbGllbnQiXSwiaXNzIjoiaHR0cHM6Ly9vcC5leGFtcGxlLmNvbSIsImlhdCI6MTU1MTI5NDEzNywiZXhwIjoxNTUxMzAxMzM3fQ.YmtApwaGRBWlL9O8avbmpYcJ5UwNy0R8rpbxZqHxNd4 -``` -
- ---- - -#### `JWT.verify(token, keyOrStore[, options])` - -Verifies the claims and signature of a JSON Web Token. - -- `token`: `` JSON Web Token to verify -- `keyOrStore`: `` | `` The key or store to verify with. When - `` instance is provided a selection of possible candidate keys will be done and the - operation will succeed if just one key matches. Any `JWK.asKey()` compatible input also works. - `` instances are recommended for performance purposes when re-using the same key for - every operation. -- `options`: `` - - `algorithms`: `string[]` Array of expected signing algorithms. JWT signed with an algorithm not - found in this option will be rejected. **Default:** accepts all algorithms available on the - passed key (or keys in the keystore) - - `audience`: `` | `string[]` Expected audience value(s). When string an exact match must - be found in the payload, when array at least one must be matched. - - `typ`: `` Expected JWT "typ" Header Parameter value. An exact match must be found in the - JWT header. **Default:** 'undefined' unless a `profile` with a specific value is used, in which - case this option will be ignored. - - `clockTolerance`: `` Clock Tolerance for comparing timestamps, provided as timespan - string e.g. `120s`, `2 minutes`, etc. **Default:** no clock tolerance - - `complete`: `` When false only the parsed payload is returned, otherwise an object with - a parsed header, payload, the key that verified and the base64url encoded signature will be - returned - **Default:** 'false' - - `crit`: `string[]` Array of Critical Header Parameter names to recognize. **Default:** '[]' - - `ignoreExp`: `` When true will not be validating the "exp" claim value to be in the - future from now. **Default:** 'false' - - `ignoreIat`: `` When true will not be validating the "iat" claim value to be in the - past from now if expiration is not present. **Default:** 'false' - - `ignoreNbf`: `` When true will not be validating the "nbf" claim value to be in the - past from now. **Default:** 'false' - - `issuer`: `` | `string[]` Expected issuer value(s). When string an exact match must - be found in the payload, when array at least one must be matched. - - `jti`: `` Expected jti value. An exact match must be found in the payload. - - `maxTokenAge`: `` When provided the payload is checked to have the "iat" claim and its - value is validated not to be older than the provided timespan string e.g. `30m`, `24 hours`. - Do not confuse with maxAuthAge option. - - `now`: `` Date object to be used instead of the current unix epoch timestamp. - **Default:** 'new Date()' - - `subject`: `` Expected subject value. An exact match must be found in the payload. -- Returns: `` - -
-Example (Click to expand) - -```js -const { JWK, JWT } = require('jose') - -const key = JWK.asKey({ - kty: 'oct', - k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg' -}) - -const token = 'eyJ0eXAiOiJKV1QiLCJraWQiOiJSdG9SdXJfMURpcjVNNHd1T2ZxTmtEWU9mOU9fNFJKLWFIa1RBNzVSTEE4IiwiYWxnIjoiSFMyNTYifQ.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6ImZvbyIsImF1ZCI6WyJ1cm46ZXhhbXBsZTpjbGllbnQiXSwiaXNzIjoiaHR0cHM6Ly9vcC5leGFtcGxlLmNvbSIsImlhdCI6MTU1MTI5NDEzNywiZXhwIjoxNTUxMzAxMzM3fQ.YmtApwaGRBWlL9O8avbmpYcJ5UwNy0R8rpbxZqHxNd4' - -JWT.verify(token, key, { - audience: 'urn:example:client', - issuer: 'https://op.example.com', - clockTolerance: '1 min' -}) -``` -
- -
-Need to peak into a JWT without verifying it? (Click to expand) - -#### `JWT.decode(token[, options])` - -Decodes the JWT payload and optionally the header. Does not perform any claim validations what so -ever and also, clearly, **does not verify the token.** For JWT Verification use -[`JWT.verify`](#jwtverifytoken-keyorstore-options) - -- `token`: `` JSON Web Token to decode -- `options`: `` - - `complete`: `` When false only the parsed payload is returned, otherwise an object with - a parsed header, payload and the base64url encoded signature will be returned **Default:** 'false' -- Returns: `` - -```js -const { JWT } = require('jose') - -const token = 'eyJ0eXAiOiJKV1QiLCJraWQiOiJSdG9SdXJfMURpcjVNNHd1T2ZxTmtEWU9mOU9fNFJKLWFIa1RBNzVSTEE4IiwiYWxnIjoiSFMyNTYifQ.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6ImZvbyIsImF1ZCI6WyJ1cm46ZXhhbXBsZTpjbGllbnQiXSwiaXNzIjoiaHR0cHM6Ly9vcC5leGFtcGxlLmNvbSIsImlhdCI6MTU1MTI5NDEzNywiZXhwIjoxNTUxMzAxMzM3fQ.YmtApwaGRBWlL9O8avbmpYcJ5UwNy0R8rpbxZqHxNd4' - -JWT.decode(token) -// { 'urn:example:claim': 'foo', -// aud: [ 'urn:example:client' ], -// iss: 'https://op.example.com', -// iat: 1551294137, -// exp: 1551301337 } -JWT.decode(token, { complete: true }) -// { header: -// { typ: 'JWT', -// kid: 'RtoRur_1Dir5M4wuOfqNkDYOf9O_4RJ-aHkTA75RLA8', -// alg: 'HS256' }, -// payload: -// { 'urn:example:claim': 'foo', -// aud: [ 'urn:example:client' ], -// iss: 'https://op.example.com', -// iat: 1551294137, -// exp: 1551301337 }, -// signature: 'YmtApwaGRBWlL9O8avbmpYcJ5UwNy0R8rpbxZqHxNd4' } -``` - - ---- - -#### `JWT.AccessToken.verify(token, keyOrStore, options])` - -A shorthand for [`JWT.verify`](#jwtverifytoken-keyorstore-options) with additional constraints and options -to verify an Access Token according to -[JWT Profile for OAuth 2.0 Access Tokens](https://tools.ietf.org/html/draft-ietf-oauth-access-token-jwt-06). -This is an IETF **draft** implementation. Breaking draft implementations are included as minor versions of -the jose library, therefore, the ~ semver operator should be used and close attention be payed to library -changelog as well as the drafts themselves. - -The function arguments are the same as for [`JWT.verify`](#jwtverifytoken-keyorstore-options), only difference -is that `issuer` and `audience` options are required and the additional option: - -- see [`JWT.verify`](#jwtverifytoken-keyorstore-options) -- `issuer`: `` REQUIRED -- `audience`: `` REQUIRED -- `maxAuthAge`: `` When provided the payload is checked to have the "auth_time" claim and - its value is validated, provided as timespan string e.g. `30m`, `24 hours`. See - [OpenID Connect Core 1.0][connect-core] for details. Do not confuse with maxTokenAge option. - -
-Example (Click to expand) - -```js -jose.JWT.AccessToken.verify( - 'eyJhbGciOiJQUzI1NiIsInR5cCI6ImF0K0pXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJzdWIiOiJmb28iLCJjbGllbnRfaWQiOiJ1cm46ZXhhbXBsZTpjbGllbnRfaWQiLCJhdWQiOiJ1cm46ZXhhbXBsZTpyZXNvdXJjZS1zZXJ2ZXIiLCJleHAiOjE1NjM4ODg4MzAsImlzcyI6Imh0dHBzOi8vb3AuZXhhbXBsZS5jb20iLCJzY29wZSI6ImFwaTpyZWFkIn0.UYy8vEGWS0cS24giCYobMMy9-bqI45p807yV1l-2WXX2J4UO-eohV_R58LE2oM88gl414c6XydO6QSYXul5roNPoOs41jpEvreQIP-HmegjbWGutktWJKfvoOblE5FjYwjrwStjLQGUzkq6KWcnDLPGmpFy7n6gZ4LF8YVz4dLEaO335hMNVNrmSPSXYqr7bAWybnLVpLxjDYwNfCO1g0_TlFx8fHh2OftHoOOmJFltFwb8JypkSB-JXVVSEh43IOEjeeMJIG_ylWIOxfLLi5Q7vPWgub83ZTkuGNe4KmlQJKIsH5k0yZSshsLYUOOH0RiXqQ-SA4Ubh3Fowigdu-g', - keyOrStore, - { - issuer: 'https://op.example.com', - audience: 'urn:example:resource-server', - algorithms: ['PS256'] - } -) -``` -
- ---- - -#### `JWT.IdToken.verify(token, keyOrStore, options])` - -A shorthand for [`JWT.verify`](#jwtverifytoken-keyorstore-options) with the `profile` option set to `id_token`. - -The function arguments are the same as for [`JWT.verify`](#jwtverifytoken-keyorstore-options), only difference -is that `issuer` and `audience` options are required and the additional options: - -- see [`JWT.verify`](#jwtverifytoken-keyorstore-options) -- `issuer`: `` REQUIRED -- `audience`: `` REQUIRED -- `maxAuthAge`: `` When provided the payload is checked to have the "auth_time" claim and - its value is validated, provided as timespan string e.g. `30m`, `24 hours`. See - [OpenID Connect Core 1.0][connect-core] for details. Do not confuse with maxTokenAge option. -- `nonce`: `` Expected nonce value. An exact match must be found in the payload. See - [OpenID Connect Core 1.0][connect-core] for details. - -
-Example (Click to expand) - -```js -jose.JWT.IdToken.verify( - 'eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJzdWIiOiJmb28iLCJub25jZSI6ImE1MWNjZjA4ZjRiYmIwNmU4ODcxNWRkYzRiYmI0MWQ4IiwiYXVkIjoidXJuOmV4YW1wbGU6Y2xpZW50X2lkIiwiZXhwIjoxNTYzODg4ODMwLCJpYXQiOjE1NjM4ODUyMzAsImlzcyI6Imh0dHBzOi8vb3AuZXhhbXBsZS5jb20ifQ.RKCZczgICF5G9XdNDSwe4dolGauQHptpFKPzahA2wYGG2HKrKhyC8ZzqpeVc8cbntuqFBgABJVv6_9YICRx_dgwPYydTpZfZYjHnxrdWF9QsIPEGs672mrnhqIXUnXoseZ0TF6GOq6P7Qbf6gk1ru7TAbr_ieyJnNWcJhh5iHpz1k3mFz0TyTh7UNXshtQXftPUipqz4OBni5r9UaZXHw8B3QYOnms8__GJ3owOxaqkr1jgRs_EWqMlBNjPaj7ElVaeBWljDKuoK673tH0heSpgzUmUX_W8IDUVqs33uglpZwAQC7cAA5mGEg2odcRpvpP5M-WaP4RE9dl9jzcYmrw', - keyOrStore, - { - issuer: 'https://op.example.com', - audience: 'urn:example:client_id', - nonce: 'a51ccf08f4bbb06e88715ddc4bbb41d8', - algorithms: ['PS256'] - } -) -``` -
- ---- - -#### `JWT.LogoutToken.verify(token, keyOrStore, options])` - -A shorthand for [`JWT.verify`](#jwtverifytoken-keyorstore-options) with the `profile` option set to `logout_token`. -This is an OIDF **draft** implementation. Breaking draft implementations are included as minor versions of -the jose library, therefore, the ~ semver operator should be used and close attention be payed to library -changelog as well as the drafts themselves. - -The function arguments are the same as for [`JWT.verify`](#jwtverifytoken-keyorstore-options), only difference -is that `issuer` and `audience` options are required. - -- see [`JWT.verify`](#jwtverifytoken-keyorstore-options) -- `issuer`: `` REQUIRED -- `audience`: `` REQUIRED - -
-Example (Click to expand) - -```js -jose.JWT.LogoutToken.verify( - 'eyJhbGciOiJQUzI1NiJ9.eyJzdWIiOiJmb28iLCJhdWQiOiJ1cm46ZXhhbXBsZTpjbGllbnRfaWQiLCJpYXQiOjE1NjM4ODg4MzAsImp0aSI6ImhqazMyN2RzYSIsImlzcyI6Imh0dHBzOi8vb3AuZXhhbXBsZS5jb20iLCJldmVudHMiOnsiaHR0cDovL3NjaGVtYXMub3BlbmlkLm5ldC9ldmVudC9iYWNrY2hhbm5lbC1sb2dvdXQiOnt9fX0.SBi7uNUvjHL9TFoFzautGgTQ1MjyeGUNYHL7inpgq3XgTv6xc9EAKuPRtpixmhdNhmInGwUvAeqDSJxomwv1KK1cTndrC9zAMZ7h657BGQAwGhu7nTm41fWMpKQdiLa9sqp3yit5_FNBmqUNeOoMPrYT_Vl9ytsoNO89MUQy2aqCd-Z7BrNJZH0QycdW6dmYlrmZL7w3t3TaAXoJDJ4Hgl2Itkkkb6_6gO-VoPIdVD8sDuf1zQzGhIkmcFrk0fXczVYOkeF2hNYBuvsM8LuO-EPA3oyE2In9djai3M7yceTQetRa1vwlqWkg_xmYS59ry-6wT44aN7-Y6p0TdXm-Zg', - keyOrStore, - { - issuer: 'https://op.example.com', - audience: 'urn:example:client_id', - algorithms: ['PS256'] - } -) -``` -
- ---- - -## JWS (JSON Web Signature) - - -- [Class: <JWS.Sign>](#class-jwssign) - - [new JWS.Sign(payload)](#new-jwssignpayload) - - [sign.recipient(key[, protected[, header]])](#signrecipientkey-protected-header) - - [sign.sign(serialization)](#signsignserialization) -- [JWS.sign(payload, key[, protected])](#jwssignpayload-key-protected) -- [JWS.sign.flattened(payload, key[, protected[, header]])](#jwssignflattenedpayload-key-protected-header) -- [JWS.verify(jws, keyOrStore[, options])](#jwsverifyjws-keyorstore-options) - - -The `` module provides methods required to sign or verify JSON Web Signatures in either one of -the defined serializations. - -```js -const { JWS } = require('jose') -// { Sign: [Function: Sign], -// sign: -// { [Function: bound single] -// flattened: [Function: bound single] }, -// verify: [Function: bound jwsVerify] } -``` - -#### Class: `` - -`` is the class used when you need to produce a JWS for multiple recipients (with multiple -signatures of the same payload) using the General JWS JSON Serialization Syntax. - -
-Example (Click to expand) - -```js -const { JWK, JWS } = require('jose') - -const key = JWK.asKey({ - kty: 'oct', - k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg' -}) -const key2 = JWK.asKey({ - kty: 'oct', - k: 'AAPapAv4LbFbiVawEjagUBluYqN5rhna-8nuldDvOx8' -}) - -const payload = { - sub: 'John Doe' -} - -const sig = new JWS.Sign(payload) -sig.recipient(key, { alg: 'HS256' }, { foo: 'bar' }) -sig.recipient(key2, { alg: 'HS512' }, { foo: 'baz' }) -sig.sign('general') -// { payload: 'eyJzdWIiOiJKb2huIERvZSJ9', -// signatures: -// [ { protected: 'eyJhbGciOiJIUzI1NiJ9', -// header: { foo: 'bar' }, -// signature: 'mnBcKK-9setCco03NtYws-RMlYXP3LGlDu2RUB7vetQ' }, -// { protected: 'eyJhbGciOiJIUzUxMiJ9', -// header: { foo: 'baz' }, -// signature: -// 'R7e5ZUkgiZQLh8JagoCbwAY21e9A-Y0rhUGQkhihLOvIU8JG2AyZ9zROOUICaUucf8NQKc2dEaIKdRCXy-fDdQ' } ] } -``` -
- ---- - -#### `new JWS.Sign(payload)` - -Creates a new Sign object for the provided payload, intended for one or more recipients. - -- `payload`: `` | `` | `` The payload that will be signed. When `` - it will be automatically serialized to JSON before signing -- Returns: `` - ---- - -#### `sign.recipient(key[, protected[, header]])` - -Adds a recipient to the JWS, the Algorithm that will be used to sign with is either provided as part -of the Protected or Unprotected Header or inferred from the provided `` instance. - -- `key`: `` The key to sign with. Any `JWK.asKey()` compatible input also works. - `` instances are recommended for performance purposes when re-using the same key for - every operation. -- `protected`: `` Protected Header for this recipient -- `header`: `` Unprotected Header for this recipient - ---- - -#### `sign.sign(serialization)` - -Performs the signing operations for each registered recipient and returns the final JWS -representation in the serialization requested. The JWS is validated for conformance during this -step. Please note that only 'general' and 'flattened' serialization supports Unprotected -Per-Recipient Header and only the 'general' serialization supports multiple recipients. See -`` and `` for shorthand methods to sign for a single recipient. - -- `serialization`: `` JWS Serialization. Must be one of 'general', 'flattened', 'compact' -- Returns: `` | `` - ---- - -#### `JWS.sign(payload, key[, protected])` - -Performs the signing operation and 'compact' JWS serialization of the result. The Algorithm that -will be used to sign with is either provided as part of the Protected Header or inferred from the -provided `` instance. - -- `payload`: `` | `` | `` The payload that will be signed. When `` - it will be automatically serialized to JSON before signing -- `key`: `` The key to sign with. Any `JWK.asKey()` compatible input also works. - `` instances are recommended for performance purposes when re-using the same key for - every operation. -- `protected`: `` Protected Header -- Returns: `` - -
-Example (Click to expand) - -```js -const { JWK, JWS } = require('jose') - -const key = JWK.asKey({ - kty: 'oct', - k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg' -}) - -const payload = { - sub: 'John Doe' -} -JWS.sign(payload, key, { alg: 'HS256' }) -// eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2huIERvZSJ9.mnBcKK-9setCco03NtYws-RMlYXP3LGlDu2RUB7vetQ -``` -
- ---- - -#### `JWS.sign.flattened(payload, key[, protected[, header]])` - -Performs the signing operation and 'flattened' JWS serialization of the result. The Algorithm that -will be used to sign with is either provided as part of the Protected or Unprotected Header or -inferred from the provided `` instance. - -- `payload`: `` | `` | `` The payload that will be signed. When `` - it will be automatically serialized to JSON before signing -- `key`: `` The key to sign with. Any `JWK.asKey()` compatible input also works. - `` instances are recommended for performance purposes when re-using the same key for - every operation. -- `protected`: `` Protected Header -- `header`: `` Unprotected Header -- Returns: `` - -
-Example (Click to expand) - -```js -const { JWK, JWS } = require('jose') - -const key = JWK.asKey({ - kty: 'oct', - k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg' -}) - -const payload = { - sub: 'John Doe' -} - -JWS.sign.flattened(payload, key) -// { payload: 'eyJzdWIiOiJKb2huIERvZSJ9', -// protected: 'eyJhbGciOiJIUzI1NiJ9', -// signature: 'mnBcKK-9setCco03NtYws-RMlYXP3LGlDu2RUB7vetQ' } -``` -
- ---- - -#### `JWS.verify(jws, keyOrStore[, options])` - -Verifies the provided JWS in either serialization with a given `` or `` - -- `jws`: `` | `` The JWS to verify. This must be a valid JWS. -- `keyOrStore`: `` | `` The key or store to verify with. When - `` instance is provided a selection of possible candidate keys will be done and the - operation will succeed if just one key or signature (in case of General JWS JSON Serialization - Syntax) matches. Any `JWK.asKey()` compatible input also works. `` instances are - recommended for performance purposes when re-using the same key for every operation. -- `options`: `` - - `algorithms`: `string[]` Array of Algorithms to accept, when the signature does not use an - algorithm from this list the verification will fail. **Default:** 'undefined' - accepts all - algorithms available on the keys - - `complete`: `` When true returns a complete object with the parsed headers and payload - instead of only the verified payload. **Default:** 'false' - - `crit`: `string[]` Array of Critical Header Parameter names to recognize. **Default:** '[]' -- Returns: `` - -
-Example (Click to expand) - -```js -const { JWK, JWS, JWKS } = require('jose') - -const key = JWK.asKey({ - kty: 'oct', - k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg' -}) -const key2 = JWK.asKey({ - kty: 'oct', - k: 'AAPapAv4LbFbiVawEjagUBluYqN5rhna-8nuldDvOx8' -}) - -const compact = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2huIERvZSJ9.mnBcKK-9setCco03NtYws-RMlYXP3LGlDu2RUB7vetQ' - -const flattened = { payload: 'eyJzdWIiOiJKb2huIERvZSJ9', - protected: 'eyJhbGciOiJIUzI1NiJ9', - signature: 'mnBcKK-9setCco03NtYws-RMlYXP3LGlDu2RUB7vetQ' } - -const general = { payload: 'eyJzdWIiOiJKb2huIERvZSJ9', - signatures: - [ { protected: 'eyJhbGciOiJIUzI1NiJ9', - header: { foo: 'bar' }, - signature: 'mnBcKK-9setCco03NtYws-RMlYXP3LGlDu2RUB7vetQ' }, - { protected: 'eyJhbGciOiJIUzUxMiJ9', - header: { foo: 'baz' }, - signature: - 'R7e5ZUkgiZQLh8JagoCbwAY21e9A-Y0rhUGQkhihLOvIU8JG2AyZ9zROOUICaUucf8NQKc2dEaIKdRCXy-fDdQ' } ] } - -JWS.verify(compact, key) -// - -JWS.verify(flattened, key2) -// Thrown: -// JWSVerificationFailed: signature verification failed - -JWS.verify(compact, key, { complete: true }) -// { payload: , protected: { alg: 'HS256' }, key: OctKey {} } - -JWS.verify(flattened, key, { algorithms: ['PS256'] }) -// JOSEAlgNotWhitelisted: alg not whitelisted - -JWS.verify(general, key) -// -JWS.verify(general, key2) -// - -JWS.verify(general, key, { complete: true }) -// { payload: , -// protected: { alg: 'HS256' }, -// header: { foo: 'bar' }, -// key: : OctKey {} } <- key -JWS.verify(general, key2, { complete: true }) -// { payload: , -// protected: { alg: 'HS512' }, -// header: { foo: 'baz' }, -// key: : OctKey {} } <- key2 -const keystore = new JWKS.KeyStore(key) -JWS.verify(general, keystore, { complete: true }) -// { payload: , -// protected: { alg: 'HS256' }, -// header: { foo: 'bar' }, -// key: : OctKey {} } <- key that matched in the keystore -``` -
- ---- - -## JWE (JSON Web Encryption) - - -- [Class: <JWE.Encrypt>](#class-jweencrypt) - - [new JWE.Encrypt(cleartext[, protected[, aad[, unprotected]]])](#new-jweencryptcleartext-protected-aad-unprotected) - - [encrypt.recipient(key[, header])](#encryptrecipientkey-header) - - [encrypt.encrypt(serialization)](#encryptencryptserialization) -- [JWE.encrypt(cleartext, key[, protected])](#jweencryptcleartext-key-protected) -- [JWE.encrypt.flattened(cleartext, key[, protected[, aad[, unprotected]]])](#jweencryptflattenedcleartext-key-protected-aad-unprotected) -- [JWE.decrypt(jwe, keyOrStore[, options])](#jwedecryptjwe-keyorstore-options) - - -The `` module provides methods required to encrypt or decrypt JSON Web Encryptions in either -one of the defined serializations. - -```js -const { JWE } = require('jose') -// { Encrypt: [Function: Encrypt], -// encrypt: -// { [Function: bound single] -// flattened: [Function: bound single] }, -// decrypt: [Function: bound jweDecrypt] } -``` - -#### Class: `` - -`` is the class used when you need to produce a JWE for multiple recipients using the -General JWE JSON Serialization Syntax. - ---- - -#### `new JWE.Encrypt(cleartext[, protected[, aad[, unprotected]]])` - -Creates a new Encrypt object for the provided cleartext with optional Protected and Unprotected -Headers and Additional Authenticated Data. - -- `cleartext`: `` | `` The cleartext that will be encrypted. -- `protected`: `` JWE Protected Header -- `aad`: `` | `` JWE Additional Authenticated Data -- `unprotected`: `` JWE Shared Unprotected Header -- Returns: `` - ---- - -#### `encrypt.recipient(key[, header])` - -Adds a recipient to the JWE, the Algorithm that will be used to wrap or derive the Content -Encryption Key (CEK) is either provided as part of the combined JWE Header for the recipient or -inferred from the provided `` instance. - -- `key`: `` The key to use for Key Management or Direct Encryption. Any `JWK.asKey()` - compatible input also works. `` instances are recommended for performance purposes when - re-using the same key for every operation. -- `header`: `` JWE Per-Recipient Unprotected Header - ---- - -#### `encrypt.encrypt(serialization)` - -Performs the encryption operations for each registered recipient and returns the final JWE -representation in the serialization requested. The JWE is validated for conformance during this -step. Please note that only 'general' and 'flattened' serialization supports Unprotected -Per-Recipient Header and AAD and only the 'general' serialization supports multiple recipients. See -`` and `` for shorthand methods to encrypt for a single -recipient. - -- `serialization`: `` JWE Serialization. Must be one of 'general', 'flattened', 'compact' -- Returns: `` | `` - ---- - -#### `JWE.encrypt(cleartext, key[, protected])` - -Performs the encryption operation and 'compact' JWE serialization of the result. The Algorithm that -will be used to wrap or derive the Content Encryption Key (CEK) is either provided as part of the -Protected Header or inferred from the provided `` instance. - -- `cleartext`: `` | `` The cleartext that will be encrypted. -- `key`: `` The key to use for Key Management or Direct Encryption. Any `JWK.asKey()` - compatible input also works. `` instances are recommended for performance purposes when - re-using the same key for every operation. -- `protected`: `` JWE Protected Header -- Returns: `` - ---- - -#### `JWE.encrypt.flattened(cleartext, key[, protected[, aad[, unprotected]]])` - -Performs the encryption operation and 'flattened' JWE serialization of the result. The Algorithm -that will be used to wrap or derive the Content Encryption Key (CEK) is either provided as part of -the combined JWE Header or inferred from the provided `` instance. - -- `cleartext`: `` | `` The cleartext that will be encrypted. -- `key`: `` The key to use for Key Management or Direct Encryption. Any `JWK.asKey()` - compatible input also works. `` instances are recommended for performance purposes when - re-using the same key for every operation. -- `protected`: `` JWE Protected Header -- `aad`: `` | `` JWE Additional Authenticated Data -- `unprotected`: `` JWE Shared Unprotected Header -- Returns: `` - ---- - -#### `JWE.decrypt(jwe, keyOrStore[, options])` - -Decrypts the provided JWE in either serialization with a given `` or `` - -Note: This performs only the authenticated decryption, it does not process the resulting cleartext -in any way. If the resulting cleartext is a signed JWS/JWT, you must run it through a JWS/JWT verify -operation. - -- `jwe`: `` | `` The JWE to decrypt. This must be a valid JWE. -- `keyOrStore`: `` | `` The key or store to decrypt with. When - `` instance is provided a selection of possible candidate keys will be done and the - operation will succeed if just one key or signature (in case of General JWE JSON Serialization - Syntax) matches. Any `JWK.asKey()` compatible input also works. `` instances are - recommended for performance purposes when re-using the same key for every operation. -- `options`: `` - - `contentEncryptionAlgorithms`: `string[]` Array of algorithms to accept as the `enc` (content - encryption), when the JWE does not use an Key Management algorithm from this list the decryption - will fail. **Default:** 'undefined' - accepts all content encryption algorithms. - - `keyManagementAlgorithms`: `string[]` Array of algorithms to accept as the `alg` (key management), - when the JWE does not use an Key Management algorithm from this list the decryption will fail. - **Default:** 'undefined' - accepts all algorithms available on the key or key store. - - `complete`: `` When true returns an object with the parsed headers, verified - AAD, the content encryption key, the key that was used to unwrap or derive the content - encryption key, and cleartext instead of only the cleartext. - **Default:** 'false' -- Returns: `` | `` - ---- - -## Errors - - -- [Class: <TypeError>](#class-typeerror) -- [Class: <JOSEError>](#class-joseerror) -- [Class: <JOSEAlgNotWhitelisted>](#class-josealgnotwhitelisted) -- [Class: <JOSECritNotUnderstood>](#class-josecritnotunderstood) -- [Class: <JOSEMultiError>](#class-josemultierror) -- [Class: <JOSEInvalidEncoding>](#class-joseinvalidencoding) -- [Class: <JOSENotSupported>](#class-josenotsupported) -- [Class: <JWEDecryptionFailed>](#class-jwedecryptionfailed) -- [Class: <JWEInvalid>](#class-jweinvalid) -- [Class: <JWKImportFailed>](#class-jwkimportfailed) -- [Class: <JWKKeyInvalid>](#class-jwkkeyinvalid) -- [Class: <JWKKeySupport>](#class-jwkkeysupport) -- [Class: <JWKSNoMatchingKey>](#class-jwksnomatchingkey) -- [Class: <JWSInvalid>](#class-jwsinvalid) -- [Class: <JWSVerificationFailed>](#class-jwsverificationfailed) -- [Class: <JWTClaimInvalid>](#class-jwtclaiminvalid) -- [Class: <JWTExpired>](#class-jwtexpired) -- [Class: <JWTMalformed>](#class-jwtmalformed) - - - -The following errors are expected to be thrown by `jose` runtime and have their prototypes -exported in `jose.errors`. If you encounter an `Error` other then `TypeError` or one that's -`instanceof jose.errors.JOSEError` please report it, it is not intended. - -#### Class: `TypeError` - -Thrown when unexpected argument types or their format is encountered. This is the standard built-in -[`TypeError`](https://nodejs.org/api/errors.html#errors_class_typeerror). - -#### Class: `JOSEError` - -Base Error the others inherit from. - -#### Class: `JOSEAlgNotWhitelisted` - -Thrown when an algorithm whitelist is provided but the validated JWE/JWS does not use one from it. - -```js -if (err instanceof jose.errors.JOSEError && err.code === 'ERR_JOSE_ALG_NOT_WHITELISTED') { - // ... -} -``` - -#### Class: `JOSECritNotUnderstood` - -Thrown when a Critical member is encountered that's not acknowledged. The only built in "crit" -handler is for "b64", it must still be acknowledged though. - -```js -if (err instanceof jose.errors.JOSEError && err.code === 'ERR_JOSE_CRIT_NOT_UNDERSTOOD') { - // ... -} -``` - -#### Class: `JOSEMultiError` - -This error is thrown when - -- multi-recipient JWE decryption fails for each recipient with errors other than `JWEDecryptionFailed (ERR_JWE_DECRYPTION_FAILED)` -- multi-recipient JWS verification fails for each recipient with errors other than `JWSVerificationFailed (ERR_JWS_VERIFICATION_FAILED)` -- KeyStore instance is passed to JWT/JWS verify, there are multiple usable keys and all of them fail with errors other than `JWSVerificationFailed (ERR_JWS_VERIFICATION_FAILED)` -- KeyStore instance is passed to JWE decrypt, there are multiple usable keys and all of them fail with errors other than `JWEDecryptionFailed (ERR_JWE_DECRYPTION_FAILED)` - -The error is an [Iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#Iterables) -and yields every single one of the encountered errors. - -```js -if (err instanceof jose.errors.JOSEError && err.code === 'ERR_JOSE_MULTIPLE_ERRORS') { - for (const e of err) { - console.log(e) - // ... - } -} -``` - -#### Class: `JOSEInvalidEncoding` - -Thrown when invalid base64url encoding is detected. - -```js -if (err instanceof jose.errors.JOSEError && err.code === 'ERR_JOSE_INVALID_ENCODING') { - // ... -} -``` - -#### Class: `JOSENotSupported` - -Thrown when an unsupported "alg", "kty" or specific header value like "zip" is encountered. - -```js -if (err instanceof jose.errors.JOSEError && err.code === 'ERR_JOSE_NOT_SUPPORTED') { - // ... -} -``` - -#### Class: `JWEDecryptionFailed` - -Thrown when JWE decrypt operations are started but fail to decrypt. Only generic error message is -provided. - -```js -if (err instanceof jose.errors.JOSEError && err.code === 'ERR_JWE_DECRYPTION_FAILED') { - // ... -} -``` - -#### Class: `JWEInvalid` - -Thrown when syntactically incorrect JWE is either requested to be encrypted or decrypted - -```js -if (err instanceof jose.errors.JOSEError && err.code === 'ERR_JWE_INVALID') { - // ... -} -``` - -#### Class: `JWKImportFailed` - -Thrown when a key failed to import as `` - -```js -if (err instanceof jose.errors.JOSEError && err.code === 'ERR_JWK_IMPORT_FAILED') { - // ... -} -``` - -#### Class: `JWKKeyInvalid` - -Thrown when key's parameters are invalid, e.g. key_ops and use values are inconsistent. - -```js -if (err instanceof jose.errors.JOSEError && err.code === 'ERR_JWK_INVALID') { - // ... -} -``` - -#### Class: `JWKKeySupport` - -Thrown when a key does not support the request algorithm. - -```js -if (err instanceof jose.errors.JOSEError && err.code === 'ERR_JWK_KEY_SUPPORT') { - // ... -} -``` - -#### Class: `JWKSNoMatchingKey` - -Thrown when `` is used as argument for decrypt / verify operation and no usable key -for the crypto operation is found in it - -```js -if (err instanceof jose.errors.JOSEError && err.code === 'ERR_JWKS_NO_MATCHING_KEY') { - // ... -} -``` - -#### Class: `JWSInvalid` - -Thrown when syntactically incorrect JWS is either requested to be signed or - verified - -```js -if (err instanceof jose.errors.JOSEError && err.code === 'ERR_JWS_INVALID') { - // ... -} -``` - -#### Class: `JWSVerificationFailed` - -Thrown when JWS verify operations are started but fail to verify. Only generic error message is -provided. - -```js -if (err instanceof jose.errors.JOSEError && err.code === 'ERR_JWS_VERIFICATION_FAILED') { - // ... -} -``` - -#### Class: `JWTClaimInvalid` - -Thrown when JWT Claim is either of incorrect type or fails to validate by the provided options. -Instances of `` have a `claim` property with the name of the claim as well as -`reason` property with one of the following values `'prohibited' | 'missing' | 'invalid' | 'check_failed' | 'unspecified'`. - -```js -if (err instanceof jose.errors.JOSEError && err.code === 'ERR_JWT_CLAIM_INVALID') { - // ... -} -``` - -#### Class: `JWTExpired` - -Thrown when the JWT Claims indicate the JWT is expired by the provided options. `` -is a descendant of `` with a unique `code` property. - -```js -if (err instanceof jose.errors.JOSEError && err.code === 'ERR_JWT_EXPIRED') { - // ... -} -``` - -#### Class: `JWTMalformed` - -Thrown when malformed JWT is either being verified. - -```js -if (err instanceof jose.errors.JOSEError && err.code === 'ERR_JWT_MALFORMED') { - // ... -} -``` - +## Available modules + +- JSON Web Tokens (JWT) + - [Signing](classes/_jwt_sign_.signjwt.md#readme) + - [Verification & Claims Set Validation](functions/_jwt_verify_.jwtverify.md#readme) + - Encrypted JSON Web Tokens + - [Encryption](classes/_jwt_encrypt_.encryptjwt.md#readme) + - [Decryption & Claims Set Validation](functions/_jwt_decrypt_.jwtdecrypt.md#readme) +- JSON Web Encryption (JWE) + - Encryption - [Compact](classes/_jwe_compact_encrypt_.compactencrypt.md#readme), [Flattened](classes/_jwe_flattened_encrypt_.flattenedencrypt.md#readme) + - Decryption - [Compact](functions/_jwe_compact_decrypt_.compactdecrypt.md#readme), [Flattened](functions/_jwe_flattened_decrypt_.flatteneddecrypt.md#readme) +- JSON Web Signature (JWS) + - Signing - [Compact](classes/_jws_compact_sign_.compactsign.md#readme), [Flattened](classes/_jws_flattened_sign_.flattenedsign.md#readme) + - Verification - [Compact](functions/_jws_compact_verify_.compactverify.md#readme), [Flattened](functions/_jws_flattened_verify_.flattenedverify.md#readme) +- JSON Web Key (JWK) + - [Parsing & Conversion](functions/_jwk_parse_.parsejwk.md#readme) + - [Thumbprints](functions/_jwk_thumbprint_.calculatethumbprint.md#readme) + - [EmbeddedJWK](functions/_jwk_embedded_.embeddedjwk.md#readme) +- JSON Web Key Set (JWKS) + - [Verify using a remote JWKSet](functions/_jwks_remote_.createremotejwkset.md#readme) +- Key Pair or Secret Generation + - [Asymmetric Key Pair Generation](functions/_util_generate_key_pair_.generatekeypair.md#readme) + - [Symmetric Secret Generation](functions/_util_generate_secret_.generatesecret.md#readme) +- [Unsecured JWT](classes/_jwt_unsecured_.unsecuredjwt.md#readme) +- [JOSE Errors](modules/_util_errors_.md) -[spec-thumbprint]: https://tools.ietf.org/html/rfc7638 [support-sponsor]: https://github.com/sponsors/panva -[connect-core]: https://openid.net/specs/openid-connect-core-1_0.html diff --git a/docs/classes/_jwe_compact_encrypt_.compactencrypt.md b/docs/classes/_jwe_compact_encrypt_.compactencrypt.md new file mode 100644 index 0000000000..63845aa87d --- /dev/null +++ b/docs/classes/_jwe_compact_encrypt_.compactencrypt.md @@ -0,0 +1,164 @@ +# Class: CompactEncrypt + +The CompactEncrypt class is a utility for creating Compact JWE strings. + +**`example`** +```js +// ESM import +import CompactEncrypt from 'jose/jwe/compact/encrypt' +``` + +**`example`** +```js +// CJS import +const { default: CompactEncrypt } = require('jose/jwe/compact/encrypt') +``` + +**`example`** +```js +// usage +import parseJwk from 'jose/jwk/parse' + +const encoder = new TextEncoder() + +const publicKey = await parseJwk({ + e: 'AQAB', + n: 'qpzYkTGRKSUcd12hZaJnYEKVLfdEsqu6HBAxZgRSvzLFj_zTSAEXjbf3fX47MPEHRw8NDcEXPjVOz84t4FTXYF2w2_LGWfp_myjV8pR6oUUncJjS7DhnUmTG5bpuK2HFXRMRJYz_iNR48xRJPMoY84jrnhdIFx8Tqv6w4ZHVyEvcvloPgwG3UjLidP6jmqbTiJtidVLnpQJRuFNFQJiluQXBZ1nOLC7raQshu7L9y0IatVU7vf0BPnmuSkcNNvmQkSta6ODQBPaL5-o5SW8H37vQjPDkrlJpreViNa3jqP5DB5HYUO-DMh4FegRv9gZWLDEvXpSd9A13YXCa9Q8K_w', + kty: 'RSA' +}, 'RSA-OAEP-256') + +const jwe = await new CompactEncrypt(encoder.encode('It’s a dangerous business, Frodo, going out your door.')) + .setProtectedHeader({ alg: 'RSA-OAEP-256', enc: 'A256GCM' }) + .encrypt(publicKey) + +console.log(jwe) +``` + +## Index + +### Constructors + +* [constructor](_jwe_compact_encrypt_.compactencrypt.md#constructor) + +### Methods + +* [encrypt](_jwe_compact_encrypt_.compactencrypt.md#encrypt) +* [setContentEncryptionKey](_jwe_compact_encrypt_.compactencrypt.md#setcontentencryptionkey) +* [setInitializationVector](_jwe_compact_encrypt_.compactencrypt.md#setinitializationvector) +* [setKeyManagementParameters](_jwe_compact_encrypt_.compactencrypt.md#setkeymanagementparameters) +* [setProtectedHeader](_jwe_compact_encrypt_.compactencrypt.md#setprotectedheader) + +## Constructors + +### constructor + +\+ **new CompactEncrypt**(`plaintext`: Uint8Array): [CompactEncrypt](_jwe_compact_encrypt_.compactencrypt.md) + +*Defined in [src/jwe/compact/encrypt.ts:45](https://github.com/panva/jose/blob/v3.x/src/jwe/compact/encrypt.ts#L45)* + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`plaintext` | Uint8Array | Binary representation of the plaintext to encrypt. | + +**Returns:** [CompactEncrypt](_jwe_compact_encrypt_.compactencrypt.md) + +## Methods + +### encrypt + +▸ **encrypt**(`key`: [KeyLike](../types/_types_d_.keylike.md), `options?`: [EncryptOptions](../interfaces/_types_d_.encryptoptions.md)): Promise\ + +*Defined in [src/jwe/compact/encrypt.ts:108](https://github.com/panva/jose/blob/v3.x/src/jwe/compact/encrypt.ts#L108)* + +Encrypts and resolves the value of the Compact JWE string. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`key` | [KeyLike](../types/_types_d_.keylike.md) | Public Key or Secret to encrypt the JWE with. | +`options?` | [EncryptOptions](../interfaces/_types_d_.encryptoptions.md) | JWE Encryption options. | + +**Returns:** Promise\ + +___ + +### setContentEncryptionKey + +▸ **setContentEncryptionKey**(`cek`: Uint8Array): this + +*Defined in [src/jwe/compact/encrypt.ts:62](https://github.com/panva/jose/blob/v3.x/src/jwe/compact/encrypt.ts#L62)* + +Sets a content encryption key to use, by default a random suitable one +is generated for the JWE enc" (Encryption Algorithm) Header Parameter. +You do not need to invoke this method, it is only really intended for +test and vector validation purposes. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`cek` | Uint8Array | JWE Content Encryption Key. | + +**Returns:** this + +___ + +### setInitializationVector + +▸ **setInitializationVector**(`iv`: Uint8Array): this + +*Defined in [src/jwe/compact/encrypt.ts:75](https://github.com/panva/jose/blob/v3.x/src/jwe/compact/encrypt.ts#L75)* + +Sets the JWE Initialization Vector to use for content encryption, by default +a random suitable one is generated for the JWE enc" (Encryption Algorithm) +Header Parameter. You do not need to invoke this method, it is only really +intended for test and vector validation purposes. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`iv` | Uint8Array | JWE Initialization Vector. | + +**Returns:** this + +___ + +### setKeyManagementParameters + +▸ **setKeyManagementParameters**(`parameters`: [JWEKeyManagementHeaderParameters](../interfaces/_types_d_.jwekeymanagementheaderparameters.md)): this + +*Defined in [src/jwe/compact/encrypt.ts:97](https://github.com/panva/jose/blob/v3.x/src/jwe/compact/encrypt.ts#L97)* + +Sets the JWE Key Management parameters to be used when encrypting the Content +Encryption Key. You do not need to invoke this method, it is only really +intended for test and vector validation purposes. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`parameters` | [JWEKeyManagementHeaderParameters](../interfaces/_types_d_.jwekeymanagementheaderparameters.md) | JWE Key Management parameters. | + +**Returns:** this + +___ + +### setProtectedHeader + +▸ **setProtectedHeader**(`protectedHeader`: [JWEHeaderParameters](../interfaces/_types_d_.jweheaderparameters.md)): this + +*Defined in [src/jwe/compact/encrypt.ts:85](https://github.com/panva/jose/blob/v3.x/src/jwe/compact/encrypt.ts#L85)* + +Sets the JWE Protected Header on the CompactEncrypt object. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`protectedHeader` | [JWEHeaderParameters](../interfaces/_types_d_.jweheaderparameters.md) | JWE Protected Header object. | + +**Returns:** this diff --git a/docs/classes/_jwe_flattened_encrypt_.flattenedencrypt.md b/docs/classes/_jwe_flattened_encrypt_.flattenedencrypt.md new file mode 100644 index 0000000000..ac4a1ea4c7 --- /dev/null +++ b/docs/classes/_jwe_flattened_encrypt_.flattenedencrypt.md @@ -0,0 +1,223 @@ +# Class: FlattenedEncrypt + +The FlattenedEncrypt class is a utility for creating Flattened JWE +objects. + +**`example`** +```js +// ESM import +import FlattenedEncrypt from 'jose/jwe/flattened/encrypt' +``` + +**`example`** +```js +// CJS import +const { default: FlattenedEncrypt } = require('jose/jwe/flattened/encrypt') +``` + +**`example`** +```js +// usage +import parseJwk from 'jose/jwk/parse' + +const encoder = new TextEncoder() +const publicKey = await parseJwk({ + e: 'AQAB', + n: 'qpzYkTGRKSUcd12hZaJnYEKVLfdEsqu6HBAxZgRSvzLFj_zTSAEXjbf3fX47MPEHRw8NDcEXPjVOz84t4FTXYF2w2_LGWfp_myjV8pR6oUUncJjS7DhnUmTG5bpuK2HFXRMRJYz_iNR48xRJPMoY84jrnhdIFx8Tqv6w4ZHVyEvcvloPgwG3UjLidP6jmqbTiJtidVLnpQJRuFNFQJiluQXBZ1nOLC7raQshu7L9y0IatVU7vf0BPnmuSkcNNvmQkSta6ODQBPaL5-o5SW8H37vQjPDkrlJpreViNa3jqP5DB5HYUO-DMh4FegRv9gZWLDEvXpSd9A13YXCa9Q8K_w', + kty: 'RSA' +}, 'RSA-OAEP-256') + +const jwe = await new FlattenedEncrypt(encoder.encode('It’s a dangerous business, Frodo, going out your door.')) + .setProtectedHeader({ alg: 'RSA-OAEP-256', enc: 'A256GCM' }) + .setAdditionalAuthenticatedData(encoder.encode('The Fellowship of the Ring')) + .encrypt(publicKey) + +console.log(jwe) +``` + +## Index + +### Constructors + +* [constructor](_jwe_flattened_encrypt_.flattenedencrypt.md#constructor) + +### Methods + +* [encrypt](_jwe_flattened_encrypt_.flattenedencrypt.md#encrypt) +* [setAdditionalAuthenticatedData](_jwe_flattened_encrypt_.flattenedencrypt.md#setadditionalauthenticateddata) +* [setContentEncryptionKey](_jwe_flattened_encrypt_.flattenedencrypt.md#setcontentencryptionkey) +* [setInitializationVector](_jwe_flattened_encrypt_.flattenedencrypt.md#setinitializationvector) +* [setKeyManagementParameters](_jwe_flattened_encrypt_.flattenedencrypt.md#setkeymanagementparameters) +* [setProtectedHeader](_jwe_flattened_encrypt_.flattenedencrypt.md#setprotectedheader) +* [setSharedUnprotectedHeader](_jwe_flattened_encrypt_.flattenedencrypt.md#setsharedunprotectedheader) +* [setUnprotectedHeader](_jwe_flattened_encrypt_.flattenedencrypt.md#setunprotectedheader) + +## Constructors + +### constructor + +\+ **new FlattenedEncrypt**(`plaintext`: Uint8Array): [FlattenedEncrypt](_jwe_flattened_encrypt_.flattenedencrypt.md) + +*Defined in [src/jwe/flattened/encrypt.ts:75](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L75)* + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`plaintext` | Uint8Array | Binary representation of the plaintext to encrypt. | + +**Returns:** [FlattenedEncrypt](_jwe_flattened_encrypt_.flattenedencrypt.md) + +## Methods + +### encrypt + +▸ **encrypt**(`key`: [KeyLike](../types/_types_d_.keylike.md), `options?`: [EncryptOptions](../interfaces/_types_d_.encryptoptions.md)): Promise\<[FlattenedJWE](../interfaces/_types_d_.flattenedjwe.md)> + +*Defined in [src/jwe/flattened/encrypt.ts:187](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L187)* + +Encrypts and resolves the value of the Flattened JWE object. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`key` | [KeyLike](../types/_types_d_.keylike.md) | Public Key or Secret to encrypt the JWE with. | +`options?` | [EncryptOptions](../interfaces/_types_d_.encryptoptions.md) | JWE Encryption options. | + +**Returns:** Promise\<[FlattenedJWE](../interfaces/_types_d_.flattenedjwe.md)> + +___ + +### setAdditionalAuthenticatedData + +▸ **setAdditionalAuthenticatedData**(`aad`: Uint8Array): this + +*Defined in [src/jwe/flattened/encrypt.ts:144](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L144)* + +Sets the Additional Authenticated Data on the FlattenedEncrypt object. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`aad` | Uint8Array | Additional Authenticated Data. | + +**Returns:** this + +___ + +### setContentEncryptionKey + +▸ **setContentEncryptionKey**(`cek`: Uint8Array): this + +*Defined in [src/jwe/flattened/encrypt.ts:157](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L157)* + +Sets a content encryption key to use, by default a random suitable one +is generated for the JWE enc" (Encryption Algorithm) Header Parameter. +You do not need to invoke this method, it is only really intended for +test and vector validation purposes. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`cek` | Uint8Array | JWE Content Encryption Key. | + +**Returns:** this + +___ + +### setInitializationVector + +▸ **setInitializationVector**(`iv`: Uint8Array): this + +*Defined in [src/jwe/flattened/encrypt.ts:173](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L173)* + +Sets the JWE Initialization Vector to use for content encryption, by default +a random suitable one is generated for the JWE enc" (Encryption Algorithm) +Header Parameter. You do not need to invoke this method, it is only really +intended for test and vector validation purposes. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`iv` | Uint8Array | JWE Initialization Vector. | + +**Returns:** this + +___ + +### setKeyManagementParameters + +▸ **setKeyManagementParameters**(`parameters`: [JWEKeyManagementHeaderParameters](../interfaces/_types_d_.jwekeymanagementheaderparameters.md)): this + +*Defined in [src/jwe/flattened/encrypt.ts:92](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L92)* + +Sets the JWE Key Management parameters to be used when encrypting. +Use of this is method is really only needed for ECDH-ES based algorithms +when utilizing the Agreement PartyUInfo or Agreement PartyVInfo parameters. +Other parameters will always be randomly generated when needed and missing. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`parameters` | [JWEKeyManagementHeaderParameters](../interfaces/_types_d_.jwekeymanagementheaderparameters.md) | JWE Key Management parameters. | + +**Returns:** this + +___ + +### setProtectedHeader + +▸ **setProtectedHeader**(`protectedHeader`: [JWEHeaderParameters](../interfaces/_types_d_.jweheaderparameters.md)): this + +*Defined in [src/jwe/flattened/encrypt.ts:105](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L105)* + +Sets the JWE Protected Header on the FlattenedEncrypt object. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`protectedHeader` | [JWEHeaderParameters](../interfaces/_types_d_.jweheaderparameters.md) | JWE Protected Header. | + +**Returns:** this + +___ + +### setSharedUnprotectedHeader + +▸ **setSharedUnprotectedHeader**(`sharedUnprotectedHeader`: [JWEHeaderParameters](../interfaces/_types_d_.jweheaderparameters.md)): this + +*Defined in [src/jwe/flattened/encrypt.ts:118](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L118)* + +Sets the JWE Shared Unprotected Header on the FlattenedEncrypt object. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`sharedUnprotectedHeader` | [JWEHeaderParameters](../interfaces/_types_d_.jweheaderparameters.md) | JWE Shared Unprotected Header. | + +**Returns:** this + +___ + +### setUnprotectedHeader + +▸ **setUnprotectedHeader**(`unprotectedHeader`: [JWEHeaderParameters](../interfaces/_types_d_.jweheaderparameters.md)): this + +*Defined in [src/jwe/flattened/encrypt.ts:131](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L131)* + +Sets the JWE Per-Recipient Unprotected Header on the FlattenedEncrypt object. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`unprotectedHeader` | [JWEHeaderParameters](../interfaces/_types_d_.jweheaderparameters.md) | JWE Per-Recipient Unprotected Header. | + +**Returns:** this diff --git a/docs/classes/_jws_compact_sign_.compactsign.md b/docs/classes/_jws_compact_sign_.compactsign.md new file mode 100644 index 0000000000..158237c8ef --- /dev/null +++ b/docs/classes/_jws_compact_sign_.compactsign.md @@ -0,0 +1,100 @@ +# Class: CompactSign + +The CompactSign class is a utility for creating Compact JWS strings. + +**`example`** +```js +// ESM import +import CompactSign from 'jose/jws/compact/sign' +``` + +**`example`** +```js +// CJS import +const { default: CompactSign } = require('jose/jws/compact/sign') +``` + +**`example`** +```js +// usage +import parseJwk from 'jose/jwk/parse' + +const encoder = new TextEncoder() +const privateKey = await parseJwk({ + alg: 'ES256', + crv: 'P-256', + kty: 'EC', + d: 'VhsfgSRKcvHCGpLyygMbO_YpXc7bVKwi12KQTE4yOR4', + x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', + y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' +}) + +const jws = await new CompactSign(encoder.encode('It’s a dangerous business, Frodo, going out your door.')) + .setProtectedHeader({ alg: 'ES256' }) + .sign(privateKey) + +console.log(jws) +``` + +## Index + +### Constructors + +* [constructor](_jws_compact_sign_.compactsign.md#constructor) + +### Methods + +* [setProtectedHeader](_jws_compact_sign_.compactsign.md#setprotectedheader) +* [sign](_jws_compact_sign_.compactsign.md#sign) + +## Constructors + +### constructor + +\+ **new CompactSign**(`payload`: Uint8Array): [CompactSign](_jws_compact_sign_.compactsign.md) + +*Defined in [src/jws/compact/sign.ts:44](https://github.com/panva/jose/blob/v3.x/src/jws/compact/sign.ts#L44)* + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`payload` | Uint8Array | Binary representation of the payload to sign. | + +**Returns:** [CompactSign](_jws_compact_sign_.compactsign.md) + +## Methods + +### setProtectedHeader + +▸ **setProtectedHeader**(`protectedHeader`: [JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md)): this + +*Defined in [src/jws/compact/sign.ts:58](https://github.com/panva/jose/blob/v3.x/src/jws/compact/sign.ts#L58)* + +Sets the JWS Protected Header on the Sign object. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`protectedHeader` | [JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md) | JWS Protected Header. | + +**Returns:** this + +___ + +### sign + +▸ **sign**(`key`: [KeyLike](../types/_types_d_.keylike.md)): Promise\ + +*Defined in [src/jws/compact/sign.ts:68](https://github.com/panva/jose/blob/v3.x/src/jws/compact/sign.ts#L68)* + +Signs and resolves the value of the Compact JWS string. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`key` | [KeyLike](../types/_types_d_.keylike.md) | Private Key or Secret to sign the JWS with. | + +**Returns:** Promise\ diff --git a/docs/classes/_jws_flattened_sign_.flattenedsign.md b/docs/classes/_jws_flattened_sign_.flattenedsign.md new file mode 100644 index 0000000000..d6f984ca1c --- /dev/null +++ b/docs/classes/_jws_flattened_sign_.flattenedsign.md @@ -0,0 +1,118 @@ +# Class: FlattenedSign + +The FlattenedSign class is a utility for creating Flattened JWS objects. + +**`example`** +```js +// ESM import +import FlattenedSign from 'jose/jws/flattened/sign' +``` + +**`example`** +```js +// CJS import +const { default: FlattenedSign } = require('jose/jws/flattened/sign') +``` + +**`example`** +```js +// usage +import parseJwk from 'jose/jwk/parse' + +const encoder = new TextEncoder() +const privateKey = await parseJwk({ + alg: 'ES256', + crv: 'P-256', + kty: 'EC', + d: 'VhsfgSRKcvHCGpLyygMbO_YpXc7bVKwi12KQTE4yOR4', + x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', + y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' +}) + +const jws = await new FlattenedSign(encoder.encode('It’s a dangerous business, Frodo, going out your door.')) + .setProtectedHeader({ alg: 'ES256' }) + .sign(privateKey) +console.log(jws) +``` + +## Index + +### Constructors + +* [constructor](_jws_flattened_sign_.flattenedsign.md#constructor) + +### Methods + +* [setProtectedHeader](_jws_flattened_sign_.flattenedsign.md#setprotectedheader) +* [setUnprotectedHeader](_jws_flattened_sign_.flattenedsign.md#setunprotectedheader) +* [sign](_jws_flattened_sign_.flattenedsign.md#sign) + +## Constructors + +### constructor + +\+ **new FlattenedSign**(`payload`: Uint8Array): [FlattenedSign](_jws_flattened_sign_.flattenedsign.md) + +*Defined in [src/jws/flattened/sign.ts:56](https://github.com/panva/jose/blob/v3.x/src/jws/flattened/sign.ts#L56)* + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`payload` | Uint8Array | Binary representation of the payload to sign. | + +**Returns:** [FlattenedSign](_jws_flattened_sign_.flattenedsign.md) + +## Methods + +### setProtectedHeader + +▸ **setProtectedHeader**(`protectedHeader`: [JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md)): this + +*Defined in [src/jws/flattened/sign.ts:70](https://github.com/panva/jose/blob/v3.x/src/jws/flattened/sign.ts#L70)* + +Sets the JWS Protected Header on the FlattenedSign object. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`protectedHeader` | [JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md) | JWS Protected Header. | + +**Returns:** this + +___ + +### setUnprotectedHeader + +▸ **setUnprotectedHeader**(`unprotectedHeader`: [JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md)): this + +*Defined in [src/jws/flattened/sign.ts:83](https://github.com/panva/jose/blob/v3.x/src/jws/flattened/sign.ts#L83)* + +Sets the JWS Unprotected Header on the FlattenedSign object. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`unprotectedHeader` | [JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md) | JWS Unprotected Header. | + +**Returns:** this + +___ + +### sign + +▸ **sign**(`key`: [KeyLike](../types/_types_d_.keylike.md)): Promise\<[FlattenedJWS](../interfaces/_types_d_.flattenedjws.md)> + +*Defined in [src/jws/flattened/sign.ts:96](https://github.com/panva/jose/blob/v3.x/src/jws/flattened/sign.ts#L96)* + +Signs and resolves the value of the Flattened JWS object. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`key` | [KeyLike](../types/_types_d_.keylike.md) | Private Key or Secret to sign the JWS with. | + +**Returns:** Promise\<[FlattenedJWS](../interfaces/_types_d_.flattenedjws.md)> diff --git a/docs/classes/_jwt_encrypt_.encryptjwt.md b/docs/classes/_jwt_encrypt_.encryptjwt.md new file mode 100644 index 0000000000..fd9e9e8efd --- /dev/null +++ b/docs/classes/_jwt_encrypt_.encryptjwt.md @@ -0,0 +1,340 @@ +# Class: EncryptJWT + +The EncryptJWT class is a utility for creating Compact JWE formatted JWT strings. + +**`example`** +```js +// ESM import +import EncryptJWT from 'jose/jwt/encrypt' +``` + +**`example`** +```js +// CJS import +const { default: EncryptJWT } = require('jose/jwt/encrypt') +``` + +**`example`** +```js +// usage +const secretKey = Uint8Array.from([ + 206, 203, 53, 165, 235, 214, 153, 188, + 248, 225, 1, 132, 105, 204, 75, 42, + 186, 185, 24, 223, 136, 66, 116, 59, + 183, 155, 52, 52, 101, 167, 201, 85 +]) +const jwt = await new EncryptJWT({ 'urn:example:claim': true }) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' }) + .setIssuedAt() + .setIssuer('urn:example:issuer') + .setAudience('urn:example:audience') + .setExpirationTime('2h') + .encrypt(secretKey) + +console.log(jwt) +``` + +## Index + +### Constructors + +* [constructor](_jwt_encrypt_.encryptjwt.md#constructor) + +### Methods + +* [encrypt](_jwt_encrypt_.encryptjwt.md#encrypt) +* [replicateAudienceAsHeader](_jwt_encrypt_.encryptjwt.md#replicateaudienceasheader) +* [replicateIssuerAsHeader](_jwt_encrypt_.encryptjwt.md#replicateissuerasheader) +* [replicateSubjectAsHeader](_jwt_encrypt_.encryptjwt.md#replicatesubjectasheader) +* [setAudience](_jwt_encrypt_.encryptjwt.md#setaudience) +* [setContentEncryptionKey](_jwt_encrypt_.encryptjwt.md#setcontentencryptionkey) +* [setExpirationTime](_jwt_encrypt_.encryptjwt.md#setexpirationtime) +* [setInitializationVector](_jwt_encrypt_.encryptjwt.md#setinitializationvector) +* [setIssuedAt](_jwt_encrypt_.encryptjwt.md#setissuedat) +* [setIssuer](_jwt_encrypt_.encryptjwt.md#setissuer) +* [setJti](_jwt_encrypt_.encryptjwt.md#setjti) +* [setKeyManagementParameters](_jwt_encrypt_.encryptjwt.md#setkeymanagementparameters) +* [setNotBefore](_jwt_encrypt_.encryptjwt.md#setnotbefore) +* [setProtectedHeader](_jwt_encrypt_.encryptjwt.md#setprotectedheader) +* [setSubject](_jwt_encrypt_.encryptjwt.md#setsubject) + +## Constructors + +### constructor + +\+ **new EncryptJWT**(`payload`: [JWTPayload](../interfaces/_types_d_.jwtpayload.md)): [EncryptJWT](_jwt_encrypt_.encryptjwt.md) + +*Defined in [src/lib/jwt_producer.ts:10](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L10)* + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`payload` | [JWTPayload](../interfaces/_types_d_.jwtpayload.md) | The JWT Claims Set object. | + +**Returns:** [EncryptJWT](_jwt_encrypt_.encryptjwt.md) + +## Methods + +### encrypt + +▸ **encrypt**(`key`: [KeyLike](../types/_types_d_.keylike.md), `options?`: [EncryptOptions](../interfaces/_types_d_.encryptoptions.md)): Promise\ + +*Defined in [src/jwt/encrypt.ts:160](https://github.com/panva/jose/blob/v3.x/src/jwt/encrypt.ts#L160)* + +Encrypts and returns the JWT. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`key` | [KeyLike](../types/_types_d_.keylike.md) | Public Key or Secret to encrypt the JWT with. | +`options?` | [EncryptOptions](../interfaces/_types_d_.encryptoptions.md) | JWE Encryption options. | + +**Returns:** Promise\ + +___ + +### replicateAudienceAsHeader + +▸ **replicateAudienceAsHeader**(): this + +*Defined in [src/jwt/encrypt.ts:149](https://github.com/panva/jose/blob/v3.x/src/jwt/encrypt.ts#L149)* + +Replicates the "aud" (Audience) Claim as a JWE Protected Header Parameter as per +[RFC7519#section-5.3](https://tools.ietf.org/html/rfc7519#section-5.3). + +**Returns:** this + +___ + +### replicateIssuerAsHeader + +▸ **replicateIssuerAsHeader**(): this + +*Defined in [src/jwt/encrypt.ts:131](https://github.com/panva/jose/blob/v3.x/src/jwt/encrypt.ts#L131)* + +Replicates the "iss" (Issuer) Claim as a JWE Protected Header Parameter as per +[RFC7519#section-5.3](https://tools.ietf.org/html/rfc7519#section-5.3). + +**Returns:** this + +___ + +### replicateSubjectAsHeader + +▸ **replicateSubjectAsHeader**(): this + +*Defined in [src/jwt/encrypt.ts:140](https://github.com/panva/jose/blob/v3.x/src/jwt/encrypt.ts#L140)* + +Replicates the "sub" (Subject) Claim as a JWE Protected Header Parameter as per +[RFC7519#section-5.3](https://tools.ietf.org/html/rfc7519#section-5.3). + +**Returns:** this + +___ + +### setAudience + +▸ **setAudience**(`audience`: string \| string[]): this + +*Defined in [src/lib/jwt_producer.ts:47](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L47)* + +Set "aud" (Audience) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`audience` | string \| string[] | "aud" (Audience) Claim value to set on the JWT Claims Set. | + +**Returns:** this + +___ + +### setContentEncryptionKey + +▸ **setContentEncryptionKey**(`cek`: Uint8Array): this + +*Defined in [src/jwt/encrypt.ts:103](https://github.com/panva/jose/blob/v3.x/src/jwt/encrypt.ts#L103)* + +Sets a content encryption key to use, by default a random suitable one +is generated for the JWE enc" (Encryption Algorithm) Header Parameter. +You do not need to invoke this method, it is only really intended for +test and vector validation purposes. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`cek` | Uint8Array | JWE Content Encryption Key. | + +**Returns:** this + +___ + +### setExpirationTime + +▸ **setExpirationTime**(`input`: number \| string): this + +*Defined in [src/lib/jwt_producer.ts:85](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L85)* + +Set "exp" (Expiration Time) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`input` | number \| string | "exp" (Expiration Time) Claim value to set on the JWT Claims Set. When number is passed that is used as a value, when string is passed it is resolved to a time span and added to the current timestamp. | + +**Returns:** this + +___ + +### setInitializationVector + +▸ **setInitializationVector**(`iv`: Uint8Array): this + +*Defined in [src/jwt/encrypt.ts:119](https://github.com/panva/jose/blob/v3.x/src/jwt/encrypt.ts#L119)* + +Sets the JWE Initialization Vector to use for content encryption, by default +a random suitable one is generated for the JWE enc" (Encryption Algorithm) +Header Parameter. You do not need to invoke this method, it is only really +intended for test and vector validation purposes. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`iv` | Uint8Array | JWE Initialization Vector. | + +**Returns:** this + +___ + +### setIssuedAt + +▸ **setIssuedAt**(`input?`: number): this + +*Defined in [src/lib/jwt_producer.ts:100](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L100)* + +Set "iat" (Issued At) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`input?` | number | "iat" (Issued At) Claim value to set on the JWT Claims Set. Default is current timestamp. | + +**Returns:** this + +___ + +### setIssuer + +▸ **setIssuer**(`issuer`: string): this + +*Defined in [src/lib/jwt_producer.ts:27](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L27)* + +Set "iss" (Issuer) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`issuer` | string | "Issuer" Claim value to set on the JWT Claims Set. | + +**Returns:** this + +___ + +### setJti + +▸ **setJti**(`jwtId`: string): this + +*Defined in [src/lib/jwt_producer.ts:57](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L57)* + +Set "jti" (JWT ID) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`jwtId` | string | "jti" (JWT ID) Claim value to set on the JWT Claims Set. | + +**Returns:** this + +___ + +### setKeyManagementParameters + +▸ **setKeyManagementParameters**(`parameters`: [JWEKeyManagementHeaderParameters](../interfaces/_types_d_.jwekeymanagementheaderparameters.md)): this + +*Defined in [src/jwt/encrypt.ts:87](https://github.com/panva/jose/blob/v3.x/src/jwt/encrypt.ts#L87)* + +Sets the JWE Key Management parameters to be used when encrypting. +Use of this is method is really only needed for ECDH-ES based algorithms +when utilizing the Agreement PartyUInfo or Agreement PartyVInfo parameters. +Other parameters will always be randomly generated when needed and missing. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`parameters` | [JWEKeyManagementHeaderParameters](../interfaces/_types_d_.jwekeymanagementheaderparameters.md) | JWE Key Management parameters. | + +**Returns:** this + +___ + +### setNotBefore + +▸ **setNotBefore**(`input`: number \| string): this + +*Defined in [src/lib/jwt_producer.ts:69](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L69)* + +Set "nbf" (Not Before) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`input` | number \| string | "nbf" (Not Before) Claim value to set on the JWT Claims Set. When number is passed that is used as a value, when string is passed it is resolved to a time span and added to the current timestamp. | + +**Returns:** this + +___ + +### setProtectedHeader + +▸ **setProtectedHeader**(`protectedHeader`: [JWEHeaderParameters](../interfaces/_types_d_.jweheaderparameters.md)): this + +*Defined in [src/jwt/encrypt.ts:71](https://github.com/panva/jose/blob/v3.x/src/jwt/encrypt.ts#L71)* + +Sets the JWE Protected Header on the EncryptJWT object. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`protectedHeader` | [JWEHeaderParameters](../interfaces/_types_d_.jweheaderparameters.md) | JWE Protected Header. Must contain an "alg" (JWE Algorithm) and "enc" (JWE Encryption Algorithm) properties. | + +**Returns:** this + +___ + +### setSubject + +▸ **setSubject**(`subject`: string): this + +*Defined in [src/lib/jwt_producer.ts:37](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L37)* + +Set "sub" (Subject) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`subject` | string | "sub" (Subject) Claim value to set on the JWT Claims Set. | + +**Returns:** this diff --git a/docs/classes/_jwt_sign_.signjwt.md b/docs/classes/_jwt_sign_.signjwt.md new file mode 100644 index 0000000000..2e02106582 --- /dev/null +++ b/docs/classes/_jwt_sign_.signjwt.md @@ -0,0 +1,236 @@ +# Class: SignJWT + +The SignJWT class is a utility for creating Compact JWS formatted JWT strings. + +**`example`** +```js +// ESM import +import SignJWT from 'jose/jwt/sign' +``` + +**`example`** +```js +// CJS import +const { default: SignJWT } = require('jose/jwt/sign') +``` + +**`example`** +```js +// usage +import parseJwk from 'jose/jwk/parse' + +const privateKey = await parseJwk({ + alg: 'ES256', + crv: 'P-256', + kty: 'EC', + d: 'VhsfgSRKcvHCGpLyygMbO_YpXc7bVKwi12KQTE4yOR4', + x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', + y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' +}) + +const jwt = await new SignJWT({ 'urn:example:claim': true }) + .setProtectedHeader({ alg: 'ES256' }) + .setIssuedAt() + .setIssuer('urn:example:issuer') + .setAudience('urn:example:audience') + .setExpirationTime('2h') + .sign(privateKey) + +console.log(jwt) +``` + +## Index + +### Constructors + +* [constructor](_jwt_sign_.signjwt.md#constructor) + +### Methods + +* [setAudience](_jwt_sign_.signjwt.md#setaudience) +* [setExpirationTime](_jwt_sign_.signjwt.md#setexpirationtime) +* [setIssuedAt](_jwt_sign_.signjwt.md#setissuedat) +* [setIssuer](_jwt_sign_.signjwt.md#setissuer) +* [setJti](_jwt_sign_.signjwt.md#setjti) +* [setNotBefore](_jwt_sign_.signjwt.md#setnotbefore) +* [setProtectedHeader](_jwt_sign_.signjwt.md#setprotectedheader) +* [setSubject](_jwt_sign_.signjwt.md#setsubject) +* [sign](_jwt_sign_.signjwt.md#sign) + +## Constructors + +### constructor + +\+ **new SignJWT**(`payload`: [JWTPayload](../interfaces/_types_d_.jwtpayload.md)): [SignJWT](_jwt_sign_.signjwt.md) + +*Defined in [src/lib/jwt_producer.ts:10](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L10)* + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`payload` | [JWTPayload](../interfaces/_types_d_.jwtpayload.md) | The JWT Claims Set object. | + +**Returns:** [SignJWT](_jwt_sign_.signjwt.md) + +## Methods + +### setAudience + +▸ **setAudience**(`audience`: string \| string[]): this + +*Defined in [src/lib/jwt_producer.ts:47](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L47)* + +Set "aud" (Audience) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`audience` | string \| string[] | "aud" (Audience) Claim value to set on the JWT Claims Set. | + +**Returns:** this + +___ + +### setExpirationTime + +▸ **setExpirationTime**(`input`: number \| string): this + +*Defined in [src/lib/jwt_producer.ts:85](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L85)* + +Set "exp" (Expiration Time) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`input` | number \| string | "exp" (Expiration Time) Claim value to set on the JWT Claims Set. When number is passed that is used as a value, when string is passed it is resolved to a time span and added to the current timestamp. | + +**Returns:** this + +___ + +### setIssuedAt + +▸ **setIssuedAt**(`input?`: number): this + +*Defined in [src/lib/jwt_producer.ts:100](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L100)* + +Set "iat" (Issued At) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`input?` | number | "iat" (Issued At) Claim value to set on the JWT Claims Set. Default is current timestamp. | + +**Returns:** this + +___ + +### setIssuer + +▸ **setIssuer**(`issuer`: string): this + +*Defined in [src/lib/jwt_producer.ts:27](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L27)* + +Set "iss" (Issuer) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`issuer` | string | "Issuer" Claim value to set on the JWT Claims Set. | + +**Returns:** this + +___ + +### setJti + +▸ **setJti**(`jwtId`: string): this + +*Defined in [src/lib/jwt_producer.ts:57](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L57)* + +Set "jti" (JWT ID) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`jwtId` | string | "jti" (JWT ID) Claim value to set on the JWT Claims Set. | + +**Returns:** this + +___ + +### setNotBefore + +▸ **setNotBefore**(`input`: number \| string): this + +*Defined in [src/lib/jwt_producer.ts:69](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L69)* + +Set "nbf" (Not Before) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`input` | number \| string | "nbf" (Not Before) Claim value to set on the JWT Claims Set. When number is passed that is used as a value, when string is passed it is resolved to a time span and added to the current timestamp. | + +**Returns:** this + +___ + +### setProtectedHeader + +▸ **setProtectedHeader**(`protectedHeader`: [JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md)): this + +*Defined in [src/jwt/sign.ts:57](https://github.com/panva/jose/blob/v3.x/src/jwt/sign.ts#L57)* + +Sets the JWS Protected Header on the SignJWT object. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`protectedHeader` | [JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md) | JWS Protected Header. | + +**Returns:** this + +___ + +### setSubject + +▸ **setSubject**(`subject`: string): this + +*Defined in [src/lib/jwt_producer.ts:37](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L37)* + +Set "sub" (Subject) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`subject` | string | "sub" (Subject) Claim value to set on the JWT Claims Set. | + +**Returns:** this + +___ + +### sign + +▸ **sign**(`key`: [KeyLike](../types/_types_d_.keylike.md)): Promise\ + +*Defined in [src/jwt/sign.ts:67](https://github.com/panva/jose/blob/v3.x/src/jwt/sign.ts#L67)* + +Signs and returns the JWT. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`key` | [KeyLike](../types/_types_d_.keylike.md) | Private Key or Secret to sign the JWT with. | + +**Returns:** Promise\ diff --git a/docs/classes/_jwt_unsecured_.unsecuredjwt.md b/docs/classes/_jwt_unsecured_.unsecuredjwt.md new file mode 100644 index 0000000000..1b5553a2e3 --- /dev/null +++ b/docs/classes/_jwt_unsecured_.unsecuredjwt.md @@ -0,0 +1,246 @@ +# Class: UnsecuredJWT + +The UnsecuredJWT class is a utility for creating `{ "alg": "none" }` Unsecured JWTs. + +**`example`** +```js +// ESM import +import UnsecuredJWT from 'jose/jwt/unsecured' +``` + +**`example`** +```js +// CJS import +const { default: UnsecuredJWT } = require('jose/jwt/unsecured') +``` + +**`example`** +```js +// encoding + +const unsecuredJwt = new UnsecuredJWT({ 'urn:example:claim': true }) + .setIssuedAt() + .setIssuer('urn:example:issuer') + .setAudience('urn:example:audience') + .setExpirationTime('2h') + .encode() + +console.log(unsecuredJwt) +``` + +**`example`** +```js +// decoding + +const payload = new UnsecuredJWT.decode(jwt, { + issuer: 'urn:example:issuer', + audience: 'urn:example:audience' +}) + +console.log(payload) +``` + +## Index + +### Constructors + +* [constructor](_jwt_unsecured_.unsecuredjwt.md#constructor) + +### Methods + +* [encode](_jwt_unsecured_.unsecuredjwt.md#encode) +* [setAudience](_jwt_unsecured_.unsecuredjwt.md#setaudience) +* [setExpirationTime](_jwt_unsecured_.unsecuredjwt.md#setexpirationtime) +* [setIssuedAt](_jwt_unsecured_.unsecuredjwt.md#setissuedat) +* [setIssuer](_jwt_unsecured_.unsecuredjwt.md#setissuer) +* [setJti](_jwt_unsecured_.unsecuredjwt.md#setjti) +* [setNotBefore](_jwt_unsecured_.unsecuredjwt.md#setnotbefore) +* [setSubject](_jwt_unsecured_.unsecuredjwt.md#setsubject) +* [decode](_jwt_unsecured_.unsecuredjwt.md#decode) + +## Constructors + +### constructor + +\+ **new UnsecuredJWT**(`payload`: [JWTPayload](../interfaces/_types_d_.jwtpayload.md)): [UnsecuredJWT](_jwt_unsecured_.unsecuredjwt.md) + +*Defined in [src/lib/jwt_producer.ts:10](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L10)* + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`payload` | [JWTPayload](../interfaces/_types_d_.jwtpayload.md) | The JWT Claims Set object. | + +**Returns:** [UnsecuredJWT](_jwt_unsecured_.unsecuredjwt.md) + +## Methods + +### encode + +▸ **encode**(): string + +*Defined in [src/jwt/unsecured.ts:55](https://github.com/panva/jose/blob/v3.x/src/jwt/unsecured.ts#L55)* + +Encodes the Unsecured JWT. + +**Returns:** string + +___ + +### setAudience + +▸ **setAudience**(`audience`: string \| string[]): this + +*Defined in [src/lib/jwt_producer.ts:47](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L47)* + +Set "aud" (Audience) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`audience` | string \| string[] | "aud" (Audience) Claim value to set on the JWT Claims Set. | + +**Returns:** this + +___ + +### setExpirationTime + +▸ **setExpirationTime**(`input`: number \| string): this + +*Defined in [src/lib/jwt_producer.ts:85](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L85)* + +Set "exp" (Expiration Time) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`input` | number \| string | "exp" (Expiration Time) Claim value to set on the JWT Claims Set. When number is passed that is used as a value, when string is passed it is resolved to a time span and added to the current timestamp. | + +**Returns:** this + +___ + +### setIssuedAt + +▸ **setIssuedAt**(`input?`: number): this + +*Defined in [src/lib/jwt_producer.ts:100](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L100)* + +Set "iat" (Issued At) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`input?` | number | "iat" (Issued At) Claim value to set on the JWT Claims Set. Default is current timestamp. | + +**Returns:** this + +___ + +### setIssuer + +▸ **setIssuer**(`issuer`: string): this + +*Defined in [src/lib/jwt_producer.ts:27](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L27)* + +Set "iss" (Issuer) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`issuer` | string | "Issuer" Claim value to set on the JWT Claims Set. | + +**Returns:** this + +___ + +### setJti + +▸ **setJti**(`jwtId`: string): this + +*Defined in [src/lib/jwt_producer.ts:57](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L57)* + +Set "jti" (JWT ID) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`jwtId` | string | "jti" (JWT ID) Claim value to set on the JWT Claims Set. | + +**Returns:** this + +___ + +### setNotBefore + +▸ **setNotBefore**(`input`: number \| string): this + +*Defined in [src/lib/jwt_producer.ts:69](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L69)* + +Set "nbf" (Not Before) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`input` | number \| string | "nbf" (Not Before) Claim value to set on the JWT Claims Set. When number is passed that is used as a value, when string is passed it is resolved to a time span and added to the current timestamp. | + +**Returns:** this + +___ + +### setSubject + +▸ **setSubject**(`subject`: string): this + +*Defined in [src/lib/jwt_producer.ts:37](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L37)* + +Set "sub" (Subject) Claim. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`subject` | string | "sub" (Subject) Claim value to set on the JWT Claims Set. | + +**Returns:** this + +___ + +### decode + +▸ `Static`**decode**(`jwt`: string, `options?`: [JWTClaimVerificationOptions](../interfaces/_types_d_.jwtclaimverificationoptions.md)): object + +*Defined in [src/jwt/unsecured.ts:77](https://github.com/panva/jose/blob/v3.x/src/jwt/unsecured.ts#L77)* + +Decodes an unsecured JWT. + +**`example`** +```js +// decoding +const { payload, header } = UnsecuredJWT.decode(unsecuredJwt) + +console.log(header) +console.log(payload) +``` + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`jwt` | string | Unsecured JWT to decode the payload of. | +`options?` | [JWTClaimVerificationOptions](../interfaces/_types_d_.jwtclaimverificationoptions.md) | JWT Claims Set validation options. | + +**Returns:** object + +Name | Type | +------ | ------ | +`header` | [JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md) | +`payload` | [JWTPayload](../interfaces/_types_d_.jwtpayload.md) | diff --git a/docs/classes/_util_errors_.josealgnotallowed.md b/docs/classes/_util_errors_.josealgnotallowed.md new file mode 100644 index 0000000000..338c8b67ee --- /dev/null +++ b/docs/classes/_util_errors_.josealgnotallowed.md @@ -0,0 +1,66 @@ +# Class: JOSEAlgNotAllowed + +An error subclass thrown when a JOSE Algorithm is not allowed per developer preference. + +## Index + +### Constructors + +* [constructor](_util_errors_.josealgnotallowed.md#constructor) + +### Properties + +* [code](_util_errors_.josealgnotallowed.md#code) +* [message](_util_errors_.josealgnotallowed.md#message) +* [name](_util_errors_.josealgnotallowed.md#name) +* [stack](_util_errors_.josealgnotallowed.md#stack) + +## Constructors + +### constructor + +\+ **new JOSEAlgNotAllowed**(`message?`: string): [JOSEAlgNotAllowed](_util_errors_.josealgnotallowed.md) + +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* + +#### Parameters: + +Name | Type | +------ | ------ | +`message?` | string | + +**Returns:** [JOSEAlgNotAllowed](_util_errors_.josealgnotallowed.md) + +## Properties + +### code + +• **code**: string = "ERR\_JOSE\_ALG\_NOT\_ALLOWED" + +*Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* + +*Defined in [src/util/errors.ts:49](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L49)* + +___ + +### message + +• **message**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:974* + +___ + +### name + +• **name**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:973* + +___ + +### stack + +• `Optional` **stack**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:975* diff --git a/docs/classes/_util_errors_.joseerror.md b/docs/classes/_util_errors_.joseerror.md new file mode 100644 index 0000000000..d986cf1df9 --- /dev/null +++ b/docs/classes/_util_errors_.joseerror.md @@ -0,0 +1,76 @@ +# Class: JOSEError + +A generic Error subclass that all other specific +JOSE Error subclasses inherit from. + +## Index + +### Constructors + +* [constructor](_util_errors_.joseerror.md#constructor) + +### Properties + +* [code](_util_errors_.joseerror.md#code) +* [message](_util_errors_.joseerror.md#message) +* [name](_util_errors_.joseerror.md#name) +* [stack](_util_errors_.joseerror.md#stack) +* [Error](_util_errors_.joseerror.md#error) + +## Constructors + +### constructor + +\+ **new JOSEError**(`message?`: string): [JOSEError](_util_errors_.joseerror.md) + +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* + +#### Parameters: + +Name | Type | +------ | ------ | +`message?` | string | + +**Returns:** [JOSEError](_util_errors_.joseerror.md) + +## Properties + +### code + +• **code**: string = "ERR\_JOSE\_GENERIC" + +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* + +A unique error code for the particular error subclass. + +___ + +### message + +• **message**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:974* + +___ + +### name + +• **name**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:973* + +___ + +### stack + +• `Optional` **stack**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:975* + +___ + +### Error + +▪ `Static` **Error**: ErrorConstructor + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:984* diff --git a/docs/classes/_util_errors_.josenotsupported.md b/docs/classes/_util_errors_.josenotsupported.md new file mode 100644 index 0000000000..4d036aa831 --- /dev/null +++ b/docs/classes/_util_errors_.josenotsupported.md @@ -0,0 +1,67 @@ +# Class: JOSENotSupported + +An error subclass thrown when a particular feature or algorithm is not supported by this +implementation or JOSE in general. + +## Index + +### Constructors + +* [constructor](_util_errors_.josenotsupported.md#constructor) + +### Properties + +* [code](_util_errors_.josenotsupported.md#code) +* [message](_util_errors_.josenotsupported.md#message) +* [name](_util_errors_.josenotsupported.md#name) +* [stack](_util_errors_.josenotsupported.md#stack) + +## Constructors + +### constructor + +\+ **new JOSENotSupported**(`message?`: string): [JOSENotSupported](_util_errors_.josenotsupported.md) + +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* + +#### Parameters: + +Name | Type | +------ | ------ | +`message?` | string | + +**Returns:** [JOSENotSupported](_util_errors_.josenotsupported.md) + +## Properties + +### code + +• **code**: string = "ERR\_JOSE\_NOT\_SUPPORTED" + +*Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* + +*Defined in [src/util/errors.ts:57](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L57)* + +___ + +### message + +• **message**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:974* + +___ + +### name + +• **name**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:973* + +___ + +### stack + +• `Optional` **stack**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:975* diff --git a/docs/classes/_util_errors_.jwedecryptionfailed.md b/docs/classes/_util_errors_.jwedecryptionfailed.md new file mode 100644 index 0000000000..4e521a0969 --- /dev/null +++ b/docs/classes/_util_errors_.jwedecryptionfailed.md @@ -0,0 +1,68 @@ +# Class: JWEDecryptionFailed + +An error subclass thrown when a JWE ciphertext decryption fails. + +## Index + +### Constructors + +* [constructor](_util_errors_.jwedecryptionfailed.md#constructor) + +### Properties + +* [code](_util_errors_.jwedecryptionfailed.md#code) +* [message](_util_errors_.jwedecryptionfailed.md#message) +* [name](_util_errors_.jwedecryptionfailed.md#name) +* [stack](_util_errors_.jwedecryptionfailed.md#stack) + +## Constructors + +### constructor + +\+ **new JWEDecryptionFailed**(`message?`: string): [JWEDecryptionFailed](_util_errors_.jwedecryptionfailed.md) + +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* + +#### Parameters: + +Name | Type | +------ | ------ | +`message?` | string | + +**Returns:** [JWEDecryptionFailed](_util_errors_.jwedecryptionfailed.md) + +## Properties + +### code + +• **code**: string = "ERR\_JWE\_DECRYPTION\_FAILED" + +*Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* + +*Defined in [src/util/errors.ts:64](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L64)* + +___ + +### message + +• **message**: string = "decryption operation failed" + +*Overrides [JOSEError](_util_errors_.joseerror.md).[message](_util_errors_.joseerror.md#message)* + +*Defined in [src/util/errors.ts:66](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L66)* + +___ + +### name + +• **name**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:973* + +___ + +### stack + +• `Optional` **stack**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:975* diff --git a/docs/classes/_util_errors_.jweinvalid.md b/docs/classes/_util_errors_.jweinvalid.md new file mode 100644 index 0000000000..00b1564b60 --- /dev/null +++ b/docs/classes/_util_errors_.jweinvalid.md @@ -0,0 +1,66 @@ +# Class: JWEInvalid + +An error subclass thrown when a JWE is invalid. + +## Index + +### Constructors + +* [constructor](_util_errors_.jweinvalid.md#constructor) + +### Properties + +* [code](_util_errors_.jweinvalid.md#code) +* [message](_util_errors_.jweinvalid.md#message) +* [name](_util_errors_.jweinvalid.md#name) +* [stack](_util_errors_.jweinvalid.md#stack) + +## Constructors + +### constructor + +\+ **new JWEInvalid**(`message?`: string): [JWEInvalid](_util_errors_.jweinvalid.md) + +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* + +#### Parameters: + +Name | Type | +------ | ------ | +`message?` | string | + +**Returns:** [JWEInvalid](_util_errors_.jweinvalid.md) + +## Properties + +### code + +• **code**: string = "ERR\_JWE\_INVALID" + +*Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* + +*Defined in [src/util/errors.ts:73](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L73)* + +___ + +### message + +• **message**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:974* + +___ + +### name + +• **name**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:973* + +___ + +### stack + +• `Optional` **stack**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:975* diff --git a/docs/classes/_util_errors_.jwkinvalid.md b/docs/classes/_util_errors_.jwkinvalid.md new file mode 100644 index 0000000000..72e919de84 --- /dev/null +++ b/docs/classes/_util_errors_.jwkinvalid.md @@ -0,0 +1,66 @@ +# Class: JWKInvalid + +An error subclass thrown when a JWK is invalid. + +## Index + +### Constructors + +* [constructor](_util_errors_.jwkinvalid.md#constructor) + +### Properties + +* [code](_util_errors_.jwkinvalid.md#code) +* [message](_util_errors_.jwkinvalid.md#message) +* [name](_util_errors_.jwkinvalid.md#name) +* [stack](_util_errors_.jwkinvalid.md#stack) + +## Constructors + +### constructor + +\+ **new JWKInvalid**(`message?`: string): [JWKInvalid](_util_errors_.jwkinvalid.md) + +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* + +#### Parameters: + +Name | Type | +------ | ------ | +`message?` | string | + +**Returns:** [JWKInvalid](_util_errors_.jwkinvalid.md) + +## Properties + +### code + +• **code**: string = "ERR\_JWK\_INVALID" + +*Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* + +*Defined in [src/util/errors.ts:94](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L94)* + +___ + +### message + +• **message**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:974* + +___ + +### name + +• **name**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:973* + +___ + +### stack + +• `Optional` **stack**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:975* diff --git a/docs/classes/_util_errors_.jwksinvalid.md b/docs/classes/_util_errors_.jwksinvalid.md new file mode 100644 index 0000000000..ab78162a8d --- /dev/null +++ b/docs/classes/_util_errors_.jwksinvalid.md @@ -0,0 +1,66 @@ +# Class: JWKSInvalid + +An error subclass thrown when a JWKS is invalid. + +## Index + +### Constructors + +* [constructor](_util_errors_.jwksinvalid.md#constructor) + +### Properties + +* [code](_util_errors_.jwksinvalid.md#code) +* [message](_util_errors_.jwksinvalid.md#message) +* [name](_util_errors_.jwksinvalid.md#name) +* [stack](_util_errors_.jwksinvalid.md#stack) + +## Constructors + +### constructor + +\+ **new JWKSInvalid**(`message?`: string): [JWKSInvalid](_util_errors_.jwksinvalid.md) + +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* + +#### Parameters: + +Name | Type | +------ | ------ | +`message?` | string | + +**Returns:** [JWKSInvalid](_util_errors_.jwksinvalid.md) + +## Properties + +### code + +• **code**: string = "ERR\_JWKS\_INVALID" + +*Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* + +*Defined in [src/util/errors.ts:101](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L101)* + +___ + +### message + +• **message**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:974* + +___ + +### name + +• **name**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:973* + +___ + +### stack + +• `Optional` **stack**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:975* diff --git a/docs/classes/_util_errors_.jwksmultiplematchingkeys.md b/docs/classes/_util_errors_.jwksmultiplematchingkeys.md new file mode 100644 index 0000000000..e040782d5a --- /dev/null +++ b/docs/classes/_util_errors_.jwksmultiplematchingkeys.md @@ -0,0 +1,68 @@ +# Class: JWKSMultipleMatchingKeys + +An error subclass thrown when multiple keys match from a JWKS. + +## Index + +### Constructors + +* [constructor](_util_errors_.jwksmultiplematchingkeys.md#constructor) + +### Properties + +* [code](_util_errors_.jwksmultiplematchingkeys.md#code) +* [message](_util_errors_.jwksmultiplematchingkeys.md#message) +* [name](_util_errors_.jwksmultiplematchingkeys.md#name) +* [stack](_util_errors_.jwksmultiplematchingkeys.md#stack) + +## Constructors + +### constructor + +\+ **new JWKSMultipleMatchingKeys**(`message?`: string): [JWKSMultipleMatchingKeys](_util_errors_.jwksmultiplematchingkeys.md) + +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* + +#### Parameters: + +Name | Type | +------ | ------ | +`message?` | string | + +**Returns:** [JWKSMultipleMatchingKeys](_util_errors_.jwksmultiplematchingkeys.md) + +## Properties + +### code + +• **code**: string = "ERR\_JWKS\_MULTIPLE\_MATCHING\_KEYS" + +*Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* + +*Defined in [src/util/errors.ts:117](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L117)* + +___ + +### message + +• **message**: string = "multiple matching keys found in the JSON Web Key Set" + +*Overrides [JOSEError](_util_errors_.joseerror.md).[message](_util_errors_.joseerror.md#message)* + +*Defined in [src/util/errors.ts:119](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L119)* + +___ + +### name + +• **name**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:973* + +___ + +### stack + +• `Optional` **stack**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:975* diff --git a/docs/classes/_util_errors_.jwksnomatchingkey.md b/docs/classes/_util_errors_.jwksnomatchingkey.md new file mode 100644 index 0000000000..61eaf2161f --- /dev/null +++ b/docs/classes/_util_errors_.jwksnomatchingkey.md @@ -0,0 +1,68 @@ +# Class: JWKSNoMatchingKey + +An error subclass thrown when no keys match from a JWKS. + +## Index + +### Constructors + +* [constructor](_util_errors_.jwksnomatchingkey.md#constructor) + +### Properties + +* [code](_util_errors_.jwksnomatchingkey.md#code) +* [message](_util_errors_.jwksnomatchingkey.md#message) +* [name](_util_errors_.jwksnomatchingkey.md#name) +* [stack](_util_errors_.jwksnomatchingkey.md#stack) + +## Constructors + +### constructor + +\+ **new JWKSNoMatchingKey**(`message?`: string): [JWKSNoMatchingKey](_util_errors_.jwksnomatchingkey.md) + +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* + +#### Parameters: + +Name | Type | +------ | ------ | +`message?` | string | + +**Returns:** [JWKSNoMatchingKey](_util_errors_.jwksnomatchingkey.md) + +## Properties + +### code + +• **code**: string = "ERR\_JWKS\_NO\_MATCHING\_KEY" + +*Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* + +*Defined in [src/util/errors.ts:108](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L108)* + +___ + +### message + +• **message**: string = "no applicable key found in the JSON Web Key Set" + +*Overrides [JOSEError](_util_errors_.joseerror.md).[message](_util_errors_.joseerror.md#message)* + +*Defined in [src/util/errors.ts:110](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L110)* + +___ + +### name + +• **name**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:973* + +___ + +### stack + +• `Optional` **stack**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:975* diff --git a/docs/classes/_util_errors_.jwsinvalid.md b/docs/classes/_util_errors_.jwsinvalid.md new file mode 100644 index 0000000000..d8425a4913 --- /dev/null +++ b/docs/classes/_util_errors_.jwsinvalid.md @@ -0,0 +1,66 @@ +# Class: JWSInvalid + +An error subclass thrown when a JWS is invalid. + +## Index + +### Constructors + +* [constructor](_util_errors_.jwsinvalid.md#constructor) + +### Properties + +* [code](_util_errors_.jwsinvalid.md#code) +* [message](_util_errors_.jwsinvalid.md#message) +* [name](_util_errors_.jwsinvalid.md#name) +* [stack](_util_errors_.jwsinvalid.md#stack) + +## Constructors + +### constructor + +\+ **new JWSInvalid**(`message?`: string): [JWSInvalid](_util_errors_.jwsinvalid.md) + +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* + +#### Parameters: + +Name | Type | +------ | ------ | +`message?` | string | + +**Returns:** [JWSInvalid](_util_errors_.jwsinvalid.md) + +## Properties + +### code + +• **code**: string = "ERR\_JWS\_INVALID" + +*Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* + +*Defined in [src/util/errors.ts:80](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L80)* + +___ + +### message + +• **message**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:974* + +___ + +### name + +• **name**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:973* + +___ + +### stack + +• `Optional` **stack**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:975* diff --git a/docs/classes/_util_errors_.jwssignatureverificationfailed.md b/docs/classes/_util_errors_.jwssignatureverificationfailed.md new file mode 100644 index 0000000000..ee9af34f4b --- /dev/null +++ b/docs/classes/_util_errors_.jwssignatureverificationfailed.md @@ -0,0 +1,68 @@ +# Class: JWSSignatureVerificationFailed + +An error subclass thrown when JWS signature verification fails. + +## Index + +### Constructors + +* [constructor](_util_errors_.jwssignatureverificationfailed.md#constructor) + +### Properties + +* [code](_util_errors_.jwssignatureverificationfailed.md#code) +* [message](_util_errors_.jwssignatureverificationfailed.md#message) +* [name](_util_errors_.jwssignatureverificationfailed.md#name) +* [stack](_util_errors_.jwssignatureverificationfailed.md#stack) + +## Constructors + +### constructor + +\+ **new JWSSignatureVerificationFailed**(`message?`: string): [JWSSignatureVerificationFailed](_util_errors_.jwssignatureverificationfailed.md) + +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* + +#### Parameters: + +Name | Type | +------ | ------ | +`message?` | string | + +**Returns:** [JWSSignatureVerificationFailed](_util_errors_.jwssignatureverificationfailed.md) + +## Properties + +### code + +• **code**: string = "ERR\_JWS\_SIGNATURE\_VERIFICATION\_FAILED" + +*Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* + +*Defined in [src/util/errors.ts:126](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L126)* + +___ + +### message + +• **message**: string = "signature verification failed" + +*Overrides [JOSEError](_util_errors_.joseerror.md).[message](_util_errors_.joseerror.md#message)* + +*Defined in [src/util/errors.ts:128](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L128)* + +___ + +### name + +• **name**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:973* + +___ + +### stack + +• `Optional` **stack**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:975* diff --git a/docs/classes/_util_errors_.jwtclaimvalidationfailed.md b/docs/classes/_util_errors_.jwtclaimvalidationfailed.md new file mode 100644 index 0000000000..521124b196 --- /dev/null +++ b/docs/classes/_util_errors_.jwtclaimvalidationfailed.md @@ -0,0 +1,92 @@ +# Class: JWTClaimValidationFailed + +An error subclass thrown when a JWT Claim Set member validation fails. + +## Index + +### Constructors + +* [constructor](_util_errors_.jwtclaimvalidationfailed.md#constructor) + +### Properties + +* [claim](_util_errors_.jwtclaimvalidationfailed.md#claim) +* [code](_util_errors_.jwtclaimvalidationfailed.md#code) +* [message](_util_errors_.jwtclaimvalidationfailed.md#message) +* [name](_util_errors_.jwtclaimvalidationfailed.md#name) +* [reason](_util_errors_.jwtclaimvalidationfailed.md#reason) +* [stack](_util_errors_.jwtclaimvalidationfailed.md#stack) + +## Constructors + +### constructor + +\+ **new JWTClaimValidationFailed**(`message`: string, `claim?`: string, `reason?`: string): [JWTClaimValidationFailed](_util_errors_.jwtclaimvalidationfailed.md) + +*Overrides [JOSEError](_util_errors_.joseerror.md).[constructor](_util_errors_.joseerror.md#constructor)* + +*Defined in [src/util/errors.ts:36](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L36)* + +#### Parameters: + +Name | Type | Default value | +------ | ------ | ------ | +`message` | string | - | +`claim` | string | "unspecified" | +`reason` | string | "unspecified" | + +**Returns:** [JWTClaimValidationFailed](_util_errors_.jwtclaimvalidationfailed.md) + +## Properties + +### claim + +• **claim**: string + +*Defined in [src/util/errors.ts:31](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L31)* + +The Claim for which the validation failed. + +___ + +### code + +• **code**: string = "ERR\_JWT\_CLAIM\_VALIDATION\_FAILED" + +*Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* + +*Defined in [src/util/errors.ts:26](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L26)* + +___ + +### message + +• **message**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:974* + +___ + +### name + +• **name**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:973* + +___ + +### reason + +• **reason**: string + +*Defined in [src/util/errors.ts:36](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L36)* + +Reason code for the validation failure. + +___ + +### stack + +• `Optional` **stack**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:975* diff --git a/docs/classes/_util_errors_.jwtexpired.md b/docs/classes/_util_errors_.jwtexpired.md new file mode 100644 index 0000000000..2d95e7ae13 --- /dev/null +++ b/docs/classes/_util_errors_.jwtexpired.md @@ -0,0 +1,92 @@ +# Class: JWTExpired + +An error subclass thrown when a JWT is expired. + +## Index + +### Constructors + +* [constructor](_util_errors_.jwtexpired.md#constructor) + +### Properties + +* [claim](_util_errors_.jwtexpired.md#claim) +* [code](_util_errors_.jwtexpired.md#code) +* [message](_util_errors_.jwtexpired.md#message) +* [name](_util_errors_.jwtexpired.md#name) +* [reason](_util_errors_.jwtexpired.md#reason) +* [stack](_util_errors_.jwtexpired.md#stack) + +## Constructors + +### constructor + +\+ **new JWTExpired**(`message`: string, `claim?`: string, `reason?`: string): [JWTExpired](_util_errors_.jwtexpired.md) + +*Overrides [JOSEError](_util_errors_.joseerror.md).[constructor](_util_errors_.joseerror.md#constructor)* + +*Defined in [src/util/errors.ts:36](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L36)* + +#### Parameters: + +Name | Type | Default value | +------ | ------ | ------ | +`message` | string | - | +`claim` | string | "unspecified" | +`reason` | string | "unspecified" | + +**Returns:** [JWTExpired](_util_errors_.jwtexpired.md) + +## Properties + +### claim + +• **claim**: string + +*Defined in [src/util/errors.ts:31](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L31)* + +The Claim for which the validation failed. + +___ + +### code + +• **code**: string = "ERR\_JWT\_EXPIRED" + +*Overrides [JWTClaimValidationFailed](_util_errors_.jwtclaimvalidationfailed.md).[code](_util_errors_.jwtclaimvalidationfailed.md#code)* + +*Defined in [src/util/errors.ts:135](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L135)* + +___ + +### message + +• **message**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:974* + +___ + +### name + +• **name**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:973* + +___ + +### reason + +• **reason**: string + +*Defined in [src/util/errors.ts:36](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L36)* + +Reason code for the validation failure. + +___ + +### stack + +• `Optional` **stack**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:975* diff --git a/docs/classes/_util_errors_.jwtinvalid.md b/docs/classes/_util_errors_.jwtinvalid.md new file mode 100644 index 0000000000..4eed358b28 --- /dev/null +++ b/docs/classes/_util_errors_.jwtinvalid.md @@ -0,0 +1,66 @@ +# Class: JWTInvalid + +An error subclass thrown when a JWT is invalid. + +## Index + +### Constructors + +* [constructor](_util_errors_.jwtinvalid.md#constructor) + +### Properties + +* [code](_util_errors_.jwtinvalid.md#code) +* [message](_util_errors_.jwtinvalid.md#message) +* [name](_util_errors_.jwtinvalid.md#name) +* [stack](_util_errors_.jwtinvalid.md#stack) + +## Constructors + +### constructor + +\+ **new JWTInvalid**(`message?`: string): [JWTInvalid](_util_errors_.jwtinvalid.md) + +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* + +#### Parameters: + +Name | Type | +------ | ------ | +`message?` | string | + +**Returns:** [JWTInvalid](_util_errors_.jwtinvalid.md) + +## Properties + +### code + +• **code**: string = "ERR\_JWT\_INVALID" + +*Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* + +*Defined in [src/util/errors.ts:87](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L87)* + +___ + +### message + +• **message**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:974* + +___ + +### name + +• **name**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:973* + +___ + +### stack + +• `Optional` **stack**: string + +*Defined in node_modules/typescript/lib/lib.es5.d.ts:975* diff --git a/docs/functions/_jwe_compact_decrypt_.compactdecrypt.md b/docs/functions/_jwe_compact_decrypt_.compactdecrypt.md new file mode 100644 index 0000000000..50573d666e --- /dev/null +++ b/docs/functions/_jwe_compact_decrypt_.compactdecrypt.md @@ -0,0 +1,54 @@ +# Function: compactDecrypt + +▸ **compactDecrypt**(`jwe`: string, `key`: [KeyLike](../types/_types_d_.keylike.md) \| [CompactDecryptGetKey](../interfaces/_jwe_compact_decrypt_.compactdecryptgetkey.md), `options?`: [DecryptOptions](../interfaces/_types_d_.decryptoptions.md)): Promise\<[CompactDecryptResult](../interfaces/_types_d_.compactdecryptresult.md)> + +*Defined in [src/jwe/compact/decrypt.ts:62](https://github.com/panva/jose/blob/v3.x/src/jwe/compact/decrypt.ts#L62)* + +Decrypts a Compact JWE. + +**`example`** +```js +// ESM import +import compactDecrypt from 'jose/jwe/compact/decrypt' +``` + +**`example`** +```js +// CJS import +const { default: compactDecrypt } = require('jose/jwe/compact/decrypt') +``` + +**`example`** +```js +// usage +import parseJwk from 'jose/jwk/parse' + +const decoder = new TextDecoder() +const jwe = 'eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIn0.nyQ19eq9ogh9wA7fFtnI2oouzy5_8b5DeLkoRMfi2yijgfTs2zEnayCEofz_qhnL-nwszabd9qUeHv0-IwvhhJJS7GUJOU3ikiIe42qcIAFme1A_Fo9CTxw4XTOy-I5qanl8So91u6hwfyN1VxAqVLsSE7_23EC-gfGEg_5znew9PyXXsOIE-K_HH7IQowRrlZ1X_bM_Liu53RzDpLDvRz59mp3S8L56YqpM8FexFGTGpEaoTcEIst375qncYt3-79IVR7gZN1RWsWgjPatfvVbnh74PglQcATSf3UUhaW0OAKn6q7r3PDx6DIKQ35bgHQg5QopuN00eIfLQL2trGw.W3grIVj5HVuAb76X.6PcuDe5D6ttWFYyv0oqqdDXfI2R8wBg1F2Q80UUA_Gv8eEimNWfxIWdLxrjzgQGSvIhxmFKuLM0.a93_Ug3uZHuczj70Zavx8Q' +const privateKey = await parseJwk({ + e: 'AQAB', + n: 'qpzYkTGRKSUcd12hZaJnYEKVLfdEsqu6HBAxZgRSvzLFj_zTSAEXjbf3fX47MPEHRw8NDcEXPjVOz84t4FTXYF2w2_LGWfp_myjV8pR6oUUncJjS7DhnUmTG5bpuK2HFXRMRJYz_iNR48xRJPMoY84jrnhdIFx8Tqv6w4ZHVyEvcvloPgwG3UjLidP6jmqbTiJtidVLnpQJRuFNFQJiluQXBZ1nOLC7raQshu7L9y0IatVU7vf0BPnmuSkcNNvmQkSta6ODQBPaL5-o5SW8H37vQjPDkrlJpreViNa3jqP5DB5HYUO-DMh4FegRv9gZWLDEvXpSd9A13YXCa9Q8K_w', + d: 'YAfYfiEAK8CPvUAeUC6RMUVI4o6DRG4UWydiJqHYUXYqbVlJMwYqU8Jws1oRxwJjrkNyfYNpqcInkh_jApm-gKc7nRGRQ6QTnynlAp1ASPW7tUzPq9YzkdTXfwboa9KkXDcXN6OdUU8GpQuODYFTegBfXqSMFzeOwniI5u5G_m2I6YU1zU4x7dxaKhPSK2mJ1v-tJu88j855DYIY0AiX5uf_oa0CgaqyOOY3LaxGjV0FxrkAzYluHfQef7ux-1ocXD1aUrdj3owk48ZVEb2o-V1bMLtk415ngS-u89bABHuJ50-gIwpO-y7ofe6ik4fAd9NfD8PVKHHsrNYbC5FdAQ', + p: '4WlvPw4Vf-mHzoqem_2VUf7hMiLEM5sl_th-CZyA0dowhEnNBJPtaqCz2k_6_ECKZ5C-KoT-EmQOBILQFJtR9SOs6fI9yZGL1OpbjGNKpWzym8iQrFcKAhFvQ_hG7Fkwz6_yRV5fKnOWSD78Rk6wuOTaXqwJS7uljvrn7SmRFpE', + q: 'wcO_PHrkHazbqDgBVvTDaMXJ7W5l0RTxhrOsU6qGCLp367Zc2F9BwPAlMy9KKMhf9RLxgv32lGqWxVh3WQ1GSJqswSIKhfAOzmuTDjlYxqrte_TMcaVDxtRuO8Bxp5A8Y7i3VxQ_Rjfa04QLxJfiRdap4UamYWco25WKH4rkcI8', + dp: 'rWynEIZPeEg-GmSAP1fMqHdG34HsHiBCDV6XKeHlIo-SQFVfjSQax6y4c0CRw74MPj4YcTI9H_0m48WZPiF53vcBtESR0SFPyhI9OTezWK8HwV-AH3gf1ROA3XSJbJH6ge_GoCRJZ6nid9ct1RH52WcJs0j9Je1LJURZaBhQ7mE', + dq: 'tYrMc0ME1dTuHQcUIj_Dkje2gLGtzZ6cyMMw01byq9zhnMRI6yUcu0OE5xcImXtbhIfSJhQCYn4XcyD2-UWZs07QS0e0qlcH2Fkr9-i9B66AQWJT5qqb_P9tpKgjFIbsPdaEWJ8MxaJxcTnHuNNBWoPMuNfz7VC1FD9goTsF23s', + qi: 'qAZmEWhWcDgW_pQZA5e7r185-sOnNPAW53y16QKh5wNThGjpUl7OvePZWY59ekd6PYwvkloNIRki6mLskP9NZ73CsAdZknSAPaAmBuNGYDabtObcigQDPFQ5DeqyAdRUrim66eN7whE5mf_XgOwVAx3-9PtfHvvmTTNezHfoZdo', + kty: 'RSA' +}, 'RSA-OAEP-256') + +const { plaintext, protectedHeader } = await compactDecrypt(jwe, privateKey) + +console.log(protectedHeader) +console.log(decoder.decode(plaintext)) +``` + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`jwe` | string | Compact JWE. | +`key` | [KeyLike](../types/_types_d_.keylike.md) \| [CompactDecryptGetKey](../interfaces/_jwe_compact_decrypt_.compactdecryptgetkey.md) | Private Key or Secret, or a function resolving one, to decrypt the JWE with. | +`options?` | [DecryptOptions](../interfaces/_types_d_.decryptoptions.md) | JWE Decryption options. | + +**Returns:** Promise\<[CompactDecryptResult](../interfaces/_types_d_.compactdecryptresult.md)> diff --git a/docs/functions/_jwe_flattened_decrypt_.flatteneddecrypt.md b/docs/functions/_jwe_flattened_decrypt_.flatteneddecrypt.md new file mode 100644 index 0000000000..38acf834ec --- /dev/null +++ b/docs/functions/_jwe_flattened_decrypt_.flatteneddecrypt.md @@ -0,0 +1,66 @@ +# Function: flattenedDecrypt + +▸ **flattenedDecrypt**(`jwe`: [FlattenedJWE](../interfaces/_types_d_.flattenedjwe.md), `key`: [KeyLike](../types/_types_d_.keylike.md) \| [FlattenedDecryptGetKey](../interfaces/_jwe_flattened_decrypt_.flatteneddecryptgetkey.md), `options?`: [DecryptOptions](../interfaces/_types_d_.decryptoptions.md)): Promise\<[FlattenedDecryptResult](../interfaces/_types_d_.flatteneddecryptresult.md)> + +*Defined in [src/jwe/flattened/decrypt.ts:92](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/decrypt.ts#L92)* + +Decrypts a Flattened JWE. + +**`example`** +```js +// ESM import +import flattenedDecrypt from 'jose/jwe/flattened/decrypt' +``` + +**`example`** +```js +// CJS import +const { default: flattenedDecrypt } = require('jose/jwe/flattened/decrypt') +``` + +**`example`** +```js +// usage +import parseJwk from 'jose/jwk/parse' + +const decoder = new TextDecoder() +const jwe = { + ciphertext: '9EzjFISUyoG-ifC2mSihfP0DPC80yeyrxhTzKt1C_VJBkxeBG0MI4Te61Pk45RAGubUvBpU9jm4', + iv: '8Fy7A_IuoX5VXG9s', + tag: 'W76IYV6arGRuDSaSyWrQNg', + encrypted_key: 'Z6eD4UK_yFb5ZoKvKkGAdqywEG_m0e4IYo0x8Vf30LAMJcsc-_zSgIeiF82teZyYi2YYduHKoqImk7MRnoPZOlEs0Q5BNK1OgBmSOhCE8DFyqh9Zh48TCTP6lmBQ52naqoUJFMtHzu-0LwZH26hxos0GP3Dt19O379MJB837TdKKa87skq0zHaVLAquRHOBF77GI54Bc7O49d8aOrSu1VEFGMThlW2caspPRiTSePDMDPq7_WGk50izRhB3Asl9wmP9wEeaTrkJKRnQj5ips1SAZ1hDBsqEQKKukxP1HtdcopHV5_qgwU8Hjm5EwSLMluMQuiE6hwlkXGOujZLVizA', + aad: 'VGhlIEZlbGxvd3NoaXAgb2YgdGhlIFJpbmc', + protected: 'eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIn0' +} +const privateKey = await parseJwk({ + e: 'AQAB', + n: 'qpzYkTGRKSUcd12hZaJnYEKVLfdEsqu6HBAxZgRSvzLFj_zTSAEXjbf3fX47MPEHRw8NDcEXPjVOz84t4FTXYF2w2_LGWfp_myjV8pR6oUUncJjS7DhnUmTG5bpuK2HFXRMRJYz_iNR48xRJPMoY84jrnhdIFx8Tqv6w4ZHVyEvcvloPgwG3UjLidP6jmqbTiJtidVLnpQJRuFNFQJiluQXBZ1nOLC7raQshu7L9y0IatVU7vf0BPnmuSkcNNvmQkSta6ODQBPaL5-o5SW8H37vQjPDkrlJpreViNa3jqP5DB5HYUO-DMh4FegRv9gZWLDEvXpSd9A13YXCa9Q8K_w', + d: 'YAfYfiEAK8CPvUAeUC6RMUVI4o6DRG4UWydiJqHYUXYqbVlJMwYqU8Jws1oRxwJjrkNyfYNpqcInkh_jApm-gKc7nRGRQ6QTnynlAp1ASPW7tUzPq9YzkdTXfwboa9KkXDcXN6OdUU8GpQuODYFTegBfXqSMFzeOwniI5u5G_m2I6YU1zU4x7dxaKhPSK2mJ1v-tJu88j855DYIY0AiX5uf_oa0CgaqyOOY3LaxGjV0FxrkAzYluHfQef7ux-1ocXD1aUrdj3owk48ZVEb2o-V1bMLtk415ngS-u89bABHuJ50-gIwpO-y7ofe6ik4fAd9NfD8PVKHHsrNYbC5FdAQ', + p: '4WlvPw4Vf-mHzoqem_2VUf7hMiLEM5sl_th-CZyA0dowhEnNBJPtaqCz2k_6_ECKZ5C-KoT-EmQOBILQFJtR9SOs6fI9yZGL1OpbjGNKpWzym8iQrFcKAhFvQ_hG7Fkwz6_yRV5fKnOWSD78Rk6wuOTaXqwJS7uljvrn7SmRFpE', + q: 'wcO_PHrkHazbqDgBVvTDaMXJ7W5l0RTxhrOsU6qGCLp367Zc2F9BwPAlMy9KKMhf9RLxgv32lGqWxVh3WQ1GSJqswSIKhfAOzmuTDjlYxqrte_TMcaVDxtRuO8Bxp5A8Y7i3VxQ_Rjfa04QLxJfiRdap4UamYWco25WKH4rkcI8', + dp: 'rWynEIZPeEg-GmSAP1fMqHdG34HsHiBCDV6XKeHlIo-SQFVfjSQax6y4c0CRw74MPj4YcTI9H_0m48WZPiF53vcBtESR0SFPyhI9OTezWK8HwV-AH3gf1ROA3XSJbJH6ge_GoCRJZ6nid9ct1RH52WcJs0j9Je1LJURZaBhQ7mE', + dq: 'tYrMc0ME1dTuHQcUIj_Dkje2gLGtzZ6cyMMw01byq9zhnMRI6yUcu0OE5xcImXtbhIfSJhQCYn4XcyD2-UWZs07QS0e0qlcH2Fkr9-i9B66AQWJT5qqb_P9tpKgjFIbsPdaEWJ8MxaJxcTnHuNNBWoPMuNfz7VC1FD9goTsF23s', + qi: 'qAZmEWhWcDgW_pQZA5e7r185-sOnNPAW53y16QKh5wNThGjpUl7OvePZWY59ekd6PYwvkloNIRki6mLskP9NZ73CsAdZknSAPaAmBuNGYDabtObcigQDPFQ5DeqyAdRUrim66eN7whE5mf_XgOwVAx3-9PtfHvvmTTNezHfoZdo', + kty: 'RSA' +}, 'RSA-OAEP-256') + +const { + plaintext, + protectedHeader, + additionalAuthenticatedData +} = await flattenedDecrypt(jwe, privateKey) + +console.log(protectedHeader) +console.log(decoder.decode(plaintext)) +console.log(decoder.decode(additionalAuthenticatedData)) +``` + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`jwe` | [FlattenedJWE](../interfaces/_types_d_.flattenedjwe.md) | Flattened JWE. | +`key` | [KeyLike](../types/_types_d_.keylike.md) \| [FlattenedDecryptGetKey](../interfaces/_jwe_flattened_decrypt_.flatteneddecryptgetkey.md) | Public Key or Secret, or a function resolving one, to decrypt the JWE with. | +`options?` | [DecryptOptions](../interfaces/_types_d_.decryptoptions.md) | JWE Decryption options. | + +**Returns:** Promise\<[FlattenedDecryptResult](../interfaces/_types_d_.flatteneddecryptresult.md)> diff --git a/docs/functions/_jwk_embedded_.embeddedjwk.md b/docs/functions/_jwk_embedded_.embeddedjwk.md new file mode 100644 index 0000000000..4fe6d2c45a --- /dev/null +++ b/docs/functions/_jwk_embedded_.embeddedjwk.md @@ -0,0 +1,48 @@ +# Function: EmbeddedJWK + +▸ **EmbeddedJWK**(`protectedHeader`: [JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md), `token`: [FlattenedJWSInput](../interfaces/_types_d_.flattenedjwsinput.md)): Promise\ + +*Defined in [src/jwk/embedded.ts:43](https://github.com/panva/jose/blob/v3.x/src/jwk/embedded.ts#L43)* + +EmbeddedJWK is an implementation of a GetKeyFunction intended to be used with the +JWS/JWT verify operations whenever you need to opt-in to verify signatures with +a public key embedded in the token's "jwk" (JSON Web Key) Header Parameter. +It is recommended to combine this with the verify algorithms option to whitelist +JWS algorithms to accept. + +**`example`** +```js +// ESM import +import EmbeddedJWK from 'jose/jwk/embedded' +``` + +**`example`** +```js +// CJS import +const { default: EmbeddedJWK } = require('jose/jwk/embedded') +``` + +**`example`** +```js +// usage +import jwtVerify from 'jose/jwt/verify' + +const jwt = 'eyJqd2siOnsiY3J2IjoiUC0yNTYiLCJ4IjoiVU05ZzVuS25aWFlvdldBbE03NmNMejl2VG96UmpfX0NIVV9kT2wtZ09vRSIsInkiOiJkczhhZVF3MWwyY0RDQTdiQ2tPTnZ3REtwWEFidFhqdnFDbGVZSDhXc19VIiwia3R5IjoiRUMifSwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJ1cm46ZXhhbXBsZTppc3N1ZXIiLCJhdWQiOiJ1cm46ZXhhbXBsZTphdWRpZW5jZSIsImlhdCI6MTYwNDU4MDc5NH0.60boak3_dErnW47ZPty1C0nrjeVq86EN_eK0GOq6K8w2OA0thKoBxFK4j-NuU9yZ_A9UKGxPT_G87DladBaV9g' + +const { payload, protectedHeader } = await jwtVerify(jwt, EmbeddedJWK, { + issuer: 'urn:example:issuer', + audience: 'urn:example:audience' +}) + +console.log(protectedHeader) +console.log(payload) +``` + +#### Parameters: + +Name | Type | +------ | ------ | +`protectedHeader` | [JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md) | +`token` | [FlattenedJWSInput](../interfaces/_types_d_.flattenedjwsinput.md) | + +**Returns:** Promise\ diff --git a/docs/functions/_jwk_parse_.parsejwk.md b/docs/functions/_jwk_parse_.parsejwk.md new file mode 100644 index 0000000000..08c15b0911 --- /dev/null +++ b/docs/functions/_jwk_parse_.parsejwk.md @@ -0,0 +1,51 @@ +# Function: parseJwk + +▸ **parseJwk**(`jwk`: [JWK](../interfaces/_types_d_.jwk.md), `alg?`: string, `octAsKeyObject?`: false \| true): Promise\<[KeyLike](../types/_types_d_.keylike.md)> + +*Defined in [src/jwk/parse.ts:50](https://github.com/panva/jose/blob/v3.x/src/jwk/parse.ts#L50)* + +Converts a JWK to a runtime-specific key representation. Either JWK "alg" (Algorithm) +Parameter must be present or the optional "alg" argument. When running on a platform +using [Web Cryptography API](https://www.w3.org/TR/WebCryptoAPI/) the jwk parameters +"use", "key_ops", and "ext" are also used in the resulting `CryptoKey`. + +**`example`** +```js +// ESM import +import parseJwk from 'jose/jwk/parse' +``` + +**`example`** +```js +// CJS import +const { default: parseJwk } = require('jose/jwk/parse') +``` + +**`example`** +```js +// usage +const ecPrivateKey = await parseJwk({ + alg: 'ES256', + crv: 'P-256', + kty: 'EC', + d: 'VhsfgSRKcvHCGpLyygMbO_YpXc7bVKwi12KQTE4yOR4', + x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', + y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' +}) + +const rsaPublicKey = await parseJwk({ + kty: 'RSA', + e: 'AQAB', + n: '12oBZRhCiZFJLcPg59LkZZ9mdhSMTKAQZYq32k_ti5SBB6jerkh-WzOMAO664r_qyLkqHUSp3u5SbXtseZEpN3XPWGKSxjsy-1JyEFTdLSYe6f9gfrmxkUF_7DTpq0gn6rntP05g2-wFW50YO7mosfdslfrTJYWHFhJALabAeYirYD7-9kqq9ebfFMF4sRRELbv9oi36As6Q9B3Qb5_C1rAzqfao_PCsf9EPsTZsVVVkA5qoIAr47lo1ipfiBPxUCCNSdvkmDTYgvvRm6ZoMjFbvOtgyts55fXKdMWv7I9HMD5HwE9uW839PWA514qhbcIsXEYSFMPMV6fnlsiZvQQ' +}, 'PS256') +``` + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`jwk` | [JWK](../interfaces/_types_d_.jwk.md) | JSON Web Key. | +`alg?` | string | JSON Web Algorithm identifier to be used with the converted key. Default is the "alg" property on the JWK. | +`octAsKeyObject?` | false \| true | Forces a symmetric key to be converted to a KeyObject or CryptoKey. Default is true unless JWK "ext" (Extractable) is true. | + +**Returns:** Promise\<[KeyLike](../types/_types_d_.keylike.md)> diff --git a/docs/functions/_jwk_thumbprint_.calculatethumbprint.md b/docs/functions/_jwk_thumbprint_.calculatethumbprint.md new file mode 100644 index 0000000000..35b7802272 --- /dev/null +++ b/docs/functions/_jwk_thumbprint_.calculatethumbprint.md @@ -0,0 +1,41 @@ +# Function: calculateThumbprint + +▸ **calculateThumbprint**(`jwk`: [JWK](../interfaces/_types_d_.jwk.md), `digestAlgorithm?`: \"sha256\" \| \"sha384\" \| \"sha512\"): Promise\ + +*Defined in [src/jwk/thumbprint.ts:47](https://github.com/panva/jose/blob/v3.x/src/jwk/thumbprint.ts#L47)* + +Calculates a base64url-encoded JSON Web Key (JWK) Thumbprint as per +[RFC7638](https://tools.ietf.org/html/rfc7638). + +**`example`** +```js +// ESM import +import calculateThumbprint from 'jose/jwk/thumbprint' +``` + +**`example`** +```js +// CJS import +const { default: calculateThumbprint } = require('jose/jwk/thumbprint') +``` + +**`example`** +```js +// usage +const thumbprint = await calculateThumbprint({ + kty: 'RSA', + e: 'AQAB', + n: '12oBZRhCiZFJLcPg59LkZZ9mdhSMTKAQZYq32k_ti5SBB6jerkh-WzOMAO664r_qyLkqHUSp3u5SbXtseZEpN3XPWGKSxjsy-1JyEFTdLSYe6f9gfrmxkUF_7DTpq0gn6rntP05g2-wFW50YO7mosfdslfrTJYWHFhJALabAeYirYD7-9kqq9ebfFMF4sRRELbv9oi36As6Q9B3Qb5_C1rAzqfao_PCsf9EPsTZsVVVkA5qoIAr47lo1ipfiBPxUCCNSdvkmDTYgvvRm6ZoMjFbvOtgyts55fXKdMWv7I9HMD5HwE9uW839PWA514qhbcIsXEYSFMPMV6fnlsiZvQQ' +}) + +console.log(thumbprint) +``` + +#### Parameters: + +Name | Type | Default value | Description | +------ | ------ | ------ | ------ | +`jwk` | [JWK](../interfaces/_types_d_.jwk.md) | - | JSON Web Key. | +`digestAlgorithm` | \"sha256\" \| \"sha384\" \| \"sha512\" | "sha256" | Digest Algorithm to use for calculating the thumbprint. Default is sha256. Accepted is "sha256", "sha384", "sha512". | + +**Returns:** Promise\ diff --git a/docs/functions/_jwks_remote_.createremotejwkset.md b/docs/functions/_jwks_remote_.createremotejwkset.md new file mode 100644 index 0000000000..4deef39a70 --- /dev/null +++ b/docs/functions/_jwks_remote_.createremotejwkset.md @@ -0,0 +1,46 @@ +# Function: createRemoteJWKSet + +▸ **createRemoteJWKSet**(`url`: URL, `options?`: [RemoteJWKSetOptions](../interfaces/_jwks_remote_.remotejwksetoptions.md)): [GetKeyFunction](../interfaces/_types_d_.getkeyfunction.md)\<[JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md), [FlattenedJWSInput](../interfaces/_types_d_.flattenedjwsinput.md)> + +*Defined in [src/jwks/remote.ts:233](https://github.com/panva/jose/blob/v3.x/src/jwks/remote.ts#L233)* + +Returns a function that resolves to a key object downloaded from a +remote endpoint returning a JSON Web Key Set, that is, for example, +an OAuth 2.0 or OIDC jwks_uri. Only a single public key must match +the selection process. + +**`example`** +```js +// ESM import +import createRemoteJWKSet from 'jose/jwks/remote' +``` + +**`example`** +```js +// CJS import +const { default: createRemoteJWKSet } = require('jose/jwks/remote') +``` + +**`example`** +```js +// usage +import jwtVerify from 'jose/jwt/verify' + +const JWKS = createRemoteJWKSet(new URL('https://www.googleapis.com/oauth2/v3/certs')) + +const { payload, protectedHeader } = await jwtVerify(jwt, JWKS, { + issuer: 'urn:example:issuer', + audience: 'urn:example:audience' +}) +console.log(protectedHeader) +console.log(payload) +``` + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`url` | URL | URL to fetch the JSON Web Key Set from. | +`options?` | [RemoteJWKSetOptions](../interfaces/_jwks_remote_.remotejwksetoptions.md) | Options for the remote JSON Web Key Set. | + +**Returns:** [GetKeyFunction](../interfaces/_types_d_.getkeyfunction.md)\<[JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md), [FlattenedJWSInput](../interfaces/_types_d_.flattenedjwsinput.md)> diff --git a/docs/functions/_jws_compact_verify_.compactverify.md b/docs/functions/_jws_compact_verify_.compactverify.md new file mode 100644 index 0000000000..f93b90a837 --- /dev/null +++ b/docs/functions/_jws_compact_verify_.compactverify.md @@ -0,0 +1,50 @@ +# Function: compactVerify + +▸ **compactVerify**(`jws`: string, `key`: [KeyLike](../types/_types_d_.keylike.md) \| [CompactVerifyGetKey](../interfaces/_jws_compact_verify_.compactverifygetkey.md), `options?`: [VerifyOptions](../interfaces/_types_d_.verifyoptions.md)): Promise\<[CompactVerifyResult](../interfaces/_types_d_.compactverifyresult.md)> + +*Defined in [src/jws/compact/verify.ts:59](https://github.com/panva/jose/blob/v3.x/src/jws/compact/verify.ts#L59)* + +Verifies the signature and format of and afterwards decodes the Compact JWS. + +**`example`** +```js +// ESM import +import compactVerify from 'jose/jws/compact/verify' +``` + +**`example`** +```js +// CJS import +const { default: compactVerify } = require('jose/jws/compact/verify') +``` + +**`example`** +```js +// usage +import parseJwk from 'jose/jwk/parse' + +const decoder = new TextDecoder() +const jws = 'eyJhbGciOiJFUzI1NiJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4.kkAs_gPPxWMI3rHuVlxHaTPfDWDoqdI8jSvuSmqV-8IHIWXg9mcAeC9ggV-45ZHRbiRJ3obUIFo1rHphPA5URg' +const publicKey = await parseJwk({ + alg: 'ES256', + crv: 'P-256', + kty: 'EC', + x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', + y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' +}) + +const { payload, protectedHeader } = await compactVerify(jws, publicKey) + +console.log(protectedHeader) +console.log(decoder.decode(payload)) +``` + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`jws` | string | Compact JWS. | +`key` | [KeyLike](../types/_types_d_.keylike.md) \| [CompactVerifyGetKey](../interfaces/_jws_compact_verify_.compactverifygetkey.md) | Key, or a function resolving a key, to verify the JWS with. | +`options?` | [VerifyOptions](../interfaces/_types_d_.verifyoptions.md) | JWS Verify options. | + +**Returns:** Promise\<[CompactVerifyResult](../interfaces/_types_d_.compactverifyresult.md)> diff --git a/docs/functions/_jws_flattened_verify_.flattenedverify.md b/docs/functions/_jws_flattened_verify_.flattenedverify.md new file mode 100644 index 0000000000..c956bc757c --- /dev/null +++ b/docs/functions/_jws_flattened_verify_.flattenedverify.md @@ -0,0 +1,54 @@ +# Function: flattenedVerify + +▸ **flattenedVerify**(`jws`: [FlattenedJWSInput](../interfaces/_types_d_.flattenedjwsinput.md), `key`: [KeyLike](../types/_types_d_.keylike.md) \| [FlattenedVerifyGetKey](../interfaces/_jws_flattened_verify_.flattenedverifygetkey.md), `options?`: [VerifyOptions](../interfaces/_types_d_.verifyoptions.md)): Promise\<[FlattenedVerifyResult](../interfaces/_types_d_.flattenedverifyresult.md)> + +*Defined in [src/jws/flattened/verify.ts:75](https://github.com/panva/jose/blob/v3.x/src/jws/flattened/verify.ts#L75)* + +Verifies the signature and format of and afterwards decodes the Flattened JWS. + +**`example`** +```js +// ESM import +import flattenedVerify from 'jose/jws/flattened/verify' +``` + +**`example`** +```js +// CJS import +const { default: flattenedVerify } = require('jose/jws/flattened/verify') +``` + +**`example`** +```js +// usage +import parseJwk from 'jose/jwk/parse' + +const decoder = new TextDecoder() +const jws = { + signature: 'FVVOXwj6kD3DqdfD9yYqfT2W9jv-Nop4kOehp_DeDGNB5dQNSPRvntBY6xH3uxlCxE8na9d_kyhYOcanpDJ0EA', + payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4', + protected: 'eyJhbGciOiJFUzI1NiJ9' +} +const publicKey = await parseJwk({ + alg: 'ES256', + crv: 'P-256', + kty: 'EC', + x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', + y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' +}) + +const { payload, protectedHeader } = await flattenedVerify(jws, publicKey) + +console.log(protectedHeader) +console.log(decoder.decode(payload)) +``` + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`jws` | [FlattenedJWSInput](../interfaces/_types_d_.flattenedjwsinput.md) | Flattened JWS. | +`key` | [KeyLike](../types/_types_d_.keylike.md) \| [FlattenedVerifyGetKey](../interfaces/_jws_flattened_verify_.flattenedverifygetkey.md) | Key, or a function resolving a key, to verify the JWS with. | +`options?` | [VerifyOptions](../interfaces/_types_d_.verifyoptions.md) | JWS Verify options. | + +**Returns:** Promise\<[FlattenedVerifyResult](../interfaces/_types_d_.flattenedverifyresult.md)> diff --git a/docs/functions/_jwt_decrypt_.jwtdecrypt.md b/docs/functions/_jwt_decrypt_.jwtdecrypt.md new file mode 100644 index 0000000000..8cfe7be4f8 --- /dev/null +++ b/docs/functions/_jwt_decrypt_.jwtdecrypt.md @@ -0,0 +1,49 @@ +# Function: jwtDecrypt + +▸ **jwtDecrypt**(`jwt`: string, `key`: [KeyLike](../types/_types_d_.keylike.md) \| [JWTDecryptGetKey](../interfaces/_jwt_decrypt_.jwtdecryptgetkey.md), `options?`: [JWTDecryptOptions](../interfaces/_jwt_decrypt_.jwtdecryptoptions.md)): Promise\<[JWTDecryptResult](../interfaces/_types_d_.jwtdecryptresult.md)> + +*Defined in [src/jwt/decrypt.ts:65](https://github.com/panva/jose/blob/v3.x/src/jwt/decrypt.ts#L65)* + +Verifies the JWT format (to be a JWE Compact format), decrypts the ciphertext, validates the JWT Claims Set. + +**`example`** +```js +// ESM import +import jwtDecrypt from 'jose/jwt/decrypt' +``` + +**`example`** +```js +// CJS import +const { default: jwtDecrypt } = require('jose/jwt/decrypt') +``` + +**`example`** +```js +// usage +const jwt = 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..KVcNLqK-3-8ZkYIC.xSwF4VxO0kUMUD2W-cifsNUxnr-swyBq-nADBptyt6y9n79-iNc5b0AALJpRwc0wwDkJw8hNOMjApNUTMsK9b-asToZ3DXFMvwfJ6n1aWefvd7RsoZ2LInWFfVAuttJDzoGB.uuexQoWHwrLMEYRElT8pBQ' +const secretKey = Uint8Array.from([ + 206, 203, 53, 165, 235, 214, 153, 188, + 248, 225, 1, 132, 105, 204, 75, 42, + 186, 185, 24, 223, 136, 66, 116, 59, + 183, 155, 52, 52, 101, 167, 201, 85 +]) + +const { payload, protectedHeader } = await jwtDecrypt(jwt, secretKey, { + issuer: 'urn:example:issuer', + audience: 'urn:example:audience' +}) + +console.log(protectedHeader) +console.log(payload) +``` + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`jwt` | string | JSON Web Token value (encoded as JWE). | +`key` | [KeyLike](../types/_types_d_.keylike.md) \| [JWTDecryptGetKey](../interfaces/_jwt_decrypt_.jwtdecryptgetkey.md) | Private Key or Secret, or a function resolving one, to decrypt and verify the JWT with. | +`options?` | [JWTDecryptOptions](../interfaces/_jwt_decrypt_.jwtdecryptoptions.md) | JWT Decryption and JWT Claims Set validation options. | + +**Returns:** Promise\<[JWTDecryptResult](../interfaces/_types_d_.jwtdecryptresult.md)> diff --git a/docs/functions/_jwt_verify_.jwtverify.md b/docs/functions/_jwt_verify_.jwtverify.md new file mode 100644 index 0000000000..6db7d0df08 --- /dev/null +++ b/docs/functions/_jwt_verify_.jwtverify.md @@ -0,0 +1,51 @@ +# Function: jwtVerify + +▸ **jwtVerify**(`jwt`: string, `key`: [KeyLike](../types/_types_d_.keylike.md) \| [JWTVerifyGetKey](../interfaces/_jwt_verify_.jwtverifygetkey.md), `options?`: [JWTVerifyOptions](../interfaces/_jwt_verify_.jwtverifyoptions.md)): Promise\<[JWTVerifyResult](../interfaces/_types_d_.jwtverifyresult.md)> + +*Defined in [src/jwt/verify.ts:66](https://github.com/panva/jose/blob/v3.x/src/jwt/verify.ts#L66)* + +Verifies the JWT format (to be a JWS Compact format), verifies the JWS signature, validates the JWT Claims Set. + +**`example`** +```js +// ESM import +import jwtVerify from 'jose/jwt/verify' +``` + +**`example`** +```js +// CJS import +const { default: jwtVerify } = require('jose/jwt/verify') +``` + +**`example`** +```js +// usage +import parseJwk from 'jose/jwk/parse' + +const jwt = 'eyJhbGciOiJFUzI1NiJ9.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6dHJ1ZSwiaWF0IjoxNjA0MzE1MDc0LCJpc3MiOiJ1cm46ZXhhbXBsZTppc3N1ZXIiLCJhdWQiOiJ1cm46ZXhhbXBsZTphdWRpZW5jZSJ9.hx1nOfAT5LlXuzu8O-bhjXBGpklWDt2EsHw7-MDn49NrnwvVsstNhEnkW2ddauB7eSikFtUNeumLpFI9CWDBsg' +const publicKey = await parseJwk({ + alg: 'ES256', + crv: 'P-256', + kty: 'EC', + x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', + y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' +}) +const { payload, protectedHeader } = await jwtVerify(jwt, publicKey, { + issuer: 'urn:example:issuer', + audience: 'urn:example:audience' +}) + +console.log(protectedHeader) +console.log(payload) +``` + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`jwt` | string | JSON Web Token value (encoded as JWS). | +`key` | [KeyLike](../types/_types_d_.keylike.md) \| [JWTVerifyGetKey](../interfaces/_jwt_verify_.jwtverifygetkey.md) | Key, or a function resolving a key, to verify the JWT with. | +`options?` | [JWTVerifyOptions](../interfaces/_jwt_verify_.jwtverifyoptions.md) | JWT Decryption and JWT Claims Set validation options. | + +**Returns:** Promise\<[JWTVerifyResult](../interfaces/_types_d_.jwtverifyresult.md)> diff --git a/docs/functions/_util_generate_key_pair_.generatekeypair.md b/docs/functions/_util_generate_key_pair_.generatekeypair.md new file mode 100644 index 0000000000..453fd054c9 --- /dev/null +++ b/docs/functions/_util_generate_key_pair_.generatekeypair.md @@ -0,0 +1,38 @@ +# Function: generateKeyPair + +▸ **generateKeyPair**(`alg`: string, `options?`: [GenerateKeyPairOptions](../interfaces/_util_generate_key_pair_.generatekeypairoptions.md)): Promise\<{ privateKey: CryptoKey \| KeyObject ; publicKey: CryptoKey \| KeyObject }> + +*Defined in [src/util/generate_key_pair.ts:41](https://github.com/panva/jose/blob/v3.x/src/util/generate_key_pair.ts#L41)* + +Generates a private and a public key for a given JWA algorithm identifier. +This can only generate asymmetric key pairs. For symmetric secrets use the +`generateSecret` function. + +**`example`** +```js +// ESM import +import generateKeyPair from 'jose/util/generate_key_pair' +``` + +**`example`** +```js +// CJS import +const { default: generateKeyPair } = require('jose/util/generate_key_pair') +``` + +**`example`** +```js +// usage +const { publicKey, privateKey } = await generateKeyPair('PS256') +console.log(publicKey) +console.log(privateKey) +``` + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`alg` | string | JWA Algorithm Identifier to be used with the generated key pair. | +`options?` | [GenerateKeyPairOptions](../interfaces/_util_generate_key_pair_.generatekeypairoptions.md) | Additional options passed down to the key pair generation. | + +**Returns:** Promise\<{ privateKey: CryptoKey \| KeyObject ; publicKey: CryptoKey \| KeyObject }> diff --git a/docs/functions/_util_generate_secret_.generatesecret.md b/docs/functions/_util_generate_secret_.generatesecret.md new file mode 100644 index 0000000000..36c3b163f3 --- /dev/null +++ b/docs/functions/_util_generate_secret_.generatesecret.md @@ -0,0 +1,34 @@ +# Function: generateSecret + +▸ **generateSecret**(`alg`: string): Promise\<[KeyLike](../types/_types_d_.keylike.md)> + +*Defined in [src/util/generate_secret.ts:28](https://github.com/panva/jose/blob/v3.x/src/util/generate_secret.ts#L28)* + +Generates a symmetric secret key for a given JWA algorithm identifier. + +**`example`** +```js +// ESM import +import generateSecret from 'jose/util/generate_secret' +``` + +**`example`** +```js +// CJS import +const { default: generateSecret } = require('jose/util/generate_secret') +``` + +**`example`** +```js +// usage +const secret = await generateSecret('HS256') +console.log(secret) +``` + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`alg` | string | JWA Algorithm Identifier to be used with the generated secret. | + +**Returns:** Promise\<[KeyLike](../types/_types_d_.keylike.md)> diff --git a/docs/interfaces/_jwe_compact_decrypt_.compactdecryptgetkey.md b/docs/interfaces/_jwe_compact_decrypt_.compactdecryptgetkey.md new file mode 100644 index 0000000000..275f987f3e --- /dev/null +++ b/docs/interfaces/_jwe_compact_decrypt_.compactdecryptgetkey.md @@ -0,0 +1,22 @@ +# Interface: CompactDecryptGetKey + +Interface for Compact JWE Decryption dynamic key resolution. +No token components have been verified at the time of this function call. + +## Callable + +▸ (`protectedHeader`: [JWEHeaderParameters](_types_d_.jweheaderparameters.md), `token`: [FlattenedJWE](_types_d_.flattenedjwe.md)): Promise\<[KeyLike](../types/_types_d_.keylike.md)> + +*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L75)* + +Interface for Compact JWE Decryption dynamic key resolution. +No token components have been verified at the time of this function call. + +#### Parameters: + +Name | Type | +------ | ------ | +`protectedHeader` | [JWEHeaderParameters](_types_d_.jweheaderparameters.md) | +`token` | [FlattenedJWE](_types_d_.flattenedjwe.md) | + +**Returns:** Promise\<[KeyLike](../types/_types_d_.keylike.md)> diff --git a/docs/interfaces/_jwe_flattened_decrypt_.flatteneddecryptgetkey.md b/docs/interfaces/_jwe_flattened_decrypt_.flatteneddecryptgetkey.md new file mode 100644 index 0000000000..ad3ed42128 --- /dev/null +++ b/docs/interfaces/_jwe_flattened_decrypt_.flatteneddecryptgetkey.md @@ -0,0 +1,22 @@ +# Interface: FlattenedDecryptGetKey + +Interface for Flattened JWE Decryption dynamic key resolution. +No token components have been verified at the time of this function call. + +## Callable + +▸ (`protectedHeader`: [JWEHeaderParameters](_types_d_.jweheaderparameters.md) \| undefined, `token`: [FlattenedJWE](_types_d_.flattenedjwe.md)): Promise\<[KeyLike](../types/_types_d_.keylike.md)> + +*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L75)* + +Interface for Flattened JWE Decryption dynamic key resolution. +No token components have been verified at the time of this function call. + +#### Parameters: + +Name | Type | +------ | ------ | +`protectedHeader` | [JWEHeaderParameters](_types_d_.jweheaderparameters.md) \| undefined | +`token` | [FlattenedJWE](_types_d_.flattenedjwe.md) | + +**Returns:** Promise\<[KeyLike](../types/_types_d_.keylike.md)> diff --git a/docs/interfaces/_jwks_remote_.remotejwksetoptions.md b/docs/interfaces/_jwks_remote_.remotejwksetoptions.md new file mode 100644 index 0000000000..332bac5b78 --- /dev/null +++ b/docs/interfaces/_jwks_remote_.remotejwksetoptions.md @@ -0,0 +1,32 @@ +# Interface: RemoteJWKSetOptions + +Options for the remote JSON Web Key Set. + +## Index + +### Properties + +* [cooldownDuration](_jwks_remote_.remotejwksetoptions.md#cooldownduration) +* [timeoutDuration](_jwks_remote_.remotejwksetoptions.md#timeoutduration) + +## Properties + +### cooldownDuration + +• `Optional` **cooldownDuration**: number + +*Defined in [src/jwks/remote.ts:45](https://github.com/panva/jose/blob/v3.x/src/jwks/remote.ts#L45)* + +Duration for which no more HTTP requests will be triggered +after a previous successful fetch. Default is 30000. + +___ + +### timeoutDuration + +• `Optional` **timeoutDuration**: number + +*Defined in [src/jwks/remote.ts:39](https://github.com/panva/jose/blob/v3.x/src/jwks/remote.ts#L39)* + +Timeout for the HTTP request. When reached the request will be +aborted and the verification will fail. Default is 5000. diff --git a/docs/interfaces/_jws_compact_verify_.compactverifygetkey.md b/docs/interfaces/_jws_compact_verify_.compactverifygetkey.md new file mode 100644 index 0000000000..3e88aba16c --- /dev/null +++ b/docs/interfaces/_jws_compact_verify_.compactverifygetkey.md @@ -0,0 +1,22 @@ +# Interface: CompactVerifyGetKey + +Interface for Compact JWS Verification dynamic key resolution. +No token components have been verified at the time of this function call. + +## Callable + +▸ (`protectedHeader`: [JWSHeaderParameters](_types_d_.jwsheaderparameters.md), `token`: [FlattenedJWSInput](_types_d_.flattenedjwsinput.md)): Promise\<[KeyLike](../types/_types_d_.keylike.md)> + +*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L75)* + +Interface for Compact JWS Verification dynamic key resolution. +No token components have been verified at the time of this function call. + +#### Parameters: + +Name | Type | +------ | ------ | +`protectedHeader` | [JWSHeaderParameters](_types_d_.jwsheaderparameters.md) | +`token` | [FlattenedJWSInput](_types_d_.flattenedjwsinput.md) | + +**Returns:** Promise\<[KeyLike](../types/_types_d_.keylike.md)> diff --git a/docs/interfaces/_jws_flattened_verify_.flattenedverifygetkey.md b/docs/interfaces/_jws_flattened_verify_.flattenedverifygetkey.md new file mode 100644 index 0000000000..f087651387 --- /dev/null +++ b/docs/interfaces/_jws_flattened_verify_.flattenedverifygetkey.md @@ -0,0 +1,22 @@ +# Interface: FlattenedVerifyGetKey + +Interface for Flattened JWS Verification dynamic key resolution. +No token components have been verified at the time of this function call. + +## Callable + +▸ (`protectedHeader`: [JWSHeaderParameters](_types_d_.jwsheaderparameters.md) \| undefined, `token`: [FlattenedJWSInput](_types_d_.flattenedjwsinput.md)): Promise\<[KeyLike](../types/_types_d_.keylike.md)> + +*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L75)* + +Interface for Flattened JWS Verification dynamic key resolution. +No token components have been verified at the time of this function call. + +#### Parameters: + +Name | Type | +------ | ------ | +`protectedHeader` | [JWSHeaderParameters](_types_d_.jwsheaderparameters.md) \| undefined | +`token` | [FlattenedJWSInput](_types_d_.flattenedjwsinput.md) | + +**Returns:** Promise\<[KeyLike](../types/_types_d_.keylike.md)> diff --git a/docs/interfaces/_jwt_decrypt_.jwtdecryptgetkey.md b/docs/interfaces/_jwt_decrypt_.jwtdecryptgetkey.md new file mode 100644 index 0000000000..6942667852 --- /dev/null +++ b/docs/interfaces/_jwt_decrypt_.jwtdecryptgetkey.md @@ -0,0 +1,22 @@ +# Interface: JWTDecryptGetKey + +Interface for JWT Decryption dynamic key resolution. +No token components have been verified at the time of this function call. + +## Callable + +▸ (`protectedHeader`: [JWEHeaderParameters](_types_d_.jweheaderparameters.md), `token`: [FlattenedJWE](_types_d_.flattenedjwe.md)): Promise\<[KeyLike](../types/_types_d_.keylike.md)> + +*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L75)* + +Interface for JWT Decryption dynamic key resolution. +No token components have been verified at the time of this function call. + +#### Parameters: + +Name | Type | +------ | ------ | +`protectedHeader` | [JWEHeaderParameters](_types_d_.jweheaderparameters.md) | +`token` | [FlattenedJWE](_types_d_.flattenedjwe.md) | + +**Returns:** Promise\<[KeyLike](../types/_types_d_.keylike.md)> diff --git a/docs/interfaces/_jwt_decrypt_.jwtdecryptoptions.md b/docs/interfaces/_jwt_decrypt_.jwtdecryptoptions.md new file mode 100644 index 0000000000..ebe6546df0 --- /dev/null +++ b/docs/interfaces/_jwt_decrypt_.jwtdecryptoptions.md @@ -0,0 +1,121 @@ +# Interface: JWTDecryptOptions + +Combination of JWE Decryption options and JWT Claims Set verification options. + +## Index + +### Properties + +* [audience](_jwt_decrypt_.jwtdecryptoptions.md#audience) +* [clockTolerance](_jwt_decrypt_.jwtdecryptoptions.md#clocktolerance) +* [contentEncryptionAlgorithms](_jwt_decrypt_.jwtdecryptoptions.md#contentencryptionalgorithms) +* [currentDate](_jwt_decrypt_.jwtdecryptoptions.md#currentdate) +* [inflateRaw](_jwt_decrypt_.jwtdecryptoptions.md#inflateraw) +* [issuer](_jwt_decrypt_.jwtdecryptoptions.md#issuer) +* [keyManagementAlgorithms](_jwt_decrypt_.jwtdecryptoptions.md#keymanagementalgorithms) +* [maxTokenAge](_jwt_decrypt_.jwtdecryptoptions.md#maxtokenage) +* [subject](_jwt_decrypt_.jwtdecryptoptions.md#subject) +* [typ](_jwt_decrypt_.jwtdecryptoptions.md#typ) + +## Properties + +### audience + +• `Optional` **audience**: string \| string[] + +*Defined in [src/types.d.ts:355](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L355)* + +Expected JWT "aud" (Audience) Claim value(s). + +___ + +### clockTolerance + +• `Optional` **clockTolerance**: string \| number + +*Defined in [src/types.d.ts:362](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L362)* + +Expected clock tolerance +- in seconds when number (e.g. 5) +- parsed as seconds when a string (e.g. "5 seconds"). + +___ + +### contentEncryptionAlgorithms + +• `Optional` **contentEncryptionAlgorithms**: string[] + +*Defined in [src/types.d.ts:328](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L328)* + +A list of accepted JWE "enc" (Encryption Algorithm) Header Parameter values. + +___ + +### currentDate + +• `Optional` **currentDate**: Date + +*Defined in [src/types.d.ts:387](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L387)* + +Date to use when comparing NumericDate claims, defaults to `new Date()`. + +___ + +### inflateRaw + +• `Optional` **inflateRaw**: [InflateFunction](_types_d_.inflatefunction.md) + +*Defined in [src/types.d.ts:334](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L334)* + +In a browser runtime you have to provide an implementation for Inflate Raw +when you expect JWEs with compressed plaintext. + +___ + +### issuer + +• `Optional` **issuer**: string \| string[] + +*Defined in [src/types.d.ts:367](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L367)* + +Expected JWT "iss" (Issuer) Claim value(s). + +___ + +### keyManagementAlgorithms + +• `Optional` **keyManagementAlgorithms**: string[] + +*Defined in [src/types.d.ts:323](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L323)* + +A list of accepted JWE "alg" (Algorithm) Header Parameter values. + +___ + +### maxTokenAge + +• `Optional` **maxTokenAge**: string + +*Defined in [src/types.d.ts:372](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L372)* + +Maximum time elapsed (in seconds) from the JWT "iat" (Issued At) Claim value. + +___ + +### subject + +• `Optional` **subject**: string + +*Defined in [src/types.d.ts:377](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L377)* + +Expected JWT "sub" (Subject) Claim value. + +___ + +### typ + +• `Optional` **typ**: string + +*Defined in [src/types.d.ts:382](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L382)* + +Expected JWT "typ" (Type) Header Parameter value. diff --git a/docs/interfaces/_jwt_verify_.jwtverifygetkey.md b/docs/interfaces/_jwt_verify_.jwtverifygetkey.md new file mode 100644 index 0000000000..2c51dbefbd --- /dev/null +++ b/docs/interfaces/_jwt_verify_.jwtverifygetkey.md @@ -0,0 +1,22 @@ +# Interface: JWTVerifyGetKey + +Interface for JWT Verification dynamic key resolution. +No token components have been verified at the time of this function call. + +## Callable + +▸ (`protectedHeader`: [JWSHeaderParameters](_types_d_.jwsheaderparameters.md), `token`: [FlattenedJWSInput](_types_d_.flattenedjwsinput.md)): Promise\<[KeyLike](../types/_types_d_.keylike.md)> + +*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L75)* + +Interface for JWT Verification dynamic key resolution. +No token components have been verified at the time of this function call. + +#### Parameters: + +Name | Type | +------ | ------ | +`protectedHeader` | [JWSHeaderParameters](_types_d_.jwsheaderparameters.md) | +`token` | [FlattenedJWSInput](_types_d_.flattenedjwsinput.md) | + +**Returns:** Promise\<[KeyLike](../types/_types_d_.keylike.md)> diff --git a/docs/interfaces/_jwt_verify_.jwtverifyoptions.md b/docs/interfaces/_jwt_verify_.jwtverifyoptions.md new file mode 100644 index 0000000000..bd36dfcb7c --- /dev/null +++ b/docs/interfaces/_jwt_verify_.jwtverifyoptions.md @@ -0,0 +1,98 @@ +# Interface: JWTVerifyOptions + +Combination of JWS Verification options and JWT Claims Set verification options. + +## Index + +### Properties + +* [algorithms](_jwt_verify_.jwtverifyoptions.md#algorithms) +* [audience](_jwt_verify_.jwtverifyoptions.md#audience) +* [clockTolerance](_jwt_verify_.jwtverifyoptions.md#clocktolerance) +* [currentDate](_jwt_verify_.jwtverifyoptions.md#currentdate) +* [issuer](_jwt_verify_.jwtverifyoptions.md#issuer) +* [maxTokenAge](_jwt_verify_.jwtverifyoptions.md#maxtokenage) +* [subject](_jwt_verify_.jwtverifyoptions.md#subject) +* [typ](_jwt_verify_.jwtverifyoptions.md#typ) + +## Properties + +### algorithms + +• `Optional` **algorithms**: string[] + +*Defined in [src/types.d.ts:397](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L397)* + +A list of accepted JWS "alg" (Algorithm) Header Parameter values. + +___ + +### audience + +• `Optional` **audience**: string \| string[] + +*Defined in [src/types.d.ts:355](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L355)* + +Expected JWT "aud" (Audience) Claim value(s). + +___ + +### clockTolerance + +• `Optional` **clockTolerance**: string \| number + +*Defined in [src/types.d.ts:362](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L362)* + +Expected clock tolerance +- in seconds when number (e.g. 5) +- parsed as seconds when a string (e.g. "5 seconds"). + +___ + +### currentDate + +• `Optional` **currentDate**: Date + +*Defined in [src/types.d.ts:387](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L387)* + +Date to use when comparing NumericDate claims, defaults to `new Date()`. + +___ + +### issuer + +• `Optional` **issuer**: string \| string[] + +*Defined in [src/types.d.ts:367](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L367)* + +Expected JWT "iss" (Issuer) Claim value(s). + +___ + +### maxTokenAge + +• `Optional` **maxTokenAge**: string + +*Defined in [src/types.d.ts:372](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L372)* + +Maximum time elapsed (in seconds) from the JWT "iat" (Issued At) Claim value. + +___ + +### subject + +• `Optional` **subject**: string + +*Defined in [src/types.d.ts:377](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L377)* + +Expected JWT "sub" (Subject) Claim value. + +___ + +### typ + +• `Optional` **typ**: string + +*Defined in [src/types.d.ts:382](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L382)* + +Expected JWT "typ" (Type) Header Parameter value. diff --git a/docs/interfaces/_types_d_.compactdecryptresult.md b/docs/interfaces/_types_d_.compactdecryptresult.md new file mode 100644 index 0000000000..f7d1628e13 --- /dev/null +++ b/docs/interfaces/_types_d_.compactdecryptresult.md @@ -0,0 +1,28 @@ +# Interface: CompactDecryptResult + +## Index + +### Properties + +* [plaintext](_types_d_.compactdecryptresult.md#plaintext) +* [protectedHeader](_types_d_.compactdecryptresult.md#protectedheader) + +## Properties + +### plaintext + +• **plaintext**: Uint8Array + +*Defined in [src/types.d.ts:491](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L491)* + +Plaintext. + +___ + +### protectedHeader + +• **protectedHeader**: [JWEHeaderParameters](_types_d_.jweheaderparameters.md) + +*Defined in [src/types.d.ts:496](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L496)* + +JWE Protected Header. diff --git a/docs/interfaces/_types_d_.compactverifyresult.md b/docs/interfaces/_types_d_.compactverifyresult.md new file mode 100644 index 0000000000..451b82bff3 --- /dev/null +++ b/docs/interfaces/_types_d_.compactverifyresult.md @@ -0,0 +1,28 @@ +# Interface: CompactVerifyResult + +## Index + +### Properties + +* [payload](_types_d_.compactverifyresult.md#payload) +* [protectedHeader](_types_d_.compactverifyresult.md#protectedheader) + +## Properties + +### payload + +• **payload**: Uint8Array + +*Defined in [src/types.d.ts:520](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L520)* + +JWS Payload. + +___ + +### protectedHeader + +• **protectedHeader**: [JWSHeaderParameters](_types_d_.jwsheaderparameters.md) + +*Defined in [src/types.d.ts:525](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L525)* + +JWS Protected Header. diff --git a/docs/interfaces/_types_d_.decryptoptions.md b/docs/interfaces/_types_d_.decryptoptions.md new file mode 100644 index 0000000000..6e7af6a0b8 --- /dev/null +++ b/docs/interfaces/_types_d_.decryptoptions.md @@ -0,0 +1,42 @@ +# Interface: DecryptOptions + +JWE Decryption options. + +## Index + +### Properties + +* [contentEncryptionAlgorithms](_types_d_.decryptoptions.md#contentencryptionalgorithms) +* [inflateRaw](_types_d_.decryptoptions.md#inflateraw) +* [keyManagementAlgorithms](_types_d_.decryptoptions.md#keymanagementalgorithms) + +## Properties + +### contentEncryptionAlgorithms + +• `Optional` **contentEncryptionAlgorithms**: string[] + +*Defined in [src/types.d.ts:328](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L328)* + +A list of accepted JWE "enc" (Encryption Algorithm) Header Parameter values. + +___ + +### inflateRaw + +• `Optional` **inflateRaw**: [InflateFunction](_types_d_.inflatefunction.md) + +*Defined in [src/types.d.ts:334](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L334)* + +In a browser runtime you have to provide an implementation for Inflate Raw +when you expect JWEs with compressed plaintext. + +___ + +### keyManagementAlgorithms + +• `Optional` **keyManagementAlgorithms**: string[] + +*Defined in [src/types.d.ts:323](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L323)* + +A list of accepted JWE "alg" (Algorithm) Header Parameter values. diff --git a/docs/interfaces/_types_d_.deflatefunction.md b/docs/interfaces/_types_d_.deflatefunction.md new file mode 100644 index 0000000000..699468b4f5 --- /dev/null +++ b/docs/interfaces/_types_d_.deflatefunction.md @@ -0,0 +1,19 @@ +# Interface: DeflateFunction + +Deflate Raw implementation, e.g. promisified [zlib.deflateRaw](https://nodejs.org/api/zlib.html#zlib_zlib_deflateraw_buffer_options_callback). + +## Callable + +▸ (`input`: Uint8Array): Promise\ + +*Defined in [src/types.d.ts:449](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L449)* + +Deflate Raw implementation, e.g. promisified [zlib.deflateRaw](https://nodejs.org/api/zlib.html#zlib_zlib_deflateraw_buffer_options_callback). + +#### Parameters: + +Name | Type | +------ | ------ | +`input` | Uint8Array | + +**Returns:** Promise\ diff --git a/docs/interfaces/_types_d_.encryptoptions.md b/docs/interfaces/_types_d_.encryptoptions.md new file mode 100644 index 0000000000..c3d6250c2a --- /dev/null +++ b/docs/interfaces/_types_d_.encryptoptions.md @@ -0,0 +1,20 @@ +# Interface: EncryptOptions + +JWE Encryption options. + +## Index + +### Properties + +* [deflateRaw](_types_d_.encryptoptions.md#deflateraw) + +## Properties + +### deflateRaw + +• `Optional` **deflateRaw**: [DeflateFunction](_types_d_.deflatefunction.md) + +*Defined in [src/types.d.ts:345](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L345)* + +In a browser runtime you have to provide an implementation for Deflate Raw +when you will be producing JWEs with compressed plaintext. diff --git a/docs/interfaces/_types_d_.flatteneddecryptresult.md b/docs/interfaces/_types_d_.flatteneddecryptresult.md new file mode 100644 index 0000000000..c7253c6cb0 --- /dev/null +++ b/docs/interfaces/_types_d_.flatteneddecryptresult.md @@ -0,0 +1,61 @@ +# Interface: FlattenedDecryptResult + +## Index + +### Properties + +* [additionalAuthenticatedData](_types_d_.flatteneddecryptresult.md#additionalauthenticateddata) +* [plaintext](_types_d_.flatteneddecryptresult.md#plaintext) +* [protectedHeader](_types_d_.flatteneddecryptresult.md#protectedheader) +* [sharedUnprotectedHeader](_types_d_.flatteneddecryptresult.md#sharedunprotectedheader) +* [unprotectedHeader](_types_d_.flatteneddecryptresult.md#unprotectedheader) + +## Properties + +### additionalAuthenticatedData + +• `Optional` **additionalAuthenticatedData**: Uint8Array + +*Defined in [src/types.d.ts:464](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L464)* + +JWE AAD. + +___ + +### plaintext + +• **plaintext**: Uint8Array + +*Defined in [src/types.d.ts:469](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L469)* + +Plaintext. + +___ + +### protectedHeader + +• `Optional` **protectedHeader**: [JWEHeaderParameters](_types_d_.jweheaderparameters.md) + +*Defined in [src/types.d.ts:474](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L474)* + +JWE Protected Header. + +___ + +### sharedUnprotectedHeader + +• `Optional` **sharedUnprotectedHeader**: [JWEHeaderParameters](_types_d_.jweheaderparameters.md) + +*Defined in [src/types.d.ts:479](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L479)* + +JWE Shared Unprotected Header. + +___ + +### unprotectedHeader + +• `Optional` **unprotectedHeader**: [JWEHeaderParameters](_types_d_.jweheaderparameters.md) + +*Defined in [src/types.d.ts:484](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L484)* + +JWE Per-Recipient Unprotected Header. diff --git a/docs/interfaces/_types_d_.flattenedjwe.md b/docs/interfaces/_types_d_.flattenedjwe.md new file mode 100644 index 0000000000..a9be78dafd --- /dev/null +++ b/docs/interfaces/_types_d_.flattenedjwe.md @@ -0,0 +1,119 @@ +# Interface: FlattenedJWE + +Flattened JWE definition. + +## Index + +### Properties + +* [aad](_types_d_.flattenedjwe.md#aad) +* [ciphertext](_types_d_.flattenedjwe.md#ciphertext) +* [encrypted\_key](_types_d_.flattenedjwe.md#encrypted_key) +* [header](_types_d_.flattenedjwe.md#header) +* [iv](_types_d_.flattenedjwe.md#iv) +* [protected](_types_d_.flattenedjwe.md#protected) +* [tag](_types_d_.flattenedjwe.md#tag) +* [unprotected](_types_d_.flattenedjwe.md#unprotected) + +## Properties + +### aad + +• `Optional` **aad**: string + +*Defined in [src/types.d.ts:228](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L228)* + +The "aad" member MUST be present and contain the value +BASE64URL(JWE AAD)) when the JWE AAD value is non-empty; +otherwise, it MUST be absent. A JWE AAD value can be included to +supply a base64url-encoded value to be integrity protected but not +encrypted. + +___ + +### ciphertext + +• **ciphertext**: string + +*Defined in [src/types.d.ts:234](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L234)* + +The "ciphertext" member MUST be present and contain the value +BASE64URL(JWE Ciphertext). + +___ + +### encrypted\_key + +• `Optional` **encrypted\_key**: string + +*Defined in [src/types.d.ts:241](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L241)* + +The "encrypted_key" member MUST be present and contain the value +BASE64URL(JWE Encrypted Key) when the JWE Encrypted Key value is +non-empty; otherwise, it MUST be absent. + +___ + +### header + +• `Optional` **header**: [JWEHeaderParameters](_types_d_.jweheaderparameters.md) + +*Defined in [src/types.d.ts:251](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L251)* + +The "header" member MUST be present and contain the value JWE Per- +Recipient Unprotected Header when the JWE Per-Recipient +Unprotected Header value is non-empty; otherwise, it MUST be +absent. This value is represented as an unencoded JSON object, +rather than as a string. These Header Parameter values are not +integrity protected. + +___ + +### iv + +• **iv**: string + +*Defined in [src/types.d.ts:258](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L258)* + +The "iv" member MUST be present and contain the value +BASE64URL(JWE Initialization Vector) when the JWE Initialization +Vector value is non-empty; otherwise, it MUST be absent. + +___ + +### protected + +• `Optional` **protected**: string + +*Defined in [src/types.d.ts:266](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L266)* + +The "protected" member MUST be present and contain the value +BASE64URL(UTF8(JWE Protected Header)) when the JWE Protected +Header value is non-empty; otherwise, it MUST be absent. These +Header Parameter values are integrity protected. + +___ + +### tag + +• **tag**: string + +*Defined in [src/types.d.ts:273](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L273)* + +The "tag" member MUST be present and contain the value +BASE64URL(JWE Authentication Tag) when the JWE Authentication Tag +value is non-empty; otherwise, it MUST be absent. + +___ + +### unprotected + +• `Optional` **unprotected**: [JWEHeaderParameters](_types_d_.jweheaderparameters.md) + +*Defined in [src/types.d.ts:282](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L282)* + +The "unprotected" member MUST be present and contain the value JWE +Shared Unprotected Header when the JWE Shared Unprotected Header +value is non-empty; otherwise, it MUST be absent. This value is +represented as an unencoded JSON object, rather than as a string. +These Header Parameter values are not integrity protected. diff --git a/docs/interfaces/_types_d_.flattenedjws.md b/docs/interfaces/_types_d_.flattenedjws.md new file mode 100644 index 0000000000..efb4222574 --- /dev/null +++ b/docs/interfaces/_types_d_.flattenedjws.md @@ -0,0 +1,28 @@ +# Interface: FlattenedJWS + +Flattened JWS definition. Payload is an optional return property, it +is not returned when JWS Unencoded Payload Option +[RFC7797](https://tools.ietf.org/html/rfc7797) is used. + +## Index + +### Properties + +* [payload](_types_d_.flattenedjws.md#payload) +* [signature](_types_d_.flattenedjws.md#signature) + +## Properties + +### payload + +• `Optional` **payload**: string + +*Defined in [src/types.d.ts:136](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L136)* + +___ + +### signature + +• **signature**: string + +*Defined in [src/types.d.ts:137](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L137)* diff --git a/docs/interfaces/_types_d_.flattenedjwsinput.md b/docs/interfaces/_types_d_.flattenedjwsinput.md new file mode 100644 index 0000000000..5b64d239e6 --- /dev/null +++ b/docs/interfaces/_types_d_.flattenedjwsinput.md @@ -0,0 +1,63 @@ +# Interface: FlattenedJWSInput + +Flattened JWS definition for verify function inputs, allows payload as +Uint8Array for detached signature validation. + +## Index + +### Properties + +* [header](_types_d_.flattenedjwsinput.md#header) +* [payload](_types_d_.flattenedjwsinput.md#payload) +* [protected](_types_d_.flattenedjwsinput.md#protected) +* [signature](_types_d_.flattenedjwsinput.md#signature) + +## Properties + +### header + +• `Optional` **header**: [JWSHeaderParameters](_types_d_.jwsheaderparameters.md) + +*Defined in [src/types.d.ts:106](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L106)* + +The "header" member MUST be present and contain the value JWS +Unprotected Header when the JWS Unprotected Header value is non- +empty; otherwise, it MUST be absent. This value is represented as +an unencoded JSON object, rather than as a string. These Header +Parameter values are not integrity protected. + +___ + +### payload + +• **payload**: string \| Uint8Array + +*Defined in [src/types.d.ts:113](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L113)* + +The "payload" member MUST be present and contain the value +BASE64URL(JWS Payload). When RFC7797 "b64": false is used +the value passed may also be a Uint8Array. + +___ + +### protected + +• `Optional` **protected**: string + +*Defined in [src/types.d.ts:121](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L121)* + +The "protected" member MUST be present and contain the value +BASE64URL(UTF8(JWS Protected Header)) when the JWS Protected +Header value is non-empty; otherwise, it MUST be absent. These +Header Parameter values are integrity protected. + +___ + +### signature + +• **signature**: string + +*Defined in [src/types.d.ts:127](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L127)* + +The "signature" member MUST be present and contain the value +BASE64URL(JWS Signature). diff --git a/docs/interfaces/_types_d_.flattenedverifyresult.md b/docs/interfaces/_types_d_.flattenedverifyresult.md new file mode 100644 index 0000000000..97ed5e1921 --- /dev/null +++ b/docs/interfaces/_types_d_.flattenedverifyresult.md @@ -0,0 +1,39 @@ +# Interface: FlattenedVerifyResult + +## Index + +### Properties + +* [payload](_types_d_.flattenedverifyresult.md#payload) +* [protectedHeader](_types_d_.flattenedverifyresult.md#protectedheader) +* [unprotectedHeader](_types_d_.flattenedverifyresult.md#unprotectedheader) + +## Properties + +### payload + +• **payload**: Uint8Array + +*Defined in [src/types.d.ts:503](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L503)* + +JWS Payload. + +___ + +### protectedHeader + +• `Optional` **protectedHeader**: [JWSHeaderParameters](_types_d_.jwsheaderparameters.md) + +*Defined in [src/types.d.ts:508](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L508)* + +JWS Protected Header. + +___ + +### unprotectedHeader + +• `Optional` **unprotectedHeader**: [JWSHeaderParameters](_types_d_.jwsheaderparameters.md) + +*Defined in [src/types.d.ts:513](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L513)* + +JWS Unprotected Header. diff --git a/docs/interfaces/_types_d_.getkeyfunction.md b/docs/interfaces/_types_d_.getkeyfunction.md new file mode 100644 index 0000000000..8c7dbf8c7f --- /dev/null +++ b/docs/interfaces/_types_d_.getkeyfunction.md @@ -0,0 +1,29 @@ +# Interface: GetKeyFunction\ + +Generic Interface for consuming operations dynamic key resolution. +No token components have been verified at the time of this function call. + +## Type parameters + +Name | +------ | +`T` | +`T2` | + +## Callable + +▸ (`protectedHeader`: T, `token`: T2): Promise\<[KeyLike](../types/_types_d_.keylike.md)> + +*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L75)* + +Generic Interface for consuming operations dynamic key resolution. +No token components have been verified at the time of this function call. + +#### Parameters: + +Name | Type | Description | +------ | ------ | ------ | +`protectedHeader` | T | JWE or JWS Protected Header. | +`token` | T2 | The consumed JWE or JWS token. | + +**Returns:** Promise\<[KeyLike](../types/_types_d_.keylike.md)> diff --git a/docs/interfaces/_types_d_.inflatefunction.md b/docs/interfaces/_types_d_.inflatefunction.md new file mode 100644 index 0000000000..b3d8dfd1ef --- /dev/null +++ b/docs/interfaces/_types_d_.inflatefunction.md @@ -0,0 +1,19 @@ +# Interface: InflateFunction + +Inflate Raw implementation, e.g. promisified [zlib.inflateRaw](https://nodejs.org/api/zlib.html#zlib_zlib_inflateraw_buffer_options_callback). + +## Callable + +▸ (`input`: Uint8Array): Promise\ + +*Defined in [src/types.d.ts:456](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L456)* + +Inflate Raw implementation, e.g. promisified [zlib.inflateRaw](https://nodejs.org/api/zlib.html#zlib_zlib_inflateraw_buffer_options_callback). + +#### Parameters: + +Name | Type | +------ | ------ | +`input` | Uint8Array | + +**Returns:** Promise\ diff --git a/docs/interfaces/_types_d_.joseheaderparameters.md b/docs/interfaces/_types_d_.joseheaderparameters.md new file mode 100644 index 0000000000..0954a9d391 --- /dev/null +++ b/docs/interfaces/_types_d_.joseheaderparameters.md @@ -0,0 +1,83 @@ +# Interface: JoseHeaderParameters + +## Index + +### Properties + +* [cty](_types_d_.joseheaderparameters.md#cty) +* [jwk](_types_d_.joseheaderparameters.md#jwk) +* [kid](_types_d_.joseheaderparameters.md#kid) +* [typ](_types_d_.joseheaderparameters.md#typ) +* [x5c](_types_d_.joseheaderparameters.md#x5c) +* [x5t](_types_d_.joseheaderparameters.md#x5t) +* [x5u](_types_d_.joseheaderparameters.md#x5u) + +## Properties + +### cty + +• `Optional` **cty**: string + +*Defined in [src/types.d.ts:174](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L174)* + +"cty" (Content Type) Header Parameter. + +___ + +### jwk + +• `Optional` **jwk**: Pick\<[JWK](_types_d_.jwk.md), \"kty\" \| \"crv\" \| \"x\" \| \"y\" \| \"e\" \| \"n\"> + +*Defined in [src/types.d.ts:164](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L164)* + +"jwk" (JSON Web Key) Header Parameter. + +___ + +### kid + +• `Optional` **kid**: string + +*Defined in [src/types.d.ts:144](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L144)* + +"kid" (Key ID) Header Parameter. + +___ + +### typ + +• `Optional` **typ**: string + +*Defined in [src/types.d.ts:169](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L169)* + +"typ" (Type) Header Parameter. + +___ + +### x5c + +• `Optional` **x5c**: string[] + +*Defined in [src/types.d.ts:154](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L154)* + +"x5c" (X.509 Certificate Chain) Header Parameter. + +___ + +### x5t + +• `Optional` **x5t**: string + +*Defined in [src/types.d.ts:149](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L149)* + +"x5t" (X.509 Certificate SHA-1 Thumbprint) Header Parameter. + +___ + +### x5u + +• `Optional` **x5u**: string + +*Defined in [src/types.d.ts:159](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L159)* + +"x5u" (X.509 URL) Header Parameter. diff --git a/docs/interfaces/_types_d_.jweheaderparameters.md b/docs/interfaces/_types_d_.jweheaderparameters.md new file mode 100644 index 0000000000..4a0be0c59a --- /dev/null +++ b/docs/interfaces/_types_d_.jweheaderparameters.md @@ -0,0 +1,136 @@ +# Interface: JWEHeaderParameters + +Recognized JWE Header Parameters, any other Header members +may also be present. + +## Indexable + +▪ [propName: string]: any + +Any other JWE Header member. + +## Index + +### Properties + +* [alg](_types_d_.jweheaderparameters.md#alg) +* [crit](_types_d_.jweheaderparameters.md#crit) +* [cty](_types_d_.jweheaderparameters.md#cty) +* [enc](_types_d_.jweheaderparameters.md#enc) +* [jwk](_types_d_.jweheaderparameters.md#jwk) +* [kid](_types_d_.jweheaderparameters.md#kid) +* [typ](_types_d_.jweheaderparameters.md#typ) +* [x5c](_types_d_.jweheaderparameters.md#x5c) +* [x5t](_types_d_.jweheaderparameters.md#x5t) +* [x5u](_types_d_.jweheaderparameters.md#x5u) +* [zip](_types_d_.jweheaderparameters.md#zip) + +## Properties + +### alg + +• `Optional` **alg**: string + +*Defined in [src/types.d.ts:293](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L293)* + +JWE "alg" (Algorithm) Header Parameter. + +___ + +### crit + +• `Optional` **crit**: string[] + +*Defined in [src/types.d.ts:303](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L303)* + +JWE "crit" (Critical) Header Parameter. + +___ + +### cty + +• `Optional` **cty**: string + +*Defined in [src/types.d.ts:174](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L174)* + +"cty" (Content Type) Header Parameter. + +___ + +### enc + +• `Optional` **enc**: string + +*Defined in [src/types.d.ts:298](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L298)* + +JWE "enc" (Encryption Algorithm) Header Parameter. + +___ + +### jwk + +• `Optional` **jwk**: Pick\<[JWK](_types_d_.jwk.md), \"kty\" \| \"crv\" \| \"x\" \| \"y\" \| \"e\" \| \"n\"> + +*Defined in [src/types.d.ts:164](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L164)* + +"jwk" (JSON Web Key) Header Parameter. + +___ + +### kid + +• `Optional` **kid**: string + +*Defined in [src/types.d.ts:144](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L144)* + +"kid" (Key ID) Header Parameter. + +___ + +### typ + +• `Optional` **typ**: string + +*Defined in [src/types.d.ts:169](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L169)* + +"typ" (Type) Header Parameter. + +___ + +### x5c + +• `Optional` **x5c**: string[] + +*Defined in [src/types.d.ts:154](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L154)* + +"x5c" (X.509 Certificate Chain) Header Parameter. + +___ + +### x5t + +• `Optional` **x5t**: string + +*Defined in [src/types.d.ts:149](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L149)* + +"x5t" (X.509 Certificate SHA-1 Thumbprint) Header Parameter. + +___ + +### x5u + +• `Optional` **x5u**: string + +*Defined in [src/types.d.ts:159](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L159)* + +"x5u" (X.509 URL) Header Parameter. + +___ + +### zip + +• `Optional` **zip**: string + +*Defined in [src/types.d.ts:308](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L308)* + +JWE "zip" (Compression Algorithm) Header Parameter. diff --git a/docs/interfaces/_types_d_.jwekeymanagementheaderparameters.md b/docs/interfaces/_types_d_.jwekeymanagementheaderparameters.md new file mode 100644 index 0000000000..2b9c918fee --- /dev/null +++ b/docs/interfaces/_types_d_.jwekeymanagementheaderparameters.md @@ -0,0 +1,62 @@ +# Interface: JWEKeyManagementHeaderParameters + +Recognized JWE Key Management-related Header Parameters. + +## Index + +### Properties + +* [apu](_types_d_.jwekeymanagementheaderparameters.md#apu) +* [apv](_types_d_.jwekeymanagementheaderparameters.md#apv) +* [epk](_types_d_.jwekeymanagementheaderparameters.md#epk) +* [iv](_types_d_.jwekeymanagementheaderparameters.md#iv) +* [p2c](_types_d_.jwekeymanagementheaderparameters.md#p2c) +* [p2s](_types_d_.jwekeymanagementheaderparameters.md#p2s) + +## Properties + +### apu + +• `Optional` **apu**: Uint8Array + +*Defined in [src/types.d.ts:209](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L209)* + +___ + +### apv + +• `Optional` **apv**: Uint8Array + +*Defined in [src/types.d.ts:210](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L210)* + +___ + +### epk + +• `Optional` **epk**: [KeyLike](../types/_types_d_.keylike.md) + +*Defined in [src/types.d.ts:211](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L211)* + +___ + +### iv + +• `Optional` **iv**: Uint8Array + +*Defined in [src/types.d.ts:212](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L212)* + +___ + +### p2c + +• `Optional` **p2c**: number + +*Defined in [src/types.d.ts:213](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L213)* + +___ + +### p2s + +• `Optional` **p2s**: Uint8Array + +*Defined in [src/types.d.ts:214](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L214)* diff --git a/docs/interfaces/_types_d_.jwk.md b/docs/interfaces/_types_d_.jwk.md new file mode 100644 index 0000000000..03654e082f --- /dev/null +++ b/docs/interfaces/_types_d_.jwk.md @@ -0,0 +1,236 @@ +# Interface: JWK + +JSON Web Key ([JWK](https://tools.ietf.org/html/rfc7517)). +"RSA", "EC", "OKP", and "oct" key types are supported. + +## Index + +### Properties + +* [alg](_types_d_.jwk.md#alg) +* [crv](_types_d_.jwk.md#crv) +* [d](_types_d_.jwk.md#d) +* [dp](_types_d_.jwk.md#dp) +* [dq](_types_d_.jwk.md#dq) +* [e](_types_d_.jwk.md#e) +* [ext](_types_d_.jwk.md#ext) +* [k](_types_d_.jwk.md#k) +* [key\_ops](_types_d_.jwk.md#key_ops) +* [kid](_types_d_.jwk.md#kid) +* [kty](_types_d_.jwk.md#kty) +* [n](_types_d_.jwk.md#n) +* [oth](_types_d_.jwk.md#oth) +* [p](_types_d_.jwk.md#p) +* [q](_types_d_.jwk.md#q) +* [qi](_types_d_.jwk.md#qi) +* [use](_types_d_.jwk.md#use) +* [x](_types_d_.jwk.md#x) +* [x5c](_types_d_.jwk.md#x5c) +* [x5t](_types_d_.jwk.md#x5t) +* [x5t#S256](_types_d_.jwk.md#x5t#s256) +* [x5u](_types_d_.jwk.md#x5u) +* [y](_types_d_.jwk.md#y) + +## Properties + +### alg + +• `Optional` **alg**: string + +*Defined in [src/types.d.ts:12](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L12)* + +JWK "alg" (Algorithm) Parameter. + +___ + +### crv + +• `Optional` **crv**: string + +*Defined in [src/types.d.ts:13](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L13)* + +___ + +### d + +• `Optional` **d**: string + +*Defined in [src/types.d.ts:14](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L14)* + +___ + +### dp + +• `Optional` **dp**: string + +*Defined in [src/types.d.ts:15](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L15)* + +___ + +### dq + +• `Optional` **dq**: string + +*Defined in [src/types.d.ts:16](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L16)* + +___ + +### e + +• `Optional` **e**: string + +*Defined in [src/types.d.ts:17](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L17)* + +___ + +### ext + +• `Optional` **ext**: false \| true + +*Defined in [src/types.d.ts:21](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L21)* + +JWK "ext" (Extractable) Parameter. + +___ + +### k + +• `Optional` **k**: string + +*Defined in [src/types.d.ts:22](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L22)* + +___ + +### key\_ops + +• `Optional` **key\_ops**: string[] + +*Defined in [src/types.d.ts:26](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L26)* + +JWK "key_ops" (Key Operations) Parameter. + +___ + +### kid + +• `Optional` **kid**: string + +*Defined in [src/types.d.ts:30](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L30)* + +JWK "kid" (Key ID) Parameter. + +___ + +### kty + +• `Optional` **kty**: string + +*Defined in [src/types.d.ts:34](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L34)* + +JWK "kty" (Key Type) Parameter. + +___ + +### n + +• `Optional` **n**: string + +*Defined in [src/types.d.ts:35](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L35)* + +___ + +### oth + +• `Optional` **oth**: Array\<{ d?: string ; r?: string ; t?: string }> + +*Defined in [src/types.d.ts:36](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L36)* + +___ + +### p + +• `Optional` **p**: string + +*Defined in [src/types.d.ts:41](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L41)* + +___ + +### q + +• `Optional` **q**: string + +*Defined in [src/types.d.ts:42](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L42)* + +___ + +### qi + +• `Optional` **qi**: string + +*Defined in [src/types.d.ts:43](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L43)* + +___ + +### use + +• `Optional` **use**: string + +*Defined in [src/types.d.ts:47](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L47)* + +JWK "use" (Public Key Use) Parameter. + +___ + +### x + +• `Optional` **x**: string + +*Defined in [src/types.d.ts:48](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L48)* + +___ + +### x5c + +• `Optional` **x5c**: string[] + +*Defined in [src/types.d.ts:53](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L53)* + +JWK "x5c" (X.509 Certificate Chain) Parameter. + +___ + +### x5t + +• `Optional` **x5t**: string + +*Defined in [src/types.d.ts:57](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L57)* + +JWK "x5t" (X.509 Certificate SHA-1 Thumbprint) Parameter. + +___ + +### x5t#S256 + +• `Optional` **x5t#S256**: string + +*Defined in [src/types.d.ts:61](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L61)* + +"x5t#S256" (X.509 Certificate SHA-256 Thumbprint) Parameter. + +___ + +### x5u + +• `Optional` **x5u**: string + +*Defined in [src/types.d.ts:65](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L65)* + +JWK "x5u" (X.509 URL) Parameter. + +___ + +### y + +• `Optional` **y**: string + +*Defined in [src/types.d.ts:49](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L49)* diff --git a/docs/interfaces/_types_d_.jwsheaderparameters.md b/docs/interfaces/_types_d_.jwsheaderparameters.md new file mode 100644 index 0000000000..445907b2bb --- /dev/null +++ b/docs/interfaces/_types_d_.jwsheaderparameters.md @@ -0,0 +1,127 @@ +# Interface: JWSHeaderParameters + +Recognized JWS Header Parameters, any other Header Members +may also be present. + +## Indexable + +▪ [propName: string]: any + +Any other JWS Header member. + +## Index + +### Properties + +* [alg](_types_d_.jwsheaderparameters.md#alg) +* [b64](_types_d_.jwsheaderparameters.md#b64) +* [crit](_types_d_.jwsheaderparameters.md#crit) +* [cty](_types_d_.jwsheaderparameters.md#cty) +* [jwk](_types_d_.jwsheaderparameters.md#jwk) +* [kid](_types_d_.jwsheaderparameters.md#kid) +* [typ](_types_d_.jwsheaderparameters.md#typ) +* [x5c](_types_d_.jwsheaderparameters.md#x5c) +* [x5t](_types_d_.jwsheaderparameters.md#x5t) +* [x5u](_types_d_.jwsheaderparameters.md#x5u) + +## Properties + +### alg + +• `Optional` **alg**: string + +*Defined in [src/types.d.ts:185](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L185)* + +JWS "alg" (Algorithm) Header Parameter. + +___ + +### b64 + +• `Optional` **b64**: false \| true + +*Defined in [src/types.d.ts:192](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L192)* + +This JWS Extension Header Parameter modifies the JWS Payload +representation and the JWS Signing Input computation as per +[RFC7797](https://tools.ietf.org/html/rfc7797). + +___ + +### crit + +• `Optional` **crit**: string[] + +*Defined in [src/types.d.ts:197](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L197)* + +JWS "crit" (Critical) Header Parameter. + +___ + +### cty + +• `Optional` **cty**: string + +*Defined in [src/types.d.ts:174](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L174)* + +"cty" (Content Type) Header Parameter. + +___ + +### jwk + +• `Optional` **jwk**: Pick\<[JWK](_types_d_.jwk.md), \"kty\" \| \"crv\" \| \"x\" \| \"y\" \| \"e\" \| \"n\"> + +*Defined in [src/types.d.ts:164](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L164)* + +"jwk" (JSON Web Key) Header Parameter. + +___ + +### kid + +• `Optional` **kid**: string + +*Defined in [src/types.d.ts:144](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L144)* + +"kid" (Key ID) Header Parameter. + +___ + +### typ + +• `Optional` **typ**: string + +*Defined in [src/types.d.ts:169](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L169)* + +"typ" (Type) Header Parameter. + +___ + +### x5c + +• `Optional` **x5c**: string[] + +*Defined in [src/types.d.ts:154](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L154)* + +"x5c" (X.509 Certificate Chain) Header Parameter. + +___ + +### x5t + +• `Optional` **x5t**: string + +*Defined in [src/types.d.ts:149](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L149)* + +"x5t" (X.509 Certificate SHA-1 Thumbprint) Header Parameter. + +___ + +### x5u + +• `Optional` **x5u**: string + +*Defined in [src/types.d.ts:159](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L159)* + +"x5u" (X.509 URL) Header Parameter. diff --git a/docs/interfaces/_types_d_.jwtclaimverificationoptions.md b/docs/interfaces/_types_d_.jwtclaimverificationoptions.md new file mode 100644 index 0000000000..a444cb855e --- /dev/null +++ b/docs/interfaces/_types_d_.jwtclaimverificationoptions.md @@ -0,0 +1,87 @@ +# Interface: JWTClaimVerificationOptions + +JWT Claims Set verification options. + +## Index + +### Properties + +* [audience](_types_d_.jwtclaimverificationoptions.md#audience) +* [clockTolerance](_types_d_.jwtclaimverificationoptions.md#clocktolerance) +* [currentDate](_types_d_.jwtclaimverificationoptions.md#currentdate) +* [issuer](_types_d_.jwtclaimverificationoptions.md#issuer) +* [maxTokenAge](_types_d_.jwtclaimverificationoptions.md#maxtokenage) +* [subject](_types_d_.jwtclaimverificationoptions.md#subject) +* [typ](_types_d_.jwtclaimverificationoptions.md#typ) + +## Properties + +### audience + +• `Optional` **audience**: string \| string[] + +*Defined in [src/types.d.ts:355](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L355)* + +Expected JWT "aud" (Audience) Claim value(s). + +___ + +### clockTolerance + +• `Optional` **clockTolerance**: string \| number + +*Defined in [src/types.d.ts:362](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L362)* + +Expected clock tolerance +- in seconds when number (e.g. 5) +- parsed as seconds when a string (e.g. "5 seconds"). + +___ + +### currentDate + +• `Optional` **currentDate**: Date + +*Defined in [src/types.d.ts:387](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L387)* + +Date to use when comparing NumericDate claims, defaults to `new Date()`. + +___ + +### issuer + +• `Optional` **issuer**: string \| string[] + +*Defined in [src/types.d.ts:367](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L367)* + +Expected JWT "iss" (Issuer) Claim value(s). + +___ + +### maxTokenAge + +• `Optional` **maxTokenAge**: string + +*Defined in [src/types.d.ts:372](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L372)* + +Maximum time elapsed (in seconds) from the JWT "iat" (Issued At) Claim value. + +___ + +### subject + +• `Optional` **subject**: string + +*Defined in [src/types.d.ts:377](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L377)* + +Expected JWT "sub" (Subject) Claim value. + +___ + +### typ + +• `Optional` **typ**: string + +*Defined in [src/types.d.ts:382](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L382)* + +Expected JWT "typ" (Type) Header Parameter value. diff --git a/docs/interfaces/_types_d_.jwtdecryptresult.md b/docs/interfaces/_types_d_.jwtdecryptresult.md new file mode 100644 index 0000000000..76a32095c4 --- /dev/null +++ b/docs/interfaces/_types_d_.jwtdecryptresult.md @@ -0,0 +1,28 @@ +# Interface: JWTDecryptResult + +## Index + +### Properties + +* [payload](_types_d_.jwtdecryptresult.md#payload) +* [protectedHeader](_types_d_.jwtdecryptresult.md#protectedheader) + +## Properties + +### payload + +• **payload**: [JWTPayload](_types_d_.jwtpayload.md) + +*Defined in [src/types.d.ts:544](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L544)* + +JWT Claims Set. + +___ + +### protectedHeader + +• **protectedHeader**: [JWEHeaderParameters](_types_d_.jweheaderparameters.md) + +*Defined in [src/types.d.ts:549](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L549)* + +JWE Protected Header. diff --git a/docs/interfaces/_types_d_.jwtpayload.md b/docs/interfaces/_types_d_.jwtpayload.md new file mode 100644 index 0000000000..06db126500 --- /dev/null +++ b/docs/interfaces/_types_d_.jwtpayload.md @@ -0,0 +1,92 @@ +# Interface: JWTPayload + +Recognized JWT Claims Set members, any other members +may also be present. + +## Indexable + +▪ [propName: string]: any + +Any other JWT Claim Set member. + +## Index + +### Properties + +* [aud](_types_d_.jwtpayload.md#aud) +* [exp](_types_d_.jwtpayload.md#exp) +* [iat](_types_d_.jwtpayload.md#iat) +* [iss](_types_d_.jwtpayload.md#iss) +* [jti](_types_d_.jwtpayload.md#jti) +* [nbf](_types_d_.jwtpayload.md#nbf) +* [sub](_types_d_.jwtpayload.md#sub) + +## Properties + +### aud + +• `Optional` **aud**: string \| string[] + +*Defined in [src/types.d.ts:418](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L418)* + +JWT Audience [RFC7519#section-4.1.3](https://tools.ietf.org/html/rfc7519#section-4.1.3). + +___ + +### exp + +• `Optional` **exp**: number + +*Defined in [src/types.d.ts:433](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L433)* + +JWT Expiration Time - [RFC7519#section-4.1.4](https://tools.ietf.org/html/rfc7519#section-4.1.4). + +___ + +### iat + +• `Optional` **iat**: number + +*Defined in [src/types.d.ts:438](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L438)* + +JWT Issued At - [RFC7519#section-4.1.6](https://tools.ietf.org/html/rfc7519#section-4.1.6). + +___ + +### iss + +• `Optional` **iss**: string + +*Defined in [src/types.d.ts:408](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L408)* + +JWT Issuer - [RFC7519#section-4.1.1](https://tools.ietf.org/html/rfc7519#section-4.1.1). + +___ + +### jti + +• `Optional` **jti**: string + +*Defined in [src/types.d.ts:423](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L423)* + +JWT ID - [RFC7519#section-4.1.7](https://tools.ietf.org/html/rfc7519#section-4.1.7). + +___ + +### nbf + +• `Optional` **nbf**: number + +*Defined in [src/types.d.ts:428](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L428)* + +JWT Not Before - [RFC7519#section-4.1.5](https://tools.ietf.org/html/rfc7519#section-4.1.5). + +___ + +### sub + +• `Optional` **sub**: string + +*Defined in [src/types.d.ts:413](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L413)* + +JWT Subject - [RFC7519#section-4.1.2](https://tools.ietf.org/html/rfc7519#section-4.1.2). diff --git a/docs/interfaces/_types_d_.jwtverifyresult.md b/docs/interfaces/_types_d_.jwtverifyresult.md new file mode 100644 index 0000000000..49bcc90c1d --- /dev/null +++ b/docs/interfaces/_types_d_.jwtverifyresult.md @@ -0,0 +1,28 @@ +# Interface: JWTVerifyResult + +## Index + +### Properties + +* [payload](_types_d_.jwtverifyresult.md#payload) +* [protectedHeader](_types_d_.jwtverifyresult.md#protectedheader) + +## Properties + +### payload + +• **payload**: [JWTPayload](_types_d_.jwtpayload.md) + +*Defined in [src/types.d.ts:532](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L532)* + +JWT Claims Set. + +___ + +### protectedHeader + +• **protectedHeader**: [JWSHeaderParameters](_types_d_.jwsheaderparameters.md) + +*Defined in [src/types.d.ts:537](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L537)* + +JWS Protected Header. diff --git a/docs/interfaces/_types_d_.verifyoptions.md b/docs/interfaces/_types_d_.verifyoptions.md new file mode 100644 index 0000000000..eb55cfb7d4 --- /dev/null +++ b/docs/interfaces/_types_d_.verifyoptions.md @@ -0,0 +1,19 @@ +# Interface: VerifyOptions + +JWS Verification options. + +## Index + +### Properties + +* [algorithms](_types_d_.verifyoptions.md#algorithms) + +## Properties + +### algorithms + +• `Optional` **algorithms**: string[] + +*Defined in [src/types.d.ts:397](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L397)* + +A list of accepted JWS "alg" (Algorithm) Header Parameter values. diff --git a/docs/interfaces/_util_generate_key_pair_.generatekeypairoptions.md b/docs/interfaces/_util_generate_key_pair_.generatekeypairoptions.md new file mode 100644 index 0000000000..c92257bccb --- /dev/null +++ b/docs/interfaces/_util_generate_key_pair_.generatekeypairoptions.md @@ -0,0 +1,19 @@ +# Interface: GenerateKeyPairOptions + +## Index + +### Properties + +* [crv](_util_generate_key_pair_.generatekeypairoptions.md#crv) + +## Properties + +### crv + +• `Optional` **crv**: string + +*Defined in [src/util/generate_key_pair.ts:10](https://github.com/panva/jose/blob/v3.x/src/util/generate_key_pair.ts#L10)* + +The EC "crv" (Curve) or OKP "crv" (Subtype of Key Pair) value to generate. +The curve must be both supported on the runtime as well as applicable for +the given JWA algorithm identifier. diff --git a/docs/modules/_jwe_compact_decrypt_.md b/docs/modules/_jwe_compact_decrypt_.md new file mode 100644 index 0000000000..09dabbd248 --- /dev/null +++ b/docs/modules/_jwe_compact_decrypt_.md @@ -0,0 +1,11 @@ +# Module: "jwe/compact/decrypt" + +## Index + +### Interfaces + +* [CompactDecryptGetKey](../interfaces/_jwe_compact_decrypt_.compactdecryptgetkey.md) + +### Functions + +* [compactDecrypt](../functions/_jwe_compact_decrypt_.compactdecrypt.md) diff --git a/docs/modules/_jwe_compact_encrypt_.md b/docs/modules/_jwe_compact_encrypt_.md new file mode 100644 index 0000000000..eafade761e --- /dev/null +++ b/docs/modules/_jwe_compact_encrypt_.md @@ -0,0 +1,7 @@ +# Module: "jwe/compact/encrypt" + +## Index + +### Classes + +* [CompactEncrypt](../classes/_jwe_compact_encrypt_.compactencrypt.md) diff --git a/docs/modules/_jwe_flattened_decrypt_.md b/docs/modules/_jwe_flattened_decrypt_.md new file mode 100644 index 0000000000..5a3ac8de6c --- /dev/null +++ b/docs/modules/_jwe_flattened_decrypt_.md @@ -0,0 +1,11 @@ +# Module: "jwe/flattened/decrypt" + +## Index + +### Interfaces + +* [FlattenedDecryptGetKey](../interfaces/_jwe_flattened_decrypt_.flatteneddecryptgetkey.md) + +### Functions + +* [flattenedDecrypt](../functions/_jwe_flattened_decrypt_.flatteneddecrypt.md) diff --git a/docs/modules/_jwe_flattened_encrypt_.md b/docs/modules/_jwe_flattened_encrypt_.md new file mode 100644 index 0000000000..50fe926b8e --- /dev/null +++ b/docs/modules/_jwe_flattened_encrypt_.md @@ -0,0 +1,7 @@ +# Module: "jwe/flattened/encrypt" + +## Index + +### Classes + +* [FlattenedEncrypt](../classes/_jwe_flattened_encrypt_.flattenedencrypt.md) diff --git a/docs/modules/_jwk_embedded_.md b/docs/modules/_jwk_embedded_.md new file mode 100644 index 0000000000..7be7b15e62 --- /dev/null +++ b/docs/modules/_jwk_embedded_.md @@ -0,0 +1,7 @@ +# Module: "jwk/embedded" + +## Index + +### Functions + +* [EmbeddedJWK](../functions/_jwk_embedded_.embeddedjwk.md) diff --git a/docs/modules/_jwk_parse_.md b/docs/modules/_jwk_parse_.md new file mode 100644 index 0000000000..508cf9efe7 --- /dev/null +++ b/docs/modules/_jwk_parse_.md @@ -0,0 +1,7 @@ +# Module: "jwk/parse" + +## Index + +### Functions + +* [parseJwk](../functions/_jwk_parse_.parsejwk.md) diff --git a/docs/modules/_jwk_thumbprint_.md b/docs/modules/_jwk_thumbprint_.md new file mode 100644 index 0000000000..dfd2b10a94 --- /dev/null +++ b/docs/modules/_jwk_thumbprint_.md @@ -0,0 +1,7 @@ +# Module: "jwk/thumbprint" + +## Index + +### Functions + +* [calculateThumbprint](../functions/_jwk_thumbprint_.calculatethumbprint.md) diff --git a/docs/modules/_jwks_remote_.md b/docs/modules/_jwks_remote_.md new file mode 100644 index 0000000000..f686c043fd --- /dev/null +++ b/docs/modules/_jwks_remote_.md @@ -0,0 +1,11 @@ +# Module: "jwks/remote" + +## Index + +### Interfaces + +* [RemoteJWKSetOptions](../interfaces/_jwks_remote_.remotejwksetoptions.md) + +### Functions + +* [createRemoteJWKSet](../functions/_jwks_remote_.createremotejwkset.md) diff --git a/docs/modules/_jws_compact_sign_.md b/docs/modules/_jws_compact_sign_.md new file mode 100644 index 0000000000..7dd41d41ea --- /dev/null +++ b/docs/modules/_jws_compact_sign_.md @@ -0,0 +1,7 @@ +# Module: "jws/compact/sign" + +## Index + +### Classes + +* [CompactSign](../classes/_jws_compact_sign_.compactsign.md) diff --git a/docs/modules/_jws_compact_verify_.md b/docs/modules/_jws_compact_verify_.md new file mode 100644 index 0000000000..8ed390f38c --- /dev/null +++ b/docs/modules/_jws_compact_verify_.md @@ -0,0 +1,11 @@ +# Module: "jws/compact/verify" + +## Index + +### Interfaces + +* [CompactVerifyGetKey](../interfaces/_jws_compact_verify_.compactverifygetkey.md) + +### Functions + +* [compactVerify](../functions/_jws_compact_verify_.compactverify.md) diff --git a/docs/modules/_jws_flattened_sign_.md b/docs/modules/_jws_flattened_sign_.md new file mode 100644 index 0000000000..6a17203c8f --- /dev/null +++ b/docs/modules/_jws_flattened_sign_.md @@ -0,0 +1,7 @@ +# Module: "jws/flattened/sign" + +## Index + +### Classes + +* [FlattenedSign](../classes/_jws_flattened_sign_.flattenedsign.md) diff --git a/docs/modules/_jws_flattened_verify_.md b/docs/modules/_jws_flattened_verify_.md new file mode 100644 index 0000000000..6ed0265fbc --- /dev/null +++ b/docs/modules/_jws_flattened_verify_.md @@ -0,0 +1,11 @@ +# Module: "jws/flattened/verify" + +## Index + +### Interfaces + +* [FlattenedVerifyGetKey](../interfaces/_jws_flattened_verify_.flattenedverifygetkey.md) + +### Functions + +* [flattenedVerify](../functions/_jws_flattened_verify_.flattenedverify.md) diff --git a/docs/modules/_jwt_decrypt_.md b/docs/modules/_jwt_decrypt_.md new file mode 100644 index 0000000000..8b4a571f62 --- /dev/null +++ b/docs/modules/_jwt_decrypt_.md @@ -0,0 +1,12 @@ +# Module: "jwt/decrypt" + +## Index + +### Interfaces + +* [JWTDecryptGetKey](../interfaces/_jwt_decrypt_.jwtdecryptgetkey.md) +* [JWTDecryptOptions](../interfaces/_jwt_decrypt_.jwtdecryptoptions.md) + +### Functions + +* [jwtDecrypt](../functions/_jwt_decrypt_.jwtdecrypt.md) diff --git a/docs/modules/_jwt_encrypt_.md b/docs/modules/_jwt_encrypt_.md new file mode 100644 index 0000000000..65bfd74769 --- /dev/null +++ b/docs/modules/_jwt_encrypt_.md @@ -0,0 +1,7 @@ +# Module: "jwt/encrypt" + +## Index + +### Classes + +* [EncryptJWT](../classes/_jwt_encrypt_.encryptjwt.md) diff --git a/docs/modules/_jwt_sign_.md b/docs/modules/_jwt_sign_.md new file mode 100644 index 0000000000..6f0f2b1dd1 --- /dev/null +++ b/docs/modules/_jwt_sign_.md @@ -0,0 +1,7 @@ +# Module: "jwt/sign" + +## Index + +### Classes + +* [SignJWT](../classes/_jwt_sign_.signjwt.md) diff --git a/docs/modules/_jwt_unsecured_.md b/docs/modules/_jwt_unsecured_.md new file mode 100644 index 0000000000..cf4fdb6aa4 --- /dev/null +++ b/docs/modules/_jwt_unsecured_.md @@ -0,0 +1,7 @@ +# Module: "jwt/unsecured" + +## Index + +### Classes + +* [UnsecuredJWT](../classes/_jwt_unsecured_.unsecuredjwt.md) diff --git a/docs/modules/_jwt_verify_.md b/docs/modules/_jwt_verify_.md new file mode 100644 index 0000000000..d7340a5b44 --- /dev/null +++ b/docs/modules/_jwt_verify_.md @@ -0,0 +1,12 @@ +# Module: "jwt/verify" + +## Index + +### Interfaces + +* [JWTVerifyGetKey](../interfaces/_jwt_verify_.jwtverifygetkey.md) +* [JWTVerifyOptions](../interfaces/_jwt_verify_.jwtverifyoptions.md) + +### Functions + +* [jwtVerify](../functions/_jwt_verify_.jwtverify.md) diff --git a/docs/modules/_types_d_.md b/docs/modules/_types_d_.md new file mode 100644 index 0000000000..636d5fad29 --- /dev/null +++ b/docs/modules/_types_d_.md @@ -0,0 +1,32 @@ +# Module: "types.d" + +## Index + +### Interfaces + +* [CompactDecryptResult](../interfaces/_types_d_.compactdecryptresult.md) +* [CompactVerifyResult](../interfaces/_types_d_.compactverifyresult.md) +* [DecryptOptions](../interfaces/_types_d_.decryptoptions.md) +* [DeflateFunction](../interfaces/_types_d_.deflatefunction.md) +* [EncryptOptions](../interfaces/_types_d_.encryptoptions.md) +* [FlattenedDecryptResult](../interfaces/_types_d_.flatteneddecryptresult.md) +* [FlattenedJWE](../interfaces/_types_d_.flattenedjwe.md) +* [FlattenedJWS](../interfaces/_types_d_.flattenedjws.md) +* [FlattenedJWSInput](../interfaces/_types_d_.flattenedjwsinput.md) +* [FlattenedVerifyResult](../interfaces/_types_d_.flattenedverifyresult.md) +* [GetKeyFunction](../interfaces/_types_d_.getkeyfunction.md) +* [InflateFunction](../interfaces/_types_d_.inflatefunction.md) +* [JWEHeaderParameters](../interfaces/_types_d_.jweheaderparameters.md) +* [JWEKeyManagementHeaderParameters](../interfaces/_types_d_.jwekeymanagementheaderparameters.md) +* [JWK](../interfaces/_types_d_.jwk.md) +* [JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md) +* [JWTClaimVerificationOptions](../interfaces/_types_d_.jwtclaimverificationoptions.md) +* [JWTDecryptResult](../interfaces/_types_d_.jwtdecryptresult.md) +* [JWTPayload](../interfaces/_types_d_.jwtpayload.md) +* [JWTVerifyResult](../interfaces/_types_d_.jwtverifyresult.md) +* [JoseHeaderParameters](../interfaces/_types_d_.joseheaderparameters.md) +* [VerifyOptions](../interfaces/_types_d_.verifyoptions.md) + +### Type aliases + +* [KeyLike](../types/_types_d_.keylike.md) diff --git a/docs/modules/_util_base64url_.md b/docs/modules/_util_base64url_.md new file mode 100644 index 0000000000..669cf65026 --- /dev/null +++ b/docs/modules/_util_base64url_.md @@ -0,0 +1 @@ +# Module: "util/base64url" diff --git a/docs/modules/_util_errors_.md b/docs/modules/_util_errors_.md new file mode 100644 index 0000000000..d4712e96c8 --- /dev/null +++ b/docs/modules/_util_errors_.md @@ -0,0 +1,20 @@ +# Module: "util/errors" + +## Index + +### Classes + +* [JOSEAlgNotAllowed](../classes/_util_errors_.josealgnotallowed.md) +* [JOSEError](../classes/_util_errors_.joseerror.md) +* [JOSENotSupported](../classes/_util_errors_.josenotsupported.md) +* [JWEDecryptionFailed](../classes/_util_errors_.jwedecryptionfailed.md) +* [JWEInvalid](../classes/_util_errors_.jweinvalid.md) +* [JWKInvalid](../classes/_util_errors_.jwkinvalid.md) +* [JWKSInvalid](../classes/_util_errors_.jwksinvalid.md) +* [JWKSMultipleMatchingKeys](../classes/_util_errors_.jwksmultiplematchingkeys.md) +* [JWKSNoMatchingKey](../classes/_util_errors_.jwksnomatchingkey.md) +* [JWSInvalid](../classes/_util_errors_.jwsinvalid.md) +* [JWSSignatureVerificationFailed](../classes/_util_errors_.jwssignatureverificationfailed.md) +* [JWTClaimValidationFailed](../classes/_util_errors_.jwtclaimvalidationfailed.md) +* [JWTExpired](../classes/_util_errors_.jwtexpired.md) +* [JWTInvalid](../classes/_util_errors_.jwtinvalid.md) diff --git a/docs/modules/_util_generate_key_pair_.md b/docs/modules/_util_generate_key_pair_.md new file mode 100644 index 0000000000..0a9c163a6b --- /dev/null +++ b/docs/modules/_util_generate_key_pair_.md @@ -0,0 +1,11 @@ +# Module: "util/generate\_key\_pair" + +## Index + +### Interfaces + +* [GenerateKeyPairOptions](../interfaces/_util_generate_key_pair_.generatekeypairoptions.md) + +### Functions + +* [generateKeyPair](../functions/_util_generate_key_pair_.generatekeypair.md) diff --git a/docs/modules/_util_generate_secret_.md b/docs/modules/_util_generate_secret_.md new file mode 100644 index 0000000000..06064dce40 --- /dev/null +++ b/docs/modules/_util_generate_secret_.md @@ -0,0 +1,7 @@ +# Module: "util/generate\_secret" + +## Index + +### Functions + +* [generateSecret](../functions/_util_generate_secret_.generatesecret.md) diff --git a/docs/modules/_util_random_.md b/docs/modules/_util_random_.md new file mode 100644 index 0000000000..798d06f026 --- /dev/null +++ b/docs/modules/_util_random_.md @@ -0,0 +1 @@ +# Module: "util/random" diff --git a/docs/types/_types_d_.keylike.md b/docs/types/_types_d_.keylike.md new file mode 100644 index 0000000000..f72a1948e3 --- /dev/null +++ b/docs/types/_types_d_.keylike.md @@ -0,0 +1,17 @@ +# Type alias: KeyLike + +Ƭ **KeyLike**: KeyObject \| CryptoKey \| Uint8Array + +*Defined in [src/types.d.ts:92](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L92)* + +KeyLike are platform-specific references to keying material. + +- [KeyObject](https://nodejs.org/api/crypto.html#crypto_class_keyobject) instances come from +node's [crypto module](https://nodejs.org/api/crypto.html) (see crypto.generateKeyPair, +crypto.createPublicKey, crypto.createPrivateKey, crypto.createSecretKey). +- [CryptoKey](https://www.w3.org/TR/WebCryptoAPI) instances come from +[Web Cryptography API](https://www.w3.org/TR/WebCryptoAPI) (see SubtleCrypto.importKey, +SubtleCrypto.generateKey, SubtleCrypto.deriveKey, SubtleCrypto.unwrapKey). +- [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) +is used exclusively for symmetric secret representations, a CryptoKey or KeyObject is +preferred, but in Web Crypto API this isn't an option for some algorithms. diff --git a/img/demo.gif b/img/demo.gif deleted file mode 100644 index 3cc751f5e18cad4a3a49497be98f3805c6e9bdd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1890101 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 biW2fXrZ4Tu`HzxXK2soaInjySV9FbbCx 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 z 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�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�PeYYO|MKMLK5 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 z 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

)kS99M@hKEmoRCoK}wY&w$?d+67bf>q@5nIAat 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˟W8nnOV9vW_LE$Ji#vS3Cdt2unQk^Yk*95 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%0Ay?fF`=OTbx?;!*BXk|QTOWEKt^un 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 SXF?<-mC?UTa1y`?Rg81* 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�qdSwG{cM10%5a7VGV(x@L0_UO6>tm=yO~>9 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�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�V)$s%3Ez3L@G|Sko-8{YIm?OG8M? z;KTXR>oF;{N{9l~Ry#TEmvU(7u_jVkN`$F*7vL+oY$i)QvDX%)=|-ve0JloA zRYoxX69xpxbpQmOV{j*<$v0&%Whbj9WFAIJknH)ve|dp#}WuQ zEq7;9OcU-)v*-A$ItK&h&RBy0pcwWcT;mlTVImWliu7V2Sug<>n9aV-hGKk}YnukP zsKoZp52*`FK9O^pq#VYu4d+?BZ@pIf3sywQR3(*?rC;T z&}<8j>AXKp{ct2#Hgv^)LK7+1th7lSNj_UUktlWLbGmx;L%^BT>+T`Jz`OuVMKxUi zFzUrb13vArH`W79>ML&rOG5)A@&U83jggroGn9oOgW`@+K@$cu#`uIW(dH{nSOegx zc^rfUT00~Wd1^TayAd6>`&eZIEj>+x$Fmf2SplMJD zls>_)CFc183wV+oo&cfXBzNL3&0@OF4bQvB6F@_KnkOc0z2tVuS-3tVg}7J$mD6am z(f_8I*9fwx@>W*}YE$v~$()G+SVnCfj-uPcn&yY3KQL$aLfVqzl2<+@dTI7b znzFo#U^R(m3A>G-3WiPV}4X8)N3MkY3$RK9TKIp^ac1T>Ty^4UUT2=c`LSR!qXAPc^*!aSk~QcWQsu?m_1A+E{ok|3)>D6v{^#!4ay&eB;3 zLn)dnjm~nDWX7Ampee1Ad0K-7F0XgM(j}0P&=Ms_%(8+14A3roLPDfvNJioUk|3N^ zrJv5yF_SLXFkor6d|tFf`LD8F2$#6aQ%QH!CAYK+`Ri z1vJ0NMw%clfq*{6h%=MUKb5HUtibL_?mIuTMNSR(3iL4*W+}IGO@NLGJ*hx@FCz|< zF*Q>%A2Tqyu2vX82#R1pmNG{Mb2pW)E$)JOY>Yks`GV`fGb$ZZ!0_@nE3-e9?jax% zH+K_0rPDe+6Dx{u2x0`$T$4t1#xkiO3Vf|ZlYrzl$847KIeqL{pp?)?^qM}?DT{*& zzOd!$FaxQX^GTC-qQCjZz!z41(=aH23^Lmx6f|Xf~uL+8EC91MnrFy5FgW3UZ-_{Hbv)N^&7G+gS zJX7{mHvk3>M^{;PRQc~)Wu@{qQ)Y8kXLpuod)8-v7HET3Xor?)i`Hn57HN}KX_uC1 zo7QQc7HXqbYNwWJtJZ3-7HhLsTUSn#bnmgQbJd?2Dfq*5QAAD zFn{K3b)`t{XnlXe+FnYx1h;?x@6}9>f*|xKc?U;Y7a#|W*XC5_KR5WM-eKB@&E%q$}RDoTVb8J9Rko9vYBbhLz%jz2E zi*}2;LQ(xZ<2W=-E!vS+X2$9WIg-NwMdX6Us6s0a5+S~-R<5P_aB@Z716aNo*2=I6 zj-x2HXQP&Nu@v}~-%*nPXNzT2swMed0pS%-q{P{=u7P;e!cl&jp?Izqz@5Mly-C11jV7=e+2wD}B7 z=9Wa5-e%RCed;=14C6?rLwg`R2*f?cwL=8x7d4_Kn2|O3?M`Y|o9pDTYGu0;(~nus zM!4`O?iet3iO^tqw9Jy{G>Q)fWc*%c56_4lBY+}n#iXoAHR6H})`SHzlD3?L1d#-E z#X@>oajL~aa-ippm{4PI2B!~X0g_rEN(*7h8IB(U{_=3CySmeWRc;4Yg{3I_An~*OJsc>S8$fmY9zTsbQi4#tq*dq-L92Zz0d%c!(mo!r7p*vOA{o zIvb1Mf_>$uK_t)JT4NE{Qixs<$t0pItcE6&ia7g3){f=vsOJXUC6(&z%EV)Pu1Qfy ztfPF5Tk3gXQmw4(cMxIiVL0csF@Q%b0yd2Aj__vKi25d>Vz(BUvu}}}BU+1e6=&SQ zCLjPeRZuqnGmg5>IV_g1dl(}K^H8?cE3Vd}wzqcX!e)bQIWk7icXIm#Yz z06wA!U-?ljZNv}r>M{Z-Y+}rmB0I|9Z5ypyDd{Wb$C`RjdcGA1$Y^j}9Hqv@P6tnJ zM}i-_nJ=?^&8@X!+t=b?X%CF8JEf-wBEsI$#xAYk2=2I`z@pxxhPpxa?A!x z?2a>HGJb_?u(F@$MOVegNt6SZy^QEst2ws2n|r$5D!L^ht*90|SdWxXeANpKqnzC0OFaH@vXz`g$?aziW1F^kn7swPaO%1V>s+5WYuTJn1ie!4SC$l z4nuNy17L(bUhDvDI^ATHqk%>SQP?EfpQfX`EoQJISLl7zd2YKbR#RXGB0)Oelkikv zCPa@M1L$N=jN?f_?jpg02#xt(NNL;LC4{?!upPoGCJJxkv0x1lW?pi0?TjISgB#f# zY;`>vk?JO59#~npM{IszI*|b8)I8`HIe|^(Q#W6U9>Jj3sbH2b|r&u`K;maG3IT|fk#VD?aD-{D?MD9MyUG# z?(8X>F$(A8=M)7y^d1T^Jh|cKg1RdxlBFJnt}cwc3Y!|cmDQoZvb&Ry^r`iJMs>WX=D1zb&G}Wd5b*Qc&C=g>PHK0M;2ws8hH79*st!8@W;mSxd+z9rvtO%KYwwY+TLFAu^2}h0ykYwi~p<`sg)gvWi+%Z4DSaefH;DWLO zsaoy3C`zBI84>sxY3EF2x}8TJv6{rsmbra14)!Ur%Hz*{?R*&NRHl>*nvX{4TPC;- z)^&+r7HPaV>EtiBT1l?e=a@AWFz`7`@C;q3d;B`Q8Jr<*0kYFb88QN?)kRCQDponN zLf?maiiBh>cy5qCAEk&!>ceK8dBo5k1?|B{S7V7L-+Q2?LDE4$Md;E05PBuSoMvxf z*2f4i6p=&@3!KEC9x`Os2T6G~mqTfPm~y z02>6g(_d@&n9vB~W#lAM9_{4DV36^*S{B%4JrWR6k->HJBw$XKRDNw4O z9{^X;P!*Xv(yTJw#GF?Q7-i~742|U|XTa`pm>oS_YuHzMD6pUZQN`LZ>jy%~LB(`J zz!j)%-VQoa8DJuG#UFopmE)foH6aIXX)3CfANS&$D8Y%5ScRV%wGnBAZdSYCM|>oK zL7+;)=BaltjeG3AeFTv#v1Ob$a1{L-w4@xh7J8AE2QivdP|_x3Y4$M2d73+orbZOVw-vlD-xqnaYn656^%#m7&szW1=hqx zr=U(ZZFLYu8OPl2#LZdOY~6O>?If$o5ye1uTWtpH!PgojDv3+1VdW7fY6K)~JGwg{ ze?`>QuxiR;syDH-I(}FckzbKRibsImKx6=3cgA0uofZNAZcNK%#UIhK`SE~%Be+qH z1w~N-;uSRrKp442e4L|Vv2E5DmFbw!)&oNBnr459&6<M@||sTV~M7HJ`~1_RiiH7K3h&|A`+Th zndS@AIf~9EMm3_vu1M4ZO%j%{1c8LX55OBhy+&9XuQ;k93rQ8MxVIGn?B{}G;+oFJ z#Gk*I<|V%x3->ysJhK_fR1gzdy$04ix&0&wL!<)#5PhHkve0ZJtrLLrc60^0tk6>k zafAM}LX-haF^5#S%@=eAte^#KgY2@%5q{VZqI_TpnUYCLB*(NRd|`S&T*BrcV!*>R z#5&4b6%7wL0G(*5Bvg=C&PtRXJqghcLF|rdinxG>WZ^deNR1TkG(YK;jeUEW6J4w~ z9AuhAGcw{Le=yQLwZMRRp_9Y$>}RC;vCAMq=o@kP);W{pU@!^M1FV=8x$990OaUU` z-QEdL3|8`NJL#L^dVr{vv`-nUw8&#G70OO`$_XAH z01%pwL8T!hIqAZ9B(%0Di$=pS99UNpl(W>-g~cqOWB$Ue%UBcvn@mx(u4RGU*`!ho z?8}~}hfAL}fhziBr9ldUMiPqYsNQ1@Gd(uDDuUGwGK2^XDR~4*Z6;p(%j)w?STEo; z42i^jeAR;q5e8N25Xw>qnw?N1da4G!7phwj zRa-<;hPN>GETPd1)#LyH=?VZsh~>>Z1GY<#nZ+!9dQ>lYtYLxFfQX5u ziNx9v+qAl_9~tVOLLz`i6jZ7>mToFTk&BBqG=QjzGM+Ssr&5!Xn|7+|3RHvf0&#*f z3esU-ba7M}@K|CQ1jRTENC}Kdv_3zYr3q#W=fYU!B>ir5y;a@OX$*@Y|GsB(TTD($ z3Dp*FvSbZ88bLvrd*ZXsu5@TUm01Vist@B)rO9qUxfakxpY@CX^R2PflT$(_gEMb@@PXoZY_^?CiEy53!<)RdJSz73$i~@J z3ge}m3iRM_hIY3~1#*|t9)v7`Y<3!T7{3{Ry{jIBv2#d+fY8J=K-wE#mm-(Kf^<7_ z9{Q)MYx7jf9~DARPH)8UB2`3t#Ul;cN)YJ!<#OtLD4doeNo>iJTiAG z&Np=Xvr>$o`{|+;u-pu=$iR>*zXjiGGIo#;C1s46lg4XF-_|gdG*vI-&&AXtMmB2D zX?J_WP`zA~0S*5)_stA3YQCxu=8FT`(qz8vL`849%eg6}SWho6dwJ9R-FCuLWkSJN z#4&7h0e~ifO$4z2I&^^mexYP*@KIGkA5`K8+Tm4;R!^5Sa3AAc%L00W_FE$OCTlP~ zThJCI7Zz1c zk`^Vpf@W3nQF5|H0=FJ=P)xVMBq+sf-;p`Ug z27P`ufz{Lh9i7&Ee1;P@p&-R4f$0@QVWS|v#eC|q79IqMm@;|!_amBtZMrlNyT>C? z^Cwp0P7iia;N~t)*f|_@2E746jv*f$NLA=Y6|SN$aYqM#Z~?vJ2HTMmRVFQ-BY)n9 zRb*9J?l>&224#gJFV|N{d}2PI(IAO;T#S@K67?h6Bw$Fm70+@Lxl&%ELp|)~kQ5=0 zZ&F@_bsgviM*C(k3n@E4a)@-{7sLdM+{Sz<^H6=GDqx~K2(WWQmR=w5fqD^N8!Uko3&DnC(F00YVLNdFIq>ICK74~WpE-P^@IV=iI~n5S=_gRbr(S>asy34Y96PUf{_+omq-nepdnFp zl4v`{(K{C*lLKi&k)m(%NSW1fqUMP$I|mbw^NEgPc(v0&x4{#|@fwrqD;#wquhVw~ z&=ZK{I15-Oywfo7LMH#E0Kk-rFyuIqAu6#$1#v`4SVm44)>$;^ED-W0`=NqQrMnj*G~~p5D^hD=@F+D^Ct~}l<~z_MK~hFBpLA+F4(yNzagX?#0RFLAuAC( zC}d39xEtw*9Te1LVz+&2L`?RfTW)E8t%8(H!(2W!nBqwqMn*?&Hk}Jnl7gcD6VEky zaY3Md8HWuwD3o~xh|*{}@`L^~Jg34JTH;};LL@lJbQd^j^+N~C0cgKkZAIdaK;k3T z^NslFQasZ!HKG@9u|#O5KTq?Cp@Sh6&_U=@S1yGmR$vEj0Tk<~KWf26AJIk{v~8Rv zesg((Q!-0y;25)&pUTr69(fdzwR8g*TdyKXg-9jdNtafIf=`s6DdH=mQFfc;QQskL z@QP(xD63BfB>Lhg4Vyd-b5NAhW9{ZDA<;TcL75qw1|t+oAULq~M5DkMLAkhegq2y5 zh(#^Ju>;Eo#{+DSBag)j;uPJkl5z4Pucwm$I1#3PRbdx9Hpy{=fD)*5{v8S%HerF&)E%91&!D?MoBk|G|i`0H2@N4P#9VetT zY&*4sQ6y4`vKA75A}CBs!$V-XBeC_3Bk3e32qF8_Zn!wLrZrNWs}jE&CwN8?gWHLN zQ?X7#db)NR<}@yoV^sn>gt|&&nIT~@;gwa|OdQlLmLgG20GEzip)a#4?;^|vRDFOqbD){ri3y&+N%&$@V%MQ zRxEI8yCJ>`EG||c78~F{0`-iB1~PO2rV*+h*!Ei>6ImKO9m*3us*)LKgu*qFSt7Am zt@nV%ioYBzz`0saNrAt|)xR}@H8C3n+v`SCQKg(#P-<~{KKC*Lg)iE>Atxfh5;lXG zffGU06KdyXrs9?Ew7@c~yW^ydY&^uQL(_ zXk^8voI*noYi?F0G^fBJh8c2cz*ekjDws=`%t14_SfrAT>xF_63Kt3F8bv_0i$-ol ze4E&e5*71U=TW|LtC<`$#lIxO%A%*gb)uD3}Fj;tblW5w!^xLHpa*t za=L{V{m}@a6@<6UCwWH&`)*oP*Lr zO*s%Cr!@Ace#s|D&C<&u7zt)VO$OC6jR01S9~ou;H)vxwJiT68jSy0Uy+D1{!&d>< z+Zi~0)R+O*B|V_kXVf*uOvU=uMCKYw9YOCDM{SK`dR-|W+E7)^(_qNLIsMjW9o34> z*o}?Yjt$w7E!loO+0mB+o0Qm;UD@D^Gn<{$3LtPTXVac-V?HoukG4b@W}7^Lmm zLj8t{eS|@s*{|KSzH8gLt=qdT)x7Q7zYW~)1hp|8+!>M*b6ni<1OY*C6e^tD6^A=> zo!c;AL07fd&%N7zOWT2l-HshyNL}0AE#BkZcI0i|wN z)CR8K7+&EU&fy(ybs8?=AnxHKPU7$+;sJi*C9dKt&f+cZ;x7*4F)rgXPUAIh<2R1u zIo{wquH!xK<3A4MK`!J&PEYpf6M~V&JP}~66SECvhX`8Iqchm9 z@gY7iFjd|cAJ8|sS~p0(fji76NiF~$UDW}gqH0X#%>ptd1_8JP8(MpuKaz$u0pKuQ zGn%=FL*f(+&^k%3))J)?eG#()UD7(ino`Zi3j5j8oxKFTXezdWqdj~NZQ(@j>7Nej zp}yIaBwG%PRT#^3Qw0{XaPO-;4!$jmH~Gn0iVXPNq9XL6EuTR0cg=oOJC=|_VY%Kji(X;_a zvYlr`h0ODSOb5`kElZki;xQOfuM5`GD(bGC;xL}?_s;K~4&3qL&^9t7TYzn3b86!U zMA;WDRN-}A*R}8jE)DO>i1l1lqnTz>(#%y+G;x+wQn-wDEjIS6{_(Dh6(!d!VZ)N_ z(abjechZ{i@Lr`wzT~8ox+k`Nf%OBcR@WYl$no61Jtq;$dr-yAQl)7pob{(4UT1N0 z(i46pK!~l0cNvG)LG)TWC&Ens$k$$R``+(7{`LMI_G4e++O0V?8WR6C5EQiC41uT= zWTHuzin?w-4H7%0m3pSO5oH1Pn(}gXNW99@G*0I0v=j3tr59@Ycvv}a89&tNOcz2? z?m+)k<7GD|aujc4?kCNmr*bc|E!=nGDulbMYg2wM%7nSLg`79xWG~=e@A|PX`+aZX zBX9esi(}7wRs{(mS_GlZ0xoR~CI0-8)H_52FcSuKv={2-uW>02<4xL|7qPRz5aOsk zm`6N$88%SAX~WHt!OjlSDv{!eYxOZFBoMd?%EMF1@x}e$xFRMMCFODy_;`A4Li|c3 zr|NQ;0C8qf6czvi0FcxF$A`g1cIXJ$uqTZGg9sNbsu)oY#)<-Nd^uAl%n^cFl3@{%Tdwq|DCJK=D^V{F z9C&6(#Rx+}mRa;cK$<>74Fc(N1;9|sk~kL2ejXTe-=jd^O_|c z1_rnMfuQ-K9~d{0*6hOvBZ4rv187#NIm(xoZj%roP#33yHhN}r96@&T&8-!e{CQpx zhD0evMks)7R)7!xK1Fu#ECL{iLIEemu037w3V6*DBLKL~2DZejDJY!E;6uHR$ZEn5 zJ$y5W1v~nvjt@K9Is!bmFv7sUi=wmRf{YwOk3b4Rl4FF5cAGAM3s5RF^uvxKpd&=O zDyRsp=X{eQ(j!XbbE^NK{F2fqS?WQLBkXX>jw=iG0RaeiQ-B5T_5$Dr2T|gvh^d^a zqBtsetghAntA4z#3XF2-11^@1=tx3B3H^ejlkAc&*xjz`DmIh;*dRRsk-eZv)vi6` z$Ous?R<#P;;4!amaiXb@gWz*(jbAOqXg~|nq&15oF&NQMgBrAnQUDt4Lq&sLoT`V` z!T>5d=8v7Y|~I%uJXCc0>&8T*;lqnB0;1MWCdz-b?p(+f#`5t4&Z zicEg)JBQj334*`Aw0yEx=rj$2I zSZU_cE>2fBC@t;=DBXRpws|G`@~UbXO4Q#B%jf}tyf|y?xPlK-z>hRQqnIJm9kd;Q z8+qpRAhZ@?^n>RYF`T1LKW_HpoueQ*thXPQ;-VX`P9JfGt{QM)hh~P=t?HTPzkmP# z2VejNShWHAk8EwqivrLxGKz@icfixyzfkkET>-{$0_f2Ljm4~15lU3daYM3dlrTgc zu18PPi>crSLLq@?0WV}2$8g3o)s$psK{#F2R>ha>U~fMqVGl_f@_{S025&lgAd&R{ z^9LF1MReDC)?Qp?I*=i14=`Jh9`MBy0$gx$`+7^n4$`4D(CvkZ>QVq`A_sr<1UNwu z7)AP1E*EX9A{4T~T_A)Xp0#E(U~HfF>;N&v4WL{^icjLmhoFKmY>*7tLlu;_kSOrT ziv~Ia%*bd+Cf2Mq%=%993OLH3C5@D)R2nK(xyk@Gz&BXbqq`!gnFnGmjbQ*^YD^hR zp@5558k$L(c(gNc?XiwwK-}wuvqg`%kB{gZQVxl8K-1V!dBPIF4pRxn(Uom$v9TQf z5=BYQ9Vb86x(^huC7{i;g-jh0W9`gE$FcN*0l-R|1jTov0x54I6-kJVNTf&qvQdax z9$SMQBa(#_Qb=qD`VcLlv>(%H!~)us)oN}d8}@LhH0@If&d_%g{qTrA2#aOb2!yZ^ zYL5?FSinwff<0E&)TTGZX-;*zQ-%=f3~4-G@K%JzEauUAqd{Ct2{RulFejactL0H^ zBAsITvNarG4%xt>$dw{MR>T6?%@TUR+Fa{32Q&~^TX!}MNo7s?jADlfg~QWS3w&zY zTs7mxIj_Ylp>CRJ*<_W4)pYBj^<==NIN25pjMWWWR4ln{B2*e37$JH4svg7E|kJdn8p!HVaG}KoBs8HItHbY7b5P4(evun<28Kt>0zQ64NOa6_GTs z$V?6TI!GJW;_yd6e4XW2RBza}XNCc0=x%W6?(Q182Bf$;-3W^W}X%yvJX#*V-TUz0do)j*}jHJ~smCa{V5+Ly^p%NpC#_%9|`eK(a$t zjx_LSH>hem&>Z{GK2BNR5y?>U?B!}2h?K~Rn*%2kQTTWlxM1uU&?qlO;q}8-9QWS=VSe&Xdq8Uvl5&MU82x!DM4Sj z<p+1-KY}RPFU4$VwHjxjj;S zky!!s+QQ#6?pqlAaOdGSPGF0Ial!I;bt}ZmX+0x}_>lnPn~Z(3%Gf!preyTvil+oN z2ZHOPOCAI6C0cx6NsAkf5WkEDo>H%9mA`&)+QV{V2fJ2|3ccm4dT=2W5*k3J9Uh9-&NBgt-x{yna};~x4hpPyy;`bKTB;}<3hK!O4?p-_A*_Zh^G&mw*%)bp;y@@<73 zWduY|2BQOoJ&r=3mn-Pw{vMIhimbxjM`1hwN`kwwZ^D=f!o`S2$kye^BS$DQM<^>t zs5(Zd$46+^M`)$;d2&H?;87UKC_U3CLt~;C0F5z3p4ons1)P7xD9cufJ#`~jTtB+3 zsKB~D%6+0BYXWBO8J%(-7?NwRb(58N9F^&Xu%(U;+#rPp62Q)5vwYILnu;tC#Tho> zZ!Z8~c9aJ^E=K~NF^&{_keBpAD!?Ong_!tJio|>oiX;*2haizBz6d3Fgr+%|&RBti z3l0^d(>Mv|;fnx65;3hox?Di%KKM!g*a&i5DiQ~b3>VLZvj!mb`ru4okjF=1<{=qG zhrpNn39?_t<>8a|B;#7N;@1?rf^m;n$RHtPf}Up3lfiF!ZKt;fn@3( zSEA`1GMR7EOMfyZQgt!_@Vjg}9;`$=Fscv?NoyA^Z-hwR9;1}R)I}3f9ucqaeYL@K8wlI0Ctr9G*jYqxsduSYAjxVHUXfV z@%P2cUNt(TvhztFuP=z5{*2MpPR!uJ!3)*0zgbC^QYSeY6FT*#3~P>H!5>*3U<%XCHN;w3zhT`uzT_~MuK zMI&=&x*O0MNn(Cu#P>qwXw|9E#t5D#*fid@5*M2`PW{9$64`bz;C%={=wcEjHAfma zSGq0G5wiG#a8^lfDRf^o;zm`eV%z56U5v>6ZLXboNCP)gv0One>n@R{? zQpESa1bCgxVu#}xo$9*wV^~^=#zH#0FjaIV1+PjS@q9EUfciO&7FZvlcM^UQ2{&6G zH$R#Dem70Pt>W@!Ws(G~AXS21OKmk0gl4hgc!vztoDvsX#<)`ECD2&+0i72{ygpI? z#iV`(UlYQ`VOw4lSSs4u3)YF==Lq{5NA(eWz zMoO3DNDa6E5gw58iR652(5NUxxVl=X7ZUpv5K*h-HLzsG zES>msj+#_WNEONcgf6Q0cP=||Mv2?-z7g{N1n!lTBb@}VS%1j~drkzD@SAkS{WPw7 z5#2(-i9!m+`Pttj5e7ev)3cO;QOj6VW?(*pL9VctL76NMvv-Nwp;cyA=8` zA)A!D{bcd1;n4=+$+@Ng)lIby6{Wio-NL=~AINr#^%SmM4KW&f?;=^GgKY6fk<0RhNY<`W8c z%UE9$FmQEaq@^1y66)E_-;?eDd7~%X9EeJ4X85BaRt$LFcjuW)BuTJ$8t`Ulh(;g zJ#bXN=xy!mGv%r;+Cy9#O@_H~P)U<&!g2xoTUid4>L(VNNtSD*hy2`en@zD8r=a@3 zA1S)5N&G(5bsPe&6TZ``-*wtDS5A8knEeV}+X^1Lr={{SM^O3iqYOSJ^Vvr8g}stO zq%&D?N1OZ7tN|f<7ym8%GnWJSX;?SzGm;s|*hH8uXf97+|4ACJj@(|vwt=xAAO23L zf3eJa!rdcjMqB)1uycwnj%QV3qlWusa^rAYv4si;w-+=ch2qlBY@3%?aQ(I>RB>EQ-KWN|KEaR$dbOEiM-|dpQc!li0!+yQoz!H;oCgEl}ZEzTR z>MUlx=tZ`+0aJ=0QZwy(2;4xU9FMD)fc@LQyGFSwm{)g{A4GFdAQ@z9FSy zv;C!pZ#dH66w3D%A7fn;?uLsVKi=hTJP&vNyI8PzxqpCaxNxyNTeQM(EW=1lU~_$b z0ppb)B=V-HhR!dn&F`6%0fXa-9_k2gqp|lh)g7j~n;JCCs-Brp1o~+bkG;>6)?z72 zuLFL;Q+mPMs4^BY>N@1gCuK=k{6f;uSiUOZuGmS{|BH@;z2{dD179&-?&>AkdEP{V z1WV$9$Mx_9U~F>LO#}e_s8aiH%!?N?T*ULBb<7h-K*3-%o-6eH*!Wd5ZlN{rpqg03yI&_N9rp zbodW$#qA$5KawFcTvG|MNn;OZKQLHT_lv(Pbju!0em^K4qjUQB;@g1I6M;9q6_`== ztUL`l$1?F;4z=>xq^CN8AjtwV7ogZ@J{3EuevU0Jd{9h^7C(7z%CuJd!FN>dG@rp& zamw#j5J;|iXSsD(fqwNlbGwc5R+aaa{)_xThc9HJw}EaKJJ$n5h?$S*Kivv{#@e#tAJCCs05I{1>}K+_m4F(ziV^4m6lISw*mxsep{;q4Vnj4lY7f~2Gx=O zX=D9!qz+8%{tchXXvDl~nksF+|9!;blFs|5ulrBGQDj{gDfkXFS%P_rAB^Dzu{-)yp8Snl(H}zK>_}kL|v16F33)8WZ^}0v)*DUYj zyvl#;D*r7wh0wmHT|T!>u>wfJLe+8@H>UpE-wKts`H$w?-^4BQZ6~XgoWDJ+5u+df zJ2Coqy2VH;_h)kpNZzCRY069iX2sZZze^5ob^3RG|L>bD&ZbpJ!xL}LFuwn1E9}&* zx8a!YPF_FVi$3~?{M$4N1M)p}rR*G)gs6#zA_-swfRS(vdDFV%rd00WcLub&Qd5Oo4YHi%r3z-wuY}p*`Wh@+OQWDEsQKr7GdI zc-$B^*?U9f|MCQ1v7t9(s_*9dU^oJw_pMZ5=D1?4+`ABgvE>Dw&ylXSD?gN&88mB( zGy6x6Uz54y#Q0NY8kL4&GUS?vV|!0no19mX+XV66#4LNyZwOJ6HSlAQzWu$iv5Y1Q zsI`cDlQ~@+!P&lDp1?awQ6Vp&W^5N!woqCwPt$|6i7w@zjEZ@@tg%z2v?eb_YVf$& zM+hiTR%O1_GdZ;&*o`gD7M&FeOXi@7rVma)kJ^ucfy(VbYWdTZ1zM(*HHAK_CN)JA zHhHJnM06?ud2)do2BJvM*w|3CBDEqvxAcd}0`zwc3?Zt7Um+apTqw{55iE~C>2nU7GJk4A8WuG7eQw|5aUO7_{uWev zeaJ+@A_WE1t8(A2Ge9!`xH_MUNY?dZG8VRu>Mjzrj0xul?x)PsXR^WUjWJ6nXNlaK z8?hs3+NT+VF>l6LeRe!b2tIA`z7z19w~q%OE4MF*9v2Ea_L0T3*Zj9YKnS8EDK$s& z`+TXU!n)e;SkqC|B3-)qO;a{PO&i)=c~c3a1;zgnl!NlUe7|P-r|~l_Pq?$O6RYPGa*uA{ zX3UDi-5I}SYb7YzpYHN{T=B)=oi`S?6IQ?(<^^ZE~aF6za;vF zWdFL&?Ue)xq{ZWye8!*@?8q8V!jN)rqcxA7pv2hI#44eXUO*n4vgEPYl0 z?$VjE?A2J#^5qd2ZEsTNh7x}W#adj%P|bjZia;y?Qk{%q#kRr zy?PQ5>xkL9Zr0OjjTx@ts`sr`&u;PVLJ|#&N|0n0fsi{<3G+kAhTYi6OS0<(Us03R zlO$le)M-G&BlWWC(7^J}w)PGKpM}?J^om@a9yWz>Q+;dq!7KdG-Lhr=&N`zxLj7Q+ zjrZkQVa@6K4ffr!Q%DGVoB5j0020|MvXSuBB$9d|e{&er#XD@Db;d_!l&JMdyt=+F z#W_5@Kww-XbZ`X>a@(0pcQAhv7;$~^hj^>X8mF#t$I$L`)OetcNN4?rS^Uo5JO9OY z$sDsA_zz!-QcmaX8m^MElK9s&(T;!J&U&ngr{Rk!3Aibm%q;>Yrc_uJGPMv=JY^ z`Ha5v2ogiR*g121G$8oNb03@-b?t%v%13fg8;ibNXi!gdZ*` zWAgfoTn7ERkV*@!C4Yh!mhC@%<2G`-3-@E6j5E#d2?;u0Z`Q^NimjS)F5LB`t<@b` z#@;?@4BaSOYWv8-s^KQBCxI+pYGBWhp`kWiQz~wH_`mDYJOesGug_*oQGmQT=m=+Y zrN)_Pi~o#LzJ9*s`swSTH{8_Gf+ZU!^Gl#`XXnM&KIG{(>yh0{@!AcA^gf-0tPhI; zJYN&ZJud6~OII|%n-+c0b8*-dR-$#S)Ca%7|_%QpIXWHz+IWa3oeasUARBN!bF@CR@K0k{B4a1Ah; zmX?-|j`qb1I(i0rCMG6kCT3P9Hg;w<4t7>9E)H&fMjio1ei0@?ab_V=0U>b_Aqi$- zNfu#g5fKGpF(pAMWo}tjPI)y>B`q!$1h=ZTo|=-1x*A+VpI57NMXP30+gMOX-vD7{ zsGk^W5cAg5McBea#A15h>XnGi%8ISGsJ*Y4qrbT0&Whviip%R)E&&q0v9fOx>6i7-%)G3h z)o)PVY-ng`d}dz1`I$w7mX?;**4DOF!w$7i9h*j7+r~XTJ-vIzeIHB)KAH|5n$3zD ztneFdoSmGV{|`4eH{XY?Z*Ok_|6eelkpAHjkx|hxv2pPUiAl*RscGpMnOWI6xq0~o zg+;|BsnVqtl~vU>wRQCkjZMuht!?e^J370%dwL_~`UZ!FQ6r;c;}erp(=)Sk^9zeh z%PXsE>l>R}+f#}F`kjN1ho6p)PfpLyCyk@5K6_t$yZL_m9L`&^<}YI@6oa9$9g zRlo@{6agXTFrRKMQ`FPJ`x=mWRyL79A?Uh4O-R+RY)=q)soGvSlfm|~-agY#n+m|E zxcg{Ri<&JE^SRoe`SD>`LG~C@>#U;KU96hHVKLiL$H5eN1Zk%?NG)WG*cbmW+u5+y zqEW_!<$}f{%4FOM2!sI|_quPNE>K01-D>iE0Y9!j%x#%(3?b35=`_WRlSgBTIW6aV z+K#7E88wPEd)rUvas}NE=6m0tFO@1L&}sE`T&~r=Y_MGD>-@acYByJ`)!+4XugB-} z!9sucw~wd@>=)VtJ>QR~GdQgl2YP>;FIQ-kXb<-N{Jj0%?c?HL|NXbav4j^oLj#XL zF4h{XmWBrZ+}|9}mFNr){rBhL$LEhr!^2Nc01UQ6B$&+kFbu*{dl-%*a&Z_zpv?9u zlEl#YQxt_`?WbrO|BFvCzaXt)Y_RNDOL$|Q-BCQ3gaCjMua!9gjeGNX0`R8850Vs5 zW4Okl;Y=T%1nQb@4GnA0P z5a%|WTz9}aBIiX@g-eB;TznMRp6)S9K89#DvMO&^zMdhO&ifQCVtfYMG}iR{2~3_! z2%ZzEiHHSAV70q7gp&1d)Jd6&r@?d(x}RI(E>tH(%A$iZnKF`pBhi8};+*jSQimRm zOyRz&8Iai0C|VHL>`1S1kOF6>Did;AXMw7L*XG3t)l7RNhK6dFP+*)hF)z!lj_GGd zfpZ?T+J5#d;;EolPxwGhC7$x|huLNpEjHUIvIacw24=L#zHhUt|EW1KJLCyFH$I>qu9snO#XUIv=M3i=!`~yVCrej#>Ad6bGsoP>eaz?n%!3i znDH(e+qQov@SZk9gqv{L((THt#mq>+W4j{#F}x<60J(|1Z2Ps_Y~U)+Yh0MI56GZ1 zE)++WD0*-M0~v63EJau1u3CtPfCi||<73O%}+ zPZ{>+(>pYC+U)NWr*McTx*5X(rT{dYfql8CQv8#UH=4|bN(MV_SL;9ALav2G8-!09 zz)Y)GflkjlXxL%Cfy9?MR3P(xz4ERoqjQ+4WBS#(2g|Xhb7JVvzu237KO!L1kGGD( z3LSN(5Y18$P)?FO&K`4wW1F$M18U7pz;aZ-4-?@NzWtsAhzrPJ^p~qU{rN3&2KZbZ zkcmgq*UI`PoK9?#AR(~Lp2ht30Q=1YogCo}DGLeZLx3tgRI52wRkNHZXL_7P;(Ht- zv7DqvRcVFki`|b0dE#if5mgufIn1y|{$ney6OI?D*M9izt&p4$T{$%xq#UMT4G^%< zVBk%)(*k(5bL>V(ee5O5?NrP}DEpNm?U_q(GmzM!;$C1|c6%?gx_dg-$|=Cd z>ZpR9AaxEqKdPvs$F`A(bsThO_wIOan`PVu^A-1}1Uz$0Qs?_9yL`@)s$k3CLj(kG zB<{)xl4{|s>MQZ4cjXidwaTKiE6G836)@a7RTU0B1%>buNR-m*BBg-g1cCSLKEt1K zVNL!#2e=c}DG?PG0F2UB`d1z)+aA@LZTX{8?K3Gfh5~?8dri)m@d@Ci1i<0&WdS{z z&4If}#R*yb2*&m@MCrSfJCY3QPx_CtUj1H=WLU6{TP9kX-0gb8Xbye%aINW83SlabFT9yk>SLGLI=BNlwh?eW!wU1+Dd-&)v7~VY{M<>jD5y-7EElJ zkIMxZj#nuc9$`8W9r1GQeIFBh5i|W%UDy!-Y_`{b_2_a^;SgbfnHRY2doTo$==ou&zGs- zccY&Ib4qQR%(;=ZX0j8ZX}b{+{U9=J+JjzB^t{w$X3y&}=-F~09?(b8y0L1SDKLgx zH;jejd1i*ab^WO^2$kpd0*N*FRcfPbhF1(Xh&FlM7=Rw6kM!# z?RT-09Ijb+8(A_i{==;R&}M;YiX>iPrxWx(GIt6PXLbF!W+NmUF0pJ25CRzwY>H(5 zZYZ=c;1?ub1z>#C_kc{C9^Rf%hqR_9d*cC|K!U75Y@M7TCgs_6wxwWQhqj z*6WFm>r*{Fq86>Vl3p4(6J2^-43;_W?)jME{k8K$C`Gtj!&MnM=1_;b9oh>h;A^VT z*}W;>Vh`D4C*9QR!@%_W@vi{Pp9@=Yeu5MFb?5zzD!!^dvWoF$ARTS( zWMx{!gN&PRXQVPVn@R+~`}>pBC+$LK&37G|mkG1KKId4?SPJUB1dLA^lOw#r+& zl!-%=54`IGZ(&rd*AJ8qe}|xm(i4l)r+7twtA*h!O5NcUt?c2@fyOc+17doM;eaW! z%zj=e7dvKIjp6U_D-ARvezOMF;R`~ahAKFRF&aj9ud)AUZ!mlk<9K20vyJwL+{%;* z>sc%Ae)igRTSnZ|Kc+f@RY}uUK=t#4h2)K?>10d~gX%9wCIhkfO5^zIZSNYnpnACo zeLDEKv33+;-BzL((CI9&Oo^aI^}Z#3UI7DUQ=^KxQq@329J{ zP2wl9lsn@T>~WH0hLplLfggTAmurcCJEwreQ^6*w7=fvfyi}~-RGghuyvI}m$}}SJ zG!m0EvcNQoyfmubG@6|>y2msaWjaA1J&-+}B`}>WFI{{KTZB)%x7zb3hHeugox>zU zBrroPFXPS#XZO||A#5KoWqH%>73UBv5tyl(m#IFJrVcdm-_o)%unM1)nazRzhXQNl zWeL?~neSww?_^Rrc~&UAebcVtu*m@xd<(J1GP}%rRhOQ4M&jcSS?l7IBK7;uAVFk} zwi*DT0f66=d2R^s0PeG+19M|{Jk*&?z}Zji7z9kd>p^&sSf~RamM9migEJ#9w{Rz~ z_%ZKVpDJ}#N_Ikf>y6|k*mHp>x+XhM8JgcpSx`!zbH^75B(TnmWUI>}tIj5S6UmqL z67e{z>4MM`icZ&0BO{qVloUVzB4KLrKYNgnIXc+jVnG71(>(znb+do zJTgMxlwkFh;_T`!ub2V)%&bAoTWmIeef2NJF*K0L_`;^Rzsq1$<>VVQ?C<@;5!n!U z=!bGyUzS1wVXt7Oasi17q203fvM1vf;&e4N%ps%vcuXgRLcHgaj z^}E`Ws>WNQ#@DpQKd2@kzb2@!CSidQRz3Lv4PH=NqfTHG7XT+`g5-}Oho>S}J# z5+=)UNu{EKAnGvXY%I`UCy08h$G#ZE2q{MZC`vsBd!W$Jh0t0hs@thv+*R1Q{}Re7 z^|lnM=Vyf=ZhW5y45A61z|pC|hCYZh3>}LPa!%!G#MfMRRlh{l5>M5XXl-V_A%#ay zkm76b&p+$y7SscQP78y$r$Q+CUPl4YnGxKsd=lo%kX6hFVEBY|b37#Hdg2N>k2uYzQ+ork)*B2JFqz?`A2h|cf%DM5f5P)?AN8?rSD z(A;NA?B>}X0YLj&->h`guDRFoY8GkfEC3baVFXr}AV9IL?O;g=Eds-}6+{k3lQ!e# z_pGb1Ysb22@JC_HUv<3t)Ah54r2C>6ow)5O016^*4<|qqRAmve?ivn2lXk1+1ES;Z zb-!0@iSK_RJ|GFLt>tj@_9t(E8e_NR*F)IdAkL)_2Q&1i-;h+S?((@;&m}6VrAp4i zg^L@J$`X*>`sOS%^kh$r(|QP(XET_(wRsK#he5bXbDs+tDBce2PgXQA4GV2-30Z}(Oy<7sH(?0Z^9TD>IP&+fCve2 z$|Q$wC5PK)sfsBo?h1x~Hw5+(4*&Tx{LtI;a5xMwM`47ZAcZKb0Tj+Y3hyt9fM$e9 zYJ|jmpFiGD zrO6kFylS*Kg4Rn{Oug1#e*nnR4BQ&5EQ4s}k{nYve~tpgcLqB6in<7S;J$6Jp!XtILJz7~ynm2ji*8 zNR}%0vJ=@@znA0yi}#OS%?>7}0$t1@AND4a=Z9a6azdhI6VQ1w9MQLIeXoenzg2g| z{nbuVZ;V;)jL~R?|IJS+oXvYfukJ1KglU|Ct&&$dnK;npj2zed(#ZipGw00k|2y~Z zWf(?}#701ITt9@8rUOCH7$rA5el=Pz^$PWurZHH2m(=@5M=Y)1td?oV%fhEQxx(?4 zM%^_WTC6u!Iw4p%06FdDv3%_6W11!M0s81oySEs~(LQLCYx~t~XBzpyEzR=u107}% ztD-e~ZhO)a$=gH}nwwa) zr<@2kS>(c{;M-c|8)Pt`TobZb6A4`tD_WBnT$B2+CiCB#9PPS-^tzBV+Vb}WO2T@$ z2km?#c9R4a+MnM3fWZpup6dM0fdGsI1R8hEMyBU#3S!i(sdp{d+aH0}EVq#Z8|1%4 z`_#AIOSnkH4T+~=`!?HDlsfod2(;(Rn1d&<*B)vHn*yz@C*5oV zF+{~3wOS=g<**QgG043x zEsC$S&`%!#k~rd3n$!F+&(Ab+_TfNl6b3eS&_E#+zKl_Y)qYbw##*BstZ^6) z#dRD*aJ+Ad!J)bNNK3)W$P^i~k?J!pTB_{OFvwEe3wAp{Ri9;fo(AvFhJWeI@5it- z!w>@mxe+{<51mKvFEML^S>Jv%vjiF@?z$o__z@V4xU*;f9bz~4GN>ATfke1!l3( zzA{Z!*q!QdqsbFoO<)0-%qN%$#sV|Y>#pW&7tk@U`yC0R|DVN|q^~+0MbRO(la-T(2UCbrP=@gy$ zeAoX@#9|uZH%Y@$pVSU@JL4!ocecKYe>)zGXUGXa%Ql7hy!Fj&2J0<;W-c1lMvZFU z?1SX`zexeiJu!r=F)?K&EX=-DeHr6O95-8jF95?(4L#@^JX|*GIB%Nx==wo&2m`OB zi$VtAz`13VIBA5y*q_I!u{a|~9KedNnf~?(Pi%}O^_p9sngxRaudOm=4$1Yqazl@h z*e63@cUF0})abbJEeGk|e!LuNx{^4)!rF5Mpku>kVFU-#bc3JfKY^@|BV9jMo}FG5 zlcQoPXK6Q~oKp_6t~Q|YjRxfm%bi$DZUyrv49mBZ%f+9&X=Gk$-tTz$dp~hv5zKmB zY+X|WaZ~veT0xRl#K4yJg~DlKosUga4}?4)A^*-ji+?9K|9bPUU!`zF*&68m?U7m* zfF(EgZ*VNLY4FuQ3ll4QU#p$i*4vd=U=ZLOD)bN>d`PX+_@dw{#!`4TfBpvRbN`3W z?#uOAPY0|mkeAjyB(KSuLpv-yzWEJPbq{yGT{tIseHe-O=_K7%cJv6-nDBg7c;iBZ z{rzD8hX{WFfWp8P5bKW+OpW7r&y3Y}pg;qHK;*7!{I<#-EQpu6si0g~1W3E47$D=p z-_Wb);mi-rj&*{S!R4*loa&~Wd()me-8m!7jJTW@8am>4-l$v4%V%$zGb3fi$|oMi#;Ml;|YJnmo>TzGdk6P8y)umxwbW`rhKXg%QWA+HHcZrwg7Aa z_Z%ftDKN!&8nypTY|UrdtLAd}>}Ctq-k(kJix3JU^^d5L#pZ`f(*kn}*%2cMcg1Ke zOQw_@HeBR%eFR0g&ezzT`;^*sYl<^mKQ`R`E>#Z+RoomuQXDwNumV2!>#)Gsu1#5KVC&5qesZ+~mAzylFIqLxD zHuWnkLdmMmh(e~)%A_Zb-s=Dd-M09owlTAy>@|6hr%g>Bhre3J&B)GHf>o2_Gz zhcCN{(ippqZ5sq*CP>4;UYI!(QP(CCcwpK2i$30@3OOzO^fxeLL=d2`G2*OF$gc#h z`zbulE^X5ep@^t-#B{QDZ=beDoeEmY9yPVW6f&D$?lNYkZc#hqlSV325@u!>L80=t zWkHRosT^(ZCfl^o-KMA+QvU1k64%&6#uEctXW|bT2xa!uOnpO_)2x}$kw`7SucAf? zgh)>{v?uT{3&|$*J6t9#4P9jte1q4ltscY_l4>M3Q!MIWJj&@VmczV{1w-@`Rh8T(N8KiOZ^d zbYY4X$Z{KJXe+cspM6o?aNYN%>+^O07A%d9No?aJf;DARVm;sa!ybJ@0Fj=eL*M2^ zc{_14VI(xG6O+tj_S!fV$4E`%qcC5iXC##T(l@U|9h?9Sjbi6itRS8BcUM;C$_2{r zGB7v_4p1rN2LzCbp-A_%bm7kGHl_-goSt46)9UsW5M25Nb9%giYbq*pa_Xl{d-px9 zbS8W*zG~%!{JJkXp@a=n5jZ%`cNB0fDnZCp8nSjLz@o)Hna!LP``bat{nz`CNX%wt zCY?wdMJ-pFKwWG8QBP7{7lu0O=GOYYc!>r+(4+3_3Sh5?R2E_Hd`f8Y+_bLC+6x{0 z>nt_&!?%`7iDgO6_ZOM=M&!JtY$sTN%GhT`)vCE?wqVi?1FOZCWlH4QmbHN-?-%_W z;nD%N$6I*kt}?)(mrcvPR_2nRGC}qYp7F0#mddZ^8Jyt9ogoi9akZ@}%0&BS&|yG` zNZ;<407gO06&BC`32e!yQ5X`-(#-VFpL9=&1#`t$48X7z?Uw{hQBUKpFT@cz>ZRRT zrHA&APlxVICrnv~G0FxjRB>1O=@k0Q;R}E;n0~Axei#xcT|fIfdODgjQxo{f$DqlO zzk^8T=6@602@aNXbHk8Q3yN3(G0KD6c)pxsN_A2o|9hf*2&`~978Tw0J;^h%g63Rx z>J({1l1Xhudp}($X&94&#HoZ~s!c0U-KNHBRx*&!Oe;&=rllrUGO?=7sGHuV=gwEM zh|bJt2i<0r;#9GzsLkr--)7coR&f}q5plQPX0;|(aXG2YneN_Z_sm!E@VA9o{JzaW z;Z*Y(9U*O~e&kMTRtx0J%sWc_$XiaV7OGKOa5epr|Fk_{Eh2b{&NWbKbcjN_@+IC?vT4<+8_lj}_X*{$2i9pislPNADXSJ+sMFSZ zj5PduS0jg8kBCuUFQ@uhtEyG6movLwE%CDskyNi=qrOpZ`m_Ey>;p2TZe)wKHCU5Y z%H~ys$eWwPOGi zn6U7cnKTsfD=gZP-Ljn0q-xhKbmUUKeYX%hiyA?EY&*s>9(`=w>pwZ8j;K!lc!n8! z+3>xya3;*G&}7ez&JU#Ou{kugue|C2W~Z<+p;Y5$^eO9z%d_(L4QyN?K4u!6#$iOd zfN(2|1e!muYAEpm;biRz(A{D%w#Fd}xo{Pwx`P~KVCQ{1BWVby5oxl#vDVZywZ1nM z>qJSbL9$a#V5)M|Go2C6FT$c|V@sjT{#h2%w#M%TFo?bi*BGURThQQ_x9czSG8y+1 zfg<48vasf`Co4(F?jptT>(EiWApL_ttz06iSoTjc?e-T}kx)t0E8@i91G1rU08=$D zPw>t0)~HA|ygJ9`n2T8Cy$i%HK!EA(;p~HY4a%9Dl{D4e3_ehb8A7KUc{RnD)-ISo!;SgZpcX>TujbVU?Xnh}|uGvdfTYkJi7 zBNY;u=63$IVYv54U?LyKxWF^dQ{L%cd42)Va$8j9XReLyjz&JxIH`#b#-B%n_qGUb ztQh}$ilAPqfa*?9TH!Xj74ajnIVQPDVM~N57k{d zKMliYS+TyaiHg(KSuxHncvjuiSQ0x48Xxz*79fRNrAs{x_3RmUMprQ$jurf!&cBwQ znPLA5Gzuz_TA#0c$NNj3q;NIy5p*G32x!_G-~V8)aA&6Xm#xtj5>}(a{OKKinLm%H z^D#Lfs>A|00{mz4Da$cX_+1Zs^X;)gCmJ;g8yNZlhVW3{IPm%>ic#w8QP>W*tOuZY5da~d> z1V}@itt+)5eDCP^-DS2TKCYRO#RjF`gEzy_q1KMZj_Ag@q0a`?Or#SH8xP|Y*vTe3 zverUwn#fw!C^t7QzbCG6JFfU5F5JPsEXM^ROq+UxJRSG5vVNQN@H!g9Mo}adDsSp9 zLW{l(Wd*^HjwoNL2DWsE5_Km)(*W(t=3@8pIAUIU6jn17M7324c~zpG3f2v0MueL< zG;gA~SnPR>1y)s{t+5bRC!*0DUcziZrGvF z>EsaQP^+5&?gulvGhcR9wJ4vIuhS-(U0A!UM7ZKan=GLpBSV_?d=6@#;Mo{}2o>~$ z9EbWU2dIl(2VaWBdHm6K;$5rP50w;vXVCf^&cW`)3$k4wO4<2du8 z%S^O4^8S7l!eiqmCH^{OJC+e6zh%S4)ET`4Lt8pJC*pmW-Px1(7sG7kM?k#wn~Y2R zM2b9Bq#3VsROwD)xp8Rcd487~QKf-TxSGmluF_`}rMJ-HqZ7BqpDNidGzVukJ~4C##GuCvtJ}@RxG2KX1Q=g_&vRX^;AuGvDDBJoTzF4_!1oZMGL@Yr%T)0`(J>#s)4_^!$Y z{{HA)@pfyXvK-8lCT=x3uLaY*=ekQ(42iu=R5+m2?1$IxDa5tYe{i6x(KA5-;^!3jKU@@V!q=q9jBj_KL(1_TSdUzpWMHGl=J0 zG1-KggjS%Go)TW)Em-KAJMx=zJ%KeZo2~3!NHUvRs06zuGJks!eWxP+z8k?ahD^HHh7L@#lpL znfgKIt#OG8XvmK_F45S)b#!6r+L%5F>JBP)jV7gz=X((%qvfVze)Q8@7%i|>SC_-d zQ{Y`${UZwftTw^Z%khMmoBW0XV8;3BPN09St=Ag6W0m)h;0pse#-$sEzi33~2qI2N zX_o|<{vFQq-DWy7G+|DD_7T~C-rR43iGHNXy1U6VzZ7x!?Ca9Nq)!a49%+@lV_VbX zIHE`QktAnmSKJgPwp)G0?#+}@)v7_Q($Na2L$o!}bG~aJ{zcXObqv4C?fuIi1kJ9Z zq~(y55g|*ksHo@r(mCRx?=S@dyeLGM)%X*o>upcNQQIY|t=ALCYz_J`!d77eZ@TJW zBWyVYkV;r5bJL479oLK9F!UUO8xEO;?fb9k3A;IaR~?`pH%IL|Vwjg6O zGPPBCknaGcw@^{)u$6a{j5ll7CnX7(L=*z3`Cj%dNSjxYUT_)ZZ!LA!-&(XrjuK>Y z9u-y$>|z?>ZzSx9D3u>f6<_^n@i&|vEtPde0bDLYu%4>OK~F_SLkILR*9pdz=5KFQ z#M}I=#0W&USKv~D)0i#y3AVM2Rgo$ZlOEcFW!dEy4qJrB;%@j9nbOez#S;x62g9f- z8HuC?=Nr&~e2mzvp0?ZoPwFD&C)V&e-m)^V@#irG7={tei#kSJrMm{5FSvUMSat-% z2_lXv0RsO^lW6Cu=UKu4O%Prr#xL;p6!c8|022>dN_ z*d0aC8jLZFqdUt<-&G0{ER`}HLF;M67D*H8?dwB=K&apuc1o^bt|7>=EblFKN;|r> zJ6=GzB)LFbLLqUpV$W|BL?G<#$|v%M->9z%c+eXL@-}SoU}2;#7TYTDUnAN^DHm1- z18kh>;{g800{STe=^M=_k3JYq?O#HbU^{yaIo}ZJqu9-1w%wzmT@+a7@BqlaZQmnJNv(y&m_LV5|ORbI<>w>@6Ic ze*C@dZ4B7R(T#L>x1$?IcXvvsD6rApjdTjq4FV!1N_R*%3W$Ko&G+{^=iKKxPw$V| zuDw66&vg-DIay1oGh)#L$r;bY{u1JBxivHH!3;_ygi`5&VPwC3rQhq)Q`CZ@VT>i1T-ZlIxPJfcvSp%^IOP=NS||jcAQn62=7< zC0m7#Bi5U2U|PY892)h1PNu;Rr2ZIiF6i~Am`RiBciGPV<65Z;ki@#T%{d8Y zkb=s&%|-$$g1%7=3@7&0{k-4lrwd>B3? z&O73@HWraEuD8ERotMF7lK>58Zt||m5$kTFdCEgl%E7mEco9I3XM)m#QUd3L6pjRd zPXg$eNKTyXHDwq%+8j-O%N$A3b}HVEUeiklsuM@NPp^MdOu`qvxO>n(9k*S`H2#{G z8{GE9-3md&@Yt33jF?jSDF1oy&CNNfnFhdb2hU+JN+TiR!W*M|Zm5BNFZRnvIv}@J z_~)Y%@&5U@@N|&@P!8?) zv4gd66o7W`k0j7w{}TIQ3r(-RM}uwb`PzIqXFGN`X5!RVD*n3Jvkofz9FIq@ANs90F#Rj0?g3v(_PlRYmfqWe008f2c zGxC0gYsp-l^u?4oYhMQ$m<*$OP2m`K!kk4H(YM_|^lExoAGsJa2a)wUm1}?~oo#&z z{Ye34-Lb_U#d#neKE;Ne^{9SY4?j9K;lurSNvoH9d~Z|lToe}4hih~7t0!Tcj+deB z>mL2rW^DY==bk^azsNqL`q(^s>~l_$eYtw}n_Zu9SgLJViRQ9KaQTfk05Y@Z18h4d zSo^Fd_o&ME2tXorT~PrLt=IrL53a;S51Ck3r^s|S6epkvVBn5WRxL+E6Lm8oO;bSf zyQ8E~Cgv2S4q`}W*8~(AmpgNS?Hf^B^F(u3AtX%CqpGMS4Vj!3g}dND2Py_ByNfOq zf2g zZWl1>flq}<0T7O(^pjyRc0UgDwS7QU7?;8`7)}Vn*#DcOIu0eR%o4F|xi;AVgT!!A@IF9T)i z-=5)$UYY@rtnhG%;n1<*4r7DB!fl!OH%1+0?Q9*_BiANJLSNf+g=0B&=!lFPrDtFi zckM!o-dpxG?;)TA30+JZ8Xwd^o~i}T3u{QZEq{=ZD)ia!8Dq=1f?EJ5K*nfZfF?vo}yHHx_HYCv~ADij-Q?uc}7}K{qkX7 zGmetDv426A_ex541IudmeZ0M9~X!6hnFH>;&`+qSe`V`yppBj5rQE9RxB&=lDf}gq&9g}qIq z)&Bd#0v6#&(*t8L0sEqbH_*a)v%}4ha)t6bEq=!W5b|zP;VPN^B=+TOjxI{%OJqF_ zKijaIpL=-tYl2@pIU{<`TFr)hpI%46B^S>372aDrE6tm`9gAf{lY-K}4Jgz9+~+2{ z?@fktlO#eQ(FO!S4BMF{M$cJtN9B^a*Vu$(>^8$#FN^xp@p!G~(9oXpT5T5fzpBA4%=T+gb*tmjl z?m0Uliyj9D6`VC^sDLmwoaOzhs*&LFZiM8gqa~q;W(gfjMC1yPx=da`W*4)|KF+BSJSW(At{QT~=3@V~4#8 zWoxyj3zL>P6vow3b6uQWS=|z%QXasMD#`dKWsg-*yNeZ18H9n zut>f1J>YUgLy}|?qhqPaE%F5m@9TSuEONav-&JK_h~g=|U?gfM-yiqi2~Rv9SM|{4 z&rRCU(*C>(Zj|$hrYQ9Ds7Zi$LrOcb!ITx5<2jWohyxoMSBqe}YerslpisBCb+-f&OA^iZY!WjyRse<=+(Y<9 zSa1!o1`;=O#s`5qNoU<`X8IPs{|c?9inn`?JTBTHTft@s>y{ZKtmL*eU-mGjuT2(L z_K-wDYF(een|U}sOXTm)vY?7j-$Z~L38Js|fdX5;zAxM^&hG>8-m`S6nqs(po4Y0)p`Mxmbv7mRjzAhB^4HX?UZ&?=9q(dA z=W3CyLkcd9QM8^DlWJ~Ca+i)^ZZ1V+rk}jH^dFW=-aV`kC}Hy&!APmHHzp)+?jt*S zt}1*p7jfds5mELE&ng1K=2*+aStfE@pYcQ!Z0L*Qa3je)>v`m zy!!pMFw*@Et}fN9ZV~Ud9k?d(XfA1&Yo=oU5MhB5Z2Epw^2O3%=x;G%-XD`@#RED2IkElwEe*Z@ zSaF;zl*ZCFm$v^@`03|qGls_cl>YNs6Qq7ZF_~Fm{}=9ptj%A4?*{Q@j@!9^Z@P_5 zzSn+nSUQ-rNX3&;oicD!t^McJ?BOS0q1L|S!}Bf|0q++#VeU5(@_#hhwn8Uty{p-MvVN0dkJL z%&!iAKNQ{*$buOZL7p2y*%d*(5bPR2MP{&FdZ5( zKa7>2DK;hdLG#WFt^RvV;63(mQ%v_z%--V_gwCvFJZ828z{lqmFe8Z*3F_&JH6q6! zi2%^g;?iBl$9E;9sU+N@yOTP@IcE*4eB& z6K;mYug(&#*CY%FB(PP|8z8uYZ-ve}lPQ)ThY0aeD)^1D918r=PQK{I2Dl1Mrd`DG z*iA`UK~&J7L{hOtNE&c7Hp*i*W(!mN4SM1i^i%rcQnlF zJvv()O=wqGGh5v6T?Uo1)IDS48yk=e9E_jCVtVcMV=(?b5ZLEze4$7@qoT>dmmJs3 zi+}WhdhN`6xDtvf>{zeNBADh_lE#ZK5KMxQhQRC!NL#&l63!p=k4?jz-O3BpmHpziV zI?)A6*yR!)jDa)5Y;Q~c!5QQ*C`^L>>?Vji@zQ-dQcgGk-Db?ZuUaFJD2uEcArQa_ zJycS*@pezQJ(m?qwq-d93@ErI^-+~?5D*kIGTM|=7_@mL>EC;K_#EtwAVs~^ssBz~elK*L|_QHlJP&MVLfx}9zNa9IKfiKLM z#qlWy+?CAUT=*%`SPIzgB?DzhlO4rz3)N+ZdOx~Ib82kZ6^`4S)q*UW_xC)N%*PkG z&@b4PIS*h|Ri+4x;TzxzS#Gm z9>#?qVFeQa^K=nKjQM~}S0Vj^vsBTqL}c?VY}ut;Lg+yqC%I{ef|w(dJl7#Pkcp?-NFU($M9s%(!3L5op^PI) z8WJalIY+X~SjVqUbtI0M#~@+BNYlk6TXjy(XQ?%C)&g?snsRVAls>4`WQ08r&PINa$bK zDLA4hG0WueQZbnK0#oYfRHdq`El|_9c?$FpDrPkj8{`OPwry2Y+F)s}!KvOx)o7NM zlIY`P)5FGC-!lB_rAnbx?Ml^$A}Lgn_3hEh#pWsoue{z;=#2{Xu<6ZUEBwYMJGZ(AaBg96uJa=>^I&i3 zTyzPP-_^=Vl&a?3l77;!NkDflSZ#dBk{kEo;F8nGwt2u6ypfZ(&BoAk8{ZMhJc7K{ z5w(V={K>Sq=ot?_8~bIdwh`sF(@OEdyAVs*FujF{%7Kocm$V0jv45nJ)AY=oe1c}a zB|EYI*jsh+j3p-_|4DXc4T*DL`lRnK%OjKI^efggXoVSFY&@;Ylx2;R-BUfGL!r;U; zOBLKnBhQ_s#22zfv3=lx_X+RPXRds-6X;I=r9~vHo+8&nux_4^HuPh!gV;rCY(9}V zE<+4M{Ijogol^T(wy|3|VRIa*aFyl_0JB?qV>Rgm*)lr1;9hcw51*fZrzGX9gfd&2 zJTr?8IjWM5P2A2gl1`ZMEgI9rE4kJkf`HoA#dt@H@LSUPzKE0Nu;M5#8z3G}6{iHB zy1^xX;OdKqteW+k8usrYFQjFXe%sy;wFY>s1U8!`O0cOfiINS8=m_NAgL*?AhfRl& zrV91bvUYLVT;mQBwat&l!al+3q`IXaP{#Rc;aHqVoW8TSQ7}p8pL+L0v8eB*kRkjG z#bqPGCp85;P1H+GL}f%OLgQ`= z%m&t`EIsq*p=~M`l%I(R+HX1FSEQm@{*!$V_<$H9ibB>egRwP3Dn$NnU5n(_^@^_) zJ}wN)_)-Q7B}kp*A`+(Tet0c|l3X?zXwa@9EZ4+e=bb51*(5fqsRtwoA^Ms=M8T8# zu{xH|r`Q|Ua(`AS|D}&3L)1qPQuWQwo+lb=@iB;xJ^o@u#Il23$6pJnf(aF50`-f+ zBIq-Q5$V1xV%IUU>&sqY3F7bOkY&;MoVvV2!nsK_zC&JBoRMWjIjez^G6z9GNve3g~s+{ZK02Wq;K`Y1K?w;#p>+8OEOds7(!#u&`ZagSdu zR-bewrtOLYqPdFpD zM|!2~_LaU#uDHg+#&ssfuF}DFuDaXH38DMzRf6xoS%rr3ezLVPYJd#QOw429$Y&={ zi}der))QEePNvrI|DAHB+s>dgfklHFEPLxPS`y1Sc(>Z3j?;=M=sNt-ZFinH=ff)x zg`j%0o;zS&Z{bT3=~tI4^KPdrnmG~OT_(ysFg16`&P1yXbSjiEWABx*{SkJW@o$qo zsM`tcoO8Q(W6nwhxA&m3KD*}PgFf`*LG0wHC70!1$?$2$+ED~uCA}6qK{#fLfC)C! z)2woh!|p+89xf}np`y>Y$oVp7MizL=t;VD{1}>j|eo58Sg%A;B|B*E=Z91t?a#>t^ z!uLPrwMUw(LP*K;zD8Ro!rQDxh)$dSAFhb6i}!Kx<0M|h3}udo#~|Gg%&+1(eD(^r zQtHtwc{6~~WVS2mW(MgA|D}mH^wZ0R%$O$JeFW@;$xcq_j(+OjJPT)W26)4#ixKqG zPt^pv1WXjUvY7w6n4X=@W&fJzrb!=G1U1c;u@Cc3$r}x!y^BKN+R_M}V-s<3R9Snk zteK3-^(E$eBTX#&$zFT{Wt1Rw(*FRiEm88_xQ zt~jJSO5t(QLTBrSLQ{(a@VP6Y0V*m{P9AEN^|rP+02~LmR(ID_2foy(j<^Q0RI&Ph zqzFA@V-#ccSk~5HG@2eoXS&XDf;8*mYHO0}o{F^*lmrqBSi$M6^$wRq&AFYlUbOV2 z$+m71dDw4O3||EBHQ*-d-Z}!Bj4H@$6~|B&2?`K!O{fDvOV>A*80qqX98OUI!fg_f zg+zYKe4`OvxsvA_*uQ&2n1-6cku{GIs*O+J2a%qGOyN56y z?(L@;Xf2G8SLl2JDYKye(l1bvRS*$ql*KCX)qi6q_4vSe*l{w-!09~>ojBWQ{#3Oe z*K3q0!P8M!lmc@AidnboXct$yO4!4h)}s;b?NcdK%Q+n)O=>Q7er9FcI^|=6rI(HV zF5p>udSN&DXI)8sSNLQ*POdL&c@G6tSy9!{w-_XA|E)H2ycPrv5_`>xN=T9_i*FBo|8@$epSK9u>FW zOA@0bddQY1Y1`GIICAza6Upap-{WH`X+{Tq7iZRR)g|$zqEGRQOiT#y%8pf_HPF{` zFe&Vuz{$;1%tKUI>sARr^Qh8|l+g561^eKQDWX@7pFoK{wpHT^Ji=jHbYwTqm>5rW zJ6=he2l=P)otn7JYyPCso9EUzMSiD;*hhgi zt`=cu16w6#N4ca|_9#~)d0MqJ9iFiEV|?HC zp+b`!4zE$(kC+*xw^90C#u;4a?b4Fy-&De(w>e^wuNLW~X53@E?LG3UrR@{3yiy0W zpvy*BmBEc#iKs$w`X{s9t|5Vgh7)YNwxD$=j>m0mVT!Fb%{uQ(Y%&WFRKU~gSl~NI z6aQ_#hcIK-qiUy$nT_u{e{aZ)lNW5gzAaK#b0`qKij znQf|-p5gE-^BsmXcd*jO2E%1yPcs2zMU~e#8V}VK|==s_{IK(&K>+&+R!fO z8qy#lbKU<{XgeH93&1$<>*5>%26d0-2$B~GAZ{i+^m+fCo8xxkC0mJ6p)Quo2hr&_ z@u~MwzeHx4&`UU&%h8Yt0ybjfO!)i}wn|EXB{5CzYPvn78K8g>{nkR!u%witHFJ@} z_Tv#r6Jm%L;>FdsXs>`#fbo-5wBYZt2NnWN{|}xcksm^yL6W^#pQ}`Os~IdU3@2J} zmlp&Zy7}a#t1*n&X6?5h5Ng~g>!;2`J~(U}4VBXTKHtu7r$Cn#l7!TW*vc2+coBh* zKmJn7eoAyIhe=^gfD7~@)sdR8$#WZVWy;Cs)Nmn|37!Cr?>)YgBp>!5dqqY)A1$)L zAFafONGDhl;p|nY8BaZbkI4AO1bD@>KuZ$ ze82{DaUoY#&e)Q^JK|Q;cH>QAWkLG%-(OjDbJL@hj!WY5)J*?;qqfU!9r}9$N@t!+ zK358iw{TQT{xzhJm@EMc)}@n9*x39wcTv6nu0`;5!+~|CyY5W9%zm*foi0|P5Yyj5 zT`dvtR_i87taK;;lw6Mk|GI(oHWGKQ?YI?2_~E6gBJK}jxu&kMI)f6|LP+j*hO13w z#NjzJ4a4sIeUNelvrQb+dKseaZe)M(OT=?34fc>s4!Ivhgj#wJ>Ev=~IU321CZxyl zS@ue=fd}lI&+`xI)(B=9FodZ66A6SzRdHALzof(54~Q2LwdG77Z5$xDLye$nhwrUb zX$S{*Q*wA2#hGFS`;kw_piqR5i^#-?8AXv$j~a1AhT#=V^2io*HVl^>Ya9KXOBvqF zgKW<1Bk*cz=H+86Wp^}5=+Hk)qhm|(U+FThjs)mCL{~!C>;d?(UP27!^DZ4w(6jY> z)4t(sRu$w2kl!{}^ks2g5m)a}@0P9ufI8!fLBd18TM%>B~A~#+{yqaegq3;)bH% zW;daT9nAwfP^Pos<+t~#Z{+OP0n}~trHq!bL2lNxY^eg8EFI7E4dJN7-L|wSI*#hSY7kfLTm_BPjilT8 zjNf*fi@>a zJccyXx$RMf_(w<9k9xoU3M!PPM_X#uT4(y|^KeLQ5WU=LiG|gVekf^%zS3RgS7g`g zM)Tvabppeq&7`P}GN)#B{)JlXN}rX}uS4(It=l%MKPTR@vNq8;=CQT9=#Kl<>?wH0bUz_rmQXC>F#vHEj*=`T4iJv%ieK*<}g-x=(AcnWZ-#a z^s=K^OeX#a?}cv!Z{g9y7mZo(*qbWJKPS9TLwj;%ru)AHPXF5a*Tr_=GDiFNF4e>Rxc0zx&h&GG$M!(zvwtqO zVQakuKUby)Zab&{d|`a~eQON!@SXPG(42?g$J%dyE`Nm`_dYm|eW215U|k=au4o~F z<)PC7k{}~5_eJT@^yWMY(_YF1gn_ScakHKoPZa90s*TV=kpqHZPW_ARVFB!iJB z7-SivFaEjM-iLh+L`CMHgJAgWFkPQng4pj`1xEgtZE9h}fShWtwD+hu5r70)~BQ62~phL=2YG zi@|_uJ)Z!B>Ie}3HvYSv2cz$XCRaX^j6seg3$%)gWMP56nPnlMPKcrxniQN&Db>}b z#tM=fcS)XdZ5&c)oRXl61>a>=Z4*@P^c=S)G(u?yf3qK%A>C5YR(E7)U-IX^GZJ&4 zA$+fgUIv?FA;}Dv!BEDHICj8{ON$%#3_QeI?(((SWuO|p_h<7V@|U!ckofKd zAxmz@0BLr)39X8bky?m~DL4qEz$r52YU9kEQr5qxj$J!O9?B*Wgds)5PG+HR(~{I< zsWe(`B4-HF_?VKS*|w2XMrEV|yAb^aN+dHFCd`1=Z1<){@Y4!ztU#JJ2{Y=J&}Rhn z!COdWp5bH$h|~5!@KqN2(J-lV7p+B4Id3$BF*yBX*SdY5_sAcj->&xfcrEZ=Xq*6y z1!r{|#NQxc4sZhLwraNfyCHqaU+#*3M#q6v`5k9T(2Oc8E#(U`t8$BFcI6fHOa#Ro z=7Y(EfPi4X8=`)=RgGM3(PCmgq3BAf#$Y=u*#W*QVIb}-&TK8-ge{@k4QyRiuYsOz z$(~wMU#Ji!%NK{E3g=~mXY~vC@|IypW5})zVj#ceMC*uk)RF+1xG@hjX7+I~L^#lV zbppu9nHSlq_|wzSsMB;}xzi}IYgqpfWqFj_C6*GJupusqt=GE>Xdk5ruFoe{b3uX$ zO6b(joF58&=ObC>WuN+>TixZ`wHe633l-DJKZw7?>M0ju%qsCB%uo`n^?RI!Q)raY z&qq?jBQg^y4#STc=*IAm!LuC>Fy3hAn#(f~O09@vg8ER#dm7z>)qI;f)3DZrcmfBru z9@v=?wW6O)q%Ji(6GJlq^U@zH%ki0MASIj)K$frj47Xm|ijmkobP}4jA}+QBZcHx+ z*pzOg=b9z-_D*0I-G%)EWe|4KLT!xC z10tadwDF^cDX>)6rq)51F2I|CPmrnDN1uKcOF2YX5i2UDr}4ZeRK_XuvMx}C0y;^~ z#5I(6V^IG+z2<}kC&8iUiUdzTL%mYRj>NRM#@Y+RMZHr20IN!+)91kashTO_Tp ztkaRhhTsrv+6jV6V;n}s_<{(@Gub!(#vV6|ib1--D?Ty&GbLZ97w}W!1iA+!$u9Y3 z*J$rNY6n7|e17_V(^>^i@-+Pz9iK|m-6q9@!0-c2nR23e7ew1g^vf~{#WKG;YpR*k zl08>oSOMv2NU=v;XI2CTvNcT)K+y>GoY-zeCesxL5;+WL&* zcL!O#3#OcK zS!~(V|0>f8$Qx@m^JGNgP|Q&0PvohivpJCm`qS44<}*9rr0jjbPZx0ITjb$W>i@&; zAo_ajrWWue+ekY)(diQFhg}}+LEKw3XQJ=;-$D@VOEznzti_8D9_+&%SNsDv^(B?F zR&>l6N$+!NBymd3Dcd3m{j!;lTf-}2pkGg>vP!rt*eXifoTW|1Z_KB)W5%ySvdR2( zT+tgCLd}A^WxNUHIV5DhQ<6IUz!F)h6hP;TvWZaf9YU03ebYAp?REadg3g%Fa^E;% zxgrH-DiW{-!+$flO$18`2}nKGW<(H!O01d^`f3q#ouH3=sqs%vYP9&YBEL=PHoXoK zSEZn|H!~nclqfo3^yV~4OVQiWIfCz)1O}~b0+v)Z+^3C;7CU05Z^t7Td;By_+UpL5 zN` zSsGi6En4yM$Rzhz(I1PWn03$c9=cJBNe)}h4GW6zU%fIFGdE93GxN(U@^88;c!6z3 zgWbn?6j0u|q!fdC-r(Ovv(6^9{yZ?GaK*PE$onz!TKH#u&?BXRY-7Y?V>E1Iyl7*x ze`9KMCFX;&84u-m7>kH{>@_L^-1VvBd*{4#rn49mKT}-Q){%L!;Oos z<*kO5zheFukCU!HODuQm-=(AYVpg>I*Z%(bEEWlt1Z;yXw`ol`-uABEjDOx|-QK_r z{c4f9QS`Z8dWWE~eJyO~lf({w@$$3v9Xd};N!V_%(*q+OtuF=cE@S#`zv}KT#tzTG zNF3vV{6++%}z(jJvUsEaNyQx_+B`0 z0GPKV@Tqm*6TCo?a0&cWw1U6OJ#dV2Eu#8HB85*!gPcI*%n6bV<+DG5D2tO zp_)PK`MU^LKBKbq!m~zuy1my!2YL!WC&7O7-)LbmT!Qc~&kATkAkXbJ+RThk?dq2x z^paT7T5C4LZGpAn$P7V1WGhfiV?Ilmj`ToF}Z1UImW5AaIa9(lYTE~?#KUk*;?cDQ{A@xG^ z?`A5`IW2997^lx4F;r0U`sNGNuTNJ}T3BpW5QSIb4l>_OQ_+GvNG2_h8vh3W%ttdk z2h4afeSNV{Ne8k_g%Ek+Fn>KY<$1U;PW_Jl1~_;Hme#&K_`B!u#8;f}E-?E3sSM=H z){*Mh1G~59J%BIxmtTK3-u@oA%X@pRz<7f;cN@hAPMrb&DZYvezs76Afu~%OPZO#a zAK=3;dHKM$R^K~b{_1-5E9UhNOUrKoCD-%-fC%6&G3p!27G0h1`)M-H#8XJb(|hqG z^jhBC_>|xC_<#DJFcd%Yvh@7A`ifcZ>)k;zc=^LmV?Mx;%>M36-wv7IseqsIe>=>+ z8X~m4UU}ZGe7(AV^>7S?&>L$*(a{4;#eo=5k${xc00vX_G^-Q3yD({~KYXWzzX5HdWln zy-Y)MZvi_m95AE8Ehz=X%N9}a3d7WzS<3Izgk!ul!vNIo zu&lkj`D#SDT9I0N-D17*8<}y5EH>UZyfW|WMWf>?sYPZQU&pa;5@L#sCc4Bn=7^d( z%QNg7lg*k2c@WUgx^Tv$Of|U~uEaST_8L-#0jf>=P}X8A%&!_yzDX@NJ09NAhxYP$ z)HLiuY^yE3xRO43p72`;p26ta%kI3Y8*Nc5pl3gJmu@1n&~iyI#?)}CdK)bI zLqOVhn2B?@vo)ITkwzqXQW}XMoQ2zmaDr%uIui=Bxnv`b&?H_a$bj!U?Q;QTP^-`J z^7pK)Y5rtPfSaV{l|nm80!cZcgcMO^WNXB6@v~f@L5$9a<{uLx#`|R97@a4=HqyDM z7N!^EEF!yQi6W=R<*7;>g>C`qMyako(c*9-{TbpXIRxB5Mxh6lOP1UdMRt9$A50x( zW!YtNpMn}yS5)yfpEKsh^~YX9HI8Q6jfBI)hOHtRz2i-DZP!}ZDU9$aPgz)OSy!IQ zzn;%98s*rnBHe26r|I+&nAm$EcB;!1vA3FCQ*k-U`L*w6>BDhUwk7)qrmf_W+}x1S z{ct79#Ma$Z^Cb@QQ2JxZ@Hj%48*VVA+?<-$=zvKH4FOgZ-Pn=4uSv>kZi_uHVVr`A z79cABB8~7%OPOn-%$0x{QPS_~(Jb5G3KEHDCprp=4-~qCrdhEly64nRfjSPII3{jH zOZ%#R#3cT4Ohiw&3ls|rvb=Y(AX-U)#!!Uy5Bl32{a_( z-X5WyteNmM?8tch^FW)$jC2sMAoz`Kci5Igj|QNdX0kHl-NAe6fY`>|yCV^2Y<^>qGHtE>tN-%T_0zC^P8P5T{&_4 zjh=8P-+Se!iiJg5Qo;Ml?>il{v)52n4i*R3)zTM zA}XruzLXG`Ei#(qKQ*@RIZUtOji+{_@mRUdVOj~+IOYG6B4mF}aMUQLTpk}4=^-Fv z2Uy(=V8#*UYJ?&~%W3b%$7Ft9rSu%r^MIlMQ;P5chweY62(%3LOhNb2T0OvjOA(-x z+Dmd775_*PCMGW`;hqiumLdq;ay@G|r~hM}`@w>mAnwy?B`@YUwl&tb6Y0F_TZ`xkIEDeE*UngkHeQhiX{4Ejh4@m;R9= za8xjLPq-z2Ba#V2QDi?#5d;is{*fX?Ff!XP`4edu)fsk9F5=UWRB2hb8jYzfwa7W- z8ROQQF0Uvr94-+u^}++;1SzH_8@KTO^jA0;`miW7SOu6L*4 z2ClLD#Z$~RDa0$z$bDlvx#nH&g`$Cp#vUo77{`nSr^yl!ijz8$5jB}m$5Z9Q+dGo`O!n!SNLv}Q-odG2hYV%e zR*@uCr)u_dF85PgmFUM4t ziyfcZBaLW`Eqqa}auz*4$KShcR=|Bn}2I{fZ&Wv%PyJYb1 zjDbN}z+=7O->rhjFu`M!;4w(>SR?p%ir}$9@Yo&rujIgEZs4&s@K_o6r!Js0{}>ne zudcvjQ{b^E@YoXgcQyd<|L24800+>K5)r11R}hMuOT3z?@e2_mEzoBb`EU`ErMYwK z_9uT@&+UhlQt#&xuU?51f1b;}7t>#VJ%mU6&(=V^n+iQe`hT_tN=nQA)fzC#RL-vX z@2!EtI)&HW|GPEtrkB5e{J&ZQ>9*=qOY0k(Tc1-QPqz0D5G!hHhiB&(UveS)gq9#Q ze(rG0_n9~535n0>OiCl4 zqzCKo(o78Q#zBd>5USK#~753wpjeJ80$p!WoPdtBJf{3#;|v^9Re z^PCj*bC`H>Om?gfu%J+ycpCK%_e8L)O9)M#fCh8*d=DMLq*9OB^+zbs>}mZr#>x?L<(B zm)`^qop}A&8u%QhR2ow86bbsNMb|=S*UxN|?03LN;F;d}3s`VAj*f+ANmP8u;CJ!zZNw*`CrZdHP2UQH0 zQQ;d`mjVYJp+Cnn90R+zH1o+Ccl#ed?8MA3kdpB-5s<$F@<+g}oeya+^l>hVF!#&= zbXWySGaIhQ}t6BaYjr|Z*CH3JA&;t)&z$kI)h9LP>qW`v{;LZ49dB@qt+P?um$Jq($c+DHRfOv z)w&)DT|M7TR>xP?3lve5cO?`LG430|X9`*?94&ws&)Y5wC|a16hf|zvoLmXXbMurc z!u*>!lEwx`4FY&)NiW{Plz%@q#J{ga`PNvP&SMS@#b7wTZ|CFe`hH>rE>rTunoG|1 zxvH>c@C52&2dNOyJ9M9ppI1C7fpZ`r&X=o0FIyIQNSU6@0x?4=exiIE;{o-9as5<^ z&3Cu!Rbf!4CR%So${Thv+C{x^hl4pBfE;&Q(@qoN8225Qo9Ev2>oS_{H;HNsQ&*iT z3tSa;0JiW2DNM%OYr^&mCb3VnI1T(Q9?zWk$-YUU6ZD0S6fXAR)~kP058r*O3P*STxDlRuaMJg8KJ2TL&11$=!xzK_*lpZtzuwt9H>i0 znMZY1!Xw6AAJc0wAYx{Z(Os!Y&pTUB)!yB!ExU&#|V z@xk&RbyXrcP6gkT^?z4aWzds~MWUBcAYIflyhGR=iQ9hs8`7Se{!eq&Kahq4rbrvq z^c;PJw5e*DyNT%+Kfe(yEGW=Cs6Im40_Cl_oE-i?=Bfn>-avX#(yB~P~z^tLz*S*f+00w^UJMa@75!vef+svH@sN2 zr}^+Eq}qDRjM}^ZGU?6pBlUkMZGd3=JnXL5^2_zzTL4~DxHr~1km`OAqQz&Ay#f70 zh!}z?dAwlMuvt=TA11f-P~k1y!8^--sp{1fqpYz@SYYfaDvXX+#kWJ$o7?g?tT|C< za))AFtbxDbDk-o~YlxPiMCzb9b+KCv@tQncUaKWNXKJ5CvU@_}MN6hpNH@FLk4fWC z*Q`<$QO#PVAX7X+@oug|fg_XygA(!VcLCT$8GgZ~j&>IeB% zqAAIZO#KsBil!H%!Jb>w!HJYZ*8rgr3D9cqiE$JWsz5J{Fe<84-=^(F&y$B%+4g__C>@Xu?)NmnAA)%isi29^>m(APuK#2S* zc7bc{*@y-cb51IJ7hc<&o=KQ%fvt$@O)*BpIZ)vV*UsYnkXh2%+_dv9GveR#E9T3JVLcg^nVfe-d|1s`?hWZ0TOEH9YgOBKssXRy-M%B zqoIR--a(4=4$?%b2Bd=uDu`G((eGaCu5s@^W88gyIsZe($n%-6_neP% ze57|(G%hF0_F{riM<-SM(rx9ncq+r)YyvP93gt)<=lV8Hohx3=lmpHY1D+>VSo7jt zH!7rr0-~28+-w2LCPs2)g_=ud>ZJB^glh9zNyeGwNvJknXHTl3_)%ib;#3!D?ecLO z0O6*%qY|m2{gz8q%|*`r;kL^SoS{J|4$xs@-zw*5n>P8LZn5%#pH=o=S%xw(Cgn-E zZ+Rp!C0+GyZPQo{)_y0kkOp8LK&&G5$g_tC%2=Q(S-+C^Mu|?P?ME7V`G_*h+uMvP zW0$fyBXI==om4GgAyn*=o@ZB-cUgV*)79HqL~iC>uHDh>x&Vy>V5`PehCts1@gO6` zK!uw(0RZ=uxxauk`#Kh(A02TmJJMnygSJ~VSMG{*X}X0kETh#G8MiEOAb=`~Pj zw$QQ9nTl@wkg~k-D4?NeC|a5j&ZpL<+v8L1NmG-;*tRAe9Tbu_qEO5YCH|atYXiSl zjWa5(Dnw_z2fs|KL%)bRFy80s*sNgU_M%o;UbIY&aowjRRc$jj8NSS{r;tN5&&n+S zx_GW)zI44XAvPPfLRvxum4}IF&vagBYL~arckf@Ohlxjhr}vAd6)J*mch3i{QU!kJ zB%d)*s7#LGX6<}HqA{?%Pl-{554F7!x~c7;J;`@e5{+-?9|$+--Cq&Z%5U0rID&k} z8qOJik`vSi10y;(yV}w7u8D&|38GAJZCbW=^wBsYdwqly zpYP?G5bX?b5pI}@b2d56s2CTkt=~jr0c+$}DpF7Q9K^azUQEpV{gx&ZRWYb#&r|D= zVfk|@XfqoFdj_O!9BC>JYJ+o)q&|78;Ko}Xl|WcL!h2FZ;6*zVZ$g3Ln9M;& z-!aI!t=KelR5q``b;#^jL93Q{bfa!DbxcgIdWPMz9<{>FCV)6ECJ#zY+tF(mQWY7( zRX=-0nM{N6;))^?Z(|@!>;z5^rEX)RIOzQi`iUVWQId3a9odZ`;|eME61&+nu_jEE z6+rM_E^ekibcL2F9t`X_09NPVzio(y+c*qnX=;`cv<`NWnM83k89ZwkqQk=>b~c(& z9yYIcHiy|}vFL8LAiMi8R{BAMn&si%NKAB5$kNF+q zOuSJ?xmM=?O7bT$EvZIE?c(G-ddh>@PC)PF=iq4XA~?xU;<3cf0Ear@eLUa(qDWnzp=iGQbOD7X0LzE=k*@ad@!~2oaJdDQ&EoIzxO&l^!zL& z%Kz?l@`Yqi8D(l>p=Y+nV{fg^H*7Q|v4j7Jq|S~YZ@G&Cn@s7P>Kk~hK9yH$PED@+13gm~mn}gPCmNE7 zNdXK+lNz8t9Imy#n0rZ?d*=`ISa^D2YU{Dk;=g2qCRjTapucSRKgArl^rV|p%UN^_ER+77pJ(O5!U zMA%)q_bflIYHmnAKZ(`ewcV5&zq}BpoFl@p$$p;{a`p``wzKEKLQk=jFB`zhnG;Dr zZAaS5jg*TM5>}XSz(S8m@t*u)*C?q?YyLq}+V9+)x!^fJu5~MWwo|G8pq17lf@Fd^ z*6lH;3Z){*?4hdc^+IY&TN(G(mef6LGW94XP7Iq&eHxrG?(k>6q4;oQ==x&P73)eh zy%VeQSAEc|C*Q!sN$ZLSS_D1|HjJ{vI)N7%3gM?Nl8mzh zCLOJncRY>Mux*l79vg|be^)?hs16-M`4)YCpE>O6&!IFrs^a;8%* zxcT~*xz4ilJI<2Gtk!E%src_(55#}|AS|nB8lYvdjQo)Yq1DHEVLNk{aBpREr@yuP z3-s=W*ZL0ZSzWu5?q`iW%V&uwlSxw{OWvTb+e%lG1MR8EtPQ52k73?3dB!pE?|vQ- zTnf&|%DWa=+OI0>J&a6l_*xMavakE(MP`oBMGe{ac0lZl*PSdc?TEmGhZZ-2ue)_G z*GP><9bd_;NLpTYlzvOMB@3N#CAI9_*lMG^GaUVC?%PKX>jTeEJ(w?ySA&c!eZF^l zcl>(31&+C#ryiUfuK+Fxm4AQs_*Ev8nHtgLO8KSet+khu0qK{ahz`OqwhF=PlvSn3MkR^Y1**O7(tC z`?g%KK5%>6ihWBMYJ0SC(|?u8@JJa1{4XXI0|?M#ne^0#B2BH5D=)VM?|AtU3fntrG|D!k#|7IWusV>0q-!Ul;K>by@mQddRhe=s} zsAP?W{y#xnJTMU}{d5Uedz|(!>1QbFd2vb1Q`OA>VA9xfmH%K;@Bd)ZnZO~Xk=cKw zpV>I~K&Es`1a{hxCpg;`MXN{0C(}&(^*lO!ZwI*Fi3#zuB@hfNvS@0BQhrN9?^-fo!)jBXAqd2oc8t$gLoDEbuOlB;5(OZ0cX`@G+$iPf z4$c}WMnp|n474HzH?h*syX$tJz8WRFe35~ek{9<6Ue=sivR$jkt}C~(NUvo)pjuls zZ$QC%)g!wdvebt>jp)ByRc5X;fmZpN7TRf!h9Oqj=zblT4qp@b`9TT|haLJnS+S9cif$ zr+k+-#}}mU+x-lo5}S=N1*|i{6qS|lt1!XzK8m3tjH>`R547`9sT%fu?;}m#OS7)s zCFjZ>iE*8ePXpYYie1Q47C<>9qVW0LurCFh&D{*+;6~K3LPbM_5AZecOc*j%mH|T7 zgT`rZqwS6qb(Y7IA^1R=w{X|{X&kCQs$55m@e2?f6(;%wqq#K{Ky{mb_gFi7=NC(3 zR_|b{AY5*E_MQ=KWa>`Qyy_49dUrFzNliP6^MORM{5O?SiZs$uI4#UIcnX!I=Qp+; z^GNV}Z2-^(L>ztWV)}s7%=5jp8dGW|C00rE7LEkye;60wX6>{J}T`EWTp)p0;N-Hy0FOB&Hnt z!cQP=(>3kaa(L&4v5!|c^F@b`O4HHP{ng1w_i)?CzX9!=C%F_4erI7ssm>x0r%DXt zYvz-5(ZUArxCuV~{vpUkx){Y$w!Z464qfhM0tzi4AY8BFs6r6;VKkxsJZ**y=`Alj0U_`cibAoBAHV$vDRR%i)L3(SAh|eoJ;G3~WQ1U> zqt}8OP6VGBGR*!qC`&(&?1ODXV%>(QE^*>U9k7*qZ2xv_Fy0U`O=4;^Y|-{4&de$e zPcVB_=%EOa;?EK~oeAtCX`duFqcjU4B)00@%+9YIN&ZfKTxR{|Jmomfk>YFI-*f4| zHsp7FQv6aCh>8E%koRl4_0PFfG(uf}mreNZhJ19~?k4x&4S8Sb%0K7Q>JmYrK^#iV z5SJ?~O1tIHhP<=5z<|o%4S8ipVh{Qm2W$|xj9C+S3ZLd>`?DeM!lcOicSF8f-HNa} z1npcxk@sgp{*7IPIF;Ss3He6-xqv@GTvDanfyOI^u+%5+)&C0O3IWcMV)5`96vNk| zx{=CM(I7O{3q)?~=q zW>j_qPj;WWQb$FQ4(3?|A89#bnY6jffITm~Vo=Y1Z{t4o0|1xRr1vZGQWq6Hc(ia!?$mCk9zf5}35Ip-2lVXE7)E_3* zGV`PP!=!Z%w6(Fc$P6r#3Q!uJnN4DuRJBULMRM9)05%W3bBeu|{$#JWu%m)#zYdT8%HU#gV&Yqy{z%UM z+t*?LB{}bEUs+rKdwBepmNUV{k{R<5;Cbb6%GDNay}dj zW!KDCZ!Y;S$$7KmU9V4y|5D~mLe&35nNuL-sijdi331^}7za;1X`8urC z$6-Q3YI15SXhZcTSK+V=bZCS=j>I$H+D zUeXZ?OeAgpk(_rxK11`^(7WC_e33VR`3fjuO)S6)QQ9viahsl&(MqaQh=UH(%ZVx8z*y zIQjofa{lLaSR6-|+fF=BMHLozIu3Ud;bT1SlWwoLVf(!MRqs>eE)U;7LE!W5rYh68 z?_wjk>fM`kZHc4Z|8VA*xm53ESp^>LJ+nje?q@q?x$oz=RaEcidUYJ_=fO?(=RnW^ z6=ECYen?61gw)_TmG~j=p?(ST9vz!u{$N~TaC*rh+j%g@QCWtG$5DBw%}fhVXVEaI3ALVWCD6ilC*10++n;}+<2*#|r1-zI!c`9xLJ)&{bi5NCs( zfFB1XX#4Q6b@%gquts|+Shd#@!e6yVf?d@q+@mdry({g|AE@Tc@iiG#KZFe>;^ ztF2XYgq%v}mJ0QP4Nhyd3qc;5a(nWgH-)IIR{VrEH%l%|Uro`%QI!}@*7ViaOYAk< zrZs@W)+oJmN(FQl$QD;#e0yUUlI-7$Mo!mpbH7k#X0`i`|ab8PXh$P zKhH*JZwwrD#-E{3XX*1z+g# z8nZAupJ63x+YhL3u_GnEZSogR9w&U$OQy?gq8T|fkW{>lmc?~rngA&@=*f}Eq191e z5U%~PdkrELzo*V5f=J{0CNpBs2~8)4XkMJfz_G8xgog+ooDZ1h zRSnVV#?^=O3dCB~#$Gmb;^9$fvoOuuBLQ&|i^(LEtRR|$pK2-@{z6g-;GuU`5(r|= zNTcMch@-1Yv61i@Yh@;@_PN7Ru$QMxk*6J3dh9bLAj&PV%UtmGME5J>^Cwe9xtzi3 zBYbrCq2F>NTY1K$lvh5=7DL~!2z9EnoYvZX_Sgk#1P%BsB;UmASnW2B6!ks~JGa_& zgpoCuB_&ja@c9eludv)DY(#BPD^xYVkEJZu5bK|%WSF2ku| zhjiSDgGCkft+wf03QLxQ3Y3z?!!IHX5&0r)`ncaApYsk+(KL=~RDLqLvFtEMzDJm8 z|MhzeNpi6mtBC2a-VbS=ar?x7Ux$4y0_#*M3LERy#34Xiy_NqdId_bn#wv4^CXC|9 z=kb!xQa?et@5FWw82OQ}u?lfVn85UDnly!IwKi)#KH#dbC0!ce3(@4=0KKf=&8Y8CPIY+OOj z_bKJTXAF*{bX{9=W?gak~MyZtRne1e)v)k@ifJh3ubM4&yk%arm)*=&WG-%nge zAk(f^P+wVFQX|ZWqKP{J=g_hB8s*K2svhfj{k||OeiPucQ5R-$AL%=y%tayv5w$R- z*cFX(tu?N4YZ0TN0My+-DKXd49)PUo0cLh2CY6;Vl8fQHRF8@xj(i5dce{3Bn&|!% z2+Z%;n=#lVM9Wg+tR+Spej`!OS;HUvIVUrTN6fSx{lvJ@@^wP_3d*?;54##ZWL`;r z&HL`lq!2{zQ23gqHzKP<*ted-k=%DzLq!z)VJ zV;rYl-{i2}hk}u%PV^${(07i|1M5cfet?EnDw&70-{%XeZD`pet$O1nTAo`FTd`4i(Mq)b55In@XL1QXJYM1#{mhp?|s(rEk*WEy$p42?CfR| zWK(1_kK5@{8#24)q-Nf3Ad!&CA9es327P%JU4Y)ZmvTgJaF!?<#3P2B-ir-^sQ)aEh1$Lmss*9X2-(WIEGCMm`!-~YIgPqo+~rk z0hfbHVS}oqQ3)$Gd4apou%X*lIt?d|eEkw{UVKOovCXku%Y8{rR>kXw@nR9hVFwDx z=;+#fqL4c7%1-E22;ID^(^9R>y$(7#3me&b4HWFQ3XyGJb=ZE}oXqbfbnx;1bd4kR zvBe3=FyrIXhc%H9c@+WSq1x%bk&Vw=dyg7dO^BC5Sm-6KL^vAPWP@n8ValrUFJFu{{%vuuR#(VM=idQFu$>EFBm)=G|7@t@`YD>6y zJDE)IZ5&|O5S6I+cuWHqc)mj~T+9bo-Fx#a!fO?Mze{n4Ryln@`7_FmH;VSkImCbf z!ghHN+2N;8pxKEId)4My>1y-46$cRK`97(0$>68gs z#d4m7t6YFXt~_ui#E|Hzh9N(EtiK$xKiTMiFtyJN|h!_ZRZ z5u%c$QYZ-G_S+rD$2e=ujM#_ku~5HnGhvPX9%f>^u!+rDL( z)2AcppZQ8ZyPt#1M?9@MOG<-!SHKc05kR)sj6&42Or%%cL{wE%pv{_f2;?TZ2JtMF zJ_j~Q0TFY4YnPFHMSNxQ=#`!8%QMfPa8ll`$LZ#|73SgR3JKYW>;|}PIvvRu19YY# zczh(+*(Vp<=e510VnE#=#U-I*1+v>Q$#+0Gd;l+U@~67-lnDZPzfVdTz#0X`v_Hi+F%c0CBJPs+m$|<~- zRvJ&$Ak5G@4iF{(mORIq5N(zS!hQIo8!I_4BD$s`FA~WeL=YNTh?p0q?8KA4C}vtO zz6znbJ*qrcB3C}@EVCx46jQA4kH@lJGEEmOW&cDk)7q2Zwyye(2UmPHfCqgEQ;|C^ zK`@kwW=JIms=xBpa7h(nPw>d*w4_~oY<~#W)PdbnCx=;IYFwQ3l~jon?_qO>`Nn}(gKg4J`|3c4qr-|m?5D4OT+ z^skXoQii>kY5aOz@O~i^oR;$t+*qW-a&g^Ata(diRUH1}E}*CKQ$*wI33mdbCOm#d zwzCEj*=8!sW}47uy1ZtFo@Sbu| zJN1wy=q6l044ynENCMjVWdJV_1&T%C-R8gPOp=AFXaOJq?_%TBQD2jS1f_dTE$OJP z__IzJ3>;{OohX7B&3DHW5#-Hx)%3hr=ceK6j3VF7)(U|bVMW?SrE&AXZhr6!ez3P4 zfmtZn4+)lp62#fz)#de0jEBG~ zwId3NJG23s&g(zUgYy08^qv$Qe%&Pj^A2yEL@GEPHXcB!r>c$5YI>96HTQ2oWKJz zTZR;+T1{r1cJ*%e#syF23#7Az5s#P+6v$1LSxr@hO;zPj)$~r)ZB8}(oN8j4ZrLnw zRH*HMzf|#ppqc1fH>a`xqsYV_0|D^c=~CGfj{aUU@1f8{_wmH0AtC^PI(5AFWQdmO zMMmn(x);=GF{Nq#rU#)-5Z?YD1lU6{d{z_P+Oh#o&tl=yQV$ zNP2Ne{g|veem@xE=j=`om@i zaQ*ZbY0!sfeMqwDZ^UlDi1t4aZR>1KroOxGdv{z<{5$y_z-Ds>jv3I$oNN*0)?o&i z%Zb2Kg?F}j5{Zx`d>WbSRQ=mbZ?{=~Z^Kx2*yMLOY<9RF?eIL`8U8{fH9s^BduP=R z<_^Ds#Lr|}_e>7@Kce|VZI}!zARiJZa_wyy@5;Pk-xyt}i1RzX{vAUDf8TqmME2wi?5S(7iL2o0KWdLf;+VnqGW2IG>+rmukAe%j7G~aak__6h5Xock zUiRb`HsO*e<7ZjdTnqs2K*xb9*&a6gpr64{ig2$UQnmi14M;tFQnaXMHQuX5CXu=n z567q2gdCsxS@gciup_uHNERx)Tjoh%dfMZCx|}r7O)fZBruFhUbl9hNiOYM|x9P+e zvmXTjDI#W%2{RG%)$p-`^zNft{FCRqpOHY1ftW`pt##6?j`JUO9zhD< z_Sx8Ml{a-raO!~s08MlJ6#Q!?_lfb_fXF0lftOAeByJ_R&LZ; z>zA-%vAdCjoczDBbD%G@!D`P5WZ|43hvBkcc{8wTN z+}YmU+dnv5s`-=H#<)1Jy`lbS;?2z+pq|!_v_Yes97YDvBs_jz87-^?@z@y|JCSMB z*gT0SuB1qdKE$k?kj`6Y=L-%#@xALSRIpl$LK!y>%sSZY2vTgr63$!VP&u2;h!%j) zv$-mWfsN>lrxrY{M^$`siD8BZTw?M@s?|*i0cjMnT2M2FQr=ipL(KebUK0qYwz4mB zR0bRf;9>f7DSiUq-we(HivaI4?XhxIjv4g6gBv^}aYUDHCU!V~3brM*6hZw{3ZMW@dbeO-h|I zQW#9;Y?+8w(r&sEJKQ^eH$C$Oz1 zjXgO#%au5B!XIR%cs)AG1W&)6n|u-10d{;p@1$glP%Ot+xK0BN+${?$TT2OW8V4&; zH(VMRrNZpTiS(nlOPIy(+@RO_$->K(a;l{}QmOAGcX07|3_uBJ01aZs%qJIW6oP>( z+qfQ13Sz|q1NrM~oE9bc){0rT4=CBA!1f8INpb67*@nnS^TxX+4|9cjn+dTly>Liu zi4UjTX2>Sa`arcZ$gNgvMZ|?IA#>5xm}F`)nuZipRb)#N?>zZDvYlR74AL>o zrn|WEI>M$f!?}j@&h2ecN-ZZITB=Z=(|HmG)Nc9@ue z5a8`r6^i#=$*Fv_HE$tn^pn&uw>r0CX22t`EC7bE5q{KMsUO$!TyZVhtCQsQMD~yY z(D}Yhs(LmWHV`BGJu3@L3(c>q!^xwt(`>rQD$z3tZ2qEXov*aNDaL_qmFk5$a=!4e z%W`;198_x~S5704&g0-@HwR9$cWwN2xoNu=p1zM3{w+%()jUC!VsO+q?CxDX#bgoP zGH^`jHJ4vEF%}R%Dm{JWd1NC(?ZL)feVsEI5(dpsblVY`)!`uat)hHINSjdv*Q1a8(App^AfNm|YW114jD)#xP^pSEIF5comi9*VS zw`uKR!Pjfk+8sJKj{C=N#yp;NGRf<5rc@uVrAUoAT)dgrZZ-93bp)`lWr13MT|XsZou?WKjRMl!88xN zB-xz~$Z!BljI8cbERVjyd40ciN_{}9$(fsVJ zV?S3e5#Y!{SdcH|tSXc8=rED$o6Bf}IMI5<6XY>2Bj!aq3h)o{PSCc6(!m6mu`5oG z9iz6Iwqpm{(^Xz)WWrN-qcS~5ce0vN<>%V^xk&yTh|4j zvt-F4Zv*Q;RS|}7mccq7>4u9p0|u(PW|Ke4$Pf`MYIZ)S)j47NJh*lLI{ta4Y{Q>E z?`M{8FC3RMz2<9keX+llGwOFv?-NyrbH4Ro%|4*Jn6_;W&+`0s`XD2r^6t><{kJLd=Rn<@U^=ry({nZYJ)knC z6%Tu$zCugRHK$k(>s?=8G2f^1iVVUYs2RUcs6VQeyP-S-FmQjL)K6*2nEvse&(gf` z)4+K~=gb~QZ0GbrdrS7Xmjq|j_Zc_rt4Usg2=P?&Fs47RCbbV_4)$k}9j(v5%^b)F znRO0bU|&t@xcOqf&&TP0Eq(>VXAv-+j`{Oy@&mETpQ;FpElHD{lP0#$TSOXgTaI&! z>kBK6mOxY0-=@ez&Bb4XwXQlR7DQ4@U0kLOj0~=pro;XHq=AjReJ3ik8y>?n9WBqS z-#E(tSX<~*EXvXO;9WB1_*R-kjz@B!eRSP->2aTU}a1LWoiMhcJe9oRxh&I zAozJ&=qUlb7t_AbRT9MK8|sT9Cv#Ps5)q8#tJ~iDQO6p2?sfmZ^7bAZMxR3NZE~E> z2IDs6VZ^wr%O&;Df~S|z;xM;&fmkE~{23}xOZTG2^4IYO*P5);ojiur^TF*r>04PT zZrshgyO-Li^2FyJeAE$24Db=GGH2iS9Qc6%|5_$pKZYM!U3OSZO*a|`_HO(&$$YJqE~O-IP!e-qE2D|9l`zX zbd5if#BJs=hbu7!EWo2O?D++Z>KWI^%7Bedupn(HK?^WA))#;5QTQ9;Cu*p4#c&s+ zhfl@=(+R>BFYYfQf-UFqEC&K~?LdRupnDh}1t{Ltv&X>!k(Nae1%#G{ey}ZuF76q= z4!67|3@^zJv@i~4nh3j36|GSPQJx_1@b|Zd1644LDu*s7wDNi1qQi=Uv7ZHrsrb6{ z!Dtx1HR_=>IHof;MDg1VC*g___))Vn`tKQ3sA8hKH(-ZeRsiIFFiY z;5Y?&Q&bEl*4j;6uPe$G6LW@)G%+Nkg5x2u4wc?5czy~kR(7A1F9U4N|K69f+Zw&g-CVb8>d=X zA|+zrK}%0}_8x{A;w*q=ckGJO@}jTdu<3LSNe z{Rj)lLOd3UOY(37DcB`{oN!B%0^MuE*Xc^`<%x64NO1(AJ^%u`VgczBsxFum_Yq~1 z*r=F^l#|sP(&ej^4=DK=eOw3i(DE}>u^HGH^TabXJ_#NXN0;D27urAl?t}3>QHktZJ&qA|1pAji+)A!o$Simna_bkg`-K ze6V|ho>%=Xm87OdG8P+hZycpBg%_gkVQhwmnkSn~xbLPvRTRx4o&bUefL6h`%_bjF zmk~NN0~~k&jL0}tcL)PCrf(n<*Dm2fhOC9Vkng0wvYUKmpnNx7jG|=JS8-q>3ZSHq zRwr;{L?&2QM>lX?qer93klAE9R{M3fY$z36m-xD~N@S4E@32CyuGk{c(JQF+u2l_Z!BdgI3AGbQq z(MZ0mf+1{GjHFwYh(Vs;6{NQ29uJO_iv>L5_P=z`4x7(Vv4aO{q>$x4Oj^UUaWA?* zLHzhTNllZlgFfzWv0}$EAQR+Sg&lf&{He@~Qn~e~B9pAAAuDxpemKgXYeH$3p-$z@k@7Q%4sfa50kCgpoI zRkdWQ4PgwoCX{6=J49M_o$lfBQXmaIy6YhAy*tUfs>)DPv;+@!F-d>!9%0#GR=CWg zRo-%cI$W^aX;vfh})Jix_H3_~gfVLrpC5Gmp@De3giVCk--{nd6}~ za5C?*Jljfi=b_U)3}?O*%~zRhD4jprmDRFt^Yp6NSA?{9t)#?U5Ai)&v@4V$H`yrX z`HFgYEZ8-ex){J)D#@F*fr<6Gtd>>?2C)`^C1SGX(Ne3#BHcBI-!fPhG9I`GI#pYh zr~^R@BxboW5!czJ3{5y%iHfw*_X!HSq~kf9OKJw6(?FW&Cc#tmvD4Kz9v$w@nV1M( z!T@wm^Yh56qS#{U?i}s)GRIE*S_|+&l~rC`ifNIhEvD*40?GAcoV!M9Mt9tCPX3cL zd=m#fOF+X;e6yND2?sqb(7cgaGQ}~fZV~ysCN+&%E34+PxP~>qvK+#40)M_&Ii=T%0<+&t8m=@up z(sS1eoW=4@Q)A;bg|2v8@0&&Nju(sOmU#pxeRA)3DXvOS4`h*U?ok7T2IH~8aaOXM zsHaJ;&6CJ!v*knEqztMFb4#jX8I(0RYb1+gzZF^q`E%1oHTFd1CSnuA-_YJNmV7T^2SOjTM6$T(m7+qH?Sww{hQrSMJ1 zaZi6=Q1_~St=@qplW|njQMmt)qH^*g?@@1ip1#{s-LH5o?$;))$>c~S_Ps}N;xSd9 z!^-;@$p$cY!-AhWn?0}U3Awl4#pH=@NbF?NdO`p$n<4be<&KJ?4gI`6xYQAUbwaBD ztZkHV@QFqD#dIjwX;-CZA;m_pBrO>_)<0RJZm1@Ph%bRH(Ol^?(6gxPg=Fu`?;NLj zeNY5qcwqjGfhBoL|*SgxU^=~Q%z3k*c>(58#mR}9?Lh0VKtCAf|mY_ zC=Q;g=5A8)v!~Rt2rIdk?Hm$Ut-*cKVshHpdomKUbRA6_q*lGYUKWts?qPA`BVWu^ zaim&~DP!xaNv=9u_&jTTVv~c~Ck*~3wr`A6aC&@swZ`@spPOAbZtpyNe(j}v1Oj-e zVqzKMswY&SQ?oI{RWqbQZ*sfkW+w7yPA_p)r3zxR;+qI-BoCWJT?oCrsveKGm6&>Y zt|BFA6KAsh6>A2bB z&U9GKVlZjH8DDY62F7^J6ZXx|txP$(csMfEBvsy&6VH~qSuM~NEHLyfFl{Zc{91r9 zFS6ZP0#wWeO%eRdQ#)6P%{h51`sCUIyReCKZPmEgPtRm6j?p6Ak2IAvgCnCQQD#yJ2jW z3(&#a2N+t%eu6UFx0o*OEq@Mebig-rreaP+(Nc_47+^DZ~k3X0`5F}CkMVgTz@e!9@Iz!Vaa>Z3}1>t~r*1~eT-p#N; z7Ef`-Z&uGVJk8m_EJer8uT7vK>hhSw!6KVB$Ko z87?AKq0a?>jR-@4<%<-1k(6AeI zUOIA-T^>g;M8%(XnEEV6p?vAq1BX~6!Kr;wuq%~%s^FtV2U!6FBQ06(ks?Cv3tF8f z(Zp?acOL^seI=73eK(Y5&$;{qHrlmc0t9V@y*ierdvBjdLhp;Rhf^E9mQ>v$p>B7U z<8@Ls{l&%_MNjTe1TkULIluSb&tP^|O!TW(rGuq%gLGv?PMG2wn9+Oa;@htan#M_{ zedW(w(y6PEVB-6{0U%nS{POGt)0+N`US__iLNYa#eA|?W*3K|>$RcOF_g*}X!UAx8 zbc9+A4|I(HfuIbPM#MKT+%0O8ZFaSfPr1rL98w5gJe#|@8i-u%4_6#ly zG)KmI0=oW?p9aff`xQtTrXBv*^#>r7c2FAkpttyND!k^ov#W>Mn55vL$ib*Ju)${Y zpHw(Bm$Ate@l|G zN;y+1`OEoHGi^O|dA;|o`G}CgGGzWE)xDeJfpf`Zv1&l+TaB4#a|rtOBIehTqyi`f z`X(i#*GvNNd!KgJrNYzPkoz*ipM9NVDkH$mC^38?v5->e?*`Z`iL^Nf!3#E-4-q6% z?`0?EC`-JLR0Bwq$v3^>wxnN4?e)32^x9etcpM)AZ5Jp}ESpwEVqdy=Lp69hV-zEY zOmYhmdh!PLzqe{1Fszo`Fityml)2kyrS0*hXbu z__TA2RE+d4Eu4xJNRhSONX-eo@m2;n;%@8`dDs()+%k9qlNGU*f;veBmnm{&$|Ygk@AV&DPiz{D4aq7I!rxM4~EQ* zHuFma0DOD}8d_T|$^+GMJ*uh|6R9J)qx2(z-PHlqtu#7O9+JTFw$?jYJxIx#6iL64 zC-sr>QG{yAky8Ljtd@^D=#)koSy!Fnl&IZvWda76STN&n(%l12iL=EfZLhN)Ov*@i z=>qK|(20B+0naZm%Ckcxd;dYI9qN@%Q(x4+P;7{D}pHiHn zG1}-6c(9E&d&MfHt_P*J*X&%QXtoWFjONJ4#>*s%x{g`R zzT%Kt$Xl8VEc&={>~I$!2Jl-opRqDtegqaPZV;9lo!%CIDloO?CaZ6CF|bzyW94iO z=5<(B2GR&Zc^FxK%|DQQ6<{eNUpB1Eh~GH3@T+c@<}}y-s>rekFSsjPfEj$(|I?XZ zXd1!ymYch}x_OiUz|yqu+$znCPmhlTN({}AxdDq+dP-?+AgEv@7^$m(2?l`S7uu4_!6cV-~apK*^-5m&S4^x#Y zGh2PdB;#mQyRuUQ6@d9n9fu{BOb9L&OObYPB+6a0?CVBJScn0Tr4v5W7u?nbIM=w>uTp>)DHx)e^$Dl2!jaI;?H@cd%iob&&l|=%| zb=Tl?>=Jum*EpCyFR%xA{kA@S;f<%AjKUJO$!o+?!RW* z;t>-Z9WlFPNf$mS8zaIE>+(+hV#H=XE?}M((W1Nwtu>xu9);8hOhOSo!<(a2LzqJe zDr%fZdm4(nhsrBHA2Qcwatow4?5o%D< zr(Nvwget0}w`Cy=LdcqmpAbTwU>Nj14X+CQsb5eoF7PUVG>qp&`DYw{bcKC+M!bd> ziH2_LkTNO zI=U3K>NVq_uk8G`N2AnxW<;l7Iijl~w1|ekGY5%ML8?!uLrAA!Pul3X=#fwvcUk4T zD`t0Diq%ylK93mmN5&jvj*;{8Ta-rQ+;Q5~W|x_aR+lp%O(!W4A)X+mlzKhjh$8lu zUSr~FLJ-~GwS!1cEgGk=mEaP3-4*mIh_NXy#+M(ZSIa4VB*0EL;|5~LPN1dwXi5f^ z=ZnpAnCH7?_7vc~7f^2%ooj)gp?;jk0hlnOIP$6f_5EX7roplltRnyOsbP5H3~_B8 zmjctk9(LP@+qOZW)Yy1TRbMtsvk4;0WzQKm2zMSpG;=ve@W*f5Y-cuNGR2+6?S<@Q z61jHw^@kSr+yVe8qx-A^QeRcWy8l>SLRq(luQ{u?XZ?OWXDw2nQ z5y*LWU6*~R5?ojFQo}`EiIA;@q&%2~9|IFbldEAwpA~*3_h6!_tqT`;^ie8{%NEY0 zgX7HAxdWX+u-yUpj~KTF&x$5gtJ^m(rXt@@&_<}_4hN7XYpJAw3~;mQC!@gJRL1IJ z(Z(m+csUuH&Xl;vy-RqfVM{e?g4QcAI=C`CDr22OcrT|TSDenwBat7-kLzEtQ@;ds zkP_H81zz*DQt{bxF6Bt+l+APXClvGBtZO^hFVe-W6W$~X_~=i*n9zOq6bM!HSe)n= zt|2$7{wZ4X>f^^ROw`~{LiW={)^+gwg-q0||6r%jKq+i zZ(9)Yp<7K}HiSR=9x&;mxznY58+k{bPmfg-EV8dqHv8z_Gj`pH7yY~jRbyzXI{}=I zZ>za29S&-Dw?^ul;2Tzu0Prdw>G<6Ik=z+Xh@OmcYUO&tZqhlPP$R&G7Wzq=YjxwX ze6;9ifRk4oRUNt7)o53V9&`V2z{h}#vOacw0>H*5*~PE*H_OG}tP%o%xX&Jw?0PEwFWTJ;6+<#acE1C7N~Iet#_~Y ztl6{I-sjAmbNvmO%=28&eSbeHEXS84Q%ea#P>`(AD2M6Jn?}wVPRyo{x^Iy02OoWC z&8Vlc{)H7XUyh3_ihQXiCFn8MWDvW!-}c_a#N{U@xOi@NkFsVmQ1SDzB(q2H`wy64 z*9>c1*(xMy(o95Rv5p#;xem`0Zb|#0iFAFP3ZnqneA7(nMq+JV7jRUr_$X0FU7w1V> zF?alYc5O!z_`YoAQ&8ySTChU}uJgul1lhmk5{Jrdb#WzW@d}nFlQC5oIP&7X}{E~4V-pp zsF6kWqlX0bhm92ZGQ0I}Iq#@BvFeRtRk_U-N0_M{P^3OJ31r?_OTIY@S$#>Ebgn;X zYy%}5nOP(#2CM*BG{XR?BB>xJ`Swp>hDe$MC->sMUr;+Hr8UhUZ0DcCgDN5S&#>Pf zd%30coYHYKV0|@q*DfP#&G2qw0VJ`pCZbtN7#O@6e9jiQLCfJ}%3$lCG+}#zm-Eoq zg4#4fKDx5ZMxP04$Ngpx?Aoj!7qDqyMn>c)WAnD+MF8P4yF|jPG6Fl#PjWbP<9PpI z&`KPcw0vh1-FbdU4A>lhab*)D!7gW%t=OURoSTnD7ZI@&WuMGw&7hz>VNIFb8s4HJ zW}u`LB*(_hAn+I}%q9rc>1O$8$HEcBSoztPu#|1xmvMktxSdobJks9D&};^Soz=#P zr-xAvm%tj!;@Uy4kwh+nlKXZlrUYoqpKC;P;HAm#E(3S5;PX5u!ExljXM49p4rdp4 z6Ac_kgFvbKs>^kEut~$nA*Lh3@fY$8^1;+{uq`aTR0lt|T=aNa)YzrL7ZIbV5raVc48<`` z2qRJ5Q8HI|Y7{B+9Kz;>K6!0TVr?CLc$xI;C162N9DT;Krb?h9BqxOhU~I?uCzG%h z3;3$exjovTVHt};)hXM$K+J^bS)J*LFW2imc3EX6c%R}32YXpC1b zDr7Ox2vJ277Sk=CXUY3dmM{}#t#dD{a}&sg!Sg)b{P&5=Y&KsmH3TXR#rlJQbz9w#11tkRWC}Iv=FSyH_p$GnT2p3SfcL8y`U8_ z8?`A9M{E<^_9*M@)#|cC>sGEnn;Er*8+FBZ_jUhlY&Ys+TwQZR>+8hLq!Q{I^Yg>7 z>TLw;+a(%0!4#vTwM`P5ef7#3ty=lY67`Bb<17_WP(%LB2iS z+#}vb*3d?44y){J-kxbA3G;?M9I<~HakfrIAm+XA1(W(4k9v9qqsteQv_(wFQqH1B#abKnJCW&>Ro zn_asnUDk7T((q0j^KM7U#yM!)4EX6|jczV{44%1`5fZE8jn44p#v$1j@adC-xDF@t zt~%U+N1?6j4&KjeGe-G3z-Fc!LcN{rB`$L=xR?eYS)2T6MfWxUssXdG0h3kzv4*Vr zCa1_{!o#H%=Du;vqK1C@94=Bhz=BV8s~;vsYyXIKp>;aO4F!XQIN6=SK+iz`J3Gr_ zjlj${ptyCOw;55rd9W}IyJRF#l>v)q&Q!9sj)(?_L^P{_k8bpb#G}&q_|M&Qvdj$) z?M4f#m7xm974cu^`c9esA5Gu)UvUkQ4`cG+W12C*y9Vl@x`T?DWih18hrc)(S_d-f zdFWL-4$EIM?=q{LKmR!nxaNuuZ13wV2o55%Mp4&pYv`VZ4Ha#6?<%$|RKPeHfI7Mb zr#ouEi9WsQZi#p;$$+@a#J*lk@Iu?LfznXD+t^KIY4N7Ww&ZAzf-Y`&Xv%3d=>qcC z)M$2a&jK}FHf2+<4_Bvutk@=o% z(5Q;@Ai)`KO7%3ag+re0YE4#FAH%*i-A$SO0W<$*lY*40{brN;8q2hM%tlC!=-fB0 z7$OUWIqez*@I|Td9NudS*r$KgQ)~B4;|r4c%+4RW5Pq*0AfjpOfk&zmPWe zm;soTMb!&Pm`%nzTyWfk)Foj2uQ2#xxE#;4Npk%){+*09?kI)iYdtIymNH~rZN(F( zf(wzS2IZ|Z>nP8y{F<1b_xMr>jSi`7Oulk;K5n@ z)R=YYdmCo_sbzoJjdE9r5H5q5qMW#ESM9uJ-`^C-Q1i~bG6yg%D$llNKB~N~Y)zhcI9;}?kblEM`h8jjB?`c|Hn+TEcdDupoz3yK z#`;ojGa&!!&`u{_!Ye{~6Z`T_c@KrLGtuF>7V{_j=UWI*yk)LyzTPvlnA%tsDm`6n z+(nv+;ZOI)$X$Az)i{5onZX!2xT*{u@bt*V044sYVR`k2We1CAh&#=4xV)xKAX0R3 zQ0=PbYH{ADe{QQ_>3e8hNV^0d=Cq-JmRRGxd=+1ty2Y^=O^&s_lDlXs=wiLMZPVQ3!mgHr`1E zRtDD;qC9;XXB>J+arlq`8RMDX$OEn`n`n^MaK-k-<+Sk1y zL4|K#_*m~`7{c97TKAi%UKIJo?xj;bMAgy>PB8sEe~W-`tT7_djk(Xx5>@bi?5fP{ zK8wA#QZ{}0$HFGdMn%srL@q#Q;785z&tU4cCOmxcBUec`m3EIdd<~ENPKNZDuf9#j zTWJyt{7&^)XPQ;s6tt^hPeU<1znZ=MRs2Oi7f1h8PGDCB2rF&1>fbG*XQubyd(RAy zZ)XC$hw-{1U1GV44v>_NX=gGH!o9&9waUt9B>=TC!92V_;0u{u6ZW>M2Zj@N&)YqI z6UPLh^%+{uq&OR(f}h2xw23_AujylfVQjz!rrA8@>tR{+o^Xscxhjw1=W{kZux{;7 zP8EQP6kB8Z`!~iHQjoBnQ3s5zuYp@g;Q|ud=@}q;XFC~t^Kt4N@y*-6pCT>J%au*< z2}Jmm{+Lod^cu<9*633~@8bzqo3+UimvuF|=>posqcPHGPzz7nMGpv7Le|}Ir$*`BzRKy^A3@AgrB_r zj($cJ4bI7(cu6FyM-m`FD4wPtLt`-6bc=~suJ7j)8TeIs)1}q^7W?*b>jg)+LfJQ~ znxK<6Sy4`cut$=*(qGuzt=!m2j*j4@pO%-N+S@zZ#*R%n%8`l9)AF~J>iU1YU%?8@ zWK!0D`NW9J=7(XP7F4Nb zH8nBM-p(~G-4~Uf5||nw4QQ1F_}Dp*&5lhvtO@z zBue_KW`V7IvP69nYv)qdroBB79!mfQv(Mo+m9a9laNpcMIt=Jt2@ZG2%1mw~#_n{P zjpA#|E(M)j>?8kVopB`{;88AiDOyQ<>L4xcQhvBqZB=`f3VAR&?j8$QT|`vkqM|WS zNdn`G4pRXMH-^FXYKFtlk5Jf&)mJODI?^I~l1IY{+_YKtwsH&)!R`(T^tJXh z{Ko-vKnxalk{dqDEBH@!wV}FY%4*4wFJEWtK`~-B#vFnViBDBjwIl$SpXC^cJU%nBYSXlHki{C<0Fl{B>Xv-(!@~`23xvzjisqUp z_VWwK)HYcy-8><-541@DzU6?o&KC)xJhp}^bjIwFCc#j8`}<@%nH>S;=kk;a*yQ_b z*0}z!{m&Dq<%PuGu)ZUs$P0R{>6Ae6W1MWuK7Gp{?yVSUOKox(teTsdx>8Q}qDgJk zDm$D3ZG%-pIg`wy>2U;l@x63f1^4<4{l>A-sE)1B`%@(tBuh&*T$Zl|8z&JG;ZQ7Y zuwMlUVvY(hv+hmDkqA(*506KCLw1c)w!^1n<-vIwv}HELr5_A10Cx#sTjIMzR!)LZ zGtE^g^>@YF+vg{lt-4~HQeLY|Njk|!VH*l>-{ufoG2FGzsv4eg07`v!C>#hgVVm4Y z*T9EYM2TK1Txbh1*H=JbI%|_s^+p><-LgAS1tFcFaR06IUc6xa5gW`$4kypjYzm(? zfAk|McAy_sEHJLjoE}P z7i)&h?EDgwGyQJuGey#_m&1PXu|FX1(fk#g!=yVx|DiG=5j(NAUC0YEmnN9rRx*ebR-KCHmpj%#-p ziz92~U{xLwxhH|{o$9drdm-ST3F47_hG4i}l=<^1WV+bM$N5sJ@w3;@UTv;Z9vw8| zP^QH=<1rXhPo<$P9aMva?5{_SUWO{ z-Q+qYj-u`IbXLxYxn)vbmK;ix(EQVTO4Aw6OER#p0CB=DXUt$wQc|4Wr#VLQsL0p3 zlh#1f4dU;kvU=+}BwYGqF+WD+OTT|B0X*MnVTQfKc@_O+)n6SK$`O6*pCU2bSwNqb zo1;8gXG!7{3EsM`@vs$2BL8D^Jq<_GSFwh5`_U>9V!UBW-?*@hB#;HcXY*8HgN=o#Su5eE1!t_ zrP3!S?Zz0h$g598Rwo|O=H3!;I|zGJ5wlS~Emu_;W_Om&TXa^0YYJhWX|ho+4#D|y znD(N@nMvhEMidsY=l9t`(#JY@mC*o(NLf?Oq}$PKa^v}O;VakID!gJW;ACs0}je{AHuAZZu<${Em|&iP`M90_0b^$T&pA z$s>D=fa!yfVU=t-ZPAY!ra1>e_bluXlwX>WCu?=0(zk1gNx0D{QA&;YHc9=lvB}-r znQ_^}m(_@!a7XMx%l(Qip+S?{x4I3EiZSFmZA*H`sU2rzwq&B;8Jx=v6-|n88QrMj za0-`u9=lfVYEw9*ga^H;wJ;y%ONP*K5eqaFreay2rfK}-Y1T`mqu7{tT4E*)3>L{r zsJbu@V5U$UxmDpgvbp~(q1HAKNhlPk=V8JjQ;VF`nnS#m+bZ~itv5{ThjVCsLKD%6 z$p%Uokwr(D2RI4_b}t|?o>TiyfFm>qUNvM(n#u*BY~mB4lUYsDTasNOc7*N zVp5I~y7hX`7TE-P5XEJpxZ*oD?4K0ySng8sm8>wf=Xws%-`sSYdI&# zFu;)t&HEcp}<>GWcFRa`Ih4@15mciIsRZ#oBHBwgXT z@DqXQaI;hkbpA3jlTQYgUvYA?K0ygbhF=WH{_5?&Ed_ zy+WZV=D(`~Qr|^B97>Xt5l4HT|O0E08K@dyDQ4-CLO;3E9P$A-Ik4Zsfw!eoP=pVu`tl=Pjti^cK4ltCt4st z6!Kn2Q5HC&L~M2#=N+rLeVH7MA-Jq7mxaPJ-g5`r5l*w>%{ch;M*($gZM9^vi{7jC zbW4Cn)MX%QIf1CJHz|s?*e_Hh1@^EBmmX{JfiXjvXk#dP4Jkf4C%?coJq(6)E_q#I zggDOw*Vpj8upYYvP>ESnAf1tg>2z1o&LcLoy_J6V#(GG-$1owczf1mMzF6nMnqh0k zo%|tM>4;7gY4xH&=aO3Z4xyABPAJHu9;K{oDjoR!DJ7%l3Y+DlJW8l{%6hv=R8S_j zBe5+zS%!c%G*^25Chbl|?dS+$SVo5GP7%ip;xXl>i{z&<<*p2hythL!>P1e$@AY)7 zp|m-O%3Z9->nhN3FIutqMX@X|5!v?gbclCy#ue;qECsMHl^dOL|2~AVijHAkjS(*= zkt61$lY_52+tC-eb_0GcV$X{t{*@cid8>2Uoz#V=-@Bd!Y4w~&rFP+Yk*)febQWO# zkjLBuJXv!81}k)F*I%)fA9KklBXfC6SvVD+Q=RtYh*$_5TXa93GSrztrtH#($3l3O z^o}Ddmcb5VmuPM#Y3J7Sa+mEQ3&8U(S733J%2*8K!UgS-h)OA(ddmMC~O_T`7EAe#KFFIz#X+r(AubJe4tnpSrxk zAVXQA^0#=E<~aBJzDhIo0)5vi=9@}u>S|kwYIF5!$Noga&}vt3<)lkxL^( z*(s0+%(VuY+V29MTa=?yD+HaGV6n8Ww8Cie8=l+tzB>ku+JG7t0h?-iKi|hf~Gf%IC ztGE5m?>wyU)Woko4|oVZRD@G^sa#RLh>pJLU@_6q$8^NV+v9-SGj?Hi6;1+b5HCvN z)$Nqsb~W`vrtQ^-zJGt%GF6hB-RZmP|y6 zN^MZ5jz?aiy?Zyqie+HMx;BPYnkPTUo4pL3=+zP|Xta?{@|{i+0IY8X9-BVl73?pU z9J(?en(5E3maKcI^4B``UIOjyX)4)3SwOqhKePmGKk z%9!G;QZvn}G^5V0`ut!O4SO)y^#&{J9-H2auefB1mB|D}Nu7zek09Y3Q-gF=qWLs!?K{NxZE3uuZwKs$o~Yt)OP zl$0&X3>gbl;cNd`7L{CM@Ki8}&o2>(fyaW=J%06U2`V{0mb@3jd1sf&hGt_sDn9v4 z!i{4SI|CS!B@JX5^beA`?_faVXqtb*Hk9>o^(EG#R34LUFt^QA1w?#rh4HMrXWf>O zV-#$zm=xG6WeF2QTd_tJf(UI<=Vak(8yJj}s;XC6^qS2|QUj3srl$P4SB=$(lbVZC zoV#wvV33O%Gr568J%%@f0OIlY()%nCpdWtd(`y%n6M*%ee1ZxmZ8<08!WaL9^i5<= zSc?XS+$YTz{eXdssxGmddGSHT5z^)y@;Q5#3rE8`Q=w*n0)}hcHj117kmGmLWyhw+Y)FgdpVmSXfbFy=tWNUy~-HH%-pqw>bIRD*)I6_V}LDvbNy z67;H5#0Zy?H@0WE?JMaPy9hR8U%8 z_`|*eQ!P(QR@+a3&18XYeyla5<%femjjDwoPAu!w-5fl;sr`%t*(qtcpRkLZKE2wZ z$gp336g7d1P=_B$ecgo{$%ZyN7JYG39?wo4m5tA zGQJ?VPw|CHLrKH?S>AmN$yC{PZ;%&_dr&N!(HYM;|HvErfmQ^m(+@K$4x*G5PaQ76 zsIE#N&Z|Kc_74KNhtKy^Up1b-+|%T7l`zXD#@zp0HYTk+$-BR5t;GZ#M{q3AzY0(j zWljI05cok>JoRNf$=B;*;u4{5&J;UuQB_Dg$R~KKSYlR;R+dK;f-C>y1x`g_!g|QH30PgKsKx3D=04 zK9^+5k3O3rb8Wki&ROzF%q29elE2mlIihd{SxF`DJF?DQO>#9qz%UG?3 z^O!`1Cz(xPwByq8f$q#SpHS%XFkUf}3O$Rhr%(gw_aghEdi{9Z(?y_O6%mzkykSa$j zYy2-Ep8EO0Pu;Gp5s>f02JNj|+nyvRwu)OoGwSe9qymo!L-F387kj#OhH>%u2p+Mq z$eEB`xBuNFVFj4WC^Ug@Gy1!lqpW6;Gz5mR%(;A7gR3GZ2($S@p^L0=zV9i8u zVHo~s-Y%Glyr=ux%)sX1RoeXU*u<33r_A2`Rk3rw*yRno|^Y5&+ z86jTQ&rD2y8hr8dcI#OKD-(wJ*6>xdT8Y=QIX%y`VU9TS#y@vbXkFk}E~e75NPJ;J z#`pKR_1euwvXgh|B(u<7zty+?p75wgKc-85k4XG@{jooLh;`g8N|E`5s)h4?@SoB% z{dGHRE;hRXH0voj+z>*hI_zc`>HN3&FBFD_!NEoTHxFugqaGsf3X3Ik!l*P=i86Wh z6#wCfZ8#=_p}liFFgghVM#Ne~V?IO?pvJ}&*@U_=*{Vr~$tApTR<)w385metisebo z05-U*xAVPjLAi|wLZl;0#JEzRJsY#y2CXZPkZ&ptuNIA_1FWp7SkxMFM{76-`XB(6 zvIW^=$-L8Fzny>oUuJCOqAN)_ANZTdnwFC!bQDvlvv!OG`8#Myj zbrOlre`jnP*E^ib>MiHGAFBQA6#+2?na%PH&X zo5epB+hU6!E&Fr1f^KgK>^lzMl`0Gg-@B@nu`bjaG+4dq?>c>`A`Gz1-aUTP*W%(e zZu!%1DN7u8F`!4VWgH+yL$~0Q+^qS_7%(jmQ$|Q%roArKI%?_mJ%hQJma~l>g`;X# zEbYniZXAOnInZc2WO@OI@kbWmvBK~V*#s|^a|IH)b3QpflF@%>Z0mn0Q790UjzE)` zcg=tZ&GRK4CeCqtGznFjGE}R56^WyGtek)Yz98Q+6=2;Rr_z?PR!cGbr()|p$x-9X z;(Ps;Q|`V}Z=AsZgg5~3fn? zF~Y+nv1r@Rzh7q~5txvJn`sVbF*{aMZkTQr7|1Z!#n-%2Pit=VbcQx3S1#C-MO%nR zfo!jg*lI|N^q5;-=z&*=*1kv(mm67!S|A5xx?KbDpM(*(L;o6QvKYCyVbs0sKK(jy zzVYy-_q~7sZ=&*Ef$poPwRl7dq5ZzB7%5==F)Aimt}1z{)|2ycn*@f1CI#iv*32Bf z{V$47y_r!UIm(6aQ+g|{q?p)#7UR{GWO@piLrQ$()6vVb(XW!lW=AIWlg`p#iqh~S zA`!p%RNS;N{8(&rHNUOEotgsP_K&##5_2MX9mfcW4Y0%grD`^># z*v8-Xz}YEmq(4%y%x!Ba?@pxqNHi;`FZ!6N^2y{j^Q(>#3ccwrrynEa|CMoNU=(C56!nv_PR$sMIXk~s z^AYOtf}D1gT4W`SB4Iq@Sy*w!ynS_Lnmne{UDjXfwvKTYIY;+kdcwq&K0J#S;s=N5 zzA%#MJnh>9a?TX@8n==|+LbB8yj0c7WN5hw!eMztFVl^B%B|jF8Z~PWt{*&QTc^by zAz}3x|45<8ax_5I2Q|?xD$q)-nG&8W4}Itm5J=d2f0762j!!o}5-R=J5c|EsqX{sf{B>>{nlrra)Ot8K-JLP8`on zx1xUFwVa{tH%19}ICG0GfUTP}la-(0NwkXgA5(V(_oobbyDYg#H97LZ0(r?eUh>i$_}h zwm7QO&pi>Lt2D6`dd2Imgs86n2RWz475wNV?yhMQLMmKd#xSq71xx2;ylDJ=3l0)qHspdR%}q3A!I)Ivn>W-{ z#t6Mlgh*piY2c>X-F-pic%aNf>=yQ**JW;UU->V{i4?!^R%7iJAY?)dj7yU%!)Lb` zUN}q_KA9$wsnF6?I!&2OMz;Z4^@YAMnqa>E6jn{bWMR*>TR3{+EOzfuG2$EzU_a!z@vFH0wfQ-~-2`-P|DtNN*LB8*jL1wq-kBK+ltnpf4>0k#R z-NA-4&iXH-dQFM96KGtu=bHN7y`g|CQLR2zX!)3rb9lc(hh{$}F(SK~tmzry?FXw> z*d$mHkmIEaI-nL-&M1pDVHtvluZ?*GyhykeBG|%gX=#@-!N$i3R<*;20q(8eqSZhV%V!B!bgVH&F^uCjRI<6J{ z;nxRjA^0QubMHV(@%NWP5iq4@Htg}kanp!Cr?<_KL7|`vMAui`G5^#gfq3q&<|3(! zDV+$)iJhPP0Q=kZgs&4H*5?jMSi9brhxFK!+u8Zv-*qf$2o6MR{i2A(yrDjdi(nOr z1m#A8bDw_$MB?8>KHS`C4$>lqN0EbImphsiy-~Eeq}cGtTpwJRYB-oboGuu_o{Qk@ zMQ~h1F*s{*Q}QZfKtGX0n=Ej4I7CZFnfFyiOOFJx9!8h?;D+;sD+kA@6XPDD`RPCQlx!KKQOxy_J0 zrVu)YY)tElsiE=8(z*LGxv4U>Z!>lCAPRlN_s+-zRj>mCh_fzBGaen@nx#jTZHt#- zfCn{R51OS!6O?6I&SY7;h}%76Y}e6(ro@J85N}nm>TMRsdY1cfj%Q!GpLlM}dXl+l z1}ZN%-X+ILO*~74`1x&4`f-kWd>k?)FSjl+p)W7NGy}|-_K`9nnJ+JsBUdvmuQo3q z-xR*I5b=gXA@=L+_2&MPmQ^A<3xj6OK5**JSGPeEMnzs<14RScHqtjhAoU=;tBq$*!TdB;)9b6M? zR_Y6e+I=Quz)7uaEw1UPi3Jz?&Sp!SdH+}hZGe(1d}`A}i?&S5@`-DC#p?3G|L2-MJ_ay4?+BF>{G?;7FtCjJ}sJYo&=p-mke4Y_(*!yEBycTLE;rss0F zbKu4cc>PX(v&n4JLH)zRwivtBY16ei`L_8-eyRU^2-kem&y5xuv&1CRmNy&qf6ZDC zL+(=>j7d^mTL~J=!#&r?8`ja`62$Q)6GxS0WIs`3d=@w7T6ASKb>KA zI&E~P>9KR8;O6QHEJ#%_xAy#A3k>Utm_yr}CuQIE#AqbNf~a}Wn8<%Yp_5G0&&btZNs~dS9A8_||4^}Q-0W|5dz_2!9$O_j zKpWEA88*;cFwp-%#%vC}`ZX|2GdL*dbm=a-xiZCt@GKqfv4+GTy4+CU@p8vN5^e+a; zE+D|(U+fG-lVw9vGChK6ryqz5C}wc zo+1*7jC+_8<;29qq)L_4T2(X}ozbYC*{q)RFfAI{Z5lc4nt2b?rBzs1SoARc+NBTk zQm6c3hIIdD14#KFn7i)(F$47989=Y3^&SAld4A&se&d6~L%@Fy?tSEQ#B+`R7XVNK zvbCeL>;D7*{ogrBga+XAf8-?p1pxhbo0ES7Kng+a51)hn3jp*09x^EWCjewnZ}GnY zfYdu{{|5kMSd~z%TcKX0zOuhm4-X7)S$g@Y!$T?Af=*}qBPD`GF+`?3{#2gB@-ZH1QQE?5z?j-A9?&1o- zIb?QBwK))TULcIyF08shmDofTozi7NHheltAbNH_22tVuK2B!xoAAEd&_bVrT4^w> zk--m>pq*HhAZi?En{etYsG^sjjnQKo)7#`z^&rrP4qxDiT5Lg z%%Ag1eUc&{qIN$s{78(n)D8Gr!;l&$H{%JTK!p`<&^6;L&e4ks=b$m3ysU?6{YrQO z-&>q#p6d?~1S6t{!RD&$2;`h%_LQ8q zJn~EgQX`mkdnQd4T^08hV>1Ba(ZiCeli7PkKhD-$X(U*PuV0E+=pr81;QPEJuWJcTkaIPnUC2L*Hmo!joYI%n~?`w z=w*DPZ@*-*^E97Sa??9VLLL3+>O3m}IhugIAm;bU)Tk>k&Mw`1Q>>NcsqZqEDINe$ zZKfozOKD9^@p_AqBe#I#-Q3sI!wFIH|bkA=P3hKTp^=*3=-7SF99$_?5YOzBdzljbsJAe)IdS@nlqtw z077qIbN8d>TK~vOg@N4fa^}SEqZ%;~-{-l2*ONaeCUzL^AAMq2o$~+D9iSPBMOO-> zR}t=9y(S2yG%o@1{gA2mQ<3c2wIY?Wq*ev-VKDC?X@6H@O^x&hP=nEa{i9G;F%0W{ zU-5}flPmukK|Ls6vFREMv&8jV2kK60oHH2z+_F-$y_a|9ks=nTl z`h&Wqa&ax8KNF@%XT)wjQ#-+qk7a{+Gz3hH!@m10KX=8O+QeH zvtQKAqy1ohX&rpjLz;3~!13!qOrvJOC7wKRME}cbx>6&B0JJB3!NYtx1cV3?=_?O- zKt)wnuV9}Fi8W>KAOB%RoXUR-=mTOo=WYcDy}+UFHPBUPQitzo<0h+l zZ)2Yp@kQa6G$kta=gV%W*HDhj=7M)*^={**Nz@IX@V<2s3V;t6M}2mXT^reL5;5&K z8Y>Vx^2ztca>`NNXSl6H-1=3b*ldR)`1>?4S4?wb+{xhrHFvYFP|ENnn9J?65p32+ z3d5^ym}qP^5QEquCnIx=EAM-fR&c1iJfn~xFF>)>;1^4r{=~jzZV02@3qLw+lAjy- zHi2DmdSma}d!^;v_#oYIPDekkLT>G8Ly{xcW$}9MaY^lKT0GDOr>Vu3LMumSX}TT! z{hP0W1HZOg684$0@GB9v-m*lIbILolk^ zAwsy8Tv{1aW{F1gXV|M#}S&|A{|$a7Qq=6=o;S)WXS z;4nrCvHL6?eB7>B)J1hl%u4*vz&vgkloPy5cJj^idT_lUl&3ckq{B~qTgiPCh#eS_ z(PV|D^MPbf0l>1w+wzzJx6Hxw7$g~-2UX0$8gKGFJp1+*3psD_WPX&*zB7KYoz%hO zH(h;pC~va2b;GP1mr+O;is<>#^AE!Pn4b11lR3Z7RuQ=tK(t*RqQ)I?TK3yFP{`h2 zf5mS5Qmd82<3+lT@Qch@8Y2x|k!xEcVhEf40m$Tv8xqJicqOWs#r`&nMFv+qw4HNB z!R7fdZ@50Ik9^qnK|pjQ{FRAVQkDQrH&QPK@2ESJSx6n_E&RqQ$g17R?Mf}5Q7)JC z9$;Qh$zuni<4stLpWf)P(QjB-E|5}&-`mz%Q<@PNgG@Vc6;7XpR(kXXY_bK^9?Nr+l zGjOCc(Q?Ljg65)ei@yPVp z(DvZKdeuv(p?XGvzotO;tkLSK&|dP8@1OK5syJ!A#rD&YrnwQxt=g4S4j4w(i)_IK zOB_*x?3doLF81-B6jB%u2j*A%Ms zJszcsgs@srH@Rl!CnOe9)SDFNX|S{?6fuu0+z9d2?oMJyvHskrk0{n0SBP%=`RMQFapg#>jx%)8%FjrU?GKEwSw1#`if}F4uY@71; z6nf#G12Qr;@H+}k?AE9hHQSwJFCgKd$b3qL0=nCAejw**Qnb%gx|a_&1+fQc|6=w) z#kv%+dA(%=&8;}}D~kunO9h6A$Ip8~juKSt0e@CKiiH3eIeu9XbpE-UH(3P+ z7*i?^0%$u@`DmCXa_#+fi8U}Y+tAyueOj^NmPHOX45tni4D+fr&br1??KV+yU&Q&q z!Z&G*{1)dXY7z>F#IQyXdf%XeYGMg-9i$902Wt3CRy7{`71~~Dxy3nLT+0}JE^%!y zJ4XuN8|N^o=P9oV3X%Dw%gUXj3VnB9kaqHzVhRDAuh>_0MQ?pil(pkI5KzcpWQ)lytN6 z$b?PofC5N>8j~rdV#Fg+Ep4ibB@*_f5YB2y1hN(F$mHD0hEO{9(jPXAy->8W%eNp& z;sH|$tv@1muE}VvB{IfC*W+D_f~G4`uAs6szB;Yg$in)%vEhs!w5SYqp)xC8n!G$! zer-&YACy=z`GjC;oRS_|Jq_T&CpS#%AfCQdX}qJ{$JVCOLoB!Yy~fT*k0#Q#)erSk z1dlW>MN*JWJo0?Nfc|~dZKH|3yyn9L03>1~pgswLfgr(p<)8YS#mZFnJ5p4z%Fo4k zp97ox)+)~OTLivqp{iJuk7Y|pU8$X1KdXW%s#`$6NE%4!T7M#8M`qV9Zut04x5{7= zw8O`o{{jHv8#e|iyYy<%0$!>hUByczomzkJC#sxZx@y``$&& zLZKG1rYBc~uhct~=SUQ?oY)J(xc)D;-h!(Q2Hd&~B!S?;-MzTGyNBTJ6f5o;+#$Hr z;9452NP!0THn{i23x&26s0-6OcV^c5)|!9u$k}IGmiBGwsIF7@{C{w= z<5fR8T6+K1ak4(-q{L*Ozl7t3{@E0%pjn>|;{dA*-;2-U6UQo?$!XqRr5hSHvki4C zVny!)RqTion@`{K6 z0(^e*a!hVq7_Wge{Za3=!Yhe_j%&IxnC`2eR}^53_>-Ym045BsA_ioS`6mE^RAVH> z0T3)E8R~73*-5B4u1r2g6+4cGg6T%ah3duy+6k>O;~dqYU#T1F(z#zWcTPQOgP{m) z1Mx**U0G24^qYqXbp%9CbOKPF+1d0sWm~t!+NtziVKoZCo>MNhL=cV!6R{DnpeBE1 zhn=T9ZP5X2|G-oww>9k&L|`G3fdtk_TrU~YaKJQEPL5^dfM>^0-kO-wOW)GN@qE}! zO*;ev#mzwBoU6`y=8R8Tlj7-5MNO*t^`RSYrqi8)5m-=~D!v)pcpMh@Jz^I1$TbZ! zm5Z5+W19YYm0YdE7pO%DVw=r{;e_1G0id`(P<*i)h)~XCc8j)*_Fv-gU$O&&LSW# zU*QrW53^n6BOxKITop7TdAj>Qb&}#rYmyFY(s66DM$EiQ?Q&1nHhji@mCxPXEfkDE zUhl8T@2lc-cD7*vNc1wH^P9b69KXZ4To_*8{-W*ZhW){YV;wvj=>Ve$+)>Dmkk`G@uY#tT3_0L+uO zX;eu?VB4WJ82u+N;5W%UYhhfRfIpN|-rj@7D3Iti#18{uP{l8Zn~Cf#A8S@vYfN^6 zn_f4D!cGZHZr)@d-?Y@MD>m%X%huIIWE6AbUXQdPA44SAAfOsZ2NN(u@y(FK)_E2- z@)Fy}yc>rCn;~Zd0wMf2`?NXn!gfBRf$QmkID;P!7^~gB6Ab)WCp?YYGtGTVCs<&P zDC@H-AxMExe%Z1*cw_u*E(CipH#&XmfVmHst$V4Y(Jmu>uKSyrAmm`q8Vx80@BZt_ zMi=RW$Hr)hJZrSt8u#aNL|0b&kMKH=zVAYt2MRNDg;T)Rj*)9Z$96Pjzcg^+`#ToN<^($(M7nqY8n#0? z3yIBJcfaCkgLul>XK#`|5cWSK$oNg5hHWf@;hbP`eOTVGF^|E}9#AAG4F${sfL_E+ zxic%oIZg&0?i=qGwmE}o4>iR0-`U+N;!1_@g z1LRG31v~(rB7xb8mn;B(YNHGMHxMZLd?Es;J01dLeXk<273=p^`SLV9Z$BA%>6^QM z;ZM4hi%?RM*sZI+?#Z#1_DI^6ICu% z(dYjp%I2d&9<|@oVH<^?-lQ4bHJS+g#~%GdvpgRQ_>_Bt-UlxH`Eg==KjT1}rh?b> z^HXa4Ud&sqe`V@GhmY9HX^t-|Rg@1+n>fS>o zQV6}UXLt!gfI|h7D{FtB<^6^{1x3LAS~}ym*th8^Lhcl?XRzH6*f+o-P#y3-g%qM3 zmz)x37-7Z&$j)X7Ne&2&@XP{;gyg4IR!LOg>u%8d~C@ zPf`7Ga#em6{XxOW+18=#sV2!asR1nyLF}j;eIugb|NCM)xpMIKzr&;B|DTKP(cbq> zM-GlnMw~r>SD*!dx4EVwo34}%@ab5t{hz4YVy)53 z{}ljT;gyLvl`G>$)7nP9$F`4~y7Ds-XC}_8i;8G4oL>v=kA;V-%M`g4RExj9@~Jra zT^VLX%4R*JM`=NiyHd%P?H|l`bIGsqK3LR?qHZC{0h2}%H`bx5z%5@c2kK^;g{c)jYB^%ZbI?T3NBLh#=-j|a6-9uyL(UwfXF{6EI_ou=XxwgSBJ32qmi zJR#y_ux{!8cd#@i4(+mdrKA{uicLOgH853aXoc5kf5nW<1Dsx4#Gv<(Hccl&ah#Ym zr@QGDa?~eTPKtY>s#C2sEtbnr7V4r!U#2OB$-sSvzn@QU^m&?AfV>`4H31GxbWUaq zWJm*E@OQYbG^Q>XsGj1|o2GCTEd(`hoR#ocQ`es+Fseg&WMu?tEwZ=<`jG8mNI2-+JIUg|c?YCW%EG`*S;P?mO`gw*Y zhsfuc@EaJV3CQ35V<4`4FPBlvxo>igj2L`_nP}a>9x#UHW@C(dvR$m(w-9wILCDzX zQ{u+0sp~W(jL(3(>%!TJ3t;Hc0lqo*JKVSMN;{jx1X1{uje1T8x9_1nz%e^ z42Xp&8L9dd+|w-wQlA9t=38PDF}ymh0B(p_U$f=JbTj~O(;9dPs03dFwS`fG)ZC7ll7?zZ8 z9S8z6&R=_K>{iT=XunLOQ-|Tmk$p*dTnHjb;{6=Ma9M2y`Dv7oqjOQjj)xj`0l1L* zAWTHZR1r3&U5q=TMbw84tjX51zH4F?&9^QbUOy0lE4OPyW8D?}bn|K{VoP5QX-F|s z9RG4wuRY6Y5w2AHp%?U4BIcY;@9YZ_GYlI!Xz3XV`m%RR8NrPGRaGT$U_gAD){uJJX`64{n?3# zstGwjM>SQJhY=iXN-n@c*TvU; zzS2YV{FCG}U9#rgjoapabgs|{j0j%(deOS+kBf38Z}$keGl`_Mj_CcY5{vz+;btU49T1`5V17sC zz1!%g@^0nl?*9mYM8?kzcxrD4WaL*<3bi$P^t;Z3AB+P1ysz}HS-$rZ=K14rD%!2T z|29GQT9lK2iEy6=-p9m3m!V!psS)uIf&WHJPsNeoGNc6deK z`oOz!r>9HXB2c~NGSo;4J0JRvNJ+k|;VEwwM^q&AoIOfNqGih)6tl_zM z)&B~BwwBJNU;bDQ%=;$*^2_64y=4j)?jE^iI##-?m{k5Nk@ZK=3rsnTP4g70r~Lpf zp{W$7NYrCk#&$cO#JO{QvRzlslcK@l@q?Uthn+;4?I`;bd^e9_b0o&Ivi>6#yCE@C9o(2e*81mxZQi=kY; z@|RzKqV%Pmvt~}bPrg1`DD2r|hJ8m~+3iV|+wh{AH=YsheVpSuzFIz*KDZn082J>>8rlLh`98t;_a?(+*r}s=xQ9GLc(2Oo=4hmY<*f_vOk|C1!n3`3OE2Q<`@3AISr> z{%h>(aK=r{;Kt+RZ`94{RB4}LbU83Ya9z<&`foRHjG#Y~>Bbo&wuFU8#(wTAPgD1q zrihZ;>@kV{{jlZa#V;#3eu&?8KEkF~h{D0I(g40=EB_NFp;oLy(=u=k$WCFks>aInq0Zvlap-BsfJh);kb*b`w0R7F&r82z3t? zgt!@`lL1@9d#Levypn#4LNw5L8i&yo5cqeQcwiY~_|WeMHh>_R`^{!@;R`t`O|Xds z4s9ggtWJt(E0M}}>~&dc_LgJJ20jx;Y7ZL(F9b+#;}gvVX=fym(4}b=KiE07YPaI1 zTCw5&hfKZ}#~}w0lC$C9zGx%Fx}p%C)MTbDoURL1wz&jv_XK9GJW+G|pB=Qk5!Lwj4lyn7`L5yttM3%Jji;s+DX&3t|IJUe!eq z+=%{y@NjvgY@w06mPCXEDV|)Rn}T`1 zOzyBG#z6=LG`k7`k}C&uqH=J)7Jokk`LbEOMI-cEQ*AGkeFMQfQL)LYc+W3D%iDR0 zx}|wMNly@>TG&!(XdWam*B}t6(3b6b97vWPw-Esxf$&&BOMzZV{2QX@h(v8nnHDUL z6BeJsm+@N$#L3UISe7$c7VqLs!WEW%ihM$8<1PeJBbx+kiB`0r;@)9!`XULXE8>3A z=0PJ_|BD1S?1;MT1T3cK5PD?+ivi|CAQS`;toKm%It>uCgV#&|5S9tqgW_$MkvtIv zk<8^%Ad9Q-RNT>(q+5yFP?DXrM1rAQCAo6a^yJt%h)RXrLPpJ}@A>W%c`h)pE-H@6 z2JT=3rX7sqfN3+lD^C^G!^nEtmVxOn$s`9M%&qWcxmvBcGUA1@@36w`z*R0bv z{%b{%*+OXOl15r`3$01t(AEMn9x-A|tm$|@=q4TMB7TV#FJ9Iwm~jw&uSiD5vqtjC z9;W}Dt%Rc*yE z9=u@foFG>lUm~{xZON)^#*5aQn^#u-QFVfDcFcJ6b;yDCeIc*Bh!r%mL$*CZwvG2^ z!Zbf`@D(m*D5%tqo~mSa&To!qBI z`A26YL0}d%+?LpauDY@ZYe}^hK z*-Bo0Lvap5vUdxUZvYAe$UEEzv`AS!3fck~EdG%W`ju775UtlfU;n4gA6oT1rXN94 z0WPY4I*ID}z3P{wmqCd|)Osa|GUVNiS5UqOedsR*eJ3RgtP*eY``9DPm=1t0kgm5S zCs+#@H#eRBZ0{FsDvKidpbJ*{*)?VX2V)>p-;}-}lQmFJU0bWWz=WSJpZj&#T2_(F z69AZRYO7DO9Fg&J{FQsOq@kH0Sxm7urr1n@)SxQ))~1DIUi6nwqx>$T&miRU0Fo!F z_zaQSRB3C@pFh*qbVdM>``*pslX`)!M=TUN^0k*tNtOK)$$sA(@Po@};rZ}ztpj_^TbWCwjJ+SLz8CGzb-{pi{wAPiz8VSLx&ZyGmY*X1Bk)cs3U zE<534WzhXk5;C^Z|JGg{+a*3ZESbQG3scJ=J8#uuBwhC^_^~y1i0&g?Z0JWdhWM1c z#SXp2HuVp7ec2ATkAyc9RfS#z61Ua%6RKSd6L1FBxC)RScvEod4Y$3_-Kqkx6GZGm zhv@`$h6vSoz9-usrr_xpYzZ)#S5&^eND(F+(y}4iZzcNjtDd{{C1*@Otz!9e>#oH` zNQl0UHN8mJ+=x4R*tk7MINR?tAQ6{O)Ezp0(b{-oH%+xUQlvNT@0LZuhWp5eq_?$d z58bz?i-WIMF7xvt&h=*p9Yfx$7++av=IL$?;UYLPX2RrU?asUSRykY^rswI4n7g)F zWr89n!Ab5`lnP(GRS`Puhln^)kp(7QCJR$}GJL@Il6VO*wNe?^hQalw)3Ae!Y%^L^ z=5Ou90%M#7zf7K?`+6(kp0Pk>g=u52@mB-o6FyT0fyvIciz}j&vTePX%%T{+i5*_G z`RZ90q8|5EoVkI)uev<(k?nNfo^Jce$vBU}S4aAP5e!s`v|gzmej|8nKY`<&=|Imj zd6;>z?}hrOzN{MM-9R!DPZnnv|MDvN!k8bt`m9txjb8U9!n*5ZpnGvAm!!PD>8e_a zn7hIrq8Rm1OSSNtuM+I~yU9JNhg>dpu_6Y*hBHcEn75lJzchJpgJJo=nAzTya*;w| zyL$MI@oEIlqExsettTg#OSM!a7P|^vnrnrZeZA}OEIHZrTbmE)k!rXO*^;8#A_OtNK$@haG%D@$EA#3*H|MAnEd=!sph=V)sZPAZ=x?4Dp@Xps*tYf};3tp$D~@-4JmOv~Pa;iC z6G$9Pk6|-145W=0A6zd)>*?jOoS9)b=o*rD-DeMC6h53x0znok>z7?9DREAw(AOfp z&W=qQ+(KePCLf?bT$ibYonfn5&!pb>QX83T(8nQ6qABCQTFMIca*`Z!#^Z8?1v?ux ziZNSS&;Aw7zhP!ey2MOD%i+X|&ICbN&hjP|MmH7*6p>%p+g_P=b=+;qP$s; z+9u)(c64E1_hL z!L^Sz_;A7EpzEb zpw?s)v3DcPtI8ZB%pZ~`K;mi0`<3GQR?U`0`q>Ie%RTNK=IY4w+^H+m+nuuh4+O*G5Xm z#F1v&S1b{}+&8z|0RP9K7!Jb{PUMvIX!VX$^g00 zG}ntq+@EX_ppV6pS)q-k+-xBqFU>-amTQFGKTvQ(M0GWq{O_;%3Z{%qD_o#)-hwo3 zIm2AEa%TW(V-87;uY=@AAde$1P?{o|o>Ss27YnVAXRz&H$u32=0J zL+p?xizqU0;STs5!eVVQRFMlQ7I&4p7)alkE)g$ ze04GdBZjoghp65<=wNjF*%?`gSFy|?hAxSgX}M{tvD&+;dK%kDO%TIwf}m;|5Wsnw z_U(Mcyo_OWCP|@EG?aoy$@7ASYNJo1fMJnYzS<%_@%v_4M=0l3Nw!7#Yr2lq5=tIL z^B+ZcN=V33Es{+t)$w0T8nNSpnIs#5)AP1OD=wPjMg+89lwC)>yvx;A!s?0X`?|t% zv2;{tiJd>;I}#gmW&-VZUC=9TK%riatipEAtI>XlW^yDwjHjAqLYI(T@sS%3etl16 zK->t5z`~N;rZMzSi8@t^k3A~TJi(#LJ%K^fw>+kglz`7*5&b3eNv1VL5a0uapL}cc8a0kPl zpzElAWr0_Wm(?Egx;yn?0|~OOZaBInn>2R8A12w@U6i_?Ci|;X6Tr#hz9Mzm#2=e; ziP`%~FJ<5Coc82|q}p>mw1J6HJ0=kFpaQ2HA(~^O9|C>8w$JM$SkEldzVWm*}!FvE{9<^kv{qA@(td_$o zkjaUBO6-#X{zt3xZ!(#Dig)OtE^U{1(5p|~LN@z+ zFb)5ely*#>&Kh>yL(nx1pVV3F<&I8Ur|Gz+q-ILm5bQ&1GyhcTBu>cj0oVKSluM&i zlc4YU_b{0%sCCLiL>e5J8Qj{)^Bx9ZF9ebaVnuPv^F8?QHxZifM8ZbWgmX$vMEwm( z%;l7XY_}R^3w2JJq(?$CrQODEZ_#+2tAdc~o1)t=RPAp=Qm{dqS2Ptq`zea|AelL= z)Jw7^XEA2U2GEfO?o}S1<8u$yiRp8e9eD+3a%!~`a;D_4> z2C*{k2qgTV|J&zB=rH&8*@CrU`}P{K`1Ps`KKq;Sij<^{f^+EODMFI%e8K;A)XNtD zdJ^!oc-)68u)L|x047kPVAe}p1dorPd49&8jXTrte2{iu6hOgbKb?r&VX8b@L^J`* z@x2RYL;3vGID2$AY$v*W)sL(zf{PY9sb5LHc&>VQ!B1I_YW<5-fM3>q%<9WUULoWf z<{a{PZALdkJBY$ah=7Z~Q>t@oM5s#Ad8+#BCDox3C0)(SW@jo;9z#Vg&U!Q{ITfPn z$4WhGM<<>a&#Ewx0qWTN5)UeEN?f0)t#0SFm~%l_+L6>nU`t|`(JYttv{F;h(wz$M z9+dqfhyyZNoOYJBZo1z{Wg=^or#rwd1oM-Sm!f=so08PRfqSSRd*&LGq(JH#Y05dE zUjNYUMUYAT_e1{EX+FUxVmnK_lBw%#c(tH=g6h&%;w#m~N`0|`vyElrr%VOncRv_x zb99`eetJ{QZHZj1&*JK)rp8*(mQvUTj0~4gh%?d@!&5Dbu_=5GcXXCuBu&_Pwkw}Z zmg7&Jn+a-lZBau#i}jrpia!EoN&zpNQ;9tQN@Bdsb4~5bT2OJnMlH&>@>s{8jWt5| zwf!ka04u$-(JyC*8vx=tGU`04-+ER|Nj%2yqqnJ7$_Yc3U{K~mGmJ9gKf&LbMa1Ix z9BPvc-0FR=OZnLsOAnu5r4{i%#!}XsxX$3-GRQJYylbUt;`v@)EOP17N{8!c9H;w` zSU>}a2+535*E4EU{g}yT%Uqj5P^9ma-};1*|IfNZT3Tu=fj3Qv?5>;0B6J(~Ju8fl zXH2ouI!GFqcPBNS>>b9D;-z|Kp%?3;w*oW1_ts3rH4L6+9vcI%IkG!}=ovbX3(`@4ye00VAiB<2U(MF|RqTnuIB4BF!plio`iq5kO8yeYD+i1W8v;AQw{}+_zX6_4yEdM6{m+6*V_bO^ zc#*o>`0x9g5&pSSxOtG&b^uQ+=U5>Y&1-G=)P~=*rQ}3p>a!@AcV8*p@Pq)@(q5)> zG)rv8u7KoO-SLO!3x*SPm+P?EeIQZWXQRisLW}{`bLR^rHdR$xtvq!Ip;%~_#Cp)( zcPHM5Ye$8fB|FII3w)=7;-*t3WZnqqmuB!ffIpe2yl9hG%hLZG@XmxR&h2TO&FiZ?x$ zc5xBT2R0B4AS>D8=b>_(D{s4Vj9Zy3_DtaIi(tsQcxYgdC9ZruSdJ-OG@$@O?5533 zPB42$C-60_lv_6YhN~r!7JBIK5hg;Ilpuo9(r^_39TLkQQNNgQSlpogG|mn{g(q-} zZ8maYT`g91Og#`%ZzWZ>am_x=Qb}6bVv@n`Ed-go#)Ici=z8Uf zLzIpRZI5v!wyAMy^cM!Ab7a!wM8m9(B8-*eoey=pyT#pQ$*4kC>;o&x?@4KXdpO}U#&(xqYh+y zLFRInV8HHY2W5(4HxQZP43{Lntmlc^v_6#41M_LW!$gN$EA$MwYtiBBBN^0Cz(`4z zb+~7V7=MZ^i(!G2r>fyp2r0`N+XYvigy>^>&p?!U@NsAahc}QsMBJ8&wRBbVh>k2# zn!-E;Bw1?u3QcxAC`Lr9ek2Pl72^p;>XB*&C=L~BQ9WdoL2)}mghqf2vNj3?T8JO3 z!X!ApE$gxsy!w$5I>K8;PrtCYaV7d-`M%VL*7h(^BWY~LJ;F6j0YlbwW&($2bPv$7 z3T!EfhBm{!HaUbEn3e}RM7naYAmBD7R)M2|j?W(ej>+9)NyHBihG{+Kc{_Vybqd4*UncR~eR zq{~&mKvRrxRSs4WxF^lwfFJlkQ}!R0I=1;i8r`4CsNwvTn~k+z`UqC+7$xgRX%40` z@rWRQaSSYKBmX^-cpYRNtj1{ATGHhSW-m0$D)MHN@%}vp*})+E!o^y{B*_*e(H^S# zSQTTl?8z0L%`?Y0TlN#4%nNK5{xi%i66u*-q+*fvvI~TyXt!{Vpv!S)t}H6b4aaJl zf>-Mbg<3+~z-(m-QjZgH73)NXb*bJK9%Uc@Z*78nsU)L85<){a(a44yzPYV#EW>?-U|G4TKQqHX}A#scIAwwPn zBGH4EKnZwBI6-ydsKzZrkam)q8VE~S^oN1~!e;a85#yu!j*MjMd|56Y+WoJDyelc}a$2Bag41jauqxbiyLpP$Oj9orzmLt-GP!m~{Ne&`! zA@zu|yw-nq!r2TH?SKqEKKq9J^HZ7DS&#H9Bibt39UO$&cTKvUpo9xNnMeMXKjFN{q7T4 z=C?^&HBd!%J-u{a_{r@Y!DqzA-R9C3R|m!kQBlkGB++1_`_@f$t`W@W+x2~*OE;N?h6HAUa>|H8><@Ig}Dk;1D% zGJa>g^by3~%Q^M5mjb2{7bBZhBS=W*SKXBJ-9Znu#1`Y&@#0Ya-qYGEp-zk86JO!9 zE1+EY6YRj)t-`~rd*2}*mw+#fQ8h1leh|U?Vn8)_t-Z&O|6ILFUnIbn92Ha-{G>tf z+Z+RB8Yi_U>?|LuPQ=&kH0t@{46kmm*bMrEy#MB!s;<0{Ch%_ zX;NHqQqq1>I(AaFdQyI5QgMG$`S+wM)0Dd6l&1ZZcI=dH^_2d|l;QrA@$V@Z(==Rh zT1GM2Ja*c82@^9v(VjR?pgGo9G`6Y0Uvo9x3&UCV9=Bh5>A5uersD-xVf-6%#)fH{ z_N$un{vgL0jtD~d(2Rx_i(6oa6Wmrt7Kmbpg ztb!5M`teU2%4pKrqI13Xh)cUj9zkU=Kokq6dSf*3xU5n;ZycWb7_=a z7E7UY32JK7df0*0<5c@=*9*rrv|bV7F4?|G?EE7J2*RmG0~=2(XhcI<140|-%&dwB zbqQU!XkzM5QjO2N1G#(caZpbt^z6o{v3e!yby{5EpoKp;IdVyg07CBOR>qy5c2DM* zhXLfZ6Tov0mgGm;D&sKH+;y&Esb?hBj1{A~A3O`19}PWAuRk;3Y~W+L+Wn}SBl8pF zD&25DXr(RPAJ(U40Ft4~C~l2u3a+Vxr@If6%x*U5@f8=^Xas#Wi_fjs;G!`AA|K)r zBzlME-j*7w!nt(}HUe&h)PIW;mSEk74UFipmyK9hG=$0hwnnBO@Wh6C{KY!f)wS!k z{6A)rE@@MKKLbDBWp2&As}Oo3tT2nRrypK*dC5_a5Mi>zc(o|i^fY3cgfQiP0Fxen z79DFnKxVH`H=dIR<;fzud`iA1;PIubJDpGxkZ{f*`5UNVpr(Lr=fW4JHr!$CarWZL zG#z`Fu{y3;GdtdT#+}}8UBmt#(LLT{9+2!hU1mt>D~sno8e6}&G{nx<>oD;qKm1tr z0FT4yU&hS~OVJ_sjL%$`>08N{uCcrcO9J_TV**L-}CWt;kWv_;fYWOa_+(lMWQs1 zAhwf3?Vj~+aJT!e^Oa_U{gO7v56}_kz9j!tq~TFsy%0C_YuStvY1)2`tIdRnF)yfO z)}441^Wo|0k=Bp(*{_9qOVtIBwu^s!nE75y&80RZ)7ipXPH_5~}y+LzYTk_0H1+ibHxr9dL7iao!vAp~OK_y~GEjw6|}+vE{ZY z5P}9+fem|+UR@IDuQYM(eb_ln$&0!b*H6lId@a$Yty45WwCjTXHKD*j0hYxGetwZF z^tk~#bgIM=pcT^0{-nvr#KpMu7*1layhA$3!XU15(T^3pJ*;zWI9UE{^iCx=-qq9e zf`KZD=-LUzG!hx}tDPq!N#^+Jk;yd)C8YpeU^%NIR0l5cLFAF?)JjkNZ7IvDw;t+T z^aJPeYZ?)@0S9cDR8>;8$LZSp@GnZXX!1vW^R}WcOry88O%V@2H7J}DLKBOSB^#QX zH~1+(+dtuuKz!ojY*Uld({VuoLF}|aA?$#nB7V1Y%M5jv^5o*D41U29#ZbElqhM=> z^ia)Yzp{*UIRLF~W^bR}a5A-ij;AUKfY4+#jxa7H)FWBF7iin?bSO^WPAyJ3TyAdB zni#jOx@Io}mSJ~{OG5+HiQq3zHUk!0uLlhWu$x7Mh^|!J5gyb)M}?P$L%1+pc)t|m zsw`%fz<^SB@~mXkc3H;WFcU}c^F~sk&KJ|@+w*K06I%3Tv<;ubQyl4QXR&uTlvMJC zP^Nk{9V;-q)?+c3)>hsbFO@{uPOSJ!BmbNAk;GuJ)Q9#M5!D`7Pcpz_@fwuB+&0k) z+yQ(q)^UU6=7`?2XSP*sOMT>26kJ%XDP=D*QUA5ng=RvVmQl!gr+kX!Bd-ux>?Fwrb^cat1JbkEtw`yq2J@07n)hOk&hEdo_}8yXv=9MaLT z8QI}K#gPi0&f}neK&_|_)zc}8bW6;f7`_5YV`@h516s_S+g1*Ez;<8=G8C#wMdCui zT~;%3p7V8^{M|;Y2Sy*kpK-;~`(^Zehf|;r#4%enrEr0-?Dei3@^CJ!4#VX!(nl=z z#KO|AQwxb~w8uB3d|4q4V`6LPb!XyNj3P0U5Sw~KJJTkiLrWqp#>9Rhd05K~R?{N! z3>PIw01fI+oAiTOC{VnHs0KX$#kdOd($8M2M}oJPc$jn(Q1Q|~!TkcjKw@civ*4Mb zWtr68L5ZnlG$~uLXE21r#_S16l(R2+f3jDFgWyaWenwlJn%J@`z@DlwX_|^#$7^HB zFLye3jxQE zTPa-lyJ7y*KABqCj?2=fGj}_M|B26b7npH6ov%GdW$2e2yjFCxdL+9=pqDdu!GrWN$dau@GZ)w8cH6sd(qv}qq4;T-Yea_!S zEQ7xrYMsu!QcFjPPj2G&J4fJY*Fb%fOaX*b7MOan=iI=Z_$(b@vqC=Vw5nPzyk;+% znMV^(i3l79Smz6utYRIzoBh}k?odH_{-fTd{cLK0@|ONM=jay>c9!zoV^0-)=kG^x zSg1nqw4mFI4n~EN{8l=i-iHry3t!^;fYeRsPcI^J{h^OyOHS(*l|Cy~Ae8~wcJ#?F z*mLJn4sP0se|4Fy%&)?mxgswl&uUYqvfnsd^OA4hu=(2YrAskIG!)h}Nt6~n_3*px z%;iqPQ%5mVCSlaThl^$t919zdT#(JQA;T zFEjBez!Hs#1eO{@n_e@{LpehDDoz(hU$V;3aYhEPqKqv;w!;3q`2u4lB6q3yQV~9o z5sa0JBGH*57n`{h{!n{o|7G)-)s~5j-u7bsRC%04X?cR&*H*O#gyzoOKRgQ`lWjDV$HslVAaO>@N9_VktZq|*c%VMeyqaUH~jckcsrkU=iPkWmuToO(Dpx?6;SYV>?9`bk-P+vz- zfiE#J@5Z^!lWFoXJ7IsgTqTB6`TObAqlDyIA?09LlVo6MpqWMCF#3%s-jQk3gwe&@ zm1SAL;~ZP(2b;<=bMma4yDEIRl18F{@aRY(pHK5_J3EJ3cqs(xifQ#ABHQa#(S5~RF|=d>FcU1 z3;Sg3r&2r$Q`P*v_$U@+rr1~C2n?^|FL2?PBb%&KxG(8I(IwmDtD66870ZW2r;z>y z5%qK5H{bcJ9|;Z`tvGfXgq2jw2Nx!pi%w7#y2AO5<;SE6H*rhVKD?LbUGn~br&C%2 zEX{CDt%@pX|B-c|^Qya;ek7!JxxZNSXOLlclZDJjfg;y_&BBi?&~g|bkXOq}$f0wmjPnmD*W7Q4gz>h9>#sw>hfX%0ixZej;w?6|ha zjz2fx@I5`zbgJ)*62-Wf zx+HGm`EL(yZyxnH?T`6$XFIW@*!*l~7g?;UC6s4C@Qf`dJdAQF)9%aiCqdyRB5i&i z1r3V$+&1g#ml2E)y~wC9j~}}c-tm)&o9M`^~Y@@!h%ngUfWfL z5^B9dnhW3n`U*&QGTJNbeaMEFPzu3M7$g;SN<2t`Tv9(ugJwB{Oqgw4{NC4%D5qHmfmISeC%cby^dxM*U z&=u^K-GmC-Mr^bt`Ey%C)A&6c*VHuDnVQ8PwUp^

jg6lNt zTe+xJCcH`RRp)})ultmU2gQp`#g%(>%tL7YQ>8sUjt#+*a&f}MPYG^x!hgG)w^ zl1oXuIseBkRL*0|1!2+4ph}w(>rf5qh>#21vW8v6d~UMzYcZ(5iHXD2BcNfnzF^Y~ zCtW_q@eSg;zLOF^lOuZppb^bJLCF1G%d7&CvzZ1yHO~aBTh~KU8EzgdNxYeRvIwj#9d6(#MI85i2J?#V`6iM5tjqi%B-0~y^##Ne<;VKjn7Sl%$}PA< z*EgLl{9}4#Dqq2Wo4y^Y+0$P&+pHAG3bMyU3oW?#)wd|$x)_utnogf%QFbB$fzzGbT&92{q#z>O<{qm3&=iw`p8I?l7#MzL@ zlPu%UpAjcZNtT}2lxqESTQwq0E>()&iuTFc4CGmlh!28oGR2;^m^PcTVK~-V* z*Z>Y8jlY$*3nDbV&u@sLUdN-UXJeCVrhM;dsMlNUi55sG<&s&Edk*rBieTMN^`w+7 zG91h@>b5acRl}7ctE#uMX~=YtbE>r{x->`BH3>3(0b32aHi#?C-l~0-;A(ki&(C3Y zZ>AJar657Aqpq&v$7j9bTAkKhG`(Y;pca&`HK%9OeeTRj+vgKTx8l8nQRlbcC>d$U;E z{~_2qEZy98>W*2URQyo3wL4x$DT-!`WOO6>!ni6mh+;3)QQpPg>9LQKcclrTbVzza z5-!--JhY^q@GUh_Ws$g?Y6h|}CkV`%TG5;`4)Uu6g-TUUt#R>$l8DdSTeW2iZZt>B zI}PLKe?hph{4m{y8<<~cMM(n)%Z}rE;+k_p01qcw_Deh3*Demq;ix!9A6l<^$thh^YhvM$;?p6vE zX=$NFN+~VFbv^I>%*?xH{=uAIl6=itk+q-4v2Ti?w|CG;9p=|8K{A(e>2y4{yy%}y zWIpPHl@(OA8q*+|V8TNV8&!^9in(Yy^<7YmpZAa-KE+}{_7NC9MOm#?Fa zZ?xhdkdbF%Jk@C?z_vuCwjN4rJTrdVAo4A7Teq6m?9pvf%QfOErs9t6zMPLLf!okg z10UMycFDsCmGTBQ(=1ns!q`fiYAC`{ts`sPLF@Z-5G7SZ1*e$r90%dnMm~3#dWR>AvYwTqb}`ipP>^H?UK_@yJl}c)RZr6buM+Y)aUm7 zcb()dP7nQ4L%wlWQc`C&S^7zCm&m=_IMu)|j%6T;B*siXO+**YPVYrfzrA`NeqK+z z*PF8!8#Xhe0~(AqL5z{+b>p^T)3Dx)u=guBhJ~1R6u!GlK;+9Retw_>x_N zsKb<8!~2w-#NdGqmww5fcJco`u}zT}ss1wJ|7BRueAJvX$mn6nq_&TuXVmgxl%A{2 zN^;E3d`v5E_*LGRbI+KiS+6UY*8O43OLE+2ryFWM9*{R4*fSoyGamXd4yT?7mz;<+ zpSb%y&?@mP1`Wl<+NAEfRrU(0HZ&2h%qSH^KHS`2jg1}qxmD)8H)V$^a)Y6-fi$th ziiB5eJ6U>1t*I#s}z$Mru28`HwPRwWNB?!|r@1xSe!)nYQ;ps-_x zj;{kPz)C4Z#h5;6t&$FNe_y(KEFl~#Lq(g0&wnJ^rMp+GySLiKpG#sCq=2@Wq!`6p zyQTG3-hZd`(J4y2dq|OBE&$7EBc=^F~3JyY*7Az}(0DaOG)x@BD>&R9PRPEVH zCcfwf>#zlO)K(Jpc45o2jLnEVeY=RHr2Dk1<4#2<#Q|KtbhCa?UMH5 z$BT<=%ZuC4i#y9fKV&pJUCRa{M3!e|xcMm|Z)*OH8+siytUx~p)gqNSexo&z8#5m{ zps&+MquEwTA0qKHSQ)id?+Ve3L7!(xm7RgfU30vjo8ORoEvW;=h(9^|-EAUyAAhFj zV|Oh&cs&o`OSxs=wv;2wrmrut56X;Y?=G&csBeUPh_ZNPOKWcQ>&1=1%NwINH_&%C zru{dw>Q-+umS+`yytc!A)wH28yCJsOrt~_k8mk?zmtH7LAJ3l;GrU3s4N1_3N=Y9K(2tjRq5T$aT&(7n<}t5k$10@^rY(f#mjt#`}xqi~Fd7&0+w`eu$);e_CuGJD+|Sdi(kZ z28V`6M#sh{Ca0!nX6NP?7F+9^^Vi6nz45x7NwT*))(#S1c&BH}_&L)aQ2O~pqy1Y^ z-y8Xn=zj*c(bu4zVNXWz%gC0qwf!KN@^Q`+V#dMkZ6HyOU={Y)qFJKT#iNl=;L+$7 zXk5!P!T4PYD0H3@4E(zRxonA<1FO7T$HJC~Im*LU4Xx34=d+PN=9$-JUNfrCUN zpR#sPV-3{B>=ke4>u+EU9ESilrDY&fIxics*1Xq+scB!*D47D4dDMl#g$C)j!!` zIrJ~AiT8sxdn(Z-6(aqySeTu|2?%8H1Z_Ef3wf###zNuAB)ZuvN%7*vtmf#)`TEP6 z#MZym0K&nyBVH>66SOpF8+sWGyR!jtl=_dM$+$EYX|fcFj~{JNeX_-d^bF6-vJTS- zr3CXsO_z#Hibp30kCL-Hn9tsPLx(X6wK=gDC1&p`EJs(CSAVXqZTtMWCXD_vhC;vA zU^8bm9*HbIx3(^~>|C%zXXV4lfpF_Y$)klS(V%U!2=3hMz0X}(4kxj7^klM6XaAK8 zFRQvePup7|93i#f4Wo!b1T?%$dFdk_^EPAE#RhvrI8Z$=Ij>8#vrkD3!HsXt$7Ym! zT7@8)bQ45}5^i!LdFeIiW9a} z%?Pf$Ud@W0)LzX={ye{$m%-$|UJ!m9c5V@*kEFw;(x~|;SP*DozhSxPle;%T&omte zPyTN23)kKl>0toZ)akS5t)+1EQk7E$9ewWex3L!^K_khT6CPBR#sTXuXMOJ z)_-mo=lOl!vhM!-YsX3bZ+c-6LF7_5=2HdB2${#j_X*bb4?ku^E*`GPIq;+gm#-K? zZqC0I{17#a=e@sq+E~256N#1S4TN#hSwB|~P$0)6K+xP4MTZQa?0PLC%m*6C2-tuWTMNC% zhDG>F13Cm|Ytqz`01w6vE9>e8!~~cg$7MneD-H-CZo7msS3iXv?z#xSJ&qAah#wIpW`qLNcMTC3%22gWxWsI z^P&g3Fu_qp_vOeVE9E6q+}-EQY!BI9i+p7Ef=`qz^HZzRvERXB8DvmtCoh%3pS%!w zolyj94UwGp=P{Fyytd5Dm|&iq2E`083+LoroMr61y{#FG6bLjM@-;43{?L|noDZn` zRzJI1qe6Ura*p(jAfolMkedOb{Q4CT>u$sr1JqeV35K{QDXl%6MPvY7c z`ZEV9ms^I&yYnL{RSG!O4qXft?!gNQkfJ67Fg3?jLyAOIx4ixu!mWrP5qrYjQUrl^ zOzZ|ljtdrdNwFfLr3@W({eC$&wT@D@28sTt99d0d>aOxsa4a}3j36En;Ao+kjc%4= zorfwT_xLPZ1w8lyj?*TnKn2JhcV_^`^X+ml46#j7|KP3l`btN+v@oiXl!krB70!~m zv3d>mZjOvPpp=YNrAH9PhJUhmdAoGoHYl*TJ?)HDumn`-Lx*DW7$oj~~geNZY zkxzwB7xzZyqJ#D*io^1Y*=v9AfA(KDSA8FXeu$rHAj&FbqvZNMT)|@u96B8!CNa|r z4a~?C2>QwuDkiHsrJu5A=ALmYYCU;7h{aX__gK_H<45>*s+OI_)W~dOXcsmX?Z9n* zKA!5?QS&#o^?vu!HPs;^v&}M1-%wXIJA`;QMylq0p|7@5BREPK=(~i`t}kp~-6q#C zA^2H>)GO$H)_R^i9+rC*ZIPb#5$SU#OyPUgksrl~HELzHXb4;|jbs3h*HS3OYV{X) zR*uYvlUKB7{l|~*MMdU7PhTYR3DBz11=~>aTkJ8PKw!Jo^kiu@TR6oi*|8xG&WbQ} zdac{^@4MGIy}WaLKb6~;QYaJj-OQdt09bl5@Y<#Uut279gRP_|r5fv6mzI8R2iuWA zQST>d|ATf?O*mE3rs7vhhEmsRbiKOdX|62ZRYAThuf7nK+4^e~20GusF;}@q6O_0Z zXucCSDGopYUv`7|Skd1ha8VNn-XEdWF@(8GUu<&OedC*Lg!LE1lzO+_kiqHrC*ZTw zcs#1h!eRPr71c;QUsoh=bB*?l{BwBwvg}SeOM~g9dP(kh$i_gGHR9^5sk=^O* ze8+$Px>*j@YG$yPHS>$7%4KX5nYg9IwxUinHG}z^OF@i%AU?PmYbn4*s6{Y>-gX2m z5pU2>Tf%PXtEaYqrWbIS&6tNJ$VArnb7yawX~unaXa^!a5LGMOZ_T{@xJFu$DP9|5 z`B{rjBxu&vf9FtjW|**>oKf;-jZWgNwW(Q35E_8SA`VfX82}vWcaJv?{vGh+?{;Uo zUq&M*-r(of&)>)F$~_sOO#5^{sQ(821-&%8eeWJXA>@;UA{kO6Tk?YNFSn zjPLl$o7EhS?vKyp1Y7lb10@TG28v}`*!$~0un2VC=;Z%|Z?vK5!CYoef`i+P?RZ15 z5Fi4b5X4h8xZ%t9cgFd=4nK*xb{&+IGC&*^!SkzTpGa-Lvj_wrUg{ewX=cK{Mn|pL zhR+jJSpxSCvI*CNLu`UnNPH0t1B|UW)Qou_zShXPOSXH8bLtA5G+v^mmh{zK zW(r-uhU!^qcq<`d$h=L(g8YR9Ow$1a!Z<_#*Zy^%HY3;w8kol^L9!|tdE;>qrO}ik z-@+{Y$E>&oe0Z%W)Ddk!2fTP? z#@G>}Tp4R8th1DrHzg*{0>fdIQAK43mo-aTf3oTj_3nh_cQ>GvcBYBxr-y_kqzK{B zk%6goGG4P44D2IJ#4@@ujbGm25W$k_PasUbfaoxQUp6gKp-oIG;5f~qGd*^SJRJku zar#V?aV%g#RFXU?zJ*SGsW=I?#lekK(M9zWR zPaJS6>JxM66Z9I1^$!3fD#UBEUs{m!w1^#s6C}e6UP*CTFrf`Be12%vP6sqxRm~cG zrDzTQz6tg(Qzuk3T7IoxnpM2eP#nqnXw?^`eS3mF?O3WnE_7vFf>@)th%P_=B}r)z zA3!9j_8I5a?=>B9@dQB7)K2%17iDX*+&LopfUX4oM7&4IV#Zj_G+@SWRlcppjK{7_ zc_Q17__drWv#`@UP*K|lszkb?w4I-uil-ar;7F@gRpwMrdzZecu8uCR?z^n+9(=!4~_qf{ks)g)lo3{d_{wo?X}Lu-UCt3s@5kg$^A>NlNTIDPk(qyG`x8{~mR z*mVJ{bz7A62jcZdruEe+wWnRRIs3J{72rUt`pf?k+d0UmD60#N!LKjtZ?>NPA-)H2 zzUNJ=DvG7kIjNjvMHh`ZbpvA+e*@-3@wW3Ds=D~x&c;#l3fZU8oa_Zk?56)49CIO<|nx?0z z^0^_;gIeG|ZEm2( z@i)C6ee+{;8(&THM?kwLXS9*qjoGQ*yZ5_yKi9Yo06a45JN}Jw6c;2iRl7KbGuBFk;{oOSKU~q4D9LlrNeq!^%{@lKf%l^Sj zB_Rsj>MsNM@%^NdLrmsF_>o;Kc|#mC{ik30pGIsuA&s2>j@Sm%4-5bIi0xC5`!FQO zH6r~K*t!nNf`_T(`jwwXY^m!pE=Qh5Y?<>$Kk3(RMe-hi_t-KJcQ8n<` ztKhNB?V%p{C~dL6Y1(QAK7`B&E>*)CI_^k22Y$%)4`hdd*;rAJHpRrzf#YC zJjZD~C)=TnL&}W(=$U_*0i&DiT?EgaY|o?NKF;;uCgtDH1Gp9x%op%*#}CF8x>y!JlBBZe*xxI`QKdck7`axsW zGA;wUyE^mRi@FS(E6hN7YylbeoWN zS+-n^) zJ0HJ5x)K_g7M4|K+nL~#L%Ta4%y#fRZO_CT(r}mNLUw=GY?q}k^e61@<@ay>5i$x{ zv--1pOw&916(>Gq?>u3Ts2k@3%P7slM%&&=KLk=ez2@i7PIql&^u^7@u)DMaVi7RBF>(CO!WkUcNl1C|$E z99dNyeFt272Rwfdc-=)vLk|S!de~_XMGFqa`wk`d4#SiVUi^0{g4PQr%R{xko}Kn1 zt-nV)w4d}|d@`{7WEA=dTA=aCwC|Jo-Y3hypR8z)ZC)JPSsuR%J$5X3+L}*R-aB^x zdkmvJ@#+&$*TD>{Jq{>13EZ3WobdDhdjh9D4S#W(9e5JcdxF%eT_Xko=zpQ1qXFLi zPv9$>hK7dr={%#MeMbB287&6YO7eP2nno&`oGQB9D!RsMa++!?s_KUN8ivm`O6N7z zI5qWkG)smxE7oT-)|a}XB*oKnRKm~joO(z3t74fTUlFJ&CFVRh}hU! z+jN-OI-1zo+u5xy**{@l4h~P)*Q@PCCue6TUlpeseV32RZU@UA9v-lF>Rw)6zOUeZ zetrROWdh-Ef?S1yl4OHJB|@SiLsH~IQsqL^w1!I_MJ=wHqHM8&RVLLD>PX5sqe6=S8Jfn&bw2s{{@_B-eWn;|1ZGV;Z!<1$@ETl zz`wrPKglo=DfqvVVIodT^9|M~-|UHo|JOHrqT%;uI{&5N<7hRzTAZfs^)VYJ3eUqM zNJzK>xc6JWZg+Tp*-L1;sZblB2x+2A4$II^Nm8c7qdKUd6M#zMGgu2<{Og<1c8xIZ z?+?Ctw7I;*`f-)7m-r^2c$}5=@=(2Ewzu!k@4Kt{Ki5({k2m1#b=5#ryZ~A_PAlt& z@cOfpLdR;UC*aI6YT@0RN0Uq)tckMqqA*OOvV|a=3}^;|xLm~~lB4bPK)>Ib%@%}{ zuDBnKK?#*hV7{H$iId?#q*}<5Ix*?+O(BbrAQPBX82Z5k69Dhp(H^2tTg7a}#eycA zVL;pPDa%eRtu*B$UvUyC-2r)-mqweFed4!tCkJzRAl(pMPMVMkCZMt+r!eUpc2ZzWUQW`dIrcrv;xq072jDO4H9K#w}}@O#~D5H z+mt39Bh9@R44tcLdi?CyaO^3Lsvx2i-(x_pH3(!(5I{gQi{&-P*N6rl@h>H`iV|R>90p&YJe3}U? z51G_ifE|gc^)|c zAJdQ}GpsDDojC3^5be$d7;E7CN}ZubL=mk&2glVg_;_&;@AcnvK?i%yrc*`kI>jwu7S|i3Q~} zPLjXLa@Az&U|NoR95V?K`3p56Mm^z|AKN^)Ud7ktc;@@ozg~B_AR2EA#;QMJZ8F|# zR)QgdMi7aOi{$yOa6I=lI^A3(;6r z2C+>q!^vj~F+?T?@d7U+=)grFWtAbqoXbeIe}my6(yq%W-uNQ0gUT@F)+Iu8rU-BQ zfIRt{S4BEl2lD7Y(L*y*WCByo!&DkV7wwT@VSt1aM_mGdJ@8oPVH;vbnBus?_n6nO z;gC59CIh`4HVi&YNb)0`J&PW!P{{ybphM%;!vc8{9}+)(v?2xRJYNCQlv%70{Bkn% z0Xw$1;Dsc0@D^%J7mnOc)-}gQKq}o~7EWMhaTxI|&}j zrF1^3cod-I{URo6x|CUPd$F90Aylc&A~R#s#P`llQXYTR1k)6Vm+&>R?1!DxV!NOf za%<#RkrWb^EmMfPNX!Bd4b+x|pa9$>2lzAZ;P%*I$>!f##7$6DWEs42ZK@~v@b@*S z<5N|HkP#Hsm0A{-e1_E;Aifgx6#ESCw=fWsngs7i`oUnO`W04_&uatftkv3#Yndiz zm=SNeV7jGqaZx3OVbIja8n7n|>1m1Xcoh!=HFqW}K55t>-de$p;3O(3r?U1Et3$l+ zxy>(*RmqKHzr)uubIw1?UflCF$=>K$OPLV}0@W%|TjR)v3gOw5GP(C$c#hH%rqYi~ z7{KUH=hn6rX2i3kFwe@GRr0uEJ3Iva-{4A$-cI9VN~_v#>MtLU=oTYEDEP)-k-||p z9BXoRjSsFM3i+7YOosKM38`T`Adb0!nlb(1s9AN=#`+iu9^*N;vp}wj&Xx0W`mA6C zOp$QbSF5NekUv7Svte1dUO(OAMh>5qcgnZ(_uiI+ zJ0Z_3!66(cb|mB8APu&`K7e#u#Ed61sZNj3&COPNUbdJD!iW(GQ7x;r$$Cs+*gMWj z&t0Q=mpOuG{eEjf;uGii3cYibyyKT?5tFtb?>l@>p{g3XYIr0w1rHvoz*(yr1}&4x zqw;3=*afvzeQo^#w%lK43(mkhdN;6d@HQ7F7a%O%OAuA|Qe|=~@Z;)5u(v|a6JsPU zZdj<7p}8EeX+dPL8nD1*;Bu}PN!*kK1u$h#VriJZB`H=d_`#Ivgz>(qIp-a%Lq>v( z60fC5H_mq%{MTRSSZz@fjNP2&Ql^#Ir<*r$U;Hz7iV%3QzgAn#wxwp$n?prbT?4NKtAf1|HEVf``I_R8dat~*z_N3bz@Zw+2AE8&V zQ|6x7nJRi=Jvl5!1Z|kf?afEQa1e3IDebzyGj58g`jFXM_ksZ&E6#{_7fa>wKJ`^x zE(FYNL4_B2j@kH^;YD4gWseW6@In%F%0- zOI@#%5M--h6@#_(s;+980VFEOblsDUA+RLVDK*v6zf2nf*Jf3rdNfkWiZ*9A_V=yu zd5sY+B&+?%{K`X6Dc3II&>+}z;FSVvWEly}gv2i5r;*8;Pnl8BwP6T{FMt+9Z6AY; za9pix3<81q?YBdP5!$X5P8MXCSO5-96^r-D-s)uTZlqp69bWAl1zBEF{!u1)TsIwT zH){3AHX9TuT~LC?ay8SiY*E-I5E_^xIu`3 zv{wQkBiB9sr* zb`RVzSX>t7i$xt8Sj_4tpMzT;grUm!G^fKy)>jA2h#ppNT9sF)lcFx0@E(F&0rdes|m|;F^{`cfbTHZ15tn84& z$?1`53GEJ_6|E%-weyYAg&GY5CJk${jLQ+IRdU*(m?Y4R0g9oC1RXFO(++Y8>Z4;&fvP#vj?G|5+^@v%hqR2vtWp(|WGJxI| zZngyHW%-4h9v(-*oSV8#gLbd>wJnjs{Hk$ID{8yrWkGF54*thPki zhPTnWe@wJ4GotVoouaA`C=0N7u>i7Uq!(RGZBe+LuQw~36E1qP_E8BIwi5JSt2i)ML#CgF*!5|oz(CQLOED0#`kO~Z$--LyiB_aTzExv zs>+>`3)CR~s+^~AM9DWWcI8n-4J)e>>0?!MXJ8F4KWkEg04gmaRf2OgQ>rUpD96PJ z`NvoLIQmu=DOSU(eQa8iB&^VKUYB}SSEe!Py`QQC2YRECy=yyizDcXf94)V_Cb&2& zy<@L@xB0dbs%l-vIuWakL7-UV2MZIgixO9!$3{C+RMT%r!ut+rC`)23^*yuP z?)~DGt9&yVm72vZ8|e|LM!T@1rL6Us8kr@$A*!)pcCcYCLJ#ANl=64@=Rj+Q?k2A7 zCZ69-yj0EnPrjLgHS?o-v#3Pi`_ImnJ|?W|F47ME1=rp&zFs1^1pELU{M=>@D)Hs) z!WV68#{;SJ4*1D=n5^L=hOV`snak2g@5Ms@#BEMrjGor3b5Z=}W5i z;8c!qA8)az8E2DdFCo7Gmqf6*%6ry!dd`j)jKOGhDg6Fkb0?~S-61_}>iU=M>KTQz za_$Tynl@*UMU{>`vktF9`|OG&t4UA45#&g@0TH@eTWKnS(}}22gKfLB3FmpCvct=} zNK9-$TV+?aq5KBcT=7lB6?;#!S0Osz_vhND=~np_)o9e3HTyb2q@gnPyUy$pOIN0*u*T;f zyGUepk?f@}^Twq0{mZdZ_LcG{n=_nUGc0dy8{-Cy(JIn}#)HB97Lj8i{~6^)1WzEJ zg5k%WiBHRDjyf0|@HfwRC)4tx@ZcD_0A4&8P|*rqcOQ7P$dslrxf%wbZIH(1;;T#0}_y9g9z3ldf!tr446S8L3TQbmoU&sJcg7l zijT}ppE(+!5M_~TR&`(59zGMiIz6m`nOr+NkvH9KK9{VE*7wjpJ%c8)FekFmuQ@bJ zxIbC_)Xxh8aqG-3?w~)+%>Qzo4PBW3tHG?hkJ;CQacw>C(I7H3gHhT#Ytt}wEV&qK zJs;EnnSKxg&CCX20ZiZ^&BA%_1<2YC29qYHYvIE6AVw%;ju0}-cd15;yF~nGv8+Z9 zbZ?2sup^pMRXYlgB{FpRo&KKaJ4(<3I=RIRo-B%@4u&@`CUwFar^1y5$tAGvQUIz1 zKn4WLhlKKC7D+Da6+%SdAQ7u&M+;)Eu@UB{1&m5jY@K>UX9<Y62Q5uw^EhZ8#{ z`1_qwYVR`Jqbr$GHqO{zqSq#%!8aC0=uy(2?r-A`pJLXEU&R(Ytd;!++$GRh zZ|3`-y{~mqH&Saji|c|kJC`&c>=rOwWY94SK2XyVk;L0KMy02b@2mAfPF>MaD^Z$p z0j#_qKAuluHGTwp?ts3n4omGddLPjA9db8X5MZ}gMJpw+k5SO?gXs@5XBKa0mI-th zgz6z$v`ue%$A$5BES!cV3qCCi*I?5bS(v9hQ!>d^IwGUrM=zM>?!%S47frf9_v5F7I;4Md$j|N2sSp~ z7CdTfoLQPdH3-M}V7`Gt_hD&f1EjO2+&fFn{rN!yM7_Jt7P7!rH~-QKeS2rgTtf%i zcS@rL(Qnt+Ln(|yx?>%qd+i+A@Scx+TOxalaq)nzAp>|Ob3XU>#A1KlX@9F`@qEb= zttbzr?fg8!Vs_De*KA?`yF^!;<+l&wJxej)Xk_O|J_0IczMa*fT!IOR3sIVTN`E+i zyAP##r!C3gQM_`@aM<0a(Tcfv#hQHyo1?^q@};d$n0 z*?&$xU{B~Jp&KTl5WW1N@;mu%y_MrT);afTpXTf;*G|jh;EA^tO0OG8^bsReYlqw8 z#|v$O#PRw*OG2(hI_w7Yi5=khpJ^_<%|`Eyu*>qxC+6uG1tz8uz#Tx)dq-v0JOz)N1 zqQhH*Tc?Yo5VVCG1(cs$dpHHV-p_uyPI}5@vBK_R32LA*GqREz3o0f+q063!&w z1D)I#-+s9Lu7UZp;EadvSHm+X%Z?H}@)uK^GlNL+Gvjc3%L72fHFwf6Pv7&O50to< zi`sa3aA4Z}j@KH>ank*k{=85@!JK9`6(JqvY z!ef?MIn^yyP3N)SS~=6N)OAoRGhO{GOZPfbl6r&p<4_#Y+=OnpgYps;8?HDVyR}^o z2J0>P50KTTf>`65Z=bf;FJ2CWq2sfdZ(LfB#E{soVi%rg<6#nwsW!9~5lFtC(`XR= zn3`Ptf_+BHItiPB(+|JS1VG1KNRBEv<5owc{7BA#L3(k#yZzH+e=rK4)pF-)2rur(wW(Uewywp2`S;xEINnVTHAY5oIE3&2b4_JJSca99)pY zxHO-knc7D^15ZU#GoSB@hjl6)*L__0x=RQ4&*;aWtKRR~mxL2Hu*&L4-EgbW?(OQ^H?b zuCyetMzpnG{Jy@@mO&-)(UHSho!3zyGJN#WRig5})>UCl_nBAaY`xag5LhK%Brk*? zL=;q`!o#)Q3-^n)WJlQ|sLX+CQAR>+$wlaSF2B(0XU~O2$tYgwt6EP#|acO z3sJ-Ntk9l`Ud!l&TN$RN({OBDPFp{-bkh)3Xs&64oMG+@BuNF)oW0jpK1@mlmCba5 z?Y*P4Bg3BN)#~~@8$^~#ILGMoP_N(=FDabmm~bSKA(W|v5oRdvWG$n2corcHDCz)v z@vV_Vgqv0!V>;Ce;-VLlez22gSPBsR-p z7HqC_9rip;cX^|Nk+{y&;w5Y|$1+vPQ=yihLJu&Zm)j;RBoDqH3#GPrZ|k&^?wBAw zxWKj^TUk@a7^=R8fC{1|WbtY|y1!Mzs+@>|SGHXH+E!GUaOJCHmy|zphNEVOpPPJZ zUYq8X0Z9EifnxcXoPf0n>{fSW_BeS4|1NAl&D=l3rv$>Kariq;1E1IP%Ne1-`;Zcl zRWr1Qg`{*slI3;*AcfORFI?$aF2Zz%VDbs`;5*x-@A4=1^n8wcC$XU=xsERE2o4Dy zp7;jxtV5|jeu+G^!i;EpEG3O+wV|X?y*|Cf$dbXg(%UH1&>BYk#QMa;t{P5PI0jE8 zerq2o^HG*osXh-`;m>_EI5g#*lI{e11)mtkvUoQq<$QhzKS- z5An;GW-D~i>T3XjS48S&i!1<>U2YgdhMP=q&J#n-8v90BidVcaCH*?bLPdbz zxigYG1;+DB1ONVZLa-IZCb-f$3vDPhYD4EL=R@k@KAy9BP-~Mu-;4^)b3&1a@69XCi(55Mc zIVd4-Au%CFYdU#StkR)%Z~a}PN#KRAolCKzfljj<5YB96FlmkrRIIKrmP)37Q@vr zd1@dBU(d(K6pMu7TR~w7_@@O!+cNoYXrvo5KMboPFKd+SVvr0BOup8hnj%Sh5Xana6^&N^FDj?qIgW1C&g{Ztzma0@>~+f z+{5$y5ex0ks+$yjT4YQj{`lqOeihq5BcLjzSWhBK@nJ@^dPzPa+$3x7mC;iiF-+s|3Vl(OnxeXS z_T}fC1-NR+Rez+HW*z2}q9PEW;?}Wjd%9phQcY$n!rYqfig ze5}N=(vvmvslv3jexwZs>GY1GgUMgr#;>7$a1W}Sl%f21;$694T&)bCSb0dpolI7pn{hGSW@?PZr`tn8n9VCBU zv?IW0!@z}3sZ@guMb!J1u>jv+@wg%}-i=mMGflv~FDhRC!Uw$-de-l9a=F@{>aBXF z=g4(#0|d-FxW3=!ta70Yyvvxb9PN_mkMa@wmYWNG>FZiJSC@5d8t7g4i#?7CwEX&O zSdG)ZOI}cNNVxfRNi?=`Q%PFgN1}@dc}AV*J%j6UtLqx}nxd*rQm-fhAH|f>MzbF) zSEcp+U`l=O3Hjt^49IF{D%o!oL!mQSjLC6QFGeig@UPpk0pTs>s4a)bvu5(4W55u> zoBG~0Nu@7xNhgBm;?aa*SYN)`T1t-12EI`iSh=nK#2I5+1N-u&nlCkngF!UtiZ>^z zC%QZ1t0!+>RRIGhA7)mZraDeF){8he&(gLG9#bq8U&Og->`_?fRg>W4FSxc(dS_xF&WGQ1;(1aO3MAeUT(U{&l7}@Myd_c_qU~Qg@PZXoN@MT< zvIGNRqVRazO>AQCLaHl4I&}`>CBU4-FyB(QQ6Rkl^>ZfFbjol_)PN>WDxuoAW@5%V z-Nup}_Kql3(Tm1>860?XPWDDlHuF{ICK2<`rp7cFK-4**bgM>>vL78e#D4w)rwH!U z6V|aX^s|XC3E1a>#z9rX@j%$0GSnURSsG16-oHy;|9Y6O26=oSO>SNiB#|)gDeqqk ze9HxOli4!Mi&4*YrNBj^!jBl5la|`&4?9%iRbr?~j{}%yV0e#X6A=nQ>C=Q6 zgiHbhwh_dV1?Gf|C@K9ouIYLF523E$-NclCyNU^G%G%q0f`(5500 z71b_=90q7awzZhaud2*Su>~Y8b_^YsgnI7WU) zRP8DXqtt@xElOcIl`nkk*52JxVnTvYAk#qIcqcC(fF=)x(l1Y1jjsgWQ+J`OT97j? zx>ER@ZsvMoeC}5`3M#*3Wvo= z!2!c_0H|=lYsNiSWiwty-422#%QV@cApR@nV2eRjzH5?T@-a$PR(4p#OQSuns@mx& zXW~pC6~u|#Su_2ad?%2`a1r2(n%z~XmRh8Y9x&i*t6by^hm>%T+Gz>GXnU<=NNS$H z`_9zOo|u8c$jM8d+7Nyj@NRR0rD;*iS~Z86f1puz9zrK!UNtwyP>FA{HK_8o7BS2E;2oXJ-Vi7vw{;8OwS9X3UwF}@;K za)r}+w!&4Fvljq>14XCrvcui!s4*zCI;6DUGlYRpz|=06@sEsyhaC295fO8}#zy@D zBu*@&E@4;WVqp1eU6j!9rAsV5d8w7506`gm{(e9SDRTMqkkVvc?H;ULxCg}A3eem& zQ21(~P4kw9Ik$}ykHYOeM+pxLk>P&Bing1f@h<)=g$Ry`;d`s}QSr14XZY2Zg}sJM z*$_i3TqA25BO7ibTPY(uO(S~?qgQT54k1R42}Vx&M$SU97#rC10bys=M($sYJVpsY zuq4sSh~?i#-crUsLWH0@88KC3{}AJVuY?-$#({OlK{RiVH%5YXjYGd0_hrE)2Y~$7 z#^K!12&vfj1FI1hP=p&af1>^b293#w#*Ts>FDN@>XQ2sF8>br+34fqTW$Ty|>q*=u zslMxxQYPsZo6a;QJP`ei1e0uTBT-NUWwuG)?51@u9>c21yFZ(oJ17iUz}Z4bp_FN9 z)CjE3gy#}o8e&>W(@WpGSy^XV(`#BgYg)H!TL0Db{U6f?T(d?RvnKmBveV6esBwue z0Rgn7C;*PPur{|)PXje8CSNK+!mF6$u?DttDo1D_DBU+Pc#i8er)JcZ+tmSZG9>iy z)U3rVlRm+meiwxTVjh=e9>TpX*f_$gv*92HuVjn!N{GeE0$3*c=)tQ6u{h#CWPVeuizUkbJN268_<4V+jW; zPJ?|`xy!4HeI%9irEGV97Fo6nUWj`8sSJsL0K*2tFFu(IodLLX-u4@U4rpQl$(EH_ z3VUwxR4BMJP|*1S_VeV3FInr7iWbFmrlPz+24+*{EP%=I4Affsl;lV;0?3X5Ie)I6%k0i3flH5!T3K zsevG=0~lssLBTF6X$swCiW){=<@kyO2$GkrsltT-2q0Z2rdq$aNVE--^%Y*~FbXFD zVZC^W&&7#{fM1_z01nm*qIFvSVBG(jtzpqs3NHp17PeU$p^+h84(bJC9KMJE;b9+6 zleYb12x(h`@Y}xi6(APkKWMm^j77rT zMm}4k?b|=bV7m1H^eALTc3ba?+=uAlm;hW+9%NP~hy@tl325Y=)vh+SiG;}FgYbaJ zh+7$uWB|}x?Gj`K5M*LDT4g>E%r%HyPUhXLsUVh#GX@GW{^DbPW(A;I2x$O8_KIkB z6AcEhP#$G(9@5GXeUFb7}x6niv>x5IIa;Tuvr{80I1oOzTs{0hnrHw7HtIw(17J>KIPjI4-Q(tPTPI20u<(K$aoHXCT{^jq02Ww)RRST1 zkBWvVNq%LA5NahbXgG*zn~-R2cHX50i_`UJGjQ62wp%a2NS~-FoR-8Eo(Rr}<4+Ed z&qV;NhThB=Y&#y;#kLMO`CX$`YXOdk2Jz@Ru-S(Az=ntbg#ZG$E)y@d=vY1jy*}u| zg_Z@8;XTgkgs|UcaS;EQWe(oHX#Y4gBaq^$7FtItXaL{>=kP9qAnT%b;q=|;F?OV( z)nJ%{T_P9@G-hB(-U^2BVn`l~dA4K?rbKczi^B#NptgzYFoH%Vf|f=IAb4Yo*kSp0 zkfqj)DLIkHz77gjY@7H%An<@1AOa{+5L)5gmmFZ(R^pkE65!1VIzA8=_JZx6DFAR1 zIC5s0ad=0S8GW@iuTGkYeo0YJeT!>%MF9{jR@V znGQU+7xcK#c$(|U$DRo5jc?s#to5{5-gZw*gkC|P=Y`o zbd9!&n!Px&`_-ONkU{{&CDFjCJ z0$^&+?&Zz^ZbQFgZc*@qVDJMN;Qxk$wf$zj<_U?=@LyH{m`XI4J?7A^5r7rgU;gYo z0FBA$jzj(lCEsA11wk(_06xzPqP;0bH|+q(W-jh+Ie=x1cy<=XgV6BeDUbE$sCBAk z^v(9J8HV+97xpYJ3o#Z_4&L%U4}f6j-r%Ngi@4SV`4X_mu2$w`XMgm6r)fBEk!5C% z1YUFeXmC$Bv?{fLwgmrfUL9P}O-W6zFXWk;;j4aQKV4sX| z*6?dD`bgLDcy{$r5m!)emjNDegLn+<#_^|?_d3o9pFexvb!$f&i#Dd}%&<-FM)yT) z_T02}Ne`2ow(d*R4NGkDIe&T!C*TxEiao!MMH*ftM&Ap*iE&r>i|F)7Nm7RWdoYh} zFW+AfCtA8L0E~D1$qoI&&FS;z4kjgX1<3FwPjvn^VXXdn^Zw+bUWgW6>`kYMO@`}x z#_Io>fcqUmUsBJ59YJ-wPwm6DaonwH(O&MZmvs(K`n=WpHO>m#oT;{cd*^+6p4W{{ zFMi1#3$j*q3jcbyMPS#*>O@2B&ewJ3Mt)8|^Yf=#g2q?{Ao>E(@7$yk?~ie;1_(0( zu`~d1poSMYc;E;rXb^x1I9?DuoPdYm!#Z3HJnZOEz{ijTIEEyWM~MPBQy}7b0l=ig z0wQJ3WGQiFNQn<>^6WX%C(ximhY~Gn^eED#N|!Qi>hvkl2tdrpF|$KK(1;sF+D{28Xs3oLa!h`uTsWm3g^lQxhz+-~*2f;-oldIrMM z)IguV5WkZwY=tfjUe*m z9hG*#X}l@8A%`7S=pl$9iZ~*P9X=qLRWSio7JZ9hSQl;iO$1b2dDUg(d_L{K7y)3J z7Mua^$rKl25sB5&0{@{Wl6Ltq_FaxIl$@l`{VAQJ4^V|E4%%ke)Q;B4d(s3iz~&OW?VVemXjXkSg|>=?A*2vS zRJJ2!PPQfNnvMzhQ9_AMMMMYv!qyg;HM|EUycCjIYaSrCs-cur`ZWIq7dv!poIx3% zb>m2N$p9dD9NETawSK*@LqcBcWDy=lbo$$|0(2MZs5somP+acbOO$j#Yql^@cq$y4 zyB>6KR+I_hVX2`*~i%0QirEZaszze>!gk_;1c@T@^Y zce*oa7p>;_PbM9Sln7V=A%X|e$x+#ZZ&7BYKPb?<( zSOM7%cq8N;0`ZnX6Hpa3hQ8Oa(C`O7Am;FAyv{{cLe`jkj{9QObafTN8mhm;Ywxl_ z3;a%Di-*P4*2$uQ%vIe?^3JkHl51}U-$pK!efY_PjO}7kvd{mMZ^U0z=65cVoP|*@ zcT)P2Xo?3U*!jdU`UBMO?#Gi|F%Kicd!GbxfFCEtfq^Aip9hf>pX4O~R7(<`fJP`l zk9c4)lX;KqGPFDYVMj6ATcP*-SG)ogFj-QX+)-@vK3~yFT2fNc{=79it+B==w_+U> zqbS8GQn7U7(NqXUbumD7tb1LwkO%CxEF~7@Okk|R3$$jXp`}rD2N1yyWM-+zNDu-Z zAOgaexF=jH5$2c<40DIbFMTS-x#h|Hkb~SwCo{PwE16PeSoxy5lGwf}g{1!j&ncux5XnWLSqTVx`(yP! z;sMwUWs*YamoG87%U^ZzW1p<$Ay)%SVb&m-gK2;!YoN^Dd2&yondUU5Ldl_Ea|cQj z8A-m_fr8kPj18pSY9=72F;=mj_Pi%P^SPnvHR*I%vZWkAsn4gl(q|H(=PawD8qrv; zJp%>Q2CIn7dDT)U9vY4h85EnLRBdNSWJ-M=icd{`Y(TGBhy+Ed(v`BbrBQs1T2^Sf zK&^!;iE=4Yt`}2+WkqwDG+P`}dQU&)(|uDAsPKe}ub4(mRAxYEErH6nr-T%zFCEoQ zjbj90TD7ZQ{VG_MLWJKPHFY$tioL=r6b}e44rl+E!Z>@fEITUoo|emJ1TZJi-fdNP zRha@VAri=<(AAAhQCck38ZN_4vwM40EMy}qS+6!Li{Yy5WQl^=%yPD~p8c#WK`YwP zhL*IZJuPZetJ>AFwzaN(Eo?0t+u4?uwzj=3Ze^?6-13$upXe=cgDc$O=JU72JuY%p zw}1?|^CJzgKy#COlngLHy4JmJ>8MK-?MhJtwe22saVh}`)Is>0|01=3= z0#k}m1u9UX2v{PD1EP=w1yCRgNH7Q!>)cG$yAU~vCPZa{_g0szD=h{1{lpyCs>SPCBiKom+$ zUkz-y!X1&q5*$zy`LYJaA6Nj9A7W$ykhsI)#c_z~+hF<9_#ypm0!1E@1VW(UA%2*{ zeSxB5DQCGR4?eJvk)mQ9`s(6!2w8Sf{;~gfIYJr0rF+8mFcYEEWBY4XkbDD?5yNM z9|gp4KCqz)V1Z7rIt>uMF&XnaW*QeE&mN(2s2dF860?}lB~Elt8i0r{3kA?)PB4sh zEMSAQHx1vV_Oe$)=svqRzzt}Cw{iarg`*&0%#t4QdxNsz28a6C9C2|0;Eez&Bw@oL zKDVP6Jz!QFq`z%mg00gqZ6r(kz9;yyVF8c-wQ1zosxxiaA1{VHVv1>VCU-hlC_7}x>r6@)=d9e|tLdf5pc@f#@4 z^EvqZ$8U%=lIUPylHYvkg4n`HdL0OuyBEGWckj~oFlAqNqzi}W0!g+EWE4*rzFXd} zAh5pl7du?g111C=eqJSwqx%LDD0SBvrjDP$QC zU>-`={XX-K487<_5rf(x45pD2g185ID{blE(VHdfau$&L)#PEZ>l$(5c};lyMJv6Ya65t?ti->bnkq}KVJ~> zpNXaL_22lp03d+f$h85W9D)=y9SV9`?ipAcR9E4}AMeRT7Sy2U(O}kM>yUP3K>D7OOhgVAt54^nH3yD3^?a$%p(Bs9j>V!Z-ib)*k<=!Ax9A9 z1#%YvNaj=mrG^QbavF==4O+}G7i8ih0xXyJ(Vm9Q-z|owe$vEpp(TrX9S?j2!--zm z$tIUYAQ&zPkD+IJPGxhV=g0-?LLmVF=wkY3l4xgzoa2O|+a6FrsrlFrLSnPzU_bf+(j@?EF2G9WCl6^? zF=COGy}=;><8=lC_7Q1df+%=V#B-6RZkC)xI%kGO=Mt_Q23EmywP#>vK!P~{lKN>$ zF6M}a*^we@pCV{wJ?T~!z=VT2N)Dm2nTf`Z$ zU=(mH8Ps1bS^&7h-N0U?$6{6wf*nBa=Kbwo8D?1P(U&NC;xtkk)h&Tc^qPwGpCN9U zPzHd35g+Vv#D^jQ(XDKcmh6{VfYha;9I}BJ@&Njo>+>}jc*Y~%P8x$@;u;*>=N+Gh zdaRG_BqYM>GjbTo!K>PSEi?9?=WUj;-dK~4UY$M!K)M|uV%>jXV3*-!)tdip{(bEN zXy5!{$(LH`lVa<7F#y4)0j@a!JdSS5CcqZ_9>Ip-C-mT>3U1yZ;Ht2}XcnKL0bIiR z?%|GHEk@|cy=OqG-YHfaR+yUNb*pjyrAM4-ob_(Z`Ito-SmlCcEe62y0UptzY2C`G z1>h^4?kFG_mY8bdoI)+tt$|rW?ldmlWj+K0fY^IcDapzm;qpWSU|zQt#HZ$*5GGyw z)*t_s?1B_;+696FDDU&RZa`WYvwE!NpD???WNu(Fai+p%a!2~FPP!38=9S%ACOld zpeoFL0i|_8g4$o7K_aN#T^T0H4;!nK&L0%W=p?6V5Y}A4rU52a7%I=-D;KWM&Zi^0 zYOJppB94a8ni9{O&B?LA8kUh-kR|FX>rwtL;%O;%O+{VTAs_HG2hZ4 z87x5*XtL-Kp^w(G3qK|{V(`~xGLz147a-kBF54{M=X=^QUrPVn;L2(NJTWTDmwm!+ z87Lf_eu0oJ*gs=p^-83GX5xtLaX%~R9AKfW#;hLeY#$aNZk`_+ICJ5t@zfP$#2WFn zf~5=YAsQcJKQ5a->zxG57d@BYfsS*Ja<1n+>z9718)K{vhGlUYz>>mT{pv5Z`Lg`A z-+OAK0&=b_IcFE>GZ>OAs6Dd+J4835aRq;;EE}<##VH!R9^C$5AMzoG73eD}sW*y? zap~*38JI~@H8r;(JZGz}_9z6x>i`s@)=69y*zVX;ZdgY#4~sPto8}T97#1VjOG?4= zu>pZ1AK8Lm7Zijgj&CeBpIz^P5}WMR&1+a{F*TZ+6Sn{7Bd&4X)pQkP?3_yVVR~{$ z5Ow@k$oDlM%>7*efU*MAZq9Nd9rP?bE9UEcfkiICxdt&0<6hd@-TE%rVLHUn@*h?p zFD_!@0*{>8we;nhB)ld8A$uK?RUHnZ*vLJuQ?FYAsBpeI-$S0|Wd>_d8z6LpZ=Aj7 zVRPyDd1A!z@d4jw%+CL1=Y-S5wxuv^LZg+pCG$U zYlk(MII2KDg~_&G&*}WKvFaW!kF#{K!d(2JxuC8=z=;JZ+J9k)Pw)iCvdoVq+4>RNV=iMQBIm6+d*+BE^YN_#hv{44svxr&bx0baOOL8Z zZeAe#tD=pg0-7ND`QNG!bu5SS6Ez7g>3BsudqB7sbt5_#>Ro-#{dSZ-s zxC+xcx}Rcdm!WCubLc%F27m1ya%Ue}JeL8zv7ROkN*a&4Xp`p|y?d-;3Mxx8vZpUd zJCiFLAfBsBT9J1cvb}FS7UzJrIlOK>zfrZid?|edw1(>8|`Y7cV9nys@v<~ z6?m34qWz5@jVF5iIlRSw9U=5ACL$Qs`PfGLY0XP;sr?+eHXyR+K6H{cJ&U6s9`tQ` zEuK-hr6O=l%)uUHcN5fgKtBJaGc+AaJ-CH`D-4Sx2hFvP|I00m+WolppX$)O?)&>+(AkjkML1r&amBdE&5 zB7ih}A#{*|A2uUz0I)*Gf`d6<6toefA_l>Y3U46V@(}2rLx651ISB{>L_|n{0*!L0 zN=Bv%3B9o(aO9i?4-LL)s&M~_AU_`-O4zgK>Q@6*2z8+Vw5x?ID1llrWTgRIf&|p^ z<+xz36$2xSaE1DiAwilv1uZsOP$?6ScMT{s35Xz_vxOxfI!YGtp$r%$KGa-T?VCV5 zfqrNlfUBRETcieJVt8>=vuJ}3ZIN|PQm~#`1E8z$?ADHZ`|?<78Br3TY*v$QiCb<} z1&mRW8JeX)Pqz%wY)6jtt5n>^_XH*|`Fw)DyJ0sa+`4hXNG3xx+@hg6>jM)2n=Z;|jRuQ! za=FHgY|0?;kb6V9K7$)5jn#l7tInwqW7I70dP?G{IXT+0r!-)y2o0+;&@9fc&MdAk zqdc{Xx;6Y7DGLg0U6H~W#cbip2A<-fzWat$@IL6gqarjef88yug`kv^Bd|ysi84A? zs_rFQRWiWOC(~eH%G5lQU^4WEv=q@mR0@PkotUJ z*h9(ySFhkqbXEVz=fVXb)C|PBPQ1{hQ?Dm`hb!V%Tmk4Tjk&Z6?XAj8x|gkQ`vQI7oiUSp zL;Zk~67Adspl-wy4L`g;hK_D3F%i|0vAm%RPU^oN`PzG9Lk@#fzeF`OkZysMGiqQE z`%-UfY2gI`VQ-cD=-w_NybsUoygMwS=m_vQO!oBciL5NpXlV{O7l^bAL7{V!A+i7r z*#MK?>X!e4kCs@_V(bO>drd_hZB#RG)rGe+%Ux$2(>F8~Bni$t(#|!@e>7k5Xs3g@ zM2ZMe^Jy=?j+aS-F$k|r!hokNO<2!T3IfN(rP^8Nc=#g#wRok!TK#P-fEiv*+Q1T* z7_U7DP|ZcE=cSzdL{*+S4}T&vpRPqtb=%R?dJ0xJ1egR_y2;m9Jf{?$^-Wxh3t|g5 zWIOhqFJjOs4CsuN6k2JBPCasfN%(a`(G=<}G9pRhvZR};XpaGPI)r>A2b8nri~tof zU!9WB1<@@Ee5)%Xq7)V?<=Cu>Pg+{)e3%!5P^L|VNn%6{7C``B%rH^#p%I}F9~WjQ zM~nX(S+alkOxtYlR}=9)Yr4wkW`8v878 zf+d{tkBsVw6v89{57wq2;LFb%}x3!&C2a@|=n}gj#AM2+j-xn%BX}F2ZEOJ~8Gk4J;rl z3GrA=hGepesOg$v(S)1MK{=J10uSsUP&#Td|Ful1XWOnG;A$B(&_(E zVwTTgauf*;7|CcBuoVt^Fk3RA33U*9lB?uoCHyoZjT}YOuzZ1^Mc|SE+(;x)M)U(S zEMuL}&;+PnCw^IwW=9R+$|x+MqeW;*4CkS+=+qh<@ zhEJ&wH@gjHv%FPKyR2+CITS=5C4`f#!~mwMl+y=JK%G6>r3nos>`WE#ufeK|SK<7n z8ljNZguF8W?Q}@fr1KaOVg|5*CD_Jb7hSZWOI|LJ>h^lm$S6LDw8Z3}!^Z!$%Ntbn zxS^rLZ27u7pDa}@Tfx&}Y@(es@VarrY} z04dd^)3h4rrA}o=1h87Ht~X9nhdgFOm6Q5PF$YLp6Y1#y17H^f>5ef=RAAXGXg~e& z_-Zt6%v@qt5j?YNs@TKoo=14o1+;TaL#a%sX05Ox;W;D@`kiVB;wqx-G(~60F6dE=8d^*6VBbP*6i+XNOEE#A0Qe4E=_kpiU_qvgVk`oVm!I6xw^U z@p(?&lBXDYe5vvzm4~C!hxU&{_{ujTvq=D?&ax$eVD85vHEr2Qcix!sRH13wLr=z_ zPH{>lk=0u{JUaxS#};O^!qRQjh!N8K1Nn#m*QH)(@2%eB39+pbBJcSO%!$&2ECUs$E`hW!o=ebW`)+Y!_`ge??uq2eh=hCLRz|l0mIr&`ow#26 zegFv{S@_in=K0p7z3LpvyIP#Sh4%4q!)AlMS}U_n2VnieecieRqWgj2ZyoS!9kMxo{E2R%lM*i zDFkck7_0geO7t|u{{F7*rfI{}@A5FOHOw!j@-IAMX7m4gZ~yGWrJhfl_T=l#jw8k| z1HVr}pv!Djko*u20Lj1#0&n@mpb9u|12+!>9gy~ThXxBE?eyhEVDI+sCw9^+0MUwn zyzd8hX|cF4DfX`Jq^<+QZ}iHd2?Vg8ijECK49yg&4T;W`;_8s%&<^hq5A#qDGl|gl z(CFrAzWh)S2k|Q)PT6dPxCl`Z7m*Pgkr1255hKwKmrfEZ5f8CT0J|5in?xRLH0o zbFqZVEtV9oz=ly7W2xZ2fYCZprk+k1mysG}5mx_Hq7@@CvZS#ZI}yV6APt158^@6x z^)L$3AnM9-5Yg-`oKYQ75unImgJQ{J(BK*0u^XM~9!IgN@X;R`(fUYB6FspX|8Wr) z0J8qcAQzG$^C$BfG7bZBA0hG}q3CePMIk9tBR7&GJJKUR5+p-XBuA1YOVT7y5+zeo zC0CLqThb+85+-9(CTEf+Ytklf5+`#~CzUZBchVhdh*4fXUa3zmce_R=pZ zV=ryVEVt4DAd@RT;Vm@4F3nOf5x`fTj`4PBFH6%dW8efn;R?~Nf(r9G42bh4A_gkc zGF4LmGIJom;uEZ(R5TM&;Bp9^k3^&o4QVq>ih=+W>uto5M9_{lw{TJX@SjsfL(($@r4F(V{ zy7OS<6FE=hwczj+-v))W#}GOxN?7T{Pz6g8;!Wu6)FOvG=-?_Lqht^-+X4XQu#CR; z21wAfF9MYyY!Oie5KiywL;y#eY~(b)=GYePtpubE+O9`Fb5A?&)aC#_NMlKEZRWfT zNW{V+<|5XbO$^*CG!)5WS|&^W#ev4c)K(QF+-FgUvS9Y~3qF&?G^2D(qzfR!LH6b< z1tXy94GK4DI$173RV7nJEQ0@L=MZ>+T0XUw?#-dNEPV(;LF{7JQ0U*P^+Lg`&3Mg} z^XE>_<@5=5I$fbmxZVa1>GOhYT+awou6?m?AES=x_=Thh|SV z(iU+(4QHf=2b`0bY~w5yU}kg-n#|Iqu1VM|!ax1yn8tQHFeC;8LqM77Ji;>d1mP13 zOF77^rr_5KE2(W6pktSpLLm9~nWAUANG(Wha+=~QF-eW&b5$N9f#Zb=Y}1j?W12X4VZZZf{wY%4%#QvA z5PF9}%VKQ>LSTTRV@s5i1aoFmcZM%f6f1^hBEeq)qGim4#iP=GLoT2I1Dr!L;1(T z_o49Ue*t6~=PfkGc^X}*jtlsJlDU%hgcHvyehPQ)j8=mZzpXd3i(moA!jB0pKb{cQ`24*DgtifsLkK z`K|vN#g!uS4LC&6+A*neO_cwI(X6R3dPqsfEkz7@n(rr4bSX042CRRYSMFnEAtbKB zB4e$Ee^fxrLP&|UWDX7tW62_)Lt{if0B}n?l*MRT-H3$VBx4QRTQIAh1BR?h8xfO5 z%i!=b;1H}H$ZQ}bDmmAUmL{2=)Q~@>EBYEbT;#RZAe{jS3PAN-FobeDqTmGPI;a3s zeVT?{WJ^-0K>3I(Fi{}u_6ZXft`(+d-vnGQB~q=M6e9zZI@Ig^0Ks%@AdYIQ;yHd^f|ext{tRlWap z`=_T3<5UlO6QFuOxX`#cM36*kWQB{}H0aQ@NlZF`ly}80%EUb}0DnoQ^P*I2MRUT$ zOPAzddnZBGvn`CGB@!bpxe|YUxY_*X)-K4yFG)$yF)N3-CQM0S^5$K(x*1QFJH$X9 z$)v+g2Rho)OQC>-_Yz7}^*c9NAvzgEs3k7l62^%P0o0sd6*_QgOW6$T*i^Dr^tG8q0C#0s7y6Nd+B$K@Ej}C=&a_nR`C3+weM#2@uhzSi6Lrwa2 z@nXe~k~{&9>t`oyFs`+L*F$;T@fDGDQ0s>{c@skg2j*&YIFx0Rm`KKrM$7-c6<`95 zIExW#v&1{5F53;qjSWCGeb#^oA%`MJb;5*j8a)AkVrj2E9OiRys%HG zJ|-4J<&#<4{g3sn^)Bihy(Ce^VhhJdQi+67l_?efy2!x4@BO@>X$ zGxj^^E-M&~I-E71WXmE2-C4Lq6UF?RL^R3m0`U->xcvOHo;zcbwN*yL*0J zKN=rMYAavb)B;v_-@mvH$@--c>DiU((_5KV#NCS2$)zyNY^T)BLgWgE^R?0X?Nf!^ zVdY+0*HO3pE$BH?&{RO{9kx5%Bz{Ln&=7~tcWVJ+0RRIUK72sH15uTM16?R2fItkQ z6EOnq5eQ%oB0)D0SfC?_z>-5q5L6*lq{yKv8UT?=f@n>HHh}*!FwC;Ci2;T;ih$&i z^58%}bSy}Ds31WWkbpL3X;45#kuNcm1P#ET3&#Oz2x%Ay(+b0nXc#Ey`i9P&IZ+Cb z-9x7VRjN{*ezo#&u0^Io2TG7A1>;dMNd})7h*yvl2@A>~DgprJr-7dU?K$j_jtYo) zUEJJAsAI!GX(Tx8!qdO+25GQ2(WB4VU1h!)6b$f9V5foR77aKmC! zu!bPtehxjl^y$toV|*w06w?A>E!g2ue$a>;A%SGL zpk@$Rr(BLPq=jC2mSF@X8UZjwSS4!0Gu>c8QoD)#vUq3kz84~!paZ>zF}$z z1<1Bg-DsaoIGTEX2;%EbX9YqAx3BTK^rV^oTfO~SXxmbAOIs#yV09Lc8o5|IR@g~ z&7b)jg_3*$prRlL^;RSr-hJkpqq5$n0ae;Umm5ZOo&ffYJKcHbrvo)0T)=&W+-%!! zS9e{b+41}98&*(dsmKZG6Xf=oB6%Y+*$e&BXf|f3H z0VE|G4qVc72zHTySk(auy9$N?a2W|t&&d`QGz2ho6)HJQAQJ$ogFfRu2wE6)*F#D; zwPi&LNE(P)YAEMJ6B_A$YN{Ko4(1XUR!DCU1BBpAq^|2>?@1uS%^Nr+K?-&u217z# zW1eNFC?scEg_#K3P&h0RG$%xyt24iI!MqZP9|=lr za#E-rvhH_AiBXVi$|F-{9(4#X`l*VTYuBvahRIBdY&u=b5+HiQDM&FbHVxXy0($ea z=cJ530LY*3en_1!3F~mtF-lXMra8H3M+}t*S14Nb^ z4L}ss-Jmi6BZ>lTRIC@}Yzv4O5tlwe5z^#RcZSO&>D|Lt_7O~a7j>oEi!K^7G zI?4$dQkhSr%vI0fP*EhpKpJw>Une4{!<;rP(NGeNOGyiG+EAndo=<>i%N#9tL&8X* z4?l;v+NlDeshF%GCY+R-3Ml`e7L0OGovnK1un5>is{!X+X;DEyB?3G%eE}{^*+{jF zgu^%*iCxm+5Hq2~N{K3pj=`H&L_o@%tHDGkGCHcE1lUIG)bKg@!l5_0=|+k4&@$uX zCQ;V%vqm~f0V>If06tm-lxoQU>^u(>F=(xTsRgZa!?2`7BFIM zJb5e%PU@nul?-dHYn^Q3m;;$HW{8gmL{|zIi`Azxi&By^BVngi$BHC%UVAeqbzIp* zuU*Chw56?wVzVFTDeA7n)TD3QCOqk&R5u79TLVx^8xK*)qDG=a`ba7Kr0ylt0MqlYWBZ*xz2*n>4gYE^nC3T3QEHwc#^H z&_O5s0#PN_?$@p@9j7YAsiBRy^H`XJRz(xgN;3Y&VGuIjvoybE#7na$D@EkZu8;&s?nShFiZ?1-DqF6dVD$ zwLJgM^l%Oc=zkEmvG_<}$|9w5``c(!rzL3sn};$`go8**ZdYuB zqnw+bJ>2i3!=BbX#h4-w3zm#GXm`6AcQz)pU_wnh6Q+LzrV~u)1BAhI(;#!o6BtI{ zyMz*WZHKuVoS;f)WMR-;Fvj!l#z_ol!F#~AA{7Y50TxlOlv>0zNiuh&Ba#sXU<5mz zCE)`OXaQOTQev7BXu?BfB%3wT1b4riVwCL)ffr2~l#r@Dk)oi^nZHu zYwM-v=hrj+2X{r#XUj)gARuE@$p0(wSTKHGwBIZ~VBL}+K9Ph#B~(%ZNl|&d8bCSa z2-p1Xrk5tiMyHE~uph?+s|HZZy49-zxCt zM}<b(i-?s$oxlaUf~19>`Hx!I6Y%L_GCTaT$a`*OXu7ks~-# z95mt>JY^gdB2r3XP|);qM0RsR_$Ug{5^^&}?*ViPmWFKb6%+u7KD867#ZGefB%-ng zEaMSZbQlzPcNkS0Hwa09LxCm19B*JSn{#W(7H} zReQJO2earo)#7>)$ zd>o@?&Q@7c_=HY^XzgQ&*%w=uG-8eQgJRHSi9r(_rj9d~h_VHU7WY#FqJo9BHpNkq z#@C3TgJUx$0T8J)%d>#1Cv4f$5d^pvWus~t$Q+MyH^c%H#Q1GuNKeVgP6`5%OaT!^ z#$$?tT9B7lAo)M4_JY5Kd{N+(P|*OXLOfOwJW-G#0w+aL`E;*gl?~CAI@AA9UEonn z@Ci<7mK=j^9wj7UNgg|NmQEQb0(UoA5CzL40Z8zcU5Rx&^c7NpB`M*Q==GJ>0R{e& z0aDNfi{XJ^mIPan7I#FLd8t4N^9En=bT2Y)AEH>u!32ir7g5kDTf~*UqATN8l9iYR zU$$yn*-xygGkIAO$X9Zr7;mo0nG9qbZuyp1gMSc31-zpIHMs?%5hxfDDB~6=PAM7! zXO?A&ZYj|pO(_8%P?%%Um0Ecp0|*6@NqhHkH&mcoO^^gw!ki6IoLs3O$B7$a#1m2Q zEEq$Yb%{@7GEJE&lV0MQ)8wAc*#xpdow#X;O>mZm_--0Dm<_R+tBLkt@S({&A1@akU!t|O_BzX|Ep@Au&?1`W*WiUI{G7k1> zTf>>z_>>n476x>fYhXtkw*(`CqizX(*}0ysiIoYED=2!DZdoaN$eH9Kd1%m<1@Izo zX#ql_nl7ME96|+BV4E0IUrPWjQjwRNAr(xbmDH&aUFweq>K|E<1>;$IS6Kz%k(dx# zn{Nu9m?omsX@0?ZC}jYdJM;xpX*hv$GIhtAZ#FIke}+Q0(e=XnyIIul%{&A2&t-WgKVt|tFcOso67%LvTCbt!+f`@tGmjp zz3QvK3ar1%oKbK^922Z=Qv_`KXU7_C%tjbX%B=X~rNoM3zzUB$7OmOZEQzG4wW_VL znycR`uH#CsK~qhr{t=xW^=6kR#Whrt^e_^m%0Q_qOY6^ zQ2|S^1#7Sei?D4IaI;siE!S?3da&_Ps^q$`hI6b80I>-xtEAFtnR;CFszPk`Ob|z+nbiLR?nbrbr)?JJA!I8$ZP2mt z2B$Z$MloQB=9!5Sgh_B)wN&c>6<4>o*F!Yq05y1jeCtQm@o5nI0h@V$8;7VLh#QDn z1^o(Kfm5LFlEWVp4_M0+-eXLWMtJ%S@)Rwy9dFJ!G-I6`YB=Ep-dB z(s2T~*|f7uyR~b(+5;Ni<~V?;CCA7Ff)SFSsyf5F2I6A?`!N(anUK)YG|Z@lI0iMp zVJdHfN{zTA4kU!N#z77z5s_uA(4i_Wm}7VdaM{8$`GJQ#Lod+UHh4oMteO!b7aUnw z9TK>8)45E-wS+}NfzBH}mzsY|$x*=}8i}DgUEu#xwNy5@%fJonz(boYEfb<4%9)61 zZUWj7Ad;*~A}jU;f6{hz35aO;p-+H7o6_MJIWtbEC{d%aPEPbTB`F1nxsp!Fc3nEb z=s{hWbu9_RJuq~I7*xQ#p)JUlN>q^_8Zf1qgde#CzcXSX<=0k`m%7e0z8R3e*#U7z z1vKbX#Y>4?$S7@ZR{$bJDLs)R71lO%^1yBE#&0~cEXhe~HAD!Cwgv!v?E8Y5!Ez(D zYzo#J<`+F1q{39Q6Ru-?1{A&5@>^f1i%mpO$@FV2HdWQ(9^(5^2WMhYRE%R}x|t+k z08K!$zeDuIhC401GaYZoA(e-NX&Yfha>)eXIllG(y3|;$T+=L}(^3qsT}xy*k4N4p|-z1s7vkt$)%?JbaGdA}++LK>B=sqOw`tbidgJ%ZuZ_ z@Zyj&sxS_ER>Prmv{Y5{lpYDn&ODU``y5Jw5GT}zuie2 z^JMbaN;Nq-tp`wCk`hVTc+0iW1R#t+GdgHOO}_RWG^ja5CCouB)I+_iJGECzGjX~y zZ-!ULxm?SZT&=Mzf*3&+z-S0v%FTJm6rv&jHD(ch;5def+yG;pfme2e-I!=T2fB{j zK7zV|<7>|@Az5e^zH+1$VW>WtjB}4nOPFX?|58W!>tUT@8P3ri&+9!hGS*|wIuT7S z_#vfYcrM(69n|)c9cNX>du_i+HfoKBN=B6ChFWc%1&0C|htLMQ zcR@LQQFL_Fn)16ut=qfJ+pRiAqETYE^aW!Q%1td%&WfAbm&|sl90%2U36XqcU zDKX(0B?e(BoDe3QI1b?ylPFR=dPOfR66zruc_bFcRF;Xe)8Tf$&a=Z}?K-jH%mz@` ze>_?!LV<@-hglqJt;|N4{DXmkkR#>)9Husd0+A_XQjI*C*T1nT35qMla+F8m6(`~( zO&n)^6>$<7Ym3}gifFuD2Vq?WJ;fR+)HHTIo!w@3YIv4PN;uGkVtphIV!e&yIj-ZF znqIh(0g`vsG*{e925rpN29H_DS2e^O6TpY_NeMVA)xB{9G9jpvHe>OF8Py%_yaf`Z z&L(_^LH9ypl2`Q&DpIjD@lDq?K`Cp#M-Lbid-GUr=FTpxVR7DThLXi<0zz?szgfyPfYV+V8+4kaHSm;fm}^LCCr zFn>`R(Zh0HfY!mr+~s1Bf%i#sDaChVpieB1#4Os*-$$f}Vt+Ph08Zq*ywN9xJwg*1 z!jS&C?zHYmtb77-$7HIth*>N|8(y{n;uooe7c)vjdBc62zahPN*|mr*5w;nij@rx= z`q5t~HuBl|!^?Xw{^NhU$8Hb?(GUce0fPiukOLQ1yLYYDpBZ2fpX_5z-*xAY{^hibGu_P$&Zb2#^H;3eX%{Ac2gbG!zCJ+GEjy6hv7JEJ4(y;l(co7R&(zzyiuH z3;-l-qu~U~kRx9rN@7!m3kngLU{nEs3ZgO+3akXwBEgqK9~weIbm)`NkQQ$22}DRK zQ-%bno&X>QQH+LL5Y4d|rK5udSLaMcio_)Yums-tSupaU%QS|hG;jb@!N@F8$(U3b z=uH5IZGlvNwz_fZ6cwjj{y|d?0!-q1FH&RLm7C@FE?j44{^TOz6-dDK-;w zwt16{%r=5(hfO;2)1fyG0(H3$0O}@@ z8ft+;lw$KsfCtaYs*0LM;%LVT=_sSOju0RKsRXg2qJX7H)2t@Yh_g{Vu8{OnJe62N zV8}ES^bka>(6~_$wt5?^vj$3A6UX4x6cd0?tg})x$AAluO0Nc-qsieoyWx|TfNVj7 z*;tH<2b0udv&J>zEYZe?KKZb*J)9aTp`3EdfTpvMkWm83@`CKH430|&#fH)4ZHCRqJ9W85Sr!-@tZ z)<9baGOn3lb0relfo)BOnBtV#Ku+7BjYe1uF|6onB$U5Z=@XEJvSO->(^c&Qa?gBN z0VMkEQ`;DPem9Gn5k?T~aT_kQu8fh$tp$m+SCLa-1SL2@3Rcj971Y4ZDi;wAUeJTyYh4G+dA@?sUl;@xJC%9ky%E-!WqX? z11xaC3saEdc|0%$EQnw{N|=Hikp)H>Oe+F>ydwmr^#VRlK?#a{VFM63g%0Efjz)+; z*u1z&PIi)eIFN%En)LuU)Bz89z`_AK0Ebl8pbnx004vX6$~@H4mO@xo1k6x}36KW} zr>x@{v`C%_Z~>Tp1Xn35sU9E*;feEkK^}}SEn}L&k%D|y4bHI3Gc0pGFTf<~{!;@Y zU^7`nP(m2+a0W;=gb1^QgBU$IPkPqVavtbqvudydBE0ed6WC?|ehG*Ff5w3bLNEdx z*QtbrB2!r%aA-2&P)RC^(>xv6WgPQ30Eix7J!UXNChHT;X+{g6aA+sx0ON&jw#Nv0 z@PM(fFi~hJV3!d!$qr_z1dH0!r#}U%vVLc*RpN00UWfw$lu%2E%HahgiDoJ>Cjvb1 zv^_Jms(nD3Qu&ZnS`gUfMy174Z(i|eBY9~|!+HISWsr8#%dNJr-XWw##1!DBn1gbu9K z48=`jSEY&8Dd3<_I7loP?8->a0^pFfm5*E7!^r45*DHwiLO2OLNh9xhZWJ7K_HEzMzbKim!N|E8m_%*0>_LFKQ>i-7xquxPGOhHwir0^(X)iW)LeV zA)HqVSGbEnIKzA)OH6gf!NYiL2wh*}Ms_DaK!N z7nn>oCwsiAfTenYqAvxhhigy(&qB4T8)nZ^SqxXS8d;tHupFq5!_Z4R!c)jJrs@=S zY2>oLcO)j(vqu%02aw*e#HCa+7sB=cr0!Wgb+ogi8-i6i7{mKBfTfv?CJs)T%6AS|%BSwOa;GU} zE>=*MTT8QZtE$*xOno<(!PwP#-c@&h#MTu{3+4^LesO-~x|@<U%I_M)P36h|7@xd^}XWwyo`|YU`dF>)<*!0E#MMIbhrD{|@Qh1z#SL&eRKj#p+;= zS_j6oIp3^aPY2NH&-HkGj&B~xgJX?PD0kV!$n?1!HBQwDD`4qfDYj^ves*5>`l>WN zE5>nqahQf$smmQq&C^3~BD5Dur>Aq#g+F{3c0I#97yRk_dF`d*^4Xmh!ZI0tN-O`E zJ+-d(D`RcVq1rg?Nl*EdYpvN%SKq3sN24JB-40)CUmlOAU**qJePqcx(hU8CF1WX9 zpCU85tb?vTUXnWiK)?7PKN@Q=9s8r3vk9c)E&%{2o|-w}i!srIy@mj#^0P7=ODjvV zCG(>XjU&7CBf#3TIobON(Qyf|Pd9>lDf9w41Ol}Z04ywksFTARtUN#e+_aYRKyR`WV*kzER-WG+0(rCV5`%UtjWqgp>ri+JDBtExNSP4Hd{d73!3#KEH3n= zHaxtxv&1*NM3H(ob-OIiTEp83Ggc!h^0P*#nm<6yjb|D-oZ2gAWUzx1I?ZD#LY%$R z`-ER}#)tyG@z}NYlCT*RE69^F7Td=KTqYBvJs@aB$g4j%TRv1o$b|eKonkbBd=KE8 zrRlOe0EoUr3n&1PJ?nDFX6r4dX(xDmwrR?_b0h%oBM(Mextv?BC!@HL=m3X55yu(PQDnS$f>`BfVL%%b|{_?6NM5cTDMFrSM-15KNh``etJe%l8 z^{}xEw4#$*rhdYsL5#q5#JnPtN{s`n)_X}e!!boFIhU-i-6F}UEWsW;BM}UM`qDdi z!nt))uunWIM7$k!;!A}T%)#`WTx&}AKtzd~DXz1%I}$PmE6X$BqpPbk1oR5cqOHYj zr)b+af@Q)!<&RLO(TgmX# zC=UC&VtOquh`Zg2u68=4)k}}UI>$>o7{FpOENHK)B&>`Y$PGCuaco6ZY_!_SzeHk; zgxa_@+oPu1CQY*>J94>MjILRWFD`Jz3=OZ8I!IdUGXSN?+oH!a+^vKYf*UnL^Z=<2 zy-N7J&o*__?!mvFO0IC6Q##$K2{5M#=&1Y%%-GydzCtRVd(kkkFM;z*KD1L;#E%F7 z(#Jc=*84049Ln_nXd??nqhT6FOr_L6B|$pn)DHcu@+78mbV*UA(^-nB29P{b>(MuL z)mOb75s+08V^bh{0EkLFVtTjZvMvw6)e)VK*<#H8(92;szyhR4 zN|tBEp#_-NSu+5HdP}&})_(=q{}2Iw?b9J5q*^^1nQJKRsX|V*u2zjz(G1v$MO2El z*o(#3jMZ3Z+}Muw*pCI-kQLdHCE1cS*^@=tlvUZ4#yp#21x9UR0>T(gZ_Qkm53i2#HO zrNN!t(IwqCo!S)G+_uYHv$fpPV1zvZpSvyH*`?k4oZ1}7ffUGEJy~6{g3#QQO)@-sDBaPe5JV#og4!$le{>%3Y675MJT^UG9lV<>lV)wXoZD-W{+=6L0oyg8fPkYxuEX8x#H zl_-K}w&uav0jBNeSzj z-UFFI8^V_Buqh1X0BoeD118V_qwbTWCW{upX`J2>%f4(D>CvCr?5yd6K*1HlfE1cG zXAP;F@L+?)W}PiiZPtb?DS7O&XoG^Dm*S8RwD1pZMKu6Xk@J!1%buFofe|sd>@1KU z9w_ZOu|Fj9*$rG$$<^GxEYzI0u!1Tp+Ex# z&x!_-oeO~qLQsu5SrEQ{mBnZbyqO&xi4hZe@b&PH=NKEfYU?t95+iwoukr71c8{N6 z0yQZb^T2EOXb#&>0t$bTJW&gQxQZqyf}c2&pbm0N0a624Y~Uzp!9a2fG4P1dly(^v z7w`>uX_o;&54O4RBFT~lf99Ym3_oB3enA8E&XO+R7w4D{D>#)fFXzZ=7aUO^0sqC! zXpA!VkC)6f;!y~=!4oTYoZKjGifEV>>68$WaDM6O=sq1NM+E5qj?G0mY~pRly0Qu8GmW z4WHTXmmUiS=nLFPi1R5AHdmjAPz|>j6kxd$F-Qyz?~KT3gWcH-54ZO8c<%E!@dN-3 zW)}-qe-EgLaULOr8843-Z;u-fmET~BukP{jkR3c{i}_~u+(>c-;S8Au6<>D&V8@aJ zf_LJO=k&mL-RS2Chwbu+_nTP&WS5U_*9c>8k6~{WLlB4zw`Dd*aR50~|5y;|2@zs1 z4;Vp-h4JqSQ6KU^6LTl`N2j$>w}N;W7eJHUJSg zWo#nXQ(jFp;-|Dbv{N3#8muH4aC*i{`t=Y)Q|IP6Bv*jmsDV`|?D7C3c;)fnh+@GJ zw;77sXb#6A7Aw(pfsgJPxd@85nIM9e4NNh#R-Q9W@7$Y5{yDr+{i-_cgHlG(a7I-~Ej*b}4Xv z*v|2yS^V*E_z`k_Sx)l3M*eno{srKei*Ev@5d8@M`H9u(cF-Af)puxVo}C<@16&ts za#xa(LZ?pjD|-#G`Uis7)K`E2AaEc-fn@xsAm{?omI4I{CXqsA&mji@<^cL2Z~+@a z5&(2LROF$+4-^CK(MZq&9Xbt2!UXUlkCB)*Z{p0Ub0^Q9K6QTjlw&B-qDF}Z9r)=I z)22?Je(Io<5!I?zuUh?-;3wCvUC*4^5hqU_I6DRs84E{_8L0x(mc@g|jDfdjvJD^!B19lIbJZ>hBY*O~%iAfg(K##vBC8xj%{1sy%Aa9@tky+)>r8#$*zY&`z#89A^ktM;Ib>V1yhs$%K~>BFuzsxNs1`?V}0=kd_zRdL{&`<;IaNTZm;FhGUGu zF@a8yAqtriFFn95W&RS>ml-dJkXC3Ld6sEUudRj%8Vn4?AZ-f5XC-ce==dS54y>77 zr^JQKTu6d+F(8aB0Vf=H5FNNjm&rwu0ZK*iyy0uud5i{iFF)r(09*#r1&{}lEGkBH z$P8u?F6355izjR>^n=PZ5o*f+Bw5IWrxZ|4HJSBo2*}jVu@}-DF{ps^Cn>JjW{Xzz zOeTAwin;{5e-ctgr%fx}LXJKPDy5fT3i+`ZH$Z+vr&ZsO1mr4Z(4-YA=!wJv1T`1P zoh`7OHX5px=kY@*BSAGFZzLdvj3nfdgf`@E<~} z%lL6|Vn0N&w3WeY>!pwq1Q`|{h~Sx}oI&>RP79D2W#p3Yn1$J-Vl<$IN2d8ap#$Yu zgzSy4)+w!Z+#0R_{{!$)pGd*4f(0yJ5$jkAOjb~uO}D}WNj$+R3}1~}Y?GG{Ts zXfRlS3vRFha4?q!9RdLVux#am9+1qv&LyuCmS#o_+sOpFB?l~+kb-iUzy*!)x$O0e zAR-tc!Z0H~07L)>4>(lneu%`^jj4I8X+yax z;ISC^KnD)XqbeQ9T|~fA53Yp^Q^0~}FzBc-;A;Wvdca)hc|yAIG!8VSskRU^m@RS7 zD>XF(!XBe7nrx*Yg=uO%X)+KaM#}=^tk@g|5RyjO5u1@oW8*>7Lu%Ba z=&5HmfHLcm(8Exj&4B_I*lV7~!?XMBa+$}W(mMxI&_ESLtUpBL#nwOw4K!(0hpXC_ z#+e3;#RLlf%_E&9GZvrd0L@dfV^1hYS=!p{)dHg}hyyINMm)YUil%ZAZN8+=hf0rf zD%fpxKDpc7n&}{vY->g97P9)`^>e?R1Np>cSl9)?YrsiD`^Ff^mV5}D7uyIqg-1NB z?WmoA6YqzB2SD#7=AMXplvMNJ&wlzZNiO&;yEqaE=}E{U3nisOd?SdxB~2i2Qs+;^ zvZ&auG{Fk~2}na4te}w8SW#);WQ#FhuBa}9nA3O9WY%O ziOx~~fUEGg+Lp}r22C8uez~KbRS8%|zM0J($v_a;h8a{LV{8J(44!gA$g`J~#qvem1;|E0VNOPVdu96B8S?hS0tI=^4 z6c#{;ymH25yhFp8p<5E;0idGRrQ>_9$h(GcmkmubTA);7UnkRyymR#*WL)|d_g)Wl zT*$*>;2W(Z5pzK{i!GV-n~{O!hqUxFPF<4I1)k+d3b^87Wt2cw41+t|Fln%Zg;lHw zBZ~$VX4WT4Aa0IoSReo+z*^jrQ_SEnUj@MERa>YngynR{(0V{){w0S*f$PQz1Gc>X ztqLvs8VY9!>hpMnLnbLO8EZ#o@<{d|>(E(lP$Vg2nI6&rMXR;qr3y75^lBb1KRVL& zv5%}-?f}B}ma>SY8LSP!MyqKSwoQ!lnL3-4;vm>Sv^NOj`!!_)0yeB<*PFmwPF&s>0daiJ zmbxMq9=|*F;wE>wivnSEGX)aMT6b1bs`~%M`={)RSm|Ag(ZJBF01+sQREB8(Vgn4j ze@OJTi(@hYAjlxu6geCqqX2JNuTkT|)j^qKqm40#KEsPmVPz+{ zBm0~Q!-HbgFgEtBm=p6afhT>!Z0PJ%M;$Fle(c5+okz@t8DPblnFx}OD4nz|n?g9( zhFA@g-3b8_0MV&H=iP+PX$W{YlmhA*(zVBth}~P2-^3|M)t!-tl#lrp$*u*8ZNv{D zV9k$|h>l>9{psN42^n#936#iSZ4FtWiHt@x007=meeB5^Fdf(V2<-e_cD>rsFbQ=q z8HvOQ@HjwRy&!XJ)TsatuHD27Ou-7}M7#*V1Jsmy-Bf$sN@vK0Kgk6D5NrllARB8f z6oatOvq6(H0RTKP2#r)p3m78lhz^W}U!*9(3*Fu$?u4&IkWN%U0kz&x5D@HL!Y72m z?9m=o*d8S!5G2|}?#)}GU_lKC0T=AW1%-iUkjC!m1uV9Z@lAm$zM?}kA54H>_1(m} z7+kiPMQjzuOhw;%RmQMUhWHR%9>kDWken1OjgmMT8#u>*!5~<5Q{{LQ+_3><9m43a zl8Su68dwfCDWDiUjtXqj$Lzt{VBp+n_rU66BMs?tgA^wg+`5heq9yrZ`L{fy1oM1yX!D0F2PX<7UBthJK z8ay?gPH-Dj z9K}K9W3`PkR4`mcG-Vks`)eB6^wQNxTiJ{)F1<_8tVKDw0^+AkZ zI3irs3l3!8j40zq2^5jkTrCmQ|IJy^!C$F`7PM8R^5};cAexAP$y1gd8$AaV{E*Xd z<%{4|4ke~JiPZ~U;d;)IllXxZK#73qojWFtWmSg+*bYkkA23nU2OQ#rf|*;rXVicU zE9KIML{x5YQj#&jMK&C7f8<^uIE;?fT)}f0JhnLY**hQ0Lh?AZh#Yn=1|iV4Xfa2j&{eF07oV* zPGQ33r1%<6ER_tL-lb$l!WG7%*pq17MP}k*hW3*GndM-1EX`K9=N^0kn1LrMwG3^b zQ&9fI5Lw1UfFGRNrfrHQ2}t57z9s=(A|}d2YD$<0G=L|rTf60iugGQ}cq(mPK%yd8 zPSg+tT#^EGz`jI^FLH*Zj_Rul5v#_;QAtq26e#F$=Ap3P-mTQ}OilhRNacVRYYkzv zd;kyVqzU1iMd^eFKw4t`s*yOrg*nZrR77umz|=(9PhiPM&=PE{W$E37B55m6V2R>k z*aBn;v)aV*Xqoi+>Inptvl75KDT%sT4zR|=t4*u)S4y>jdH41f|_dWJ%H{EwAcI6f^;% zxk{Jp?9`sX7KEJve1LCATg}2m71{(iQh^G5VMo#G{}90rn5qNFlc`Q^tr~%hVdltT zfpoSlBz7zakU-w%ZBXd#Xu`w>z(Ayutg}^Vs38cb|xa)Ojxq(PI#?NY~XK@!L|m_O%?3) zjL@{8A?iX4DjI<=dO=w5Zt6**-uCVP-R^BrRG(=Y(BKk_$)*%*o>XmKfUi96^~!AI z4sYE)Km@R@&DQM+B!SO@FDcRp&(N;_C;$@>SXQxbxKThvkO3KV4cBgO>fL}8lw%g~ zz^zWq`{D%Il&eZTKn;BF|2&_E*`fX3uTP{ZcTz6GHn2+ZE#De%@*;2Ej({X?L<(G@ z^AZ51eu6(qFG@u(r($mk%WU~ha0|Qe3&U^>%kT`-a1GnAf?C9$(`Kx{hk8^dh>sBZBb({UZ!@g1`;9_#TQM@t2JY#1l+-iEPg`bzVL z>?eHN8iQiv!f_+7Fdsv5BunxnQ*tF+^8FUC7w@nR12V@3@llkqyya>VOX32!tRpuv z6w|N=FpR54OHyrHwFp73=E?-T0BPniPBg$F=5jCZ3faWK)^$Y^NwBEymAgex350;S zX3P{CX{sfl)y?yLP)O! zOh-aEzqCo$bRfd?Nd|Nhf|kyIFB?= zGqnTIbWa;(R!8+v$MlvQfmQPcO@l%Hg|$gDHB4B`S_J1jyLH=EuqF?359f0zN}@lH zTcZ}lDHn7qPw@iO01gb>LLW*)n;u)Zay;FouFy`;Jt9E1uLGwdPn0dL81*JZg8n!_ zByd7!vvek)^k#1YNOLw+i#BO<0#q+ZX_GcGmjG*%w7b2wXMc83X98{Cc2BE7Ory4H zuk>$IbKRabCmaF)L4W~nW41v2HfLwHaECH}{6i_=HCpkF!>VpQ?2`H-4MYY-3hz z54lcQ%W}4NlM```#_%>X`nw3;{ux6ND{) zc?~cu1emG+JUOhJ*EgwNONo!%nZq+@h`FBoi#;howba0^l1n^e-Oz-UInVk{-1=0n_}KPD0p~e$c)G)OfS8ku@ZkWOUzHN+gcg*wkPpO! zKZLY9w}?Z#g^RcWu=*BA(MBT@re1sklLM_7jxA3+8&YFTm1UI7(|lYBNU&C|=ZGw>K+Zh$Fp4 zX+71$#7oOKwu8NDbGpt4CmYs_QBnM`NeXYqRzmAov%`3_gZ4U)JKbmYafh>0Pb-S6 ztNwtuh@&%v*ZmigH)!KHv#PY;WBU{Ey}=c;yGwq8HEPGs`zH5r20QAm@b$f?Fb9h& zTZh38z@kH7Un3eAhtX{S6vlgPW_#UY4a`^oTqe4FxyPT2UW$c2dCTfUzQO4wx!hC# z#`l}NSZ5=yMS(X!F>Z6aZrwvk1aR2n(_ou}fTzcUeOQ8^maGP(mMHO13r8>$k8lE0 z79#)#4lh;(DHS4Aif<8eic|t51G;;gqQnxXLtw*)5hqr>m~msrk0D2vJel(USH_<( zXC{G}L}$;RL4W?#d9>$GmQg>(+=q2**RNs6Zk;(o<tuw|D>ESBMD4J7PLNY=*EvlR)z90Er_x z03vzd$e?(ih{+B_Aeih6MD{p=q5*FJKng_CaNs~f3@n4d1PvHa0|2%_BnqA=m}3tI zGwcF^2WP^KCyHLE&m{Jga|@{DYLH`!2_mS?qy>QBjxmHBoNFz(B0*~_t}e3Rs=Y*d z$N{>3%)~2>3OXngg_e}kA~3R&ph>cvJ0h>GqIyUz^&Ep~iUZsltS|uoVgw40;nMVO zf;iViQ9j0=GUw|HBQ2UTgt|hYYfmVpJnOGS7c$67z%&Xp67}$k%d(9)(JKMP zkQ)w76G07C)KT3d)zni_4d8)KQUIZ}%|eS6v{yGf&9+Zu%T-s_GP5;R+ia>cIGkQ2 z4vyt)s_nj|KtfK({e)W)4iRdSNj&Sub1_@T2Ai(V!;tgtPH4wPPdWbP^Dfi@lK_bd z4IM}Wkq_LR7efu}z3>A;)|lu9d?k1zkRB621Ca$rO|d_aIEbl4?aWB`Ox$>63R5fx z5_8ImkIZzVAQ`O)WREFoXws98R0!p|P&$&YjH&7m^RWDY%u8(y2rO6{7cm@kBC19B%8k!HJoH2H&2{ai=-nbLpkv^ABSfU62QO?u zj6-hlosbJv@S}~s3@$NL8B}!L3$}|(R|yj=ujA=myB-4rnv8E{rI7A^?OUcx*Boe525HTIljphQELKUu%g)K};uSheuxnYJf zn9;-DbcLA<_{xQBL(Jezcr4~+YlzXY33{dnIp{zuiG-V$nLq+X`dAJ!@wKG zK;Q-4;tuMJbuQK^PI9;LVPh-=5`(os1AF)oMLJ|JGUzT}6o~2 zly9vrXzZj&O|odXnMg-n(%DS`YSKR#%@Z+ZI78zM(*T4Ppi`@B(S1@$&wH}uTNA*E zfMSBzggv>^~~q)-NIM*)Ty43LP)kror9Fq7z$06~n{L9wk$kj&x?E zGTFAlc=et{AgDPZ8(GQrFq_+?n>RM>umc%Xr+zPxLFjs;8|1vx04u4Po3^!EyCnuFRBg%&&M<`+D+Utn+7|;-p93d=j0fPz>EVJHtB*J%vnFT~BR}AxYBU;EF z*BsR059_5QWqE=Fh}yMfp4eqZoK9l@9>5;uzCg8wF%xg@gPjBTq^x6WE3%Z581Nl< zdjkPO_(G`U392lG6M^5R&j~U!~R-W0nR1p1%&&GzIGII4Naso0RBcXuxX-KC`M z!kT<1)CEMSV03?84F9|(U^)2&p#dd|72#6{#-^lF8jBzVC8e?y2MTIO+oYc?RkAN# z4`v#B8C^03DR4t1n3AH3WrA4$hb?OQCo{sQ-Dq|ucFQPexh1q=#+@lF0ZA|38~4@t z4Joa78zcee3sE%&%4Whv-wuNIMI^|Ua3{7Yk<)4Eew=5GZ=B6eu0& zz$=eJE#5r9(l}L~e`?h7D?+&L-0 zMocF#Bkllmx{SL2;?RK2()v9l`<#d#|%=n3&5v0z91w%klgG zrNh)MHK=!BP>f-{f8={vJ~F`!U;zeu_^$_CO9Si5-~`@C@kVuv;VFEg1P>nZcj3yB zD~~mUEZ#qfJ129G{;3-O-Dvd0KKaX|(>lZ?c<&gV2!{7m=VPNOx4a`*19A9KtHRa)6^#=rp>w-?x`x=?TbMh>}jY*gS6162qnfIc3*QV{DPL==! z3FXfTp)fH%PMlo-Lx(^MGCq!*LPG|lunWEL3&Ai9#c&MCkmLN13S&b6C8GefP;M}* z40R9=$+6u@P5K4_UAe zbBO9ZE)WHA3ti9=HE|O;u@gP<6ZcQEB2f}s@C7aL5@Y2P2r&ak5D6s!%$_MSD4+*d z&+#7P>IC3aC_w8}fEFEKqeKlDZ9^DsBLiaK22Q}Z;?NMQ=@YWz|GvkG?=)#LGEOpbXqd3>;|5TY4!+<*++qugz%s0$B8wmkV!$ML zfF~L9yH2eqMRG&>LJA5JD1oqTsDKJAQYjfC3wXdSkg^~Zz@w1hMv!vs0^+B}X7MP~bl8aRu~q3xzNYR4r;JeU(ED@%7f>T0R zZ9EwiF+Q>kV3c0=#Sc2tjU)gH7-X;rp&uy%34#G(~x>DJTF@wek?!08c-)y><;y_Y^U_ zOAwfpyh!Ox&$}q_E0v#Yo7j-l(bVSAAG-GX7#b6}KKvK8J zjnq;?K43ur6IVq<1=?UvJtR`OGeg~CN!z6%#q>~PCjeZH4X|K6@wGkOvk&V3rj2s- zFoi9Pa{;B1NBOIbQZgjWs%etQ{rbIZ&P*=Nc&OOZUDoWKvrE+ zBS#a%KC)2b6%8EZLXoFQ5#s}tc0Lot)uf=>s4DN+HBmp}UletVoE9;Vwr(9xGRw9L z==K8^pg?C*14xzEI10?Hc5utlYAFD4PvBpiQea4PL$&rKB%o%MvJ8 z7h@Oc)^?Eb1XRk^O0;72Wmtvw>UdR;D57MUbz(&~I7>pKHa0;fG(-WHC|}VU8TKT$ z>()MGO20HDUlDJ~5%1g;07w;K;I(aLaX?zN0C=>sSa1*bbv91pSIa;kN=n#tNRF2t9j;GedL;8p?pXk#f>c4fD7v=KrTfET&d7;hj33{wN@ z)*2;bE`LWn$?Gi3AO@PiXi);a&~|-AG)X5{NqN?dT91c?n>-R<~${hsu;k3STr}H2)|K65uNn zERJC~ioam?oH&zr*=l1dWep`t0C#)W4={{Z1A#);Kt}=9 znr)e165#frxHn{V7rphBc{i1LQ;4(fBR*i1Z{&|%fGZvU7bGrJX4AM)0~wn)8J9^F zrNo(DcTJANH&!Eboe>}s^_5@Gkj|=*U+wG@_IN}WAv5fqg;o?^xWy-kAsxB~9J;$x zy1}6v>F#cajsfWo=?3Wr=?3WrDQOjqKc#ZHPjFx0?scBveCx#e_Bs0p3nw7A@TRr^ zR&S=bBQXo$m{LPnXUG`c1_46-x35#*lKuBq%N97SfRB__Qe}UIkVWhH!kh;N>;rI8 zEQ(I*u3#Qa8H`;j6)-pclOP%P@4&Ka$T@*uY$qI7Nlc_M_N`-OX}os~7OqM6Aq4 zoO^?h_h@Ts)=BpM$6sE4F?y%w6f@Cb?)N(v`I-$&vfVVl z55k%8nfd(4_RrGrtktGRStbHPJU68Fa1whrwUuvnR?5;b>ba+ZFP^AF3 zcsY@MwUEHVh(z8A-7<;4G=$G|a=ozJ)I_t_!hrh8>zy<|-rZ8(8zW`=-Y_{`Sqb6B zSBD#97QW7>nuUKk)@QtrI?$!bgYH|f*M22t^e3GnU40X_=S;9eb^>e#<+a7tIB6_; z_zS)+@#d#tA8rM(t~NchwKazOf$(=hb@oa&I$S9Z=(I*8rtz%h>AO8i9fERMzxJ?> zbAHE-2Z!3LXv3NOJq22%l%!caNgIi_Bz{=2O!u%-MTBXHvC$+}reXD+h| zo+io4jk%eIZDEPvKj=S;g7N~%pY2oPZ>9~Nz;AF4UhFgzc7)9I!-xn8`|&UcD>2Ve z#j8?7m}`Ij+x&x_xKCt5`S$$JZD&0HbwMM zDaDp(Q_!_=alEAzWpt0xO1UYQ0fuqchuP_zJah}!zy(<3OJydBC_CU72Oc$oK*#O{ zUFGv0dnQZd7!l?+u2_XwDkjN$%w33>K zlPCmH-Wj{ci5Uz1JW89jqHg?Gg6 z#V8&A@x5A}du8%*!*8BcOv2$|XqE)=a~i+^CG;L*nfs6=bRH2fv| zeTa5kj#ZeWU2f=x=LADynjl+B966qPTTdo|bm45}0FGdtRA80EmTI0(fQIiU>Um_FBI$xhD@kE`jA?+ znCdC9WG|X9*%SpwEo%`SnnSw{WCtFXQL>Y4!ws^40~ea%XOJ9liA|-!FE~Sn8t!$j zzfP;q)5L(Hi?$onP}O2cjVrQL4Oi-u%&|6HIU(JMBA1c*;{0kX=Z#q($pnJvae9Uz zmCdXh5d`R588(`EVzgW)B@7^5f=SXUD^vY0x>Iz63YGB6$?{4A&7z9iO@rQ-D0~-P#_@Qkg6e&}#f6 z&O-w`QWaTVCCs!ssJCEpdnz92dy#~lWtv3cB>H=6Li*0MQps4Ocok!>LJ3I1oB9}1 z7==ArR8-JXxVvJhHU9G#Q1WcG%o}hp)N+kta^Ey;2^a0;XuxO^JIv|OgPDPh}=B=`l37=RIa3d{-LtDmrGw*VtVVmk*iM|sabeqt&^=+hPC zV}~AP4TY6F)u~GWgb0S)X&vUuE#w~#`*+@wPnk#WQ@(ZOj1nsK-=YE^EMn$5#5kVh z{G%cQyef(138m9~=Rs6(yuzfOGNCHnG|I?i*n|a0K#;>$C>@|o3JMom86Zmt=Wi^i zX{|AfdP$r4ezeHWGz1D&ts(YL#lLdWZv;tG_d&U-^TGlB!yr5=4>`cE3j=bjwWcVC zQ3*(ROy9Izt??=wBTPDa$r$0)G9n3%t9IeWMw2P-8iuyi41#g`Rjc! zSKQOo*C?xj;%<2sP_W$j34%Pd2G^3ImVV2vm>}JSk$aB4%w}t~G*d#!1OIVwxABO7 z?j~CGboeESn{;?zzq;(ZjKMppwY2EOCCTO^P4$?rNk=p8AouOk-LpXrv5X;L`!8yr z9~g|_#K|zdX`0IUF~uCq(V!tUTkQARiY*G^Zw!WrRvCsfnVMa(?pYD(ij}|`n`G&g zM;m2z*;sNtTqyMj>Kj`WD~tkPfedT*I;BeCh;h(!&#TDGw2jxZ2;cv`%X_t^+quho zPgV)zNchrEt{XEA)JS;F;l9!9L&Fj=8O!8P1#9`QD*3B%wnnhXJsMyAN>;bnN&`OO zO=3z`17E;4W`GC3AdP;%3EW!LsnoCIu{5EC@iWut{BbhOIRL=(sv=TE$P%w)YWv&j zVpS!K4TMD}8iouJOWBUG&^5DBl%Cqi^`3@!k=Tq-dL$L<-;mCn|Q`jjefLl!{I#HutZ$eesqhdddM(e1M!L zc`V0Z6?~Rn8BX_cG%_D4;ba?xvTIkyVIkD8EiP5z5oOknIDEeP#Ac|Uiwehg^uS4? zXwols={W$aead);mgm39E&om7^D|lBb+gKT%`R?qbPFcKH>a8TiNH?5PY~OqxhCXE zY0Fji+}OfV*3doVHdm=q?MV3Oq^@~+$I*bZ2ZMLOnsa;?3t=&`>hJihhYaEUb0gpF z_Y*Z&JHF$Ce!T(Apsm&@5;eZJurT;6e~$ieBI(IfXT<)<+(C*RX{jBLDRmG<;=`j( z2cs?XKyK-GZs~ZWln{yAvGW%Q;Z6i`;FCxjIceXh#ok<+3PeY>SZyu?7EJEl=oJ57S6%9>34mX-tDR0|~DeizDGE*0HZZTnug z_--4eQ(M`k{c5KrS9(o~3A;Oj>^~CBu!g=i^M`xS96|?%Pt<%tS*9y!jurx9_v=cf zQ6F||`aHw-@m|wpAKtlccnXG=y`MA{1S6tOCBN|}I~lwZ8d-S)D6Vsf{&dv+c)OzV zm=K>LspH9Qk}l6*d-C}QV30o$OXHCrzB$^yiXN01p5BB@$50)=^k$eSDbs5=O~b}#biz7|HP$P!%-$5^eUU0uJz zO4I3SVOc%K&@c8njPZNQq7X(1s83MW{~~%b2p%ohcDA!{DF&g@32o9t2hq&=YzhAR z&-UR9;I9m0l8@lu|EQds%wDD=1Tx8)kwiJ80?hUi+@AbTNLvZg4lbM{PF)@kILn*6 z3?PzUU0IsHHxnHX8li1~A>I|mYRMSMY@+}`GA+U!V#J_X=5a_UuA%yeRVzH%2!k`P zfDUr46hc8pjQw;%Yv^T>Kjht4b=&(xlkaBQ1eNuB2VF`%v zHo~Ap2nX}6dsAfaI2A)nl=zuiZVNm%jxj||1kB&eO-%~0ci^Hd1vKa) z%1RM1J6*D+GTMDqjN9zoozX=?Wm6 z7GwXIUmp$>;e#{Dpeu~1q9G-P(yRod(Q-1#pW4VpqB|4r55$BC2uhljy3PQH3_WzC2-*x&wYNNMHqY=8jM9mHt^Eo=QgfYA zk$=o`=aZdl=`gjsq>?l+@|8cPOyRvS_yK-C%l zVKb(dw}+n{TxC$8vP8|E)zrEyie@<5?Aj)rH+$@ty^oz%Z3!Jmg$U1y1cSc+ zCt%Ugea?4Xs^x$rM5!&_P|;V498QA7fGqgnJ!$YhRjyCgPe)N1dx3YXTo`tlvdp?e zqA&kVGXC)f5-ngbDpR2lST3NTCrnXh++)yt02W?uSvCOc{0kaku8byB>353~kv>`5 zdTP>-RNC(HTt@Kx4^Z7OH4V=*+*U!b4J@(%B#>qwuMA4is}RiK5Ml*c)Ea7HSM-6< z9KNG&I-c=Cy|MDItxOpzIoCgIsv5C*u*hZg99tWG>WM85TWF!wG+TLjGog zoS)m1Tp{K0zt@@-g2rdh(CI%q&itAt}pvY-+l@!8Nr@D2byf<+47dfO_DRonM zfT13=Ipg~Lav*OC>PuJk7ipB_Mjq zbc1+KV?A5lj|XHU8{lsco1AzX70L<==N09CqsUPU_69=^ar9_j8v>26AFCZdxSndJ zF6054k5+eWS3^zTD$0(;=|ZbKNcMv=v8l=h7#9@_lwn1s_&q1*4Wf%prw}oCN^J!p zsk+39%lC<*pD>5aQr2Wt9xBzhxD4^;o z&1a49>lPI6sooCzlF<_;D69cM|A0ap9t+l;=*jWw>B#Tx>Fp)w)q6h(jH+YB^ywUR z?zCM^sXE09dBoy|rbf)@Gc&|uuLFMR@?qG>_My5<1<`kU<-GIy_w)O|ZQ1Hk4RBVO zQ`ik$pcGspy)#k0movSRWFPlu1nfI|2^Bs*^nPS54`dVQ8>1Rb^ymvg^$`&>ePU02 z&%<_QWge~yU=oqGhcF}`avq6@_067S`QB#BXY;Yw> zjs|S(Td6t+$C$oLZ?Ao~QOFo=_n0Yent5NZ<)1Mdj&Z=%$hg{I$V^J*MBm#-u!rer zgTJhTwJoA=XvbhYsBa=y zD}*4LW7^wGHoktcs$g0kHc@ZN!V2yCC0;=hLeNw&Gyi9H0XDZJF}LE=lk3C*TC z<|ers43i5MBYu2(G;x^?S(f~}f}md2mR#)?|Flss#@^p)r&r0n`-!M~kch)r_GVGn zY|Soo&7p8DpAHD!otZ3Hy{lj8DFE?M&xj7PQ(~UHVdDrkz<$qKDZ7>#x>a4c zRog#-v9k7FdRn4yv!HOZ$8^0;eS5zbARt+F-nTXIcYBa}hcaYyjA~1EZj&>KwT)~U zD{*_j&dB=f%CO|_irMa3e>ti24ng67tk#Be$i{BrMnrJACAEu~?#g=M-bMf3RUzvO z_=Y1#pDb+MRAb{%a$>w;Kzzj|0KWV6?`HtbeqF=vedx}l+2?tgbw$(tlkLS|&V4A& z0io1pv3lS9ZtwP=-LtuoTf8;O9RSpV1I=}d$o!Bg>=5C)itDy7hqw3Cow~u(bh!EG z8~|5{jmD&UcPKV+Br(50vd2XB?qITTr+{yk#(Y>188V}OD7km6`R{mXXGG@R!L;}` zWPSvj>xgpp7_s-o{NI;Ci7&G6cDTO52s~zurG`8_zF6#?xcxh6zS^CcIg!9U^$R-< z__ysf-|16y8usrLsk!N;xe{)E787Y|IL0q=!@oG*W6C|3;|g4VPALlzOqOG zMJO>GzkNM6|29m`B-i)#WZ>Hs&CbV;zA|67uTtNCX>KkTO#*=c+Iuwg2S5>k1MnFD8%jP#65^vq0*tgMV|ob>FR44l05+p)d+`N1| ze8Nm3;!F~vQW9d%99SkPNkJ(|St)r|DFxP7(#+C|>~eAnDypg~+T3dDDr#j*>iRtD zX7(CYYnrB3ug#ra7fm9Jc(j{88JJrdWVaey@EH%ym>2|@*z%j2o0>WZn8wAKCM23U z37RLSzcJ)~<0|wfI?BRb*dpbe4Jy zohj;hU0hsTQc_a(tYNK+QLW0#%Bpeg8l{!mXHDzWKWkREL20A0vGK!)#t)zLnv{21 zRt#FTRNGVz+SUx(RS(+N3_3OpIyViwR+qcBje2&CdiRX`J{$M#n|w4l9yB}}GTa|A z+#bo3o84GnH7NmN3HUYA3uK9 zD*x<%^S>qjfBj!G0C@rkWBron0U#qGL~N#$O(i3-Pt~c6gj`s&SZ1hL^511 z0jAPYK9$a*Q)@caQZbXwV?8aQyr9Dro-dJ^%hOu*>AiF$HnnP7^*(vq<*cQ zGzcFk}EP2?~d2KXb|!NC8kE6%81`0vH&1b8lCGyg2)k zz1tpOm#9L=IvD2CktW#o6<7Oml@Te}R)lBPJX#==)+VT=JeoS>$B zH!8#5raiGa>!kNcFJSmqW-VhJM+c=)>CCa!M^uL0E2C^0^U9q8u$zmdW_)%|t@JDc z4h>OT&-e=T8>6+heLJO*n%%FdP&}KgZZ`T8!7ZD%gK_cYa!(h&u`toVv}oPjode{1 zw@G#$x8JEI$Eg>2=PG2JVy9g7V5L9H<*!3f4Fhh_Ur`zXY0Nhh6(nlqAlN^H^kD|( z@{tkrpdT!gJe>kH?^BC;STX%D26^XU6Ib5$=r7K(@Nj66J5$(1bF?!>$m^fW%o^B( zmHt6iQ~j@_D6wR`0Ty)?wg=e1H!{)94)Q7BRV9fIy-sD-HWRL?E52F0n0f*V72L8g zm!~}5J}*psLyg-nw+ImVcuu8U(b@ig;SowjT9l+}Zh;PGYsA2Pv|<#DgxG_IT4vVF ztw%n~#VQ`Bs`J~!rN`PYwAQ9|x5uwtr;U%_`fk5Hejmi-{&PJ_=KkkqlKI1*AG5;W z|NLA~;{N+<#lZdV?+yD8fB)O@|Ni%OKbHI7-Ep@2zx%VQ5C0ynI=}yWyq@5G`txhu z{ps)B>4&F(e{R1&Jppiw0hr2zAj)ebM7O-hjv${c#t@zy z!VkKRgyWV#l$3`F^RAzQCAjv=WG@1W0RpoJ4@}oloEetb!V=2( zPhJavsACH(VV@zwUnEg5L&rD;VmiXtX_11XwD?vIDfpd+QaEu3__j^?lo1ZX&E5M6 zUDLzVja}n>DOz|W&{8TtD?;vhODrx39oa4U0ON)w&I`mK(YOEDh4-=9JST@_R?e`< zU^i}fdDbxD6b#{}c?Oys`j^5K0~i@M@VLZsDlr7|8A@l4QfH7IsGd~S2LRug4rkKv zgky?e0JYSW!Nx=cs*T}(1-MNA%`3A;sSn{d2-ra3j_P`q+FAPbgYedrmdJp8lyk-x z07jsS^FI%|H!Gz)6OR3`0zTTAg2LU|?idL{om4=;AennLhG5gODqymlsuKDX<$Llo z`A~vMg1%I-IrV4p5`UG@mz?OD&4UE6Mg<*bv7#7oFu_fl=_|Pk;KTVbyfUf^{Um25 z_O7KIqQUx;I4^}?=ogBIgc-ob7NeRV<08}#79>hrq!rUnHy^Qb{zJYPb6i~M35ih6 z-jc|oV<^O5J=N6d#^ALXimz*{qMQ$eLYi*se4@U<(i{=7xIf%>ZEB5^lxCx7}rWE?v;X)W5V+E~25BXr~7EoC3)+`iE?p}mwEDm163 zljQ&?m>3l|B4FR4PY+QX`&yNLqgc%bunlt9SOYH{`Z4p-KY6KwN~G6MUNq`2g?IQ!wGlL&N@1un2n3Ydb9 z=a5ZJ1^d}cT<%eg;lMncG4{Kmo#c65OqS3fyJT@wmE3ePPL^ZKk4-z4;mu}JD7Oob|cF*cnXnzwusz@^0lt)B$W@A z-!m~5-T*ET6FN9=yZG}7(j0_D@K)Uoeac2Wj^(zE`T7#$@dr5GD83w?f|dy6l0{rF z%x;caxkctoSwy_5e}KCS0kbh_&mv6^pu7X^9b`Xi*h{^@Ceo#>(OV<)=0utI^~Y}X zvi3YI<%>&p%9s|rv9iqN%bJ(JTBstzl|*|#g~kcW&WA)t;T}L&_d15LjwWg~ODgfE z8MG(LWXhlq5viw;z` zAkrL1j2x zBf{Gb-PphnZ^+Df-xOUWN^eM0FFFXf3wk1NhI61qxf=*>JqQu8m1i_f2ay;l38Vy6zP4tTqi?E2P|H@vs|u(t77i{1MqoB-;0`rNo;WO$ zIBJ+U9*{VhlQdw}JzAY#CW78772%3@<%8Oa9$iB&@dPtXfm6Awj*Pkd1K zK6>m!k&zZQkVQvN(t!V%f>F12<`6$>CCpNhcMn~}UpAmB0fgKTNM5YS1_m(i#B(9r zF#rJ3qz{P9v9rv63+hZJjwk**34L-P{CFFZ8yhN+6Zulq$#Na&1IOg{2FG4wh-RY+ z7^ZSL5|d5Io!tROiIv04`GcPzs(~!zs>}pMDKS`{0bNx9;6zdnCa^jt*m(n!JJKCS z5ynlCDYKZ|L5zv(r<)n2VCln+91A-sr^I)_JRpCaodq@X14nkeTUZbAlJ>=H&fo?= zU$C-l0t2-Jv-z~%S+(oXESURy$LauH|I=0W4$!dPgxcF>zx4x0WQSkfW#Mevy~T(L zFv=zJ#(d9*&X}2MR^vbI4_WEVNs6~WNwte&@gj1}tm%Rfw{S+q@v z_lU^$4FI_0ccxg!VHiti-*x7V#uH+%>a-ncpZP0Mc^K1cxj5EwU&hq(` z*|z=JX}Vd(bBEE16uD%UKHe#&gj=Q9CGy#576hwiR#3M*##o#ZBEk&}(Aw%A&A$TYOi$2aOB0hm*B<5Q$0o%=`8S`L{+Pz=`I2e0^x zoNVfCjMYqg))Y873T4GpN7v+v1!^L|qW(qoRn^2LAk|_tzWq=ruwEslmf)b05m+~} znb0Waj-^!Jp72%}P#s!Jq3-|z7}hK024CjB{aqajK>FcWf--Ldik%3`R3eiDQ<6LL z2~vH38zzs(gsQ{elZ4y;?y@!K`QU{>Q}VOxQw2Oc1Vp9Ks{@#&f=HC-kjfGuzLW^*jozxDPwE5fDo&-Pp8Qrcieg>)vUvcn6RsPdS+- zNT&|ex~At|iO%NXO8yAt2B6!hbvR_%V_N2eXP}(Y9drh!=|<>wO(_T^0LZzfx)M{) z0<@}X%MFMO*{=RCJ58Cb)#B3st#E6-eg{I@!F9o2g#rlmi1e%TjYDB1i2$1P!QoWx z&_&>FPe;mq^pZ*k%cTQ*FUwmhi1}lCZXHY&VXtpb2;c9B24Ga8T5;Gred>B1s-VIa z9g)&;4&puAVr`ktJzc(SE8U@NSb%k*`UO-Els7kWn&8H$)MCL3>)Ku^<-_h%UdLuG z!CQ<@Z59CLxqv^8x?y$r;ID{7v94>jc7i%ErHuUw)0<$sw!_DmWzy;yY>a4O3nQ{r zL7rZ;s+u1$m^>KGte#oqyi`#gwm+(iC7o*+&p+y622MVb!WLqKASHaPI#-IA#j&A7 zf$jzfo9_?+uDY)gnKh;{Wa%V6S~)Z#I~n^R{%vR7>V<#Kcn6SqV5~P)C8o<<+|hof z*4r6WzY&mIiC&sDYUc1|jz510XB490)B?d-eHZnO+QZ%1J;Yy>+C_t7}|R@;5t zb8tbOp(V>&Q^#U(gQ@6F6AZF*()Ei6Z5(rA;*uT9ldFfmhMAa)QTaf^gMh_^fqWQ7U!aq60X-21Kx1T(e4`Z$(LUx3 zpl}Ix-5hdj&i=HbP3=UGNS^VrZu0APDp1LmASFD?(4h!m-}?U1$lxrD z;2dif72?g!GJb#h=}(Az&YzG~mnJ6VNKs563nhU)X+wNg^vaXkTb|C8&*F`d`_|!r zn1*cE{7XtKLk*eVgdTf=Z@dpC6d9dr)6>^os~S zsU^ryOP)$w(GTn$NB=e6?O2WZEyjt88t|pp`CS&k1sRM+IZNx*Z3A~O(@*x{nE}qB zi!x{bH<>navUu~bO1K$JtLhwE)q;D|>Y5wMq~W!Ef}Wh#l4;_que{B(yIRKXx*%No zU!|YCx=ozRQ060spXds4(n?^sfrEhKuXqB(EZ452XyYe%DA(V<<@{*3L@54c>dkgO zxibJ0X3bDnoNQ7}nlv>>4fqv1QO{mLq1NwsKI(ZNouvW6LOQK?hJZ}>uqYM<)*Xb4 z-SK4txwoz6Cbsv~(h~oE*od*!pWG%}011$8A<6pxK1BPBH!&t)Cd2lEBy4D;;*Iq8 z9Ipnba5J^~x6IA@LU3&8%~onpeBAxKProM7)fS6N+I+uSZ8a$U%pS~bZ53m>J=(C$ zx6=>f2#|-i!%+)HbD!RxIE^#!zSi9J@YFxKBPcr=bwWi8+j|+hM!PHoaL;em%mfip zd41>b;xV`XyFRJ>xWv&p&U6LdorpBq{n%|b82uz2Xt&>5tTI|NGa+Ap_`N7z+=b%5c;9{_OY!-jcv0%|8hf!Y#p558p z5dz*_@h~sLb^2}UV|M-aGS1El>h!vB5}$TjZ+4JL-yOqg+eX4-p{rLo|I?MR00sGp z)gCEHl}-zUFm=1(Wq@~5P1@az=S%V4`}NtLi5kr8%?b><#h4|~0Q9nC*DC1M zOb>Ie-Iuxfe@gSs-y9R?*SAc%LpyRlQWF5X{r*FZ=k8^J5?vPz{J8A`=j%IF90Lib zYL@szJEulWx(^5i?hQ z^}gb)01p}ma8^!^8KjFj_>JF1`0m#LprJ{-KV5T%Yu}emyX~vz4v)#zt^W5x=Q%yo zW5cfC?y$YC2DKint?TUT+W<8Fg0uadvxkA7EFA;(G|j@vLm$^dvghqcJ|868huggB zNqhA5GyB29dSnpcV)ghN)?MVKlH1C4+`0o*i?44j?1^A*G5X}r_V$(ovx&n#lo&W9 z{?wEAzEgL7v;qIC@u#fIozL2@$R0*3rpCRSBGi&Dq_YHuy#J}S(siNJD^ zuQwyOZPDiUG_!6xv4Y&0JO;2_8}Xn307FWd(!LB3jsb~UI7uN5rv||otRP81Xml6U zA|MV|He3}04``%aoF(TDhnWHZ)3nT(whqr;HEJvx?mjSSqzx|NfxQkANExD?jnu}c z5Yx3TRY|u|r0Yx7wwlBNI89pI+ofRSN9p4BSN|?ilMNsD8!Llem~?r5nXfQe|7O+~ z`1{+J?e*_(2E)-`Fqv*#TaNlOXT+z=S-cZ<9ke15@fgo{%??P*o< zx`ZC0H6R0Kv_}(QEfJypX*BWV$Y)$GOUx}q~XagzRv!IyGYo-@tyn1HTz6N^E@ ztLa{X_J_OhulFNfMX3YOa6x^>JkruW4&Up6hzOpc+xlQI$1$#~L%7tj$2(afKv(hT zFa0Cdp-&jb__V3mAs3vuVeAcpK=WbEt~?PNYo-7Eew<4SWywZP+zf)tlk>GvkQb5q0it5A)IajQjTPo21wnP1X# z+IYVqYl&tkfYD;FDwEaIf*hk|%^%W)%%+Uj2}xcqHv@425`s{%$tIq1As1L_5}mG# zpb>w7U=v4{NRm(@v0UPRNr8goe9RGf6`s(>lLWYl&}VqfQl3C`$0*8?y=#agR>8f5 zA*P`uPLM!sK|4m(S~fo0nsnbh)d=hf1iYd)VmCuAgXA$BZ8;;z{E7l>*qz+y6=m}M z9vrL7vVxpy>pGscBBlV3^OijlfhB#tTmdqeZz(P;wh6c$SigQS5aWYV86^PFI=_qc z>UNE~0oQxhVzAMubs?F+LA~NOZixCd&~@b3$uk6Z62G0RMk*`dYJ@wR*1Ml{VPAv^ zcj~qwaa59gzl*e(>U%if-5+Dd!E$7a^emmZs&Ope(a-`=j)vWu?KI$Vs5Gr-s z&%7evEP^6p6n8iRY5$zfnffII_}R=k>xRUvdAfIoVmrBQB0(h#7)!L+DFHEBiGf2Y6`a}(hQ1%pNd z6a^}^lAJmAFix7#g~qksd6!#LUmh!pY-uG2A6vitJDCIPf;)#X*wEqyPBIBy;QR9s zUqSDcl@+zq=$@gR4rdW6cG~Ir$K_zoYejlL?Tj)8Th?Z>F^N3w%sLxe_WVkuc==Lh zYq>3_>phuphGk0Uu`PG#`HZR8P4)W9e)GlDlv5R8%U4qBak=$J+MLMh3Ck-2AvKp&x5mp##uiW5$Z+srHa6ndq zkWF%gca1Z86y9xHTnb`W#qjdTl6qS}B1fwf+SCj?>n3k1{ga9Dj*Y~Pkwo76d=>pJ zG2&#(M*J1TcW~{6%8Z^OtEDxT5II{= z07P;y@#Q6u?}uNAfPVOu`sc9_h1ESM8Y32)RkmmyUmcF-gRARnUBn#uiWB@D!ZG>iDwa-MpFR)cY1;k?E z{j$)bqQI{j>b>r_gl57hblwMY8y3m6Q;k%&$o2wi^qsAEP0t7NI>&rd1pyK9TeGzX zijpUuR;ydeqpHme!|neCCY$OyKT<5XhbOjC5PmZi(~T3Ryn9Oi!gk?A_Q<*H!XS4j zEw_?2RO2|t#j*>zak})%tCNh21@8kc@@@}WH6uR~Xiu5>&37f}US}kK#h6fr=Rmal z@*|T{yn0u5`9BBHyHBS&(S*=VxZUd*!t}4)@&PyVj1}i!T|2V=+s+IVS?;7<6D*hD zk_o$tHqtmR!PKg+>enJB!6!i{F6i~+>23;!jvlHmQ(RKH$v{7eW~q;{>T(bf^sq8 z;u@kO6qaGRBHaK1j4n2UQG{-QqpO5lVuZG|?TH3eDk8$p{0r5T2f|{Jc@*t*ev~>e zi3^RCiT@$kA2%#1&))l^*>;+|Yk44ES^7I+Uzk;MB%4(D;PA{~SzfiAL3i)VL6|S zM#Aw{b}Ui>2}W3)Ku(>4X+#EL6Ga{^*=!Sa2s_xNixF+G3o1!cFC}~}!5}w0D9(q_ z=~qD;=_wY*?Hj(=85i+TGR=_vNYxU_(l6>Fe?TM`J5z>7BoR5?9ejoIKn?6ZpNy0Z z4jB_is4>Tp#u*gKwv;xJpRXJ|&S|CeL|lyPeJn3aMI0+D6rUlyz*f%+mwwmAV?h*W zSWD!93s73DNsW{+>g!G-no3Kd%P&*lAZ)VfW4UVO7}(}{XYyenkghDGbSDU9EkFFW zH!>vcRo##7;ZmkrmtJ~j(Mc-N)gB4IeAK;IN27_NmT9HT4-uv-5pk9YW;EeNu=qJj zM4V_w(I)ZgQW*rFF_Q1ite@bELl*Fl{QKF8SQ$>$?)Su{x%t-l(L6gYB!hD z*u7nHqO#II1>bM6e?LNby3`?;xyGm(%dW7FYeoC=BEP8@j<;%R>oA}dzIKazorI>i z6h%#2z7Q$PVUZ!0an-vnpNPiZNH^TFWivKLJQ~j~&3jA?@Mi~LZY<*J ziNW=1m^Wr?O=UWcCf(C|2u2lvgCGBaKVfVzMr^VD4f;gdCfw!R7*-%Gby>L~u1%Mr zHsFH`CuH}MS5u}C(4HN7>fAtPM2y^;vfzAKd}7nF=xZHtnBy5+`b@|pL_E9B(Lk$O zF<+P1zEik>tEK&G9PGdmD;q8h>fK#d_Vg}~`XTThrcqHpZ<-%>iCzA}mpF!e0iR?p ziA_RLrCpyv>!D3e@~=9J58ql#qpH{Vrhxdd_hJWSm&TU`3Wd@`4#lp?#W?wKUDe*$ zGX6*6#EPr#9|>~VD6VliK5%3WB@Qjaddz(GW+R$|t=jmq~&#KojFHbmvrrb z!p^7)+~2JoGre4OTXi0Fl7S5$0_O%~SDK0>Hd`ttm^nH0#F1{+3{2Ehb-O)5IvT*q zT7ez9SZW9&;v=T~HY-wQPeA*;b}Ay&&{|Kf2xWBc0 zvLP{}�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 e instanceof JOSEMultiError -class JOSEMultiError extends JOSEError { - constructor (errors) { - super() - let i - while ((i = errors.findIndex(isMulti)) && i !== -1) { - errors.splice(i, 1, ...errors[i]) - } - Object.defineProperty(this, 'errors', { value: errors }) - } - - * [Symbol.iterator] () { - for (const error of this.errors) { - yield error - } - } -} -module.exports.JOSEError = JOSEError - -module.exports.JOSEAlgNotWhitelisted = class JOSEAlgNotWhitelisted extends JOSEError {} -module.exports.JOSECritNotUnderstood = class JOSECritNotUnderstood extends JOSEError {} -module.exports.JOSEInvalidEncoding = class JOSEInvalidEncoding extends JOSEError {} -module.exports.JOSEMultiError = JOSEMultiError -module.exports.JOSENotSupported = class JOSENotSupported extends JOSEError {} - -module.exports.JWEDecryptionFailed = class JWEDecryptionFailed extends JOSEError {} -module.exports.JWEInvalid = class JWEInvalid extends JOSEError {} - -module.exports.JWKImportFailed = class JWKImportFailed extends JOSEError {} -module.exports.JWKInvalid = class JWKInvalid extends JOSEError {} -module.exports.JWKKeySupport = class JWKKeySupport extends JOSEError {} - -module.exports.JWKSNoMatchingKey = class JWKSNoMatchingKey extends JOSEError {} - -module.exports.JWSInvalid = class JWSInvalid extends JOSEError {} -module.exports.JWSVerificationFailed = class JWSVerificationFailed extends JOSEError {} - -class JWTClaimInvalid extends JOSEError { - constructor (message, claim = 'unspecified', reason = 'unspecified') { - super(message) - this.claim = claim - this.reason = reason - } -} -module.exports.JWTClaimInvalid = JWTClaimInvalid -module.exports.JWTExpired = class JWTExpired extends JWTClaimInvalid {} -module.exports.JWTMalformed = class JWTMalformed extends JOSEError {} diff --git a/lib/help/asn1/algorithm_identifier.js b/lib/help/asn1/algorithm_identifier.js deleted file mode 100644 index 6804d5bebf..0000000000 --- a/lib/help/asn1/algorithm_identifier.js +++ /dev/null @@ -1,8 +0,0 @@ -const oids = require('./oids') - -module.exports = function () { - this.seq().obj( - this.key('algorithm').objid(oids), - this.key('parameters').optional().choice({ namedCurve: this.objid(oids), null: this.null_() }) - ) -} diff --git a/lib/help/asn1/ec_private_key.js b/lib/help/asn1/ec_private_key.js deleted file mode 100644 index 169ab82f43..0000000000 --- a/lib/help/asn1/ec_private_key.js +++ /dev/null @@ -1,10 +0,0 @@ -const oids = require('./oids') - -module.exports = function () { - this.seq().obj( - this.key('version').int(), - this.key('privateKey').octstr(), - this.key('parameters').explicit(0).optional().choice({ namedCurve: this.objid(oids) }), - this.key('publicKey').explicit(1).optional().bitstr() - ) -} diff --git a/lib/help/asn1/index.js b/lib/help/asn1/index.js deleted file mode 100644 index c4f7aee8fc..0000000000 --- a/lib/help/asn1/index.js +++ /dev/null @@ -1,29 +0,0 @@ -const asn1 = require('@panva/asn1.js') - -const types = new Map() - -const AlgorithmIdentifier = asn1.define('AlgorithmIdentifier', require('./algorithm_identifier')) -types.set('AlgorithmIdentifier', AlgorithmIdentifier) - -const ECPrivateKey = asn1.define('ECPrivateKey', require('./ec_private_key')) -types.set('ECPrivateKey', ECPrivateKey) - -const PrivateKeyInfo = asn1.define('PrivateKeyInfo', require('./private_key_info')(AlgorithmIdentifier)) -types.set('PrivateKeyInfo', PrivateKeyInfo) - -const PublicKeyInfo = asn1.define('PublicKeyInfo', require('./public_key_info')(AlgorithmIdentifier)) -types.set('PublicKeyInfo', PublicKeyInfo) - -const PrivateKey = asn1.define('PrivateKey', require('./private_key')) -types.set('PrivateKey', PrivateKey) - -const OneAsymmetricKey = asn1.define('OneAsymmetricKey', require('./one_asymmetric_key')(AlgorithmIdentifier, PrivateKey)) -types.set('OneAsymmetricKey', OneAsymmetricKey) - -const RSAPrivateKey = asn1.define('RSAPrivateKey', require('./rsa_private_key')) -types.set('RSAPrivateKey', RSAPrivateKey) - -const RSAPublicKey = asn1.define('RSAPublicKey', require('./rsa_public_key')) -types.set('RSAPublicKey', RSAPublicKey) - -module.exports = types diff --git a/lib/help/asn1/oids.js b/lib/help/asn1/oids.js deleted file mode 100644 index be28bcf2f0..0000000000 --- a/lib/help/asn1/oids.js +++ /dev/null @@ -1,14 +0,0 @@ -const oids = { - '1 2 840 10045 3 1 7': 'P-256', - '1 3 132 0 10': 'secp256k1', - '1 3 132 0 34': 'P-384', - '1 3 132 0 35': 'P-521', - '1 2 840 10045 2 1': 'ecPublicKey', - '1 2 840 113549 1 1 1': 'rsaEncryption', - '1 3 101 110': 'X25519', - '1 3 101 111': 'X448', - '1 3 101 112': 'Ed25519', - '1 3 101 113': 'Ed448' -} - -module.exports = oids diff --git a/lib/help/asn1/one_asymmetric_key.js b/lib/help/asn1/one_asymmetric_key.js deleted file mode 100644 index c01ec4bfd6..0000000000 --- a/lib/help/asn1/one_asymmetric_key.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = (AlgorithmIdentifier, PrivateKey) => function () { - this.seq().obj( - this.key('version').int(), - this.key('algorithm').use(AlgorithmIdentifier), - this.key('privateKey').use(PrivateKey) - ) -} diff --git a/lib/help/asn1/private_key.js b/lib/help/asn1/private_key.js deleted file mode 100644 index f07618353e..0000000000 --- a/lib/help/asn1/private_key.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = function () { - this.octstr().contains().obj( - this.key('privateKey').octstr() - ) -} diff --git a/lib/help/asn1/private_key_info.js b/lib/help/asn1/private_key_info.js deleted file mode 100644 index 391fa2f036..0000000000 --- a/lib/help/asn1/private_key_info.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = (AlgorithmIdentifier) => function () { - this.seq().obj( - this.key('version').int(), - this.key('algorithm').use(AlgorithmIdentifier), - this.key('privateKey').octstr() - ) -} diff --git a/lib/help/asn1/public_key_info.js b/lib/help/asn1/public_key_info.js deleted file mode 100644 index 53d56d7a44..0000000000 --- a/lib/help/asn1/public_key_info.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = AlgorithmIdentifier => function () { - this.seq().obj( - this.key('algorithm').use(AlgorithmIdentifier), - this.key('publicKey').bitstr() - ) -} diff --git a/lib/help/asn1/rsa_private_key.js b/lib/help/asn1/rsa_private_key.js deleted file mode 100644 index acd4f7575c..0000000000 --- a/lib/help/asn1/rsa_private_key.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = function () { - this.seq().obj( - this.key('version').int({ 0: 'two-prime', 1: 'multi' }), - this.key('n').int(), - this.key('e').int(), - this.key('d').int(), - this.key('p').int(), - this.key('q').int(), - this.key('dp').int(), - this.key('dq').int(), - this.key('qi').int() - ) -} diff --git a/lib/help/asn1/rsa_public_key.js b/lib/help/asn1/rsa_public_key.js deleted file mode 100644 index 386624665e..0000000000 --- a/lib/help/asn1/rsa_public_key.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = function () { - this.seq().obj( - this.key('n').int(), - this.key('e').int() - ) -} diff --git a/lib/help/base64url.js b/lib/help/base64url.js deleted file mode 100644 index 16d77a0ce3..0000000000 --- a/lib/help/base64url.js +++ /dev/null @@ -1,65 +0,0 @@ -const fromBase64 = (base64) => { - return base64.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_') -} - -const encode = (input, encoding = 'utf8') => { - return fromBase64(Buffer.from(input, encoding).toString('base64')) -} - -const encodeBuffer = (buf) => { - return fromBase64(buf.toString('base64')) -} - -const decodeToBuffer = (input) => { - return Buffer.from(input, 'base64') -} - -const decode = (input, encoding = 'utf8') => { - return decodeToBuffer(input).toString(encoding) -} - -const b64uJSON = { - encode: (input) => { - return encode(JSON.stringify(input)) - }, - decode: (input, encoding = 'utf8') => { - return JSON.parse(decode(input, encoding)) - } -} - -b64uJSON.decode.try = (input, encoding = 'utf8') => { - try { - return b64uJSON.decode(input, encoding) - } catch (err) { - return decode(input, encoding) - } -} - -const bnToBuf = (bn) => { - let hex = BigInt(bn).toString(16) - if (hex.length % 2) { - hex = `0${hex}` - } - - const len = hex.length / 2 - const u8 = new Uint8Array(len) - - let i = 0 - let j = 0 - while (i < len) { - u8[i] = parseInt(hex.slice(j, j + 2), 16) - i += 1 - j += 2 - } - - return u8 -} - -const encodeBigInt = (bn) => encodeBuffer(Buffer.from(bnToBuf(bn))) - -module.exports.decode = decode -module.exports.decodeToBuffer = decodeToBuffer -module.exports.encode = encode -module.exports.encodeBuffer = encodeBuffer -module.exports.JSON = b64uJSON -module.exports.encodeBigInt = encodeBigInt diff --git a/lib/help/consts.js b/lib/help/consts.js deleted file mode 100644 index ca9571b931..0000000000 --- a/lib/help/consts.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports.KEYOBJECT = Symbol('KEYOBJECT') -module.exports.PRIVATE_MEMBERS = Symbol('PRIVATE_MEMBERS') -module.exports.PUBLIC_MEMBERS = Symbol('PUBLIC_MEMBERS') -module.exports.THUMBPRINT_MATERIAL = Symbol('THUMBPRINT_MATERIAL') -module.exports.JWK_MEMBERS = Symbol('JWK_MEMBERS') -module.exports.KEY_MANAGEMENT_ENCRYPT = Symbol('KEY_MANAGEMENT_ENCRYPT') -module.exports.KEY_MANAGEMENT_DECRYPT = Symbol('KEY_MANAGEMENT_DECRYPT') - -const USES_MAPPING = { - sig: new Set(['sign', 'verify']), - enc: new Set(['encrypt', 'decrypt', 'wrapKey', 'unwrapKey', 'deriveKey']) -} -const OPS = new Set([...USES_MAPPING.sig, ...USES_MAPPING.enc]) -const USES = new Set(Object.keys(USES_MAPPING)) - -module.exports.USES_MAPPING = USES_MAPPING -module.exports.OPS = OPS -module.exports.USES = USES diff --git a/lib/help/deep_clone.js b/lib/help/deep_clone.js deleted file mode 100644 index e20515c9af..0000000000 --- a/lib/help/deep_clone.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = obj => JSON.parse(JSON.stringify(obj)) diff --git a/lib/help/ecdsa_signatures.js b/lib/help/ecdsa_signatures.js deleted file mode 100644 index c6a51f0773..0000000000 --- a/lib/help/ecdsa_signatures.js +++ /dev/null @@ -1,180 +0,0 @@ -const MAX_OCTET = 0x80 -const CLASS_UNIVERSAL = 0 -const PRIMITIVE_BIT = 0x20 -const TAG_SEQ = 0x10 -const TAG_INT = 0x02 -const ENCODED_TAG_SEQ = (TAG_SEQ | PRIMITIVE_BIT) | (CLASS_UNIVERSAL << 6) -const ENCODED_TAG_INT = TAG_INT | (CLASS_UNIVERSAL << 6) - -const getParamSize = keySize => ((keySize / 8) | 0) + (keySize % 8 === 0 ? 0 : 1) - -const paramBytesForAlg = { - ES256: getParamSize(256), - ES256K: getParamSize(256), - ES384: getParamSize(384), - ES512: getParamSize(521) -} - -const countPadding = (buf, start, stop) => { - let padding = 0 - while (start + padding < stop && buf[start + padding] === 0) { - ++padding - } - - const needsSign = buf[start + padding] >= MAX_OCTET - if (needsSign) { - --padding - } - - return padding -} - -module.exports.derToJose = (signature, alg) => { - if (!Buffer.isBuffer(signature)) { - throw new TypeError('ECDSA signature must be a Buffer') - } - - if (!paramBytesForAlg[alg]) { - throw new Error(`Unknown algorithm "${alg}"`) - } - - const paramBytes = paramBytesForAlg[alg] - - // the DER encoded param should at most be the param size, plus a padding - // zero, since due to being a signed integer - const maxEncodedParamLength = paramBytes + 1 - - const inputLength = signature.length - - let offset = 0 - if (signature[offset++] !== ENCODED_TAG_SEQ) { - throw new Error('Could not find expected "seq"') - } - - let seqLength = signature[offset++] - if (seqLength === (MAX_OCTET | 1)) { - seqLength = signature[offset++] - } - - if (inputLength - offset < seqLength) { - throw new Error(`"seq" specified length of ${seqLength}", only ${inputLength - offset}" remaining`) - } - - if (signature[offset++] !== ENCODED_TAG_INT) { - throw new Error('Could not find expected "int" for "r"') - } - - const rLength = signature[offset++] - - if (inputLength - offset - 2 < rLength) { - throw new Error(`"r" specified length of "${rLength}", only "${inputLength - offset - 2}" available`) - } - - if (maxEncodedParamLength < rLength) { - throw new Error(`"r" specified length of "${rLength}", max of "${maxEncodedParamLength}" is acceptable`) - } - - const rOffset = offset - offset += rLength - - if (signature[offset++] !== ENCODED_TAG_INT) { - throw new Error('Could not find expected "int" for "s"') - } - - const sLength = signature[offset++] - - if (inputLength - offset !== sLength) { - throw new Error(`"s" specified length of "${sLength}", expected "${inputLength - offset}"`) - } - - if (maxEncodedParamLength < sLength) { - throw new Error(`"s" specified length of "${sLength}", max of "${maxEncodedParamLength}" is acceptable`) - } - - const sOffset = offset - offset += sLength - - if (offset !== inputLength) { - throw new Error(`Expected to consume entire buffer, but "${inputLength - offset}" bytes remain`) - } - - const rPadding = paramBytes - rLength - - const sPadding = paramBytes - sLength - - const dst = Buffer.allocUnsafe(rPadding + rLength + sPadding + sLength) - - for (offset = 0; offset < rPadding; ++offset) { - dst[offset] = 0 - } - signature.copy(dst, offset, rOffset + Math.max(-rPadding, 0), rOffset + rLength) - - offset = paramBytes - - for (const o = offset; offset < o + sPadding; ++offset) { - dst[offset] = 0 - } - signature.copy(dst, offset, sOffset + Math.max(-sPadding, 0), sOffset + sLength) - - return dst -} - -module.exports.joseToDer = (signature, alg) => { - if (!Buffer.isBuffer(signature)) { - throw new TypeError('ECDSA signature must be a Buffer') - } - - if (!paramBytesForAlg[alg]) { - throw new TypeError(`Unknown algorithm "${alg}"`) - } - - const paramBytes = paramBytesForAlg[alg] - - const signatureBytes = signature.length - if (signatureBytes !== paramBytes * 2) { - throw new Error(`"${alg}" signatures must be "${paramBytes * 2}" bytes, saw "${signatureBytes}"`) - } - - const rPadding = countPadding(signature, 0, paramBytes) - const sPadding = countPadding(signature, paramBytes, signature.length) - const rLength = paramBytes - rPadding - const sLength = paramBytes - sPadding - - const rsBytes = 1 + 1 + rLength + 1 + 1 + sLength - - const shortLength = rsBytes < MAX_OCTET - - const dst = Buffer.allocUnsafe((shortLength ? 2 : 3) + rsBytes) - - let offset = 0 - dst[offset++] = ENCODED_TAG_SEQ - if (shortLength) { - // Bit 8 has value "0" - // bits 7-1 give the length. - dst[offset++] = rsBytes - } else { - // Bit 8 of first octet has value "1" - // bits 7-1 give the number of additional length octets. - dst[offset++] = MAX_OCTET | 1 // eslint-disable-line no-tabs - // length, base 256 - dst[offset++] = rsBytes & 0xff - } - dst[offset++] = ENCODED_TAG_INT - dst[offset++] = rLength - if (rPadding < 0) { - dst[offset++] = 0 - offset += signature.copy(dst, offset, 0, paramBytes) - } else { - offset += signature.copy(dst, offset, rPadding, paramBytes) - } - dst[offset++] = ENCODED_TAG_INT - dst[offset++] = sLength - if (sPadding < 0) { - dst[offset++] = 0 - signature.copy(dst, offset, paramBytes) - } else { - signature.copy(dst, offset, paramBytes + sPadding) - } - - return dst -} diff --git a/lib/help/epoch.js b/lib/help/epoch.js deleted file mode 100644 index 1126fdb8cd..0000000000 --- a/lib/help/epoch.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = (date) => Math.floor(date.getTime() / 1000) diff --git a/lib/help/generate_iv.js b/lib/help/generate_iv.js deleted file mode 100644 index b9a58a20c9..0000000000 --- a/lib/help/generate_iv.js +++ /dev/null @@ -1,5 +0,0 @@ -const { randomBytes } = require('crypto') - -const { IVLENGTHS } = require('../registry') - -module.exports = alg => randomBytes(IVLENGTHS.get(alg) / 8) diff --git a/lib/help/get_key.js b/lib/help/get_key.js deleted file mode 100644 index 303c7752ae..0000000000 --- a/lib/help/get_key.js +++ /dev/null @@ -1,35 +0,0 @@ -const errors = require('../errors') -const Key = require('../jwk/key/base') -const importKey = require('../jwk/import') -const { KeyStore } = require('../jwks/keystore') - -module.exports = (input, keyStoreAllowed = false) => { - if (input instanceof Key) { - return input - } - - if (input instanceof KeyStore) { - if (!keyStoreAllowed) { - throw new TypeError('key argument for this operation must not be a JWKS.KeyStore instance') - } - - return input - } - - try { - return importKey(input) - } catch (err) { - if (err instanceof errors.JOSEError && !(err instanceof errors.JWKImportFailed)) { - throw err - } - - let msg - if (keyStoreAllowed) { - msg = 'key must be an instance of a key instantiated by JWK.asKey, a valid JWK.asKey input, or a JWKS.KeyStore instance' - } else { - msg = 'key must be an instance of a key instantiated by JWK.asKey, or a valid JWK.asKey input' - } - - throw new TypeError(msg) - } -} diff --git a/lib/help/is_disjoint.js b/lib/help/is_disjoint.js deleted file mode 100644 index 42c43643fe..0000000000 --- a/lib/help/is_disjoint.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = (a = {}, b = {}) => { - const keysA = Object.keys(a) - const keysB = new Set(Object.keys(b)) - return !keysA.some((ka) => keysB.has(ka)) -} diff --git a/lib/help/is_object.js b/lib/help/is_object.js deleted file mode 100644 index 5018e583fd..0000000000 --- a/lib/help/is_object.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = a => !!a && a.constructor === Object diff --git a/lib/help/key_object.js b/lib/help/key_object.js deleted file mode 100644 index 82b6582c0c..0000000000 --- a/lib/help/key_object.js +++ /dev/null @@ -1,435 +0,0 @@ -const { keyObjectSupported } = require('./runtime_support') - -let createPublicKey -let createPrivateKey -let createSecretKey -let KeyObject -let asInput - -if (keyObjectSupported) { - ({ createPublicKey, createPrivateKey, createSecretKey, KeyObject } = require('crypto')) - asInput = (input) => input -} else { - const { EOL } = require('os') - - const errors = require('../errors') - const isObject = require('./is_object') - const asn1 = require('./asn1') - const toInput = Symbol('toInput') - - const namedCurve = Symbol('namedCurve') - - asInput = (keyObject, needsPublic) => { - if (keyObject instanceof KeyObject) { - return keyObject[toInput](needsPublic) - } - - return createSecretKey(keyObject)[toInput](needsPublic) - } - - const pemToDer = pem => Buffer.from(pem.replace(/(?:-----(?:BEGIN|END)(?: (?:RSA|EC))? (?:PRIVATE|PUBLIC) KEY-----|\s)/g, ''), 'base64') - const derToPem = (der, label) => `-----BEGIN ${label}-----${EOL}${(der.toString('base64').match(/.{1,64}/g) || []).join(EOL)}${EOL}-----END ${label}-----` - const unsupported = (input) => { - const label = typeof input === 'string' ? input : `OID ${input.join('.')}` - throw new errors.JOSENotSupported(`${label} is not supported in your Node.js runtime version`) - } - - KeyObject = class KeyObject { - export ({ cipher, passphrase, type, format } = {}) { - if (this._type === 'secret') { - return this._buffer - } - - if (this._type === 'public') { - if (this.asymmetricKeyType === 'rsa') { - switch (type) { - case 'pkcs1': - if (format === 'pem') { - return this._pem - } - - return pemToDer(this._pem) - case 'spki': { - const PublicKeyInfo = asn1.get('PublicKeyInfo') - const pem = PublicKeyInfo.encode({ - algorithm: { - algorithm: 'rsaEncryption', - parameters: { type: 'null' } - }, - publicKey: { - unused: 0, - data: pemToDer(this._pem) - } - }, 'pem', { label: 'PUBLIC KEY' }) - - return format === 'pem' ? pem : pemToDer(pem) - } - default: - throw new TypeError(`The value ${type} is invalid for option "type"`) - } - } - - if (this.asymmetricKeyType === 'ec') { - if (type !== 'spki') { - throw new TypeError(`The value ${type} is invalid for option "type"`) - } - - if (format === 'pem') { - return this._pem - } - - return pemToDer(this._pem) - } - } - - if (this._type === 'private') { - if (passphrase !== undefined || cipher !== undefined) { - throw new errors.JOSENotSupported('encrypted private keys are not supported in your Node.js runtime version') - } - - if (type === 'pkcs8') { - if (this._pkcs8) { - if (format === 'der' && typeof this._pkcs8 === 'string') { - return pemToDer(this._pkcs8) - } - - if (format === 'pem' && Buffer.isBuffer(this._pkcs8)) { - return derToPem(this._pkcs8, 'PRIVATE KEY') - } - - return this._pkcs8 - } - - if (this.asymmetricKeyType === 'rsa') { - const parsed = this._asn1 - const RSAPrivateKey = asn1.get('RSAPrivateKey') - const privateKey = RSAPrivateKey.encode(parsed) - const PrivateKeyInfo = asn1.get('PrivateKeyInfo') - const pkcs8 = PrivateKeyInfo.encode({ - version: 0, - privateKey, - algorithm: { - algorithm: 'rsaEncryption', - parameters: { type: 'null' } - } - }) - - this._pkcs8 = pkcs8 - - return this.export({ type, format }) - } - - if (this.asymmetricKeyType === 'ec') { - const parsed = this._asn1 - const ECPrivateKey = asn1.get('ECPrivateKey') - const privateKey = ECPrivateKey.encode({ - version: parsed.version, - privateKey: parsed.privateKey, - publicKey: parsed.publicKey - }) - const PrivateKeyInfo = asn1.get('PrivateKeyInfo') - const pkcs8 = PrivateKeyInfo.encode({ - version: 0, - privateKey, - algorithm: { - algorithm: 'ecPublicKey', - parameters: this._asn1.parameters - } - }) - - this._pkcs8 = pkcs8 - - return this.export({ type, format }) - } - } - - if (this.asymmetricKeyType === 'rsa' && type === 'pkcs1') { - if (format === 'pem') { - return this._pem - } - - return pemToDer(this._pem) - } else if (this.asymmetricKeyType === 'ec' && type === 'sec1') { - if (format === 'pem') { - return this._pem - } - - return pemToDer(this._pem) - } else { - throw new TypeError(`The value ${type} is invalid for option "type"`) - } - } - } - - get type () { - return this._type - } - - get asymmetricKeyType () { - return this._asymmetricKeyType - } - - get symmetricKeySize () { - return this._symmetricKeySize - } - - [toInput] (needsPublic) { - switch (this._type) { - case 'secret': - return this._buffer - case 'public': - return this._pem - default: - if (needsPublic) { - if (!('_pub' in this)) { - this._pub = createPublicKey(this) - } - - return this._pub[toInput](false) - } - - return this._pem - } - } - } - - createSecretKey = (buffer) => { - if (!Buffer.isBuffer(buffer) || !buffer.length) { - throw new TypeError('input must be a non-empty Buffer instance') - } - - const keyObject = new KeyObject() - keyObject._buffer = Buffer.from(buffer) - keyObject._symmetricKeySize = buffer.length - keyObject._type = 'secret' - - return keyObject - } - - createPublicKey = (input) => { - if (input instanceof KeyObject) { - if (input.type !== 'private') { - throw new TypeError(`Invalid key object type ${input.type}, expected private.`) - } - - switch (input.asymmetricKeyType) { - case 'ec': { - const PublicKeyInfo = asn1.get('PublicKeyInfo') - const key = PublicKeyInfo.encode({ - algorithm: { - algorithm: 'ecPublicKey', - parameters: input._asn1.parameters - }, - publicKey: input._asn1.publicKey - }) - - return createPublicKey({ key, format: 'der', type: 'spki' }) - } - case 'rsa': { - const RSAPublicKey = asn1.get('RSAPublicKey') - const key = RSAPublicKey.encode(input._asn1) - return createPublicKey({ key, format: 'der', type: 'pkcs1' }) - } - } - } - - if (typeof input === 'string' || Buffer.isBuffer(input)) { - input = { key: input, format: 'pem' } - } - - if (!isObject(input)) { - throw new TypeError('input must be a string, Buffer or an object') - } - - const { format, passphrase } = input - let { key, type } = input - - if (typeof key !== 'string' && !Buffer.isBuffer(key)) { - throw new TypeError('key must be a string or Buffer') - } - - if (format !== 'pem' && format !== 'der') { - throw new TypeError('format must be one of "pem" or "der"') - } - - let label - if (format === 'pem') { - key = key.toString() - switch (key.split(/\r?\n/g)[0].toString()) { - case '-----BEGIN PUBLIC KEY-----': - type = 'spki' - label = 'PUBLIC KEY' - break - case '-----BEGIN RSA PUBLIC KEY-----': - type = 'pkcs1' - label = 'RSA PUBLIC KEY' - break - case '-----BEGIN CERTIFICATE-----': - throw new errors.JOSENotSupported('X.509 certificates are not supported in your Node.js runtime version') - case '-----BEGIN PRIVATE KEY-----': - case '-----BEGIN EC PRIVATE KEY-----': - case '-----BEGIN RSA PRIVATE KEY-----': - return createPublicKey(createPrivateKey(key)) - default: - throw new TypeError('unknown/unsupported PEM type') - } - } - - switch (type) { - case 'spki': { - const PublicKeyInfo = asn1.get('PublicKeyInfo') - const parsed = PublicKeyInfo.decode(key, format, { label }) - - let type, keyObject - switch (parsed.algorithm.algorithm) { - case 'ecPublicKey': { - keyObject = new KeyObject() - keyObject._asn1 = parsed - keyObject._asymmetricKeyType = 'ec' - keyObject._type = 'public' - keyObject._pem = PublicKeyInfo.encode(parsed, 'pem', { label: 'PUBLIC KEY' }) - - break - } - case 'rsaEncryption': { - type = 'pkcs1' - keyObject = createPublicKey({ type, key: parsed.publicKey.data, format: 'der' }) - break - } - default: - unsupported(parsed.algorithm.algorithm) - } - - return keyObject - } - case 'pkcs1': { - const RSAPublicKey = asn1.get('RSAPublicKey') - const parsed = RSAPublicKey.decode(key, format, { label }) - - // special case when private pkcs1 PEM / DER is used with createPublicKey - if (parsed.n === BigInt(0)) { - return createPublicKey(createPrivateKey({ key, format, type, passphrase })) - } - - const keyObject = new KeyObject() - keyObject._asn1 = parsed - keyObject._asymmetricKeyType = 'rsa' - keyObject._type = 'public' - keyObject._pem = RSAPublicKey.encode(parsed, 'pem', { label: 'RSA PUBLIC KEY' }) - - return keyObject - } - case 'pkcs8': - case 'sec1': - return createPublicKey(createPrivateKey({ format, key, type, passphrase })) - default: - throw new TypeError(`The value ${type} is invalid for option "type"`) - } - } - - createPrivateKey = (input, hints) => { - if (typeof input === 'string' || Buffer.isBuffer(input)) { - input = { key: input, format: 'pem' } - } - - if (!isObject(input)) { - throw new TypeError('input must be a string, Buffer or an object') - } - - const { format, passphrase } = input - let { key, type } = input - - if (typeof key !== 'string' && !Buffer.isBuffer(key)) { - throw new TypeError('key must be a string or Buffer') - } - - if (passphrase !== undefined) { - throw new errors.JOSENotSupported('encrypted private keys are not supported in your Node.js runtime version') - } - - if (format !== 'pem' && format !== 'der') { - throw new TypeError('format must be one of "pem" or "der"') - } - - let label - if (format === 'pem') { - key = key.toString() - switch (key.split(/\r?\n/g)[0].toString()) { - case '-----BEGIN PRIVATE KEY-----': - type = 'pkcs8' - label = 'PRIVATE KEY' - break - case '-----BEGIN EC PRIVATE KEY-----': - type = 'sec1' - label = 'EC PRIVATE KEY' - break - case '-----BEGIN RSA PRIVATE KEY-----': - type = 'pkcs1' - label = 'RSA PRIVATE KEY' - break - default: - throw new TypeError('unknown/unsupported PEM type') - } - } - - switch (type) { - case 'pkcs8': { - const PrivateKeyInfo = asn1.get('PrivateKeyInfo') - const parsed = PrivateKeyInfo.decode(key, format, { label }) - - let type, keyObject - switch (parsed.algorithm.algorithm) { - case 'ecPublicKey': { - type = 'sec1' - keyObject = createPrivateKey({ type, key: parsed.privateKey, format: 'der' }, { [namedCurve]: parsed.algorithm.parameters.value }) - break - } - case 'rsaEncryption': { - type = 'pkcs1' - keyObject = createPrivateKey({ type, key: parsed.privateKey, format: 'der' }) - break - } - default: - unsupported(parsed.algorithm.algorithm) - } - - keyObject._pkcs8 = key - return keyObject - } - case 'pkcs1': { - const RSAPrivateKey = asn1.get('RSAPrivateKey') - const parsed = RSAPrivateKey.decode(key, format, { label }) - - const keyObject = new KeyObject() - keyObject._asn1 = parsed - keyObject._asymmetricKeyType = 'rsa' - keyObject._type = 'private' - keyObject._pem = RSAPrivateKey.encode(parsed, 'pem', { label: 'RSA PRIVATE KEY' }) - - return keyObject - } - case 'sec1': { - const ECPrivateKey = asn1.get('ECPrivateKey') - let parsed = ECPrivateKey.decode(key, format, { label }) - - if (!('parameters' in parsed) && !hints[namedCurve]) { - throw new Error('invalid sec1') - } else if (!('parameters' in parsed)) { - parsed = { ...parsed, parameters: { type: 'namedCurve', value: hints[namedCurve] } } - } - - const keyObject = new KeyObject() - keyObject._asn1 = parsed - keyObject._asymmetricKeyType = 'ec' - keyObject._type = 'private' - keyObject._pem = ECPrivateKey.encode(parsed, 'pem', { label: 'EC PRIVATE KEY' }) - - return keyObject - } - default: - throw new TypeError(`The value ${type} is invalid for option "type"`) - } - } -} - -module.exports = { createPublicKey, createPrivateKey, createSecretKey, KeyObject, asInput } diff --git a/lib/help/key_utils.js b/lib/help/key_utils.js deleted file mode 100644 index 598e388030..0000000000 --- a/lib/help/key_utils.js +++ /dev/null @@ -1,300 +0,0 @@ -const { EOL } = require('os') - -const errors = require('../errors') - -const { keyObjectSupported } = require('./runtime_support') -const { createPublicKey } = require('./key_object') -const base64url = require('./base64url') -const asn1 = require('./asn1') -const computePrimes = require('./rsa_primes') -const { OKP_CURVES, EC_CURVES } = require('../registry') - -const formatPem = (base64pem, descriptor) => `-----BEGIN ${descriptor} KEY-----${EOL}${(base64pem.match(/.{1,64}/g) || []).join(EOL)}${EOL}-----END ${descriptor} KEY-----` - -const okpToJWK = { - private (crv, keyObject) { - const der = keyObject.export({ type: 'pkcs8', format: 'der' }) - const OneAsymmetricKey = asn1.get('OneAsymmetricKey') - const { privateKey: { privateKey: d } } = OneAsymmetricKey.decode(der) - - return { - ...okpToJWK.public(crv, createPublicKey(keyObject)), - d: base64url.encodeBuffer(d) - } - }, - public (crv, keyObject) { - const der = keyObject.export({ type: 'spki', format: 'der' }) - - const PublicKeyInfo = asn1.get('PublicKeyInfo') - - const { publicKey: { data: x } } = PublicKeyInfo.decode(der) - - return { - kty: 'OKP', - crv, - x: base64url.encodeBuffer(x) - } - } -} - -const keyObjectToJWK = { - rsa: { - private (keyObject) { - const der = keyObject.export({ type: 'pkcs8', format: 'der' }) - - const PrivateKeyInfo = asn1.get('PrivateKeyInfo') - const RSAPrivateKey = asn1.get('RSAPrivateKey') - - const { privateKey } = PrivateKeyInfo.decode(der) - const { version, n, e, d, p, q, dp, dq, qi } = RSAPrivateKey.decode(privateKey) - - if (version !== 'two-prime') { - throw new errors.JOSENotSupported('Private RSA keys with more than two primes are not supported') - } - - return { - kty: 'RSA', - n: base64url.encodeBigInt(n), - e: base64url.encodeBigInt(e), - d: base64url.encodeBigInt(d), - p: base64url.encodeBigInt(p), - q: base64url.encodeBigInt(q), - dp: base64url.encodeBigInt(dp), - dq: base64url.encodeBigInt(dq), - qi: base64url.encodeBigInt(qi) - } - }, - public (keyObject) { - const der = keyObject.export({ type: 'spki', format: 'der' }) - - const PublicKeyInfo = asn1.get('PublicKeyInfo') - const RSAPublicKey = asn1.get('RSAPublicKey') - - const { publicKey: { data: publicKey } } = PublicKeyInfo.decode(der) - const { n, e } = RSAPublicKey.decode(publicKey) - - return { - kty: 'RSA', - n: base64url.encodeBigInt(n), - e: base64url.encodeBigInt(e) - } - } - }, - ec: { - private (keyObject) { - const der = keyObject.export({ type: 'pkcs8', format: 'der' }) - - const PrivateKeyInfo = asn1.get('PrivateKeyInfo') - const ECPrivateKey = asn1.get('ECPrivateKey') - - const { privateKey, algorithm: { parameters: { value: crv } } } = PrivateKeyInfo.decode(der) - const { privateKey: d, publicKey } = ECPrivateKey.decode(privateKey) - - if (typeof publicKey === 'undefined') { - if (keyObjectSupported) { - return { - ...keyObjectToJWK.ec.public(createPublicKey(keyObject)), - d: base64url.encodeBuffer(d) - } - } - - throw new errors.JOSENotSupported('Private EC keys without the public key embedded are not supported in your Node.js runtime version') - } - - const x = publicKey.data.slice(1, ((publicKey.data.length - 1) / 2) + 1) - const y = publicKey.data.slice(((publicKey.data.length - 1) / 2) + 1) - - return { - kty: 'EC', - crv, - d: base64url.encodeBuffer(d), - x: base64url.encodeBuffer(x), - y: base64url.encodeBuffer(y) - } - }, - public (keyObject) { - const der = keyObject.export({ type: 'spki', format: 'der' }) - - const PublicKeyInfo = asn1.get('PublicKeyInfo') - - const { publicKey: { data: publicKey }, algorithm: { parameters: { value: crv } } } = PublicKeyInfo.decode(der) - - const x = publicKey.slice(1, ((publicKey.length - 1) / 2) + 1) - const y = publicKey.slice(((publicKey.length - 1) / 2) + 1) - - return { - kty: 'EC', - crv, - x: base64url.encodeBuffer(x), - y: base64url.encodeBuffer(y) - } - } - }, - ed25519: { - private (keyObject) { - return okpToJWK.private('Ed25519', keyObject) - }, - public (keyObject) { - return okpToJWK.public('Ed25519', keyObject) - } - }, - ed448: { - private (keyObject) { - return okpToJWK.private('Ed448', keyObject) - }, - public (keyObject) { - return okpToJWK.public('Ed448', keyObject) - } - }, - x25519: { - private (keyObject) { - return okpToJWK.private('X25519', keyObject) - }, - public (keyObject) { - return okpToJWK.public('X25519', keyObject) - } - }, - x448: { - private (keyObject) { - return okpToJWK.private('X448', keyObject) - }, - public (keyObject) { - return okpToJWK.public('X448', keyObject) - } - } -} - -module.exports.keyObjectToJWK = (keyObject) => { - if (keyObject.type === 'private') { - return keyObjectToJWK[keyObject.asymmetricKeyType].private(keyObject) - } - - return keyObjectToJWK[keyObject.asymmetricKeyType].public(keyObject) -} - -const concatEcPublicKey = (x, y) => ({ - unused: 0, - data: Buffer.concat([ - Buffer.alloc(1, 4), - base64url.decodeToBuffer(x), - base64url.decodeToBuffer(y) - ]) -}) - -const jwkToPem = { - RSA: { - private (jwk, { calculateMissingRSAPrimes }) { - const RSAPrivateKey = asn1.get('RSAPrivateKey') - - if ('oth' in jwk) { - throw new errors.JOSENotSupported('Private RSA keys with more than two primes are not supported') - } - - if (jwk.p || jwk.q || jwk.dp || jwk.dq || jwk.qi) { - if (!(jwk.p && jwk.q && jwk.dp && jwk.dq && jwk.qi)) { - throw new errors.JWKInvalid('all other private key parameters must be present when any one of them is present') - } - } else if (calculateMissingRSAPrimes) { - jwk = computePrimes(jwk) - } else if (!calculateMissingRSAPrimes) { - throw new errors.JOSENotSupported('importing private RSA keys without all other private key parameters is not enabled, see documentation and its advisory on how and when its ok to enable it') - } - - return RSAPrivateKey.encode({ - version: 0, - n: BigInt(`0x${base64url.decodeToBuffer(jwk.n).toString('hex')}`), - e: BigInt(`0x${base64url.decodeToBuffer(jwk.e).toString('hex')}`), - d: BigInt(`0x${base64url.decodeToBuffer(jwk.d).toString('hex')}`), - p: BigInt(`0x${base64url.decodeToBuffer(jwk.p).toString('hex')}`), - q: BigInt(`0x${base64url.decodeToBuffer(jwk.q).toString('hex')}`), - dp: BigInt(`0x${base64url.decodeToBuffer(jwk.dp).toString('hex')}`), - dq: BigInt(`0x${base64url.decodeToBuffer(jwk.dq).toString('hex')}`), - qi: BigInt(`0x${base64url.decodeToBuffer(jwk.qi).toString('hex')}`) - }, 'pem', { label: 'RSA PRIVATE KEY' }) - }, - public (jwk) { - const RSAPublicKey = asn1.get('RSAPublicKey') - - return RSAPublicKey.encode({ - version: 0, - n: BigInt(`0x${base64url.decodeToBuffer(jwk.n).toString('hex')}`), - e: BigInt(`0x${base64url.decodeToBuffer(jwk.e).toString('hex')}`) - }, 'pem', { label: 'RSA PUBLIC KEY' }) - } - }, - EC: { - private (jwk) { - const ECPrivateKey = asn1.get('ECPrivateKey') - - return ECPrivateKey.encode({ - version: 1, - privateKey: base64url.decodeToBuffer(jwk.d), - parameters: { type: 'namedCurve', value: jwk.crv }, - publicKey: concatEcPublicKey(jwk.x, jwk.y) - }, 'pem', { label: 'EC PRIVATE KEY' }) - }, - public (jwk) { - const PublicKeyInfo = asn1.get('PublicKeyInfo') - - return PublicKeyInfo.encode({ - algorithm: { - algorithm: 'ecPublicKey', - parameters: { type: 'namedCurve', value: jwk.crv } - }, - publicKey: concatEcPublicKey(jwk.x, jwk.y) - }, 'pem', { label: 'PUBLIC KEY' }) - } - }, - OKP: { - private (jwk) { - const OneAsymmetricKey = asn1.get('OneAsymmetricKey') - - const b64 = OneAsymmetricKey.encode({ - version: 0, - privateKey: { privateKey: base64url.decodeToBuffer(jwk.d) }, - algorithm: { algorithm: jwk.crv } - }, 'der') - - // TODO: WHYYY? https://github.com/indutny/asn1.js/issues/110 - b64.write('04', 12, 1, 'hex') - - return formatPem(b64.toString('base64'), 'PRIVATE') - }, - public (jwk) { - const PublicKeyInfo = asn1.get('PublicKeyInfo') - - return PublicKeyInfo.encode({ - algorithm: { algorithm: jwk.crv }, - publicKey: { - unused: 0, - data: base64url.decodeToBuffer(jwk.x) - } - }, 'pem', { label: 'PUBLIC KEY' }) - } - } -} - -module.exports.jwkToPem = (jwk, { calculateMissingRSAPrimes = false } = {}) => { - switch (jwk.kty) { - case 'EC': - if (!EC_CURVES.has(jwk.crv)) { - throw new errors.JOSENotSupported(`unsupported EC key curve: ${jwk.crv}`) - } - break - case 'OKP': - if (!OKP_CURVES.has(jwk.crv)) { - throw new errors.JOSENotSupported(`unsupported OKP key curve: ${jwk.crv}`) - } - break - case 'RSA': - break - default: - throw new errors.JOSENotSupported(`unsupported key type: ${jwk.kty}`) - } - - if (jwk.d) { - return jwkToPem[jwk.kty].private(jwk, { calculateMissingRSAPrimes }) - } - - return jwkToPem[jwk.kty].public(jwk) -} diff --git a/lib/help/node_alg.js b/lib/help/node_alg.js deleted file mode 100644 index 10a15665de..0000000000 --- a/lib/help/node_alg.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = alg => `sha${alg.substr(2, 3)}` diff --git a/lib/help/rsa_primes.js b/lib/help/rsa_primes.js deleted file mode 100644 index 4e2d9a3be1..0000000000 --- a/lib/help/rsa_primes.js +++ /dev/null @@ -1,170 +0,0 @@ -const { randomBytes } = require('crypto') - -const base64url = require('./base64url') -const errors = require('../errors') - -const ZERO = BigInt(0) -const ONE = BigInt(1) -const TWO = BigInt(2) - -const toJWKParameter = (n) => { - const hex = n.toString(16) - return base64url.encodeBuffer(Buffer.from(hex.length % 2 ? `0${hex}` : hex, 'hex')) -} -const fromBuffer = buf => BigInt(`0x${buf.toString('hex')}`) -const bitLength = n => n.toString(2).length - -const eGcdX = (a, b) => { - let x = ZERO - let y = ONE - let u = ONE - let v = ZERO - - while (a !== ZERO) { - const q = b / a - const r = b % a - const m = x - (u * q) - const n = y - (v * q) - b = a - a = r - x = u - y = v - u = m - v = n - } - return x -} - -const gcd = (a, b) => { - let shift = ZERO - while (!((a | b) & ONE)) { - a >>= ONE - b >>= ONE - shift++ - } - while (!(a & ONE)) { - a >>= ONE - } - do { - while (!(b & ONE)) { - b >>= ONE - } - if (a > b) { - const x = a - a = b - b = x - } - b -= a - } while (b) - - return a << shift -} - -const modPow = (a, b, n) => { - a = toZn(a, n) - let result = ONE - let x = a - while (b > 0) { - const leastSignificantBit = b % TWO - b = b / TWO - if (leastSignificantBit === ONE) { - result = result * x - result = result % n - } - x = x * x - x = x % n - } - return result -} - -const randBetween = (min, max) => { - const interval = max - min - const bitLen = bitLength(interval) - let rnd - do { - rnd = fromBuffer(randBits(bitLen)) - } while (rnd > interval) - return rnd + min -} - -const randBits = (bitLength) => { - const byteLength = Math.ceil(bitLength / 8) - const rndBytes = randomBytes(byteLength) - // Fill with 0's the extra bits - rndBytes[0] = rndBytes[0] & (2 ** (bitLength % 8) - 1) - return rndBytes -} - -const toZn = (a, n) => { - a = a % n - return (a < 0) ? a + n : a -} - -const odd = (n) => { - let r = n - while (r % TWO === ZERO) { - r = r / TWO - } - return r -} - -// not sold on these values -const maxCountWhileNoY = 30 -const maxCountWhileInot0 = 22 - -const getPrimeFactors = (e, d, n) => { - const r = odd(e * d - ONE) - - let countWhileNoY = 0 - let y - do { - countWhileNoY++ - if (countWhileNoY === maxCountWhileNoY) { - throw new errors.JWKImportFailed('failed to calculate missing primes') - } - - let countWhileInot0 = 0 - let i = modPow(randBetween(TWO, n), r, n) - let o = ZERO - while (i !== ONE) { - countWhileInot0++ - if (countWhileInot0 === maxCountWhileInot0) { - throw new errors.JWKImportFailed('failed to calculate missing primes') - } - o = i - i = (i * i) % n - } - if (o !== (n - ONE)) { - y = o - } - } while (!y) - - const p = gcd(y - ONE, n) - const q = n / p - - return p > q ? { p, q } : { p: q, q: p } -} - -module.exports = (jwk) => { - const e = fromBuffer(base64url.decodeToBuffer(jwk.e)) - const d = fromBuffer(base64url.decodeToBuffer(jwk.d)) - const n = fromBuffer(base64url.decodeToBuffer(jwk.n)) - - if (d >= n) { - throw new errors.JWKInvalid('invalid RSA private exponent') - } - - const { p, q } = getPrimeFactors(e, d, n) - const dp = d % (p - ONE) - const dq = d % (q - ONE) - const qi = toZn(eGcdX(toZn(q, p), p), p) - - return { - ...jwk, - p: toJWKParameter(p), - q: toJWKParameter(q), - dp: toJWKParameter(dp), - dq: toJWKParameter(dq), - qi: toJWKParameter(qi) - } -} diff --git a/lib/help/runtime_support.js b/lib/help/runtime_support.js deleted file mode 100644 index 300b26812d..0000000000 --- a/lib/help/runtime_support.js +++ /dev/null @@ -1,11 +0,0 @@ -const { diffieHellman, KeyObject, sign, verify } = require('crypto') - -const [major, minor] = process.version.substr(1).split('.').map(x => parseInt(x, 10)) - -module.exports = { - oaepHashSupported: major > 12 || (major === 12 && minor >= 9), - keyObjectSupported: !!KeyObject && major >= 12, - edDSASupported: !!sign && !!verify, - dsaEncodingSupported: major > 13 || (major === 13 && minor >= 2) || (major === 12 && minor >= 16), - improvedDH: !!diffieHellman -} diff --git a/lib/help/timing_safe_equal.js b/lib/help/timing_safe_equal.js deleted file mode 100644 index 7419e19a15..0000000000 --- a/lib/help/timing_safe_equal.js +++ /dev/null @@ -1,18 +0,0 @@ -const { timingSafeEqual: TSE } = require('crypto') - -const paddedBuffer = (input, length) => { - if (input.length === length) { - return input - } - - const buffer = Buffer.alloc(length) - input.copy(buffer) - return buffer -} - -const timingSafeEqual = (a, b) => { - const length = Math.max(a.length, b.length) - return TSE(paddedBuffer(a, length), paddedBuffer(b, length)) -} - -module.exports = timingSafeEqual diff --git a/lib/help/uint64be.js b/lib/help/uint64be.js deleted file mode 100644 index fca449bb51..0000000000 --- a/lib/help/uint64be.js +++ /dev/null @@ -1,10 +0,0 @@ -const MAX_INT32 = Math.pow(2, 32) - -module.exports = (value, buf = Buffer.allocUnsafe(8)) => { - const high = Math.floor(value / MAX_INT32) - const low = value % MAX_INT32 - - buf.writeUInt32BE(high, 0) - buf.writeUInt32BE(low, 4) - return buf -} diff --git a/lib/help/validate_crit.js b/lib/help/validate_crit.js deleted file mode 100644 index b97d50c3f3..0000000000 --- a/lib/help/validate_crit.js +++ /dev/null @@ -1,41 +0,0 @@ -const { JOSECritNotUnderstood, JWSInvalid } = require('../errors') - -const DEFINED = new Set([ - 'alg', 'jku', 'jwk', 'kid', 'x5u', 'x5c', 'x5t', 'x5t#S256', 'typ', 'cty', - 'crit', 'enc', 'zip', 'epk', 'apu', 'apv', 'iv', 'tag', 'p2s', 'p2c' -]) - -module.exports = function validateCrit (Err, protectedHeader, unprotectedHeader, understood) { - if (protectedHeader && 'crit' in protectedHeader) { - if ( - !Array.isArray(protectedHeader.crit) || - protectedHeader.crit.length === 0 || - protectedHeader.crit.some(s => typeof s !== 'string' || !s) - ) { - throw new Err('"crit" Header Parameter MUST be an array of non-empty strings when present') - } - const whitelisted = new Set(understood) - const combined = { ...protectedHeader, ...unprotectedHeader } - protectedHeader.crit.forEach((parameter) => { - if (DEFINED.has(parameter)) { - throw new Err(`The critical list contains a non-extension Header Parameter ${parameter}`) - } - if (!whitelisted.has(parameter)) { - throw new JOSECritNotUnderstood(`critical "${parameter}" is not understood`) - } - if (parameter === 'b64') { - if (!('b64' in protectedHeader)) { - throw new JWSInvalid('"b64" critical parameter must be integrity protected') - } - if (typeof protectedHeader.b64 !== 'boolean') { - throw new JWSInvalid('"b64" critical parameter must be a boolean') - } - } else if (!(parameter in combined)) { - throw new Err(`critical parameter "${parameter}" is missing`) - } - }) - } - if (unprotectedHeader && 'crit' in unprotectedHeader) { - throw new Err('"crit" Header Parameter MUST be integrity protected when present') - } -} diff --git a/lib/index.js b/lib/index.js deleted file mode 100644 index 861a4e6a5a..0000000000 --- a/lib/index.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - JWE: require('./jwe'), - JWK: require('./jwk'), - JWKS: require('./jwks'), - JWS: require('./jws'), - JWT: require('./jwt'), - errors: require('./errors') -} diff --git a/lib/index.mjs b/lib/index.mjs deleted file mode 100644 index 0dd40d1003..0000000000 --- a/lib/index.mjs +++ /dev/null @@ -1,9 +0,0 @@ -import mod from './index.js' - -export default mod -export const JWE = mod.JWE -export const JWK = mod.JWK -export const JWKS = mod.JWKS -export const JWS = mod.JWS -export const JWT = mod.JWT -export const errors = mod.errors diff --git a/lib/jwa/aes_cbc_hmac_sha2.js b/lib/jwa/aes_cbc_hmac_sha2.js deleted file mode 100644 index 29a2fbeac1..0000000000 --- a/lib/jwa/aes_cbc_hmac_sha2.js +++ /dev/null @@ -1,70 +0,0 @@ -const { createCipheriv, createDecipheriv, getCiphers } = require('crypto') - -const uint64be = require('../help/uint64be') -const timingSafeEqual = require('../help/timing_safe_equal') -const { KEYOBJECT } = require('../help/consts') -const { JWEInvalid, JWEDecryptionFailed } = require('../errors') - -const checkInput = function (size, iv, tag) { - if (iv.length !== 16) { - throw new JWEInvalid('invalid iv') - } - if (arguments.length === 3) { - if (tag.length !== size / 8) { - throw new JWEInvalid('invalid tag') - } - } -} - -const encrypt = (size, sign, { [KEYOBJECT]: keyObject }, cleartext, { iv, aad = Buffer.alloc(0) }) => { - const key = keyObject.export() - checkInput(size, iv) - - const keySize = size / 8 - const encKey = key.slice(keySize) - const cipher = createCipheriv(`aes-${size}-cbc`, encKey, iv) - const ciphertext = Buffer.concat([cipher.update(cleartext), cipher.final()]) - const macData = Buffer.concat([aad, iv, ciphertext, uint64be(aad.length * 8)]) - - const macKey = key.slice(0, keySize) - const tag = sign({ [KEYOBJECT]: macKey }, macData).slice(0, keySize) - - return { ciphertext, tag } -} - -const decrypt = (size, sign, { [KEYOBJECT]: keyObject }, ciphertext, { iv, tag = Buffer.alloc(0), aad = Buffer.alloc(0) }) => { - checkInput(size, iv, tag) - - const keySize = size / 8 - const key = keyObject.export() - const encKey = key.slice(keySize) - const macKey = key.slice(0, keySize) - - const macData = Buffer.concat([aad, iv, ciphertext, uint64be(aad.length * 8)]) - const expectedTag = sign({ [KEYOBJECT]: macKey }, macData, tag).slice(0, keySize) - const macCheckPassed = timingSafeEqual(tag, expectedTag) - - let cleartext - try { - const cipher = createDecipheriv(`aes-${size}-cbc`, encKey, iv) - cleartext = Buffer.concat([cipher.update(ciphertext), cipher.final()]) - } catch (err) {} - - if (!cleartext || !macCheckPassed) { - throw new JWEDecryptionFailed() - } - - return cleartext -} - -module.exports = (JWA, JWK) => { - ['A128CBC-HS256', 'A192CBC-HS384', 'A256CBC-HS512'].forEach((jwaAlg) => { - const size = parseInt(jwaAlg.substr(1, 3), 10) - const sign = JWA.sign.get(`HS${size * 2}`) - if (getCiphers().includes(`aes-${size}-cbc`)) { - JWA.encrypt.set(jwaAlg, encrypt.bind(undefined, size, sign)) - JWA.decrypt.set(jwaAlg, decrypt.bind(undefined, size, sign)) - JWK.oct.encrypt[jwaAlg] = JWK.oct.decrypt[jwaAlg] = key => (key.use === 'enc' || key.use === undefined) && key.length / 2 === size - } - }) -} diff --git a/lib/jwa/aes_gcm.js b/lib/jwa/aes_gcm.js deleted file mode 100644 index 1acc5ca95f..0000000000 --- a/lib/jwa/aes_gcm.js +++ /dev/null @@ -1,55 +0,0 @@ -const { createCipheriv, createDecipheriv, getCiphers } = require('crypto') - -const { KEYOBJECT } = require('../help/consts') -const { JWEInvalid, JWEDecryptionFailed } = require('../errors') -const { asInput } = require('../help/key_object') - -const checkInput = function (size, iv, tag) { - if (iv.length !== 12) { - throw new JWEInvalid('invalid iv') - } - if (arguments.length === 3) { - if (tag.length !== 16) { - throw new JWEInvalid('invalid tag') - } - } -} - -const encrypt = (size, { [KEYOBJECT]: keyObject }, cleartext, { iv, aad = Buffer.alloc(0) }) => { - const key = asInput(keyObject, false) - checkInput(size, iv) - - const cipher = createCipheriv(`aes-${size}-gcm`, key, iv, { authTagLength: 16 }) - cipher.setAAD(aad) - - const ciphertext = Buffer.concat([cipher.update(cleartext), cipher.final()]) - const tag = cipher.getAuthTag() - - return { ciphertext, tag } -} - -const decrypt = (size, { [KEYOBJECT]: keyObject }, ciphertext, { iv, tag = Buffer.alloc(0), aad = Buffer.alloc(0) }) => { - const key = asInput(keyObject, false) - checkInput(size, iv, tag) - - try { - const cipher = createDecipheriv(`aes-${size}-gcm`, key, iv, { authTagLength: 16 }) - cipher.setAuthTag(tag) - cipher.setAAD(aad) - - return Buffer.concat([cipher.update(ciphertext), cipher.final()]) - } catch (err) { - throw new JWEDecryptionFailed() - } -} - -module.exports = (JWA, JWK) => { - ['A128GCM', 'A192GCM', 'A256GCM'].forEach((jwaAlg) => { - const size = parseInt(jwaAlg.substr(1, 3), 10) - if (getCiphers().includes(`aes-${size}-gcm`)) { - JWA.encrypt.set(jwaAlg, encrypt.bind(undefined, size)) - JWA.decrypt.set(jwaAlg, decrypt.bind(undefined, size)) - JWK.oct.encrypt[jwaAlg] = JWK.oct.decrypt[jwaAlg] = key => (key.use === 'enc' || key.use === undefined) && key.length === size - } - }) -} diff --git a/lib/jwa/aes_gcm_kw.js b/lib/jwa/aes_gcm_kw.js deleted file mode 100644 index 3a57bb9ca4..0000000000 --- a/lib/jwa/aes_gcm_kw.js +++ /dev/null @@ -1,24 +0,0 @@ -const generateIV = require('../help/generate_iv') -const base64url = require('../help/base64url') - -module.exports = (JWA, JWK) => { - ['A128GCMKW', 'A192GCMKW', 'A256GCMKW'].forEach((jwaAlg) => { - const encAlg = jwaAlg.substr(0, 7) - const size = parseInt(jwaAlg.substr(1, 3), 10) - const encrypt = JWA.encrypt.get(encAlg) - const decrypt = JWA.decrypt.get(encAlg) - - if (encrypt && decrypt) { - JWA.keyManagementEncrypt.set(jwaAlg, (key, payload) => { - const iv = generateIV(jwaAlg) - const { ciphertext, tag } = encrypt(key, payload, { iv }) - return { - wrapped: ciphertext, - header: { tag: base64url.encodeBuffer(tag), iv: base64url.encodeBuffer(iv) } - } - }) - JWA.keyManagementDecrypt.set(jwaAlg, decrypt) - JWK.oct.wrapKey[jwaAlg] = JWK.oct.unwrapKey[jwaAlg] = key => (key.use === 'enc' || key.use === undefined) && key.length === size - } - }) -} diff --git a/lib/jwa/aes_kw.js b/lib/jwa/aes_kw.js deleted file mode 100644 index c2e2d65ce1..0000000000 --- a/lib/jwa/aes_kw.js +++ /dev/null @@ -1,37 +0,0 @@ -const { createCipheriv, createDecipheriv, getCiphers } = require('crypto') - -const { KEYOBJECT } = require('../help/consts') -const { asInput } = require('../help/key_object') - -const checkInput = (data) => { - if (data !== undefined && data.length % 8 !== 0) { - throw new Error('invalid data length') - } -} - -const wrapKey = (alg, { [KEYOBJECT]: keyObject }, payload) => { - const key = asInput(keyObject, false) - const cipher = createCipheriv(alg, key, Buffer.alloc(8, 'a6', 'hex')) - - return { wrapped: Buffer.concat([cipher.update(payload), cipher.final()]) } -} - -const unwrapKey = (alg, { [KEYOBJECT]: keyObject }, payload) => { - const key = asInput(keyObject, false) - checkInput(payload) - const cipher = createDecipheriv(alg, key, Buffer.alloc(8, 'a6', 'hex')) - - return Buffer.concat([cipher.update(payload), cipher.final()]) -} - -module.exports = (JWA, JWK) => { - ['A128KW', 'A192KW', 'A256KW'].forEach((jwaAlg) => { - const size = parseInt(jwaAlg.substr(1, 3), 10) - const alg = `aes${size}-wrap` - if (getCiphers().includes(alg)) { - JWA.keyManagementEncrypt.set(jwaAlg, wrapKey.bind(undefined, alg)) - JWA.keyManagementDecrypt.set(jwaAlg, unwrapKey.bind(undefined, alg)) - JWK.oct.wrapKey[jwaAlg] = JWK.oct.unwrapKey[jwaAlg] = key => (key.use === 'enc' || key.use === undefined) && key.length === size - } - }) -} diff --git a/lib/jwa/ecdh/compute_secret.js b/lib/jwa/ecdh/compute_secret.js deleted file mode 100644 index 0572ea11cb..0000000000 --- a/lib/jwa/ecdh/compute_secret.js +++ /dev/null @@ -1,43 +0,0 @@ -const { improvedDH } = require('../../help/runtime_support') - -if (improvedDH) { - const { diffieHellman } = require('crypto') - - const { KeyObject } = require('../../help/key_object') - const importKey = require('../../jwk/import') - - module.exports = ({ keyObject: privateKey }, publicKey) => { - if (!(publicKey instanceof KeyObject)) { - ({ keyObject: publicKey } = importKey(publicKey)) - } - - return diffieHellman({ privateKey, publicKey }) - } -} else { - const { createECDH, constants: { POINT_CONVERSION_UNCOMPRESSED } } = require('crypto') - - const base64url = require('../../help/base64url') - - const crvToCurve = (crv) => { - switch (crv) { - case 'P-256': - return 'prime256v1' - case 'P-384': - return 'secp384r1' - case 'P-521': - return 'secp521r1' - } - } - - const UNCOMPRESSED = Buffer.alloc(1, POINT_CONVERSION_UNCOMPRESSED) - const pubToBuffer = (x, y) => Buffer.concat([UNCOMPRESSED, base64url.decodeToBuffer(x), base64url.decodeToBuffer(y)]) - - module.exports = ({ crv, d }, { x, y }) => { - const curve = crvToCurve(crv) - const exchange = createECDH(curve) - - exchange.setPrivateKey(base64url.decodeToBuffer(d)) - - return exchange.computeSecret(pubToBuffer(x, y)) - } -} diff --git a/lib/jwa/ecdh/derive.js b/lib/jwa/ecdh/derive.js deleted file mode 100644 index a2166c6a08..0000000000 --- a/lib/jwa/ecdh/derive.js +++ /dev/null @@ -1,40 +0,0 @@ -const { createHash } = require('crypto') -const ecdhComputeSecret = require('./compute_secret') - -const concat = (key, length, value) => { - const iterations = Math.ceil(length / 32) - let res - - for (let iter = 1; iter <= iterations; iter++) { - const buf = Buffer.allocUnsafe(4 + key.length + value.length) - buf.writeUInt32BE(iter, 0) - key.copy(buf, 4) - value.copy(buf, 4 + key.length) - if (!res) { - res = createHash('sha256').update(buf).digest() - } else { - res = Buffer.concat([res, createHash('sha256').update(buf).digest()]) - } - } - - return res.slice(0, length) -} - -const uint32be = (value, buf = Buffer.allocUnsafe(4)) => { - buf.writeUInt32BE(value) - return buf -} - -const lengthAndInput = input => Buffer.concat([uint32be(input.length), input]) - -module.exports = (alg, keyLen, privKey, pubKey, { apu = Buffer.alloc(0), apv = Buffer.alloc(0) } = {}, computeSecret = ecdhComputeSecret) => { - const value = Buffer.concat([ - lengthAndInput(Buffer.from(alg)), - lengthAndInput(apu), - lengthAndInput(apv), - uint32be(keyLen) - ]) - - const sharedSecret = computeSecret(privKey, pubKey) - return concat(sharedSecret, keyLen / 8, value) -} diff --git a/lib/jwa/ecdh/dir.js b/lib/jwa/ecdh/dir.js deleted file mode 100644 index 5185f19fad..0000000000 --- a/lib/jwa/ecdh/dir.js +++ /dev/null @@ -1,31 +0,0 @@ -const { improvedDH } = require('../../help/runtime_support') -const { KEYLENGTHS } = require('../../registry') -const { generateSync } = require('../../jwk/generate') - -const derive = require('./derive') - -const wrapKey = (key, payload, { enc }) => { - const epk = generateSync(key.kty, key.crv) - - const derivedKey = derive(enc, KEYLENGTHS.get(enc), epk, key) - - return { - wrapped: derivedKey, - header: { epk: { kty: key.kty, crv: key.crv, x: epk.x, y: epk.y } } - } -} - -const unwrapKey = (key, payload, header) => { - const { enc, epk } = header - return derive(enc, KEYLENGTHS.get(enc), key, epk, header) -} - -module.exports = (JWA, JWK) => { - JWA.keyManagementEncrypt.set('ECDH-ES', wrapKey) - JWA.keyManagementDecrypt.set('ECDH-ES', unwrapKey) - JWK.EC.deriveKey['ECDH-ES'] = key => (key.use === 'enc' || key.use === undefined) && key.crv !== 'secp256k1' - - if (improvedDH) { - JWK.OKP.deriveKey['ECDH-ES'] = key => (key.use === 'enc' || key.use === undefined) && key.keyObject.asymmetricKeyType.startsWith('x') - } -} diff --git a/lib/jwa/ecdh/kw.js b/lib/jwa/ecdh/kw.js deleted file mode 100644 index 237a893744..0000000000 --- a/lib/jwa/ecdh/kw.js +++ /dev/null @@ -1,47 +0,0 @@ -const { improvedDH } = require('../../help/runtime_support') -const { KEYOBJECT } = require('../../help/consts') -const { generateSync } = require('../../jwk/generate') -const { ECDH_DERIVE_LENGTHS } = require('../../registry') - -const derive = require('./derive') - -const wrapKey = (wrap, derive, key, payload) => { - const epk = generateSync(key.kty, key.crv) - - const derivedKey = derive(epk, key, payload) - - const result = wrap({ [KEYOBJECT]: derivedKey }, payload) - result.header = result.header || {} - Object.assign(result.header, { epk: { kty: key.kty, crv: key.crv, x: epk.x, y: epk.y } }) - - return result -} - -const unwrapKey = (unwrap, derive, key, payload, header) => { - const { epk } = header - const derivedKey = derive(key, epk, header) - - return unwrap({ [KEYOBJECT]: derivedKey }, payload, header) -} - -module.exports = (JWA, JWK) => { - ['ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW'].forEach((jwaAlg) => { - const kw = jwaAlg.substr(-6) - const kwWrap = JWA.keyManagementEncrypt.get(kw) - const kwUnwrap = JWA.keyManagementDecrypt.get(kw) - const keylen = parseInt(jwaAlg.substr(9, 3), 10) - ECDH_DERIVE_LENGTHS.set(jwaAlg, keylen) - - if (kwWrap && kwUnwrap) { - JWA.keyManagementEncrypt.set(jwaAlg, wrapKey.bind(undefined, kwWrap, derive.bind(undefined, jwaAlg, keylen))) - JWA.keyManagementDecrypt.set(jwaAlg, unwrapKey.bind(undefined, kwUnwrap, derive.bind(undefined, jwaAlg, keylen))) - JWK.EC.deriveKey[jwaAlg] = key => (key.use === 'enc' || key.use === undefined) && key.crv !== 'secp256k1' - - if (improvedDH) { - JWK.OKP.deriveKey[jwaAlg] = key => (key.use === 'enc' || key.use === undefined) && key.keyObject.asymmetricKeyType.startsWith('x') - } - } - }) -} -module.exports.wrapKey = wrapKey -module.exports.unwrapKey = unwrapKey diff --git a/lib/jwa/ecdsa.js b/lib/jwa/ecdsa.js deleted file mode 100644 index fd114abb1f..0000000000 --- a/lib/jwa/ecdsa.js +++ /dev/null @@ -1,77 +0,0 @@ -const { sign: signOneShot, verify: verifyOneShot, createSign, createVerify, getCurves } = require('crypto') - -const { derToJose, joseToDer } = require('../help/ecdsa_signatures') -const { KEYOBJECT } = require('../help/consts') -const resolveNodeAlg = require('../help/node_alg') -const { asInput } = require('../help/key_object') -const { dsaEncodingSupported } = require('../help/runtime_support') - -let sign, verify - -if (dsaEncodingSupported) { - sign = (jwaAlg, nodeAlg, { [KEYOBJECT]: keyObject }, payload) => { - if (typeof payload === 'string') { - payload = Buffer.from(payload) - } - return signOneShot(nodeAlg, payload, { key: asInput(keyObject, false), dsaEncoding: 'ieee-p1363' }) - } - verify = (jwaAlg, nodeAlg, { [KEYOBJECT]: keyObject }, payload, signature) => { - try { - return verifyOneShot(nodeAlg, payload, { key: asInput(keyObject, true), dsaEncoding: 'ieee-p1363' }, signature) - } catch (err) { - return false - } - } -} else { - sign = (jwaAlg, nodeAlg, { [KEYOBJECT]: keyObject }, payload) => { - return derToJose(createSign(nodeAlg).update(payload).sign(asInput(keyObject, false)), jwaAlg) - } - verify = (jwaAlg, nodeAlg, { [KEYOBJECT]: keyObject }, payload, signature) => { - try { - return createVerify(nodeAlg).update(payload).verify(asInput(keyObject, true), joseToDer(signature, jwaAlg)) - } catch (err) { - return false - } - } -} - -const crvToAlg = (crv) => { - switch (crv) { - case 'P-256': - return 'ES256' - case 'secp256k1': - return 'ES256K' - case 'P-384': - return 'ES384' - case 'P-521': - return 'ES512' - } -} - -module.exports = (JWA, JWK) => { - const algs = [] - - if (getCurves().includes('prime256v1')) { - algs.push('ES256') - } - - if (getCurves().includes('secp256k1')) { - algs.push('ES256K') - } - - if (getCurves().includes('secp384r1')) { - algs.push('ES384') - } - - if (getCurves().includes('secp521r1')) { - algs.push('ES512') - } - - algs.forEach((jwaAlg) => { - const nodeAlg = resolveNodeAlg(jwaAlg) - JWA.sign.set(jwaAlg, sign.bind(undefined, jwaAlg, nodeAlg)) - JWA.verify.set(jwaAlg, verify.bind(undefined, jwaAlg, nodeAlg)) - JWK.EC.sign[jwaAlg] = key => key.private && JWK.EC.verify[jwaAlg](key) - JWK.EC.verify[jwaAlg] = key => (key.use === 'sig' || key.use === undefined) && crvToAlg(key.crv) === jwaAlg - }) -} diff --git a/lib/jwa/eddsa.js b/lib/jwa/eddsa.js deleted file mode 100644 index e19d5238da..0000000000 --- a/lib/jwa/eddsa.js +++ /dev/null @@ -1,24 +0,0 @@ -const { sign: signOneShot, verify: verifyOneShot } = require('crypto') - -const { KEYOBJECT } = require('../help/consts') -const { edDSASupported } = require('../help/runtime_support') - -const sign = ({ [KEYOBJECT]: keyObject }, payload) => { - if (typeof payload === 'string') { - payload = Buffer.from(payload) - } - return signOneShot(undefined, payload, keyObject) -} - -const verify = ({ [KEYOBJECT]: keyObject }, payload, signature) => { - return verifyOneShot(undefined, payload, keyObject, signature) -} - -module.exports = (JWA, JWK) => { - if (edDSASupported) { - JWA.sign.set('EdDSA', sign) - JWA.verify.set('EdDSA', verify) - JWK.OKP.sign.EdDSA = key => key.private && JWK.OKP.verify.EdDSA(key) - JWK.OKP.verify.EdDSA = key => (key.use === 'sig' || key.use === undefined) && key.keyObject.asymmetricKeyType.startsWith('ed') - } -} diff --git a/lib/jwa/hmac.js b/lib/jwa/hmac.js deleted file mode 100644 index a00770a297..0000000000 --- a/lib/jwa/hmac.js +++ /dev/null @@ -1,28 +0,0 @@ -const { createHmac } = require('crypto') - -const { KEYOBJECT } = require('../help/consts') -const timingSafeEqual = require('../help/timing_safe_equal') -const resolveNodeAlg = require('../help/node_alg') -const { asInput } = require('../help/key_object') - -const sign = (jwaAlg, hmacAlg, { [KEYOBJECT]: keyObject }, payload) => { - const hmac = createHmac(hmacAlg, asInput(keyObject, false)) - hmac.update(payload) - return hmac.digest() -} - -const verify = (jwaAlg, hmacAlg, key, payload, signature) => { - const expected = sign(jwaAlg, hmacAlg, key, payload) - const actual = signature - - return timingSafeEqual(actual, expected) -} - -module.exports = (JWA, JWK) => { - ['HS256', 'HS384', 'HS512'].forEach((jwaAlg) => { - const hmacAlg = resolveNodeAlg(jwaAlg) - JWA.sign.set(jwaAlg, sign.bind(undefined, jwaAlg, hmacAlg)) - JWA.verify.set(jwaAlg, verify.bind(undefined, jwaAlg, hmacAlg)) - JWK.oct.sign[jwaAlg] = JWK.oct.verify[jwaAlg] = key => key.use === 'sig' || key.use === undefined - }) -} diff --git a/lib/jwa/index.js b/lib/jwa/index.js deleted file mode 100644 index 589fdf23fe..0000000000 --- a/lib/jwa/index.js +++ /dev/null @@ -1,88 +0,0 @@ -const { JWKKeySupport, JOSENotSupported } = require('../errors') -const { KEY_MANAGEMENT_ENCRYPT, KEY_MANAGEMENT_DECRYPT } = require('../help/consts') - -const { JWA, JWK } = require('../registry') - -// sign, verify -require('./hmac')(JWA, JWK) -require('./ecdsa')(JWA, JWK) -require('./eddsa')(JWA, JWK) -require('./rsassa_pss')(JWA, JWK) -require('./rsassa')(JWA, JWK) -require('./none')(JWA) - -// encrypt, decrypt -require('./aes_cbc_hmac_sha2')(JWA, JWK) -require('./aes_gcm')(JWA, JWK) - -// wrapKey, unwrapKey -require('./rsaes')(JWA, JWK) -require('./aes_kw')(JWA, JWK) -require('./aes_gcm_kw')(JWA, JWK) - -// deriveKey -require('./pbes2')(JWA, JWK) -require('./ecdh/dir')(JWA, JWK) -require('./ecdh/kw')(JWA, JWK) - -const check = (key, op, alg) => { - const cache = `_${op}_${alg}` - - let label - let keyOp - if (op === 'keyManagementEncrypt') { - label = 'key management (encryption)' - keyOp = KEY_MANAGEMENT_ENCRYPT - } else if (op === 'keyManagementDecrypt') { - label = 'key management (decryption)' - keyOp = KEY_MANAGEMENT_DECRYPT - } - - if (cache in key) { - if (key[cache]) { - return - } - throw new JWKKeySupport(`the key does not support ${alg} ${label || op} algorithm`) - } - - let value = true - if (!JWA[op].has(alg)) { - throw new JOSENotSupported(`unsupported ${label || op} alg: ${alg}`) - } else if (!key.algorithms(keyOp).has(alg)) { - value = false - } - - Object.defineProperty(key, cache, { value, enumerable: false }) - - if (!value) { - return check(key, op, alg) - } -} - -module.exports = { - check, - sign: (alg, key, payload) => { - check(key, 'sign', alg) - return JWA.sign.get(alg)(key, payload) - }, - verify: (alg, key, payload, signature) => { - check(key, 'verify', alg) - return JWA.verify.get(alg)(key, payload, signature) - }, - keyManagementEncrypt: (alg, key, payload, opts) => { - check(key, 'keyManagementEncrypt', alg) - return JWA.keyManagementEncrypt.get(alg)(key, payload, opts) - }, - keyManagementDecrypt: (alg, key, payload, opts) => { - check(key, 'keyManagementDecrypt', alg) - return JWA.keyManagementDecrypt.get(alg)(key, payload, opts) - }, - encrypt: (alg, key, cleartext, opts) => { - check(key, 'encrypt', alg) - return JWA.encrypt.get(alg)(key, cleartext, opts) - }, - decrypt: (alg, key, ciphertext, opts) => { - check(key, 'decrypt', alg) - return JWA.decrypt.get(alg)(key, ciphertext, opts) - } -} diff --git a/lib/jwa/none.js b/lib/jwa/none.js deleted file mode 100644 index d2935bb6e0..0000000000 --- a/lib/jwa/none.js +++ /dev/null @@ -1,7 +0,0 @@ -const sign = () => Buffer.from('') -const verify = (key, payload, signature) => !signature.length - -module.exports = (JWA, JWK) => { - JWA.sign.set('none', sign) - JWA.verify.set('none', verify) -} diff --git a/lib/jwa/pbes2.js b/lib/jwa/pbes2.js deleted file mode 100644 index 9468627167..0000000000 --- a/lib/jwa/pbes2.js +++ /dev/null @@ -1,56 +0,0 @@ -const { pbkdf2Sync: pbkdf2, randomBytes } = require('crypto') - -const { KEYOBJECT } = require('../help/consts') -const base64url = require('../help/base64url') - -const SALT_LENGTH = 16 -const NULL_BUFFER = Buffer.alloc(1, 0) - -const concatSalt = (alg, p2s) => { - return Buffer.concat([ - Buffer.from(alg, 'utf8'), - NULL_BUFFER, - p2s - ]) -} - -const wrapKey = (keylen, sha, concat, wrap, { [KEYOBJECT]: keyObject }, payload) => { - // Note that if password-based encryption is used for multiple - // recipients, it is expected that each recipient use different values - // for the PBES2 parameters "p2s" and "p2c". - // here we generate p2c between 2048 and 4096 and random p2s - const p2c = Math.floor((Math.random() * 2049) + 2048) - const p2s = randomBytes(SALT_LENGTH) - const salt = concat(p2s) - - const derivedKey = pbkdf2(keyObject.export(), salt, p2c, keylen, sha) - - const result = wrap({ [KEYOBJECT]: derivedKey }, payload) - result.header = result.header || {} - Object.assign(result.header, { p2c, p2s: base64url.encodeBuffer(p2s) }) - - return result -} - -const unwrapKey = (keylen, sha, concat, unwrap, { [KEYOBJECT]: keyObject }, payload, header) => { - const { p2s, p2c } = header - const salt = concat(p2s) - const derivedKey = pbkdf2(keyObject.export(), salt, p2c, keylen, sha) - return unwrap({ [KEYOBJECT]: derivedKey }, payload, header) -} - -module.exports = (JWA, JWK) => { - ['PBES2-HS256+A128KW', 'PBES2-HS384+A192KW', 'PBES2-HS512+A256KW'].forEach((jwaAlg) => { - const kw = jwaAlg.substr(-6) - const kwWrap = JWA.keyManagementEncrypt.get(kw) - const kwUnwrap = JWA.keyManagementDecrypt.get(kw) - const keylen = parseInt(jwaAlg.substr(13, 3), 10) / 8 - const sha = `sha${jwaAlg.substr(8, 3)}` - - if (kwWrap && kwUnwrap) { - JWA.keyManagementEncrypt.set(jwaAlg, wrapKey.bind(undefined, keylen, sha, concatSalt.bind(undefined, jwaAlg), kwWrap)) - JWA.keyManagementDecrypt.set(jwaAlg, unwrapKey.bind(undefined, keylen, sha, concatSalt.bind(undefined, jwaAlg), kwUnwrap)) - JWK.oct.deriveKey[jwaAlg] = key => key.use === 'enc' || key.use === undefined - } - }) -} diff --git a/lib/jwa/rsaes.js b/lib/jwa/rsaes.js deleted file mode 100644 index f688543ee5..0000000000 --- a/lib/jwa/rsaes.js +++ /dev/null @@ -1,67 +0,0 @@ -const { publicEncrypt, privateDecrypt, constants } = require('crypto') - -const { oaepHashSupported } = require('../help/runtime_support') -const { KEYOBJECT } = require('../help/consts') -const { asInput } = require('../help/key_object') - -const resolvePadding = (alg) => { - switch (alg) { - case 'RSA-OAEP': - case 'RSA-OAEP-256': - case 'RSA-OAEP-384': - case 'RSA-OAEP-512': - return constants.RSA_PKCS1_OAEP_PADDING - case 'RSA1_5': - return constants.RSA_PKCS1_PADDING - } -} - -const resolveOaepHash = (alg) => { - switch (alg) { - case 'RSA-OAEP': - return 'sha1' - case 'RSA-OAEP-256': - return 'sha256' - case 'RSA-OAEP-384': - return 'sha384' - case 'RSA-OAEP-512': - return 'sha512' - default: - return undefined - } -} - -const wrapKey = (padding, oaepHash, { [KEYOBJECT]: keyObject }, payload) => { - const key = asInput(keyObject, true) - return { wrapped: publicEncrypt({ key, oaepHash, padding }, payload) } -} - -const unwrapKey = (padding, oaepHash, { [KEYOBJECT]: keyObject }, payload) => { - const key = asInput(keyObject, false) - return privateDecrypt({ key, oaepHash, padding }, payload) -} - -const LENGTHS = { - RSA1_5: 0, - 'RSA-OAEP': 592, - 'RSA-OAEP-256': 784, - 'RSA-OAEP-384': 1040, - 'RSA-OAEP-512': 1296 -} - -module.exports = (JWA, JWK) => { - const algs = ['RSA-OAEP', 'RSA1_5'] - - if (oaepHashSupported) { - algs.splice(1, 0, 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512') - } - - algs.forEach((jwaAlg) => { - const padding = resolvePadding(jwaAlg) - const oaepHash = resolveOaepHash(jwaAlg) - JWA.keyManagementEncrypt.set(jwaAlg, wrapKey.bind(undefined, padding, oaepHash)) - JWA.keyManagementDecrypt.set(jwaAlg, unwrapKey.bind(undefined, padding, oaepHash)) - JWK.RSA.wrapKey[jwaAlg] = key => (key.use === 'enc' || key.use === undefined) && key.length >= LENGTHS[jwaAlg] - JWK.RSA.unwrapKey[jwaAlg] = key => key.private && (key.use === 'enc' || key.use === undefined) && key.length >= LENGTHS[jwaAlg] - }) -} diff --git a/lib/jwa/rsassa.js b/lib/jwa/rsassa.js deleted file mode 100644 index 47e64da0c7..0000000000 --- a/lib/jwa/rsassa.js +++ /dev/null @@ -1,29 +0,0 @@ -const { createSign, createVerify } = require('crypto') - -const { KEYOBJECT } = require('../help/consts') -const resolveNodeAlg = require('../help/node_alg') -const { asInput } = require('../help/key_object') - -const sign = (nodeAlg, { [KEYOBJECT]: keyObject }, payload) => { - return createSign(nodeAlg).update(payload).sign(asInput(keyObject, false)) -} - -const verify = (nodeAlg, { [KEYOBJECT]: keyObject }, payload, signature) => { - return createVerify(nodeAlg).update(payload).verify(asInput(keyObject, true), signature) -} - -const LENGTHS = { - RS256: 0, - RS384: 624, - RS512: 752 -} - -module.exports = (JWA, JWK) => { - ['RS256', 'RS384', 'RS512'].forEach((jwaAlg) => { - const nodeAlg = resolveNodeAlg(jwaAlg) - JWA.sign.set(jwaAlg, sign.bind(undefined, nodeAlg)) - JWA.verify.set(jwaAlg, verify.bind(undefined, nodeAlg)) - JWK.RSA.sign[jwaAlg] = key => key.private && JWK.RSA.verify[jwaAlg](key) - JWK.RSA.verify[jwaAlg] = key => (key.use === 'sig' || key.use === undefined) && key.length >= LENGTHS[jwaAlg] - }) -} diff --git a/lib/jwa/rsassa_pss.js b/lib/jwa/rsassa_pss.js deleted file mode 100644 index bdb828904f..0000000000 --- a/lib/jwa/rsassa_pss.js +++ /dev/null @@ -1,43 +0,0 @@ -const { - createSign, - createVerify, - constants -} = require('crypto') - -const { KEYOBJECT } = require('../help/consts') -const resolveNodeAlg = require('../help/node_alg') -const { asInput } = require('../help/key_object') - -const sign = (nodeAlg, { [KEYOBJECT]: keyObject }, payload) => { - const key = asInput(keyObject, false) - return createSign(nodeAlg).update(payload).sign({ - key, - padding: constants.RSA_PKCS1_PSS_PADDING, - saltLength: constants.RSA_PSS_SALTLEN_DIGEST - }) -} - -const verify = (nodeAlg, { [KEYOBJECT]: keyObject }, payload, signature) => { - const key = asInput(keyObject, true) - return createVerify(nodeAlg).update(payload).verify({ - key, - padding: constants.RSA_PKCS1_PSS_PADDING, - saltLength: constants.RSA_PSS_SALTLEN_DIGEST - }, signature) -} - -const LENGTHS = { - PS256: 528, - PS384: 784, - PS512: 1040 -} - -module.exports = (JWA, JWK) => { - ['PS256', 'PS384', 'PS512'].forEach((jwaAlg) => { - const nodeAlg = resolveNodeAlg(jwaAlg) - JWA.sign.set(jwaAlg, sign.bind(undefined, nodeAlg)) - JWA.verify.set(jwaAlg, verify.bind(undefined, nodeAlg)) - JWK.RSA.sign[jwaAlg] = key => key.private && JWK.RSA.verify[jwaAlg](key) - JWK.RSA.verify[jwaAlg] = key => (key.use === 'sig' || key.use === undefined) && key.length >= LENGTHS[jwaAlg] - }) -} diff --git a/lib/jwe/decrypt.js b/lib/jwe/decrypt.js deleted file mode 100644 index fb5da68aaa..0000000000 --- a/lib/jwe/decrypt.js +++ /dev/null @@ -1,229 +0,0 @@ -const { inflateRawSync } = require('zlib') - -const base64url = require('../help/base64url') -const getKey = require('../help/get_key') -const { KeyStore } = require('../jwks') -const errors = require('../errors') -const { check, decrypt, keyManagementDecrypt } = require('../jwa') -const JWK = require('../jwk') - -const { createSecretKey } = require('../help/key_object') -const generateCEK = require('./generate_cek') -const validateHeaders = require('./validate_headers') -const { detect: resolveSerialization } = require('./serializers') - -const SINGLE_RECIPIENT = new Set(['compact', 'flattened']) - -const combineHeader = (prot = {}, unprotected = {}, header = {}) => { - if (typeof prot === 'string') { - prot = base64url.JSON.decode(prot) - } - - const p2s = prot.p2s || unprotected.p2s || header.p2s - const apu = prot.apu || unprotected.apu || header.apu - const apv = prot.apv || unprotected.apv || header.apv - const iv = prot.iv || unprotected.iv || header.iv - const tag = prot.tag || unprotected.tag || header.tag - - return { - ...prot, - ...unprotected, - ...header, - ...(typeof p2s === 'string' ? { p2s: base64url.decodeToBuffer(p2s) } : undefined), - ...(typeof apu === 'string' ? { apu: base64url.decodeToBuffer(apu) } : undefined), - ...(typeof apv === 'string' ? { apv: base64url.decodeToBuffer(apv) } : undefined), - ...(typeof iv === 'string' ? { iv: base64url.decodeToBuffer(iv) } : undefined), - ...(typeof tag === 'string' ? { tag: base64url.decodeToBuffer(tag) } : undefined) - } -} - -const validateAlgorithms = (algorithms, option) => { - if (algorithms !== undefined && (!Array.isArray(algorithms) || algorithms.some(s => typeof s !== 'string' || !s))) { - throw new TypeError(`"${option}" option must be an array of non-empty strings`) - } - - if (!algorithms) { - return undefined - } - - return new Set(algorithms) -} - -/* - * @public - */ -const jweDecrypt = (skipValidateHeaders, serialization, jwe, key, { crit = [], complete = false, keyManagementAlgorithms, contentEncryptionAlgorithms } = {}) => { - key = getKey(key, true) - - keyManagementAlgorithms = validateAlgorithms(keyManagementAlgorithms, 'keyManagementAlgorithms') - contentEncryptionAlgorithms = validateAlgorithms(contentEncryptionAlgorithms, 'contentEncryptionAlgorithms') - - if (!Array.isArray(crit) || crit.some(s => typeof s !== 'string' || !s)) { - throw new TypeError('"crit" option must be an array of non-empty strings') - } - - if (!serialization) { - serialization = resolveSerialization(jwe) - } - - let alg, ciphertext, enc, encryptedKey, iv, opts, prot, tag, unprotected, cek, aad, header - - // treat general format with one recipient as flattened - // skips iteration and avoids multi errors in this case - if (serialization === 'general' && jwe.recipients.length === 1) { - serialization = 'flattened' - const { recipients, ...root } = jwe - jwe = { ...root, ...recipients[0] } - } - - if (SINGLE_RECIPIENT.has(serialization)) { - if (serialization === 'compact') { // compact serialization format - ([prot, encryptedKey, iv, ciphertext, tag] = jwe.split('.')) - } else { // flattened serialization format - ({ protected: prot, encrypted_key: encryptedKey, iv, ciphertext, tag, unprotected, aad, header } = jwe) - } - - if (!skipValidateHeaders) { - validateHeaders(prot, unprotected, [{ header }], true, crit) - } - - opts = combineHeader(prot, unprotected, header) - - ;({ alg, enc } = opts) - - if (keyManagementAlgorithms && !keyManagementAlgorithms.has(alg)) { - throw new errors.JOSEAlgNotWhitelisted('key management algorithm not whitelisted') - } - - if (contentEncryptionAlgorithms && !contentEncryptionAlgorithms.has(enc)) { - throw new errors.JOSEAlgNotWhitelisted('content encryption algorithm not whitelisted') - } - - if (key instanceof KeyStore) { - const keystore = key - let keys - if (opts.alg === 'dir') { - keys = keystore.all({ kid: opts.kid, alg: opts.enc, key_ops: ['decrypt'] }) - } else { - keys = keystore.all({ kid: opts.kid, alg: opts.alg, key_ops: ['unwrapKey'] }) - } - switch (keys.length) { - case 0: - throw new errors.JWKSNoMatchingKey() - case 1: - // treat the call as if a Key instance was passed in - // skips iteration and avoids multi errors in this case - key = keys[0] - break - default: { - const errs = [] - for (const key of keys) { - try { - return jweDecrypt(true, serialization, jwe, key, { - crit, - complete, - contentEncryptionAlgorithms: contentEncryptionAlgorithms ? [...contentEncryptionAlgorithms] : undefined, - keyManagementAlgorithms: keyManagementAlgorithms ? [...keyManagementAlgorithms] : undefined - }) - } catch (err) { - errs.push(err) - continue - } - } - - const multi = new errors.JOSEMultiError(errs) - if ([...multi].some(e => e instanceof errors.JWEDecryptionFailed)) { - throw new errors.JWEDecryptionFailed() - } - throw multi - } - } - } - - check(key, ...(alg === 'dir' ? ['decrypt', enc] : ['keyManagementDecrypt', alg])) - - try { - if (alg === 'dir') { - cek = JWK.asKey(key, { alg: enc, use: 'enc' }) - } else if (alg === 'ECDH-ES') { - const unwrapped = keyManagementDecrypt(alg, key, undefined, opts) - cek = JWK.asKey(createSecretKey(unwrapped), { alg: enc, use: 'enc' }) - } else { - const unwrapped = keyManagementDecrypt(alg, key, base64url.decodeToBuffer(encryptedKey), opts) - cek = JWK.asKey(createSecretKey(unwrapped), { alg: enc, use: 'enc' }) - } - } catch (err) { - // To mitigate the attacks described in RFC 3218, the - // recipient MUST NOT distinguish between format, padding, and length - // errors of encrypted keys. It is strongly recommended, in the event - // of receiving an improperly formatted key, that the recipient - // substitute a randomly generated CEK and proceed to the next step, to - // mitigate timing attacks. - cek = generateCEK(enc) - } - - let adata - if (aad) { - adata = Buffer.concat([ - Buffer.from(prot || ''), - Buffer.from('.'), - Buffer.from(aad) - ]) - } else { - adata = Buffer.from(prot || '') - } - - try { - iv = base64url.decodeToBuffer(iv) - } catch (err) {} - try { - tag = base64url.decodeToBuffer(tag) - } catch (err) {} - - let cleartext = decrypt(enc, cek, base64url.decodeToBuffer(ciphertext), { iv, tag, aad: adata }) - - if (opts.zip) { - cleartext = inflateRawSync(cleartext) - } - - if (complete) { - const result = { cleartext, key, cek } - if (aad) result.aad = aad - if (header) result.header = header - if (unprotected) result.unprotected = unprotected - if (prot) result.protected = base64url.JSON.decode(prot) - return result - } - - return cleartext - } - - validateHeaders(jwe.protected, jwe.unprotected, jwe.recipients.map(({ header }) => ({ header })), true, crit) - - // general serialization format - const { recipients, ...root } = jwe - const errs = [] - for (const recipient of recipients) { - try { - return jweDecrypt(true, 'flattened', { ...root, ...recipient }, key, { - crit, - complete, - contentEncryptionAlgorithms: contentEncryptionAlgorithms ? [...contentEncryptionAlgorithms] : undefined, - keyManagementAlgorithms: keyManagementAlgorithms ? [...keyManagementAlgorithms] : undefined - }) - } catch (err) { - errs.push(err) - continue - } - } - - const multi = new errors.JOSEMultiError(errs) - if ([...multi].some(e => e instanceof errors.JWEDecryptionFailed)) { - throw new errors.JWEDecryptionFailed() - } else if ([...multi].every(e => e instanceof errors.JWKSNoMatchingKey)) { - throw new errors.JWKSNoMatchingKey() - } - throw multi -} - -module.exports = jweDecrypt.bind(undefined, false, undefined) diff --git a/lib/jwe/encrypt.js b/lib/jwe/encrypt.js deleted file mode 100644 index 9851f392bc..0000000000 --- a/lib/jwe/encrypt.js +++ /dev/null @@ -1,214 +0,0 @@ -const { deflateRawSync } = require('zlib') - -const { KEYOBJECT } = require('../help/consts') -const generateIV = require('../help/generate_iv') -const base64url = require('../help/base64url') -const getKey = require('../help/get_key') -const isObject = require('../help/is_object') -const { createSecretKey } = require('../help/key_object') -const deepClone = require('../help/deep_clone') -const importKey = require('../jwk/import') -const { JWEInvalid } = require('../errors') -const { check, keyManagementEncrypt, encrypt } = require('../jwa') - -const serializers = require('./serializers') -const generateCEK = require('./generate_cek') -const validateHeaders = require('./validate_headers') - -const PROCESS_RECIPIENT = Symbol('PROCESS_RECIPIENT') - -class Encrypt { - constructor (cleartext, protectedHeader, aad, unprotectedHeader) { - if (!Buffer.isBuffer(cleartext) && typeof cleartext !== 'string') { - throw new TypeError('cleartext argument must be a Buffer or a string') - } - cleartext = Buffer.from(cleartext) - - if (aad !== undefined && !Buffer.isBuffer(aad) && typeof aad !== 'string') { - throw new TypeError('aad argument must be a Buffer or a string when provided') - } - aad = aad ? Buffer.from(aad) : undefined - - if (protectedHeader !== undefined && !isObject(protectedHeader)) { - throw new TypeError('protectedHeader argument must be a plain object when provided') - } - - if (unprotectedHeader !== undefined && !isObject(unprotectedHeader)) { - throw new TypeError('unprotectedHeader argument must be a plain object when provided') - } - - this._recipients = [] - this._cleartext = cleartext - this._aad = aad - this._unprotected = unprotectedHeader ? deepClone(unprotectedHeader) : undefined - this._protected = protectedHeader ? deepClone(protectedHeader) : undefined - } - - /* - * @public - */ - recipient (key, header) { - key = getKey(key) - - if (header !== undefined && !isObject(header)) { - throw new TypeError('header argument must be a plain object when provided') - } - - this._recipients.push({ - key, - header: header ? deepClone(header) : undefined - }) - - return this - } - - /* - * @private - */ - [PROCESS_RECIPIENT] (recipient) { - const unprotectedHeader = this._unprotected - const protectedHeader = this._protected - const { length: recipientCount } = this._recipients - - const jweHeader = { - ...protectedHeader, - ...unprotectedHeader, - ...recipient.header - } - const { key } = recipient - - const enc = jweHeader.enc - let alg = jweHeader.alg - - if (key.use === 'sig') { - throw new TypeError('a key with "use":"sig" is not usable for encryption') - } - - if (alg === 'dir') { - check(key, 'encrypt', enc) - } else if (alg) { - check(key, 'keyManagementEncrypt', alg) - } else { - alg = key.alg || [...key.algorithms('wrapKey')][0] || [...key.algorithms('deriveKey')][0] - - if (alg === 'ECDH-ES' && recipientCount !== 1) { - alg = [...key.algorithms('deriveKey')][1] - } - - if (!alg) { - throw new JWEInvalid('could not resolve a usable "alg" for a recipient') - } - - if (recipientCount === 1) { - if (protectedHeader) { - protectedHeader.alg = alg - } else { - this._protected = { alg } - } - } else { - if (recipient.header) { - recipient.header.alg = alg - } else { - recipient.header = { alg } - } - } - } - - let wrapped - let generatedHeader - - if (key.kty === 'oct' && alg === 'dir') { - this._cek = importKey(key[KEYOBJECT], { use: 'enc', alg: enc }) - } else { - check(this._cek, 'encrypt', enc) - ;({ wrapped, header: generatedHeader } = keyManagementEncrypt(alg, key, this._cek[KEYOBJECT].export(), { enc, alg })) - if (alg === 'ECDH-ES') { - this._cek = importKey(createSecretKey(wrapped), { use: 'enc', alg: enc }) - } - } - - if (alg === 'dir' || alg === 'ECDH-ES') { - recipient.encrypted_key = '' - } else { - recipient.encrypted_key = base64url.encodeBuffer(wrapped) - } - - if (generatedHeader) { - recipient.generatedHeader = generatedHeader - } - } - - /* - * @public - */ - encrypt (serialization) { - const serializer = serializers[serialization] - if (!serializer) { - throw new TypeError('serialization must be one of "compact", "flattened", "general"') - } - - if (!this._recipients.length) { - throw new JWEInvalid('missing recipients') - } - - serializer.validate(this._protected, this._unprotected, this._aad, this._recipients) - - let enc = validateHeaders(this._protected, this._unprotected, this._recipients, false, this._protected ? this._protected.crit : undefined) - if (!enc) { - enc = 'A128CBC-HS256' - if (this._protected) { - this._protected.enc = enc - } else { - this._protected = { enc } - } - } - const final = {} - this._cek = generateCEK(enc) - - for (const recipient of this._recipients) { - this[PROCESS_RECIPIENT](recipient) - } - - const iv = generateIV(enc) - final.iv = base64url.encodeBuffer(iv) - - if (this._recipients.length === 1 && this._recipients[0].generatedHeader) { - const [{ generatedHeader }] = this._recipients - delete this._recipients[0].generatedHeader - this._protected = { - ...this._protected, - ...generatedHeader - } - } - - if (this._protected) { - final.protected = base64url.JSON.encode(this._protected) - } - final.unprotected = this._unprotected - - let aad - if (this._aad) { - final.aad = base64url.encode(this._aad) - aad = Buffer.concat([ - Buffer.from(final.protected || ''), - Buffer.from('.'), - Buffer.from(final.aad) - ]) - } else { - aad = Buffer.from(final.protected || '') - } - - let cleartext = this._cleartext - if (this._protected && 'zip' in this._protected) { - cleartext = deflateRawSync(cleartext) - } - - const { ciphertext, tag } = encrypt(enc, this._cek, cleartext, { iv, aad }) - final.tag = base64url.encodeBuffer(tag) - final.ciphertext = base64url.encodeBuffer(ciphertext) - - return serializer(final, this._recipients) - } -} - -module.exports = Encrypt diff --git a/lib/jwe/generate_cek.js b/lib/jwe/generate_cek.js deleted file mode 100644 index 15392af476..0000000000 --- a/lib/jwe/generate_cek.js +++ /dev/null @@ -1,15 +0,0 @@ -const { randomBytes } = require('crypto') - -const { createSecretKey } = require('../help/key_object') -const { KEYLENGTHS } = require('../registry') -const Key = require('../jwk/key/oct') - -module.exports = (alg) => { - const keyLength = KEYLENGTHS.get(alg) - - if (!keyLength) { - return new Key({ type: 'secret' }) - } - - return new Key(createSecretKey(randomBytes(keyLength / 8)), { use: 'enc', alg }) -} diff --git a/lib/jwe/index.js b/lib/jwe/index.js deleted file mode 100644 index 68bf292967..0000000000 --- a/lib/jwe/index.js +++ /dev/null @@ -1,15 +0,0 @@ -const Encrypt = require('./encrypt') -const decrypt = require('./decrypt') - -const single = (serialization, cleartext, key, protectedHeader, aad, unprotectedHeader) => { - return new Encrypt(cleartext, protectedHeader, aad, unprotectedHeader) - .recipient(key) - .encrypt(serialization) -} - -module.exports.Encrypt = Encrypt -module.exports.encrypt = single.bind(undefined, 'compact') -module.exports.encrypt.flattened = single.bind(undefined, 'flattened') -module.exports.encrypt.general = single.bind(undefined, 'general') - -module.exports.decrypt = decrypt diff --git a/lib/jwe/serializers.js b/lib/jwe/serializers.js deleted file mode 100644 index 9907c144b5..0000000000 --- a/lib/jwe/serializers.js +++ /dev/null @@ -1,121 +0,0 @@ -const isObject = require('../help/is_object') -let validateCrit = require('../help/validate_crit') - -const { JWEInvalid } = require('../errors') - -validateCrit = validateCrit.bind(undefined, JWEInvalid) - -const compactSerializer = (final, [recipient]) => { - return `${final.protected}.${recipient.encrypted_key}.${final.iv}.${final.ciphertext}.${final.tag}` -} -compactSerializer.validate = (protectedHeader, unprotectedHeader, aad, { 0: { header }, length }) => { - if (length !== 1 || aad || unprotectedHeader || header) { - throw new JWEInvalid('JWE Compact Serialization doesn\'t support multiple recipients, JWE unprotected headers or AAD') - } - validateCrit(protectedHeader, unprotectedHeader, protectedHeader ? protectedHeader.crit : undefined) -} - -const flattenedSerializer = (final, [recipient]) => { - const { header, encrypted_key: encryptedKey } = recipient - - return { - ...(final.protected ? { protected: final.protected } : undefined), - ...(final.unprotected ? { unprotected: final.unprotected } : undefined), - ...(header ? { header } : undefined), - ...(encryptedKey ? { encrypted_key: encryptedKey } : undefined), - ...(final.aad ? { aad: final.aad } : undefined), - iv: final.iv, - ciphertext: final.ciphertext, - tag: final.tag - } -} -flattenedSerializer.validate = (protectedHeader, unprotectedHeader, aad, { 0: { header }, length }) => { - if (length !== 1) { - throw new JWEInvalid('Flattened JWE JSON Serialization doesn\'t support multiple recipients') - } - validateCrit(protectedHeader, { ...unprotectedHeader, ...header }, protectedHeader ? protectedHeader.crit : undefined) -} - -const generalSerializer = (final, recipients) => { - const result = { - ...(final.protected ? { protected: final.protected } : undefined), - ...(final.unprotected ? { unprotected: final.unprotected } : undefined), - recipients: recipients.map(({ header, encrypted_key: encryptedKey, generatedHeader }) => { - if (!header && !encryptedKey && !generatedHeader) { - return false - } - - return { - ...(header || generatedHeader ? { header: { ...header, ...generatedHeader } } : undefined), - ...(encryptedKey ? { encrypted_key: encryptedKey } : undefined) - } - }).filter(Boolean), - ...(final.aad ? { aad: final.aad } : undefined), - iv: final.iv, - ciphertext: final.ciphertext, - tag: final.tag - } - - if (!result.recipients.length) { - delete result.recipients - } - - return result -} -generalSerializer.validate = (protectedHeader, unprotectedHeader, aad, recipients) => { - recipients.forEach(({ header }) => { - validateCrit(protectedHeader, { ...header, ...unprotectedHeader }, protectedHeader ? protectedHeader.crit : undefined) - }) -} - -const isJSON = (input) => { - return isObject(input) && - typeof input.ciphertext === 'string' && - typeof input.iv === 'string' && - typeof input.tag === 'string' && - (input.unprotected === undefined || isObject(input.unprotected)) && - (input.protected === undefined || typeof input.protected === 'string') && - (input.aad === undefined || typeof input.aad === 'string') -} - -const isSingleRecipient = (input) => { - return (input.encrypted_key === undefined || typeof input.encrypted_key === 'string') && - (input.header === undefined || isObject(input.header)) -} - -const isValidRecipient = (recipient) => { - return isObject(recipient) && typeof recipient.encrypted_key === 'string' && (recipient.header === undefined || isObject(recipient.header)) -} - -const isMultiRecipient = (input) => { - if (Array.isArray(input.recipients) && input.recipients.every(isValidRecipient)) { - return true - } - - return false -} - -const detect = (input) => { - if (typeof input === 'string' && input.split('.').length === 5) { - return 'compact' - } - - if (isJSON(input)) { - if (isMultiRecipient(input)) { - return 'general' - } - - if (isSingleRecipient(input)) { - return 'flattened' - } - } - - throw new JWEInvalid('JWE malformed or invalid serialization') -} - -module.exports = { - compact: compactSerializer, - flattened: flattenedSerializer, - general: generalSerializer, - detect -} diff --git a/lib/jwe/validate_headers.js b/lib/jwe/validate_headers.js deleted file mode 100644 index f104176d7a..0000000000 --- a/lib/jwe/validate_headers.js +++ /dev/null @@ -1,70 +0,0 @@ -const isDisjoint = require('../help/is_disjoint') -const base64url = require('../help/base64url') -let validateCrit = require('../help/validate_crit') -const { JWEInvalid, JOSENotSupported } = require('../errors') - -validateCrit = validateCrit.bind(undefined, JWEInvalid) - -module.exports = (prot, unprotected, recipients, checkAlgorithms, crit) => { - if (typeof prot === 'string') { - try { - prot = base64url.JSON.decode(prot) - } catch (err) { - throw new JWEInvalid('could not parse JWE protected header') - } - } - - let alg = [] - const enc = new Set() - if (!isDisjoint(prot, unprotected) || !recipients.every(({ header }) => { - if (typeof header === 'object') { - alg.push(header.alg) - enc.add(header.enc) - } - const combined = { ...unprotected, ...header } - validateCrit(prot, combined, crit) - if ('zip' in combined) { - throw new JWEInvalid('"zip" Header Parameter MUST be integrity protected') - } else if (prot && 'zip' in prot && prot.zip !== 'DEF') { - throw new JOSENotSupported('only "DEF" compression algorithm is supported') - } - return isDisjoint(header, prot) && isDisjoint(header, unprotected) - })) { - throw new JWEInvalid('JWE Shared Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint') - } - - if (typeof prot === 'object') { - alg.push(prot.alg) - enc.add(prot.enc) - } - if (typeof unprotected === 'object') { - alg.push(unprotected.alg) - enc.add(unprotected.enc) - } - - alg = alg.filter(Boolean) - enc.delete(undefined) - - if (recipients.length !== 1) { - if (alg.includes('dir') || alg.includes('ECDH-ES')) { - throw new JWEInvalid('dir and ECDH-ES alg may only be used with a single recipient') - } - } - - if (checkAlgorithms) { - if (alg.length !== recipients.length) { - throw new JWEInvalid('missing Key Management algorithm') - } - if (enc.size === 0) { - throw new JWEInvalid('missing Content Encryption algorithm') - } else if (enc.size !== 1) { - throw new JWEInvalid('there must only be one Content Encryption algorithm') - } - } else { - if (enc.size > 1) { - throw new JWEInvalid('there must only be one Content Encryption algorithm') - } - } - - return [...enc][0] -} diff --git a/lib/jwk/generate.js b/lib/jwk/generate.js deleted file mode 100644 index fbc9c0d9e7..0000000000 --- a/lib/jwk/generate.js +++ /dev/null @@ -1,53 +0,0 @@ -const errors = require('../errors') - -const importKey = require('./import') - -const RSAKey = require('./key/rsa') -const ECKey = require('./key/ec') -const OKPKey = require('./key/okp') -const OctKey = require('./key/oct') - -const generate = async (kty, crvOrSize, params, generatePrivate = true) => { - switch (kty) { - case 'RSA': - return importKey( - await RSAKey.generate(crvOrSize, generatePrivate), - params - ) - case 'EC': - return importKey( - await ECKey.generate(crvOrSize, generatePrivate), - params - ) - case 'OKP': - return importKey( - await OKPKey.generate(crvOrSize, generatePrivate), - params - ) - case 'oct': - return importKey( - await OctKey.generate(crvOrSize, generatePrivate), - params - ) - default: - throw new errors.JOSENotSupported(`unsupported key type: ${kty}`) - } -} - -const generateSync = (kty, crvOrSize, params, generatePrivate = true) => { - switch (kty) { - case 'RSA': - return importKey(RSAKey.generateSync(crvOrSize, generatePrivate), params) - case 'EC': - return importKey(ECKey.generateSync(crvOrSize, generatePrivate), params) - case 'OKP': - return importKey(OKPKey.generateSync(crvOrSize, generatePrivate), params) - case 'oct': - return importKey(OctKey.generateSync(crvOrSize, generatePrivate), params) - default: - throw new errors.JOSENotSupported(`unsupported key type: ${kty}`) - } -} - -module.exports.generate = generate -module.exports.generateSync = generateSync diff --git a/lib/jwk/import.js b/lib/jwk/import.js deleted file mode 100644 index 160d3f4892..0000000000 --- a/lib/jwk/import.js +++ /dev/null @@ -1,134 +0,0 @@ -const { createPublicKey, createPrivateKey, createSecretKey, KeyObject } = require('../help/key_object') -const base64url = require('../help/base64url') -const isObject = require('../help/is_object') -const { jwkToPem } = require('../help/key_utils') -const errors = require('../errors') - -const RSAKey = require('./key/rsa') -const ECKey = require('./key/ec') -const OKPKey = require('./key/okp') -const OctKey = require('./key/oct') - -const importable = new Set(['string', 'buffer', 'object']) - -const mergedParameters = (target = {}, source = {}) => { - return { - alg: source.alg, - key_ops: source.key_ops, - kid: source.kid, - use: source.use, - x5c: source.x5c, - x5t: source.x5t, - 'x5t#S256': source['x5t#S256'], - ...target - } -} - -const openSSHpublicKey = /^[a-zA-Z0-9-]+ AAAA(?:[0-9A-Za-z+/])+(?:==|=)?(?: .*)?$/ - -const asKey = (key, parameters, { calculateMissingRSAPrimes = false } = {}) => { - let privateKey, publicKey, secret - - if (!importable.has(typeof key)) { - throw new TypeError('key argument must be a string, buffer or an object') - } - - if (parameters !== undefined && !isObject(parameters)) { - throw new TypeError('parameters argument must be a plain object when provided') - } - - if (key instanceof KeyObject) { - switch (key.type) { - case 'private': - privateKey = key - break - case 'public': - publicKey = key - break - case 'secret': - secret = key - break - } - } else if (typeof key === 'object' && key && 'kty' in key && key.kty === 'oct') { // symmetric key - try { - secret = createSecretKey(base64url.decodeToBuffer(key.k)) - } catch (err) { - if (!('k' in key)) { - secret = { type: 'secret' } - } - } - parameters = mergedParameters(parameters, key) - } else if (typeof key === 'object' && key && 'kty' in key) { // assume JWK formatted asymmetric key - ({ calculateMissingRSAPrimes = false } = parameters || { calculateMissingRSAPrimes }) - let pem - - try { - pem = jwkToPem(key, { calculateMissingRSAPrimes }) - } catch (err) { - if (err instanceof errors.JOSEError) { - throw err - } - } - - if (pem && key.d) { - privateKey = createPrivateKey(pem) - } else if (pem) { - publicKey = createPublicKey(pem) - } - - parameters = mergedParameters({}, key) - } else if (key && (typeof key === 'object' || typeof key === 'string')) { // | | passed to crypto.createPrivateKey or crypto.createPublicKey or passed to crypto.createSecretKey - try { - privateKey = createPrivateKey(key) - } catch (err) { - if (err instanceof errors.JOSEError) { - throw err - } - } - - try { - publicKey = createPublicKey(key) - if (key.startsWith('-----BEGIN CERTIFICATE-----') && (!parameters || !('x5c' in parameters))) { - parameters = mergedParameters(parameters, { - x5c: [key.replace(/(?:-----(?:BEGIN|END) CERTIFICATE-----|\s)/g, '')] - }) - } - } catch (err) { - if (err instanceof errors.JOSEError) { - throw err - } - } - - try { - // this is to filter out invalid PEM keys and certs, i'll rather have them fail import then - // have them imported as symmetric "oct" keys - if (!key.includes('-----BEGIN') && !openSSHpublicKey.test(key.toString('ascii').replace(/[\r\n]/g, ''))) { - secret = createSecretKey(Buffer.isBuffer(key) ? key : Buffer.from(key)) - } - } catch (err) {} - } - - const keyObject = privateKey || publicKey || secret - - if (privateKey || publicKey) { - switch (keyObject.asymmetricKeyType) { - case 'rsa': - return new RSAKey(keyObject, parameters) - case 'ec': - return new ECKey(keyObject, parameters) - case 'ed25519': - case 'ed448': - case 'x25519': - case 'x448': - return new OKPKey(keyObject, parameters) - default: - throw new errors.JOSENotSupported('only RSA, EC and OKP asymmetric keys are supported') - } - } else if (secret) { - return new OctKey(keyObject, parameters) - } - - throw new errors.JWKImportFailed('key import failed') -} - -module.exports = asKey diff --git a/lib/jwk/index.js b/lib/jwk/index.js deleted file mode 100644 index 6d0d41c80f..0000000000 --- a/lib/jwk/index.js +++ /dev/null @@ -1,15 +0,0 @@ -const Key = require('./key/base') -const None = require('./key/none') -const EmbeddedJWK = require('./key/embedded.jwk') -const EmbeddedX5C = require('./key/embedded.x5c') -const importKey = require('./import') -const generate = require('./generate') - -module.exports = { - ...generate, - asKey: importKey, - isKey: input => input instanceof Key, - None, - EmbeddedJWK, - EmbeddedX5C -} diff --git a/lib/jwk/key/base.js b/lib/jwk/key/base.js deleted file mode 100644 index 0773b7fb27..0000000000 --- a/lib/jwk/key/base.js +++ /dev/null @@ -1,339 +0,0 @@ -const { strict: assert } = require('assert') -const { inspect } = require('util') -const { EOL } = require('os') - -const { keyObjectSupported } = require('../../help/runtime_support') -const { createPublicKey } = require('../../help/key_object') -const { keyObjectToJWK } = require('../../help/key_utils') -const { - THUMBPRINT_MATERIAL, PUBLIC_MEMBERS, PRIVATE_MEMBERS, JWK_MEMBERS, KEYOBJECT, - USES_MAPPING, OPS, USES -} = require('../../help/consts') -const isObject = require('../../help/is_object') -const thumbprint = require('../thumbprint') -const errors = require('../../errors') - -const privateApi = Symbol('privateApi') -const { JWK } = require('../../registry') - -class Key { - constructor (keyObject, { alg, use, kid, key_ops: ops, x5c, x5t, 'x5t#S256': x5t256 } = {}) { - if (use !== undefined) { - if (typeof use !== 'string' || !USES.has(use)) { - throw new TypeError('`use` must be either "sig" or "enc" string when provided') - } - } - - if (alg !== undefined) { - if (typeof alg !== 'string' || !alg) { - throw new TypeError('`alg` must be a non-empty string when provided') - } - } - - if (kid !== undefined) { - if (typeof kid !== 'string' || !kid) { - throw new TypeError('`kid` must be a non-empty string when provided') - } - } - - if (ops !== undefined) { - if (!Array.isArray(ops) || !ops.length || ops.some(o => typeof o !== 'string')) { - throw new TypeError('`key_ops` must be a non-empty array of strings when provided') - } - ops = Array.from(new Set(ops)).filter(x => OPS.has(x)) - } - - if (ops && use) { - if ( - (use === 'enc' && ops.some(x => USES_MAPPING.sig.has(x))) || - (use === 'sig' && ops.some(x => USES_MAPPING.enc.has(x))) - ) { - throw new errors.JWKInvalid('inconsistent JWK "use" and "key_ops"') - } - } - - if (keyObjectSupported && x5c !== undefined) { - if (!Array.isArray(x5c) || !x5c.length || x5c.some(c => typeof c !== 'string')) { - throw new TypeError('`x5c` must be an array of one or more PKIX certificates when provided') - } - - x5c.forEach((cert, i) => { - let publicKey - try { - publicKey = createPublicKey({ - key: `-----BEGIN CERTIFICATE-----${EOL}${(cert.match(/.{1,64}/g) || []).join(EOL)}${EOL}-----END CERTIFICATE-----`, format: 'pem' - }) - } catch (err) { - throw new errors.JWKInvalid(`\`x5c\` member at index ${i} is not a valid base64-encoded DER PKIX certificate`) - } - if (i === 0) { - try { - assert.deepEqual( - publicKey.export({ type: 'spki', format: 'der' }), - (keyObject.type === 'public' ? keyObject : createPublicKey(keyObject)).export({ type: 'spki', format: 'der' }) - ) - } catch (err) { - throw new errors.JWKInvalid('The key in the first `x5c` certificate MUST match the public key represented by the JWK') - } - } - }) - } - - Object.defineProperties(this, { - [KEYOBJECT]: { value: isObject(keyObject) ? undefined : keyObject }, - keyObject: { - get () { - if (!keyObjectSupported) { - throw new errors.JOSENotSupported('KeyObject class is not supported in your Node.js runtime version') - } - - return this[KEYOBJECT] - } - }, - type: { value: keyObject.type }, - private: { value: keyObject.type === 'private' }, - public: { value: keyObject.type === 'public' }, - secret: { value: keyObject.type === 'secret' }, - alg: { value: alg, enumerable: alg !== undefined }, - use: { value: use, enumerable: use !== undefined }, - x5c: { - enumerable: x5c !== undefined, - ...(x5c ? { get () { return [...x5c] } } : { value: undefined }) - }, - key_ops: { - enumerable: ops !== undefined, - ...(ops ? { get () { return [...ops] } } : { value: undefined }) - }, - kid: { - enumerable: true, - ...(kid - ? { value: kid } - : { - get () { - Object.defineProperty(this, 'kid', { value: this.thumbprint, configurable: false }) - return this.kid - }, - configurable: true - }) - }, - ...(x5c - ? { - x5t: { - enumerable: true, - ...(x5t - ? { value: x5t } - : { - get () { - Object.defineProperty(this, 'x5t', { value: thumbprint.x5t(this.x5c[0]), configurable: false }) - return this.x5t - }, - configurable: true - }) - } - } - : undefined), - ...(x5c - ? { - 'x5t#S256': { - enumerable: true, - ...(x5t256 - ? { value: x5t256 } - : { - get () { - Object.defineProperty(this, 'x5t#S256', { value: thumbprint['x5t#S256'](this.x5c[0]), configurable: false }) - return this['x5t#S256'] - }, - configurable: true - }) - } - } - : undefined), - thumbprint: { - get () { - Object.defineProperty(this, 'thumbprint', { value: thumbprint.kid(this[THUMBPRINT_MATERIAL]()), configurable: false }) - return this.thumbprint - }, - configurable: true - } - }) - } - - toPEM (priv = false, encoding = {}) { - if (this.secret) { - throw new TypeError('symmetric keys cannot be exported as PEM') - } - - if (priv && this.public === true) { - throw new TypeError('public key cannot be exported as private') - } - - const { type = priv ? 'pkcs8' : 'spki', cipher, passphrase } = encoding - - let keyObject = this[KEYOBJECT] - - if (!priv) { - if (this.private) { - keyObject = createPublicKey(keyObject) - } - if (cipher || passphrase) { - throw new TypeError('cipher and passphrase can only be applied when exporting private keys') - } - } - - if (priv) { - return keyObject.export({ format: 'pem', type, cipher, passphrase }) - } - - return keyObject.export({ format: 'pem', type }) - } - - toJWK (priv = false) { - if (priv && this.public === true) { - throw new TypeError('public key cannot be exported as private') - } - - const components = [...this.constructor[priv ? PRIVATE_MEMBERS : PUBLIC_MEMBERS]] - .map(k => [k, this[k]]) - - const result = {} - - Object.keys(components).forEach((key) => { - const [k, v] = components[key] - - result[k] = v - }) - - result.kty = this.kty - result.kid = this.kid - - if (this.alg) { - result.alg = this.alg - } - - if (this.key_ops && this.key_ops.length) { - result.key_ops = this.key_ops - } - - if (this.use) { - result.use = this.use - } - - if (this.x5c) { - result.x5c = this.x5c - } - - if (this.x5t) { - result.x5t = this.x5t - } - - if (this['x5t#S256']) { - result['x5t#S256'] = this['x5t#S256'] - } - - return result - } - - [JWK_MEMBERS] () { - const props = this[KEYOBJECT].type === 'private' ? this.constructor[PRIVATE_MEMBERS] : this.constructor[PUBLIC_MEMBERS] - Object.defineProperties(this, [...props].reduce((acc, component) => { - acc[component] = { - get () { - const jwk = keyObjectToJWK(this[KEYOBJECT]) - Object.defineProperties( - this, - Object.entries(jwk) - .filter(([key]) => props.has(key)) - .reduce((acc, [key, value]) => { - acc[key] = { value, enumerable: this.constructor[PUBLIC_MEMBERS].has(key), configurable: false } - return acc - }, {}) - ) - - return this[component] - }, - enumerable: this.constructor[PUBLIC_MEMBERS].has(component), - configurable: true - } - return acc - }, {})) - } - - /* c8 ignore next 8 */ - [inspect.custom] () { - return `${this.constructor.name} ${inspect(this.toJWK(false), { - depth: Infinity, - colors: process.stdout.isTTY, - compact: false, - sorted: true - })}` - } - - /* c8 ignore next 3 */ - [THUMBPRINT_MATERIAL] () { - throw new Error(`"[THUMBPRINT_MATERIAL]()" is not implemented on ${this.constructor.name}`) - } - - algorithms (operation, /* the rest is private API */ int, opts) { - const { use = this.use, alg = this.alg, key_ops: ops = this.key_ops } = int === privateApi ? opts : {} - if (alg) { - return new Set(this.algorithms(operation, privateApi, { alg: null, use, key_ops: ops }).has(alg) ? [alg] : undefined) - } - - if (typeof operation === 'symbol') { - try { - return this[operation]() - } catch (err) { - return new Set() - } - } - - if (operation && ops && !ops.includes(operation)) { - return new Set() - } - - switch (operation) { - case 'decrypt': - case 'deriveKey': - case 'encrypt': - case 'sign': - case 'unwrapKey': - case 'verify': - case 'wrapKey': - return new Set(Object.entries(JWK[this.kty][operation]).map(([alg, fn]) => fn(this) ? alg : undefined).filter(Boolean)) - case undefined: - return new Set([ - ...this.algorithms('sign'), - ...this.algorithms('verify'), - ...this.algorithms('decrypt'), - ...this.algorithms('encrypt'), - ...this.algorithms('unwrapKey'), - ...this.algorithms('wrapKey'), - ...this.algorithms('deriveKey') - ]) - default: - throw new TypeError('invalid key operation') - } - } - - /* c8 ignore next 3 */ - static async generate () { - throw new Error(`"static async generate()" is not implemented on ${this.name}`) - } - - /* c8 ignore next 3 */ - static generateSync () { - throw new Error(`"static generateSync()" is not implemented on ${this.name}`) - } - - /* c8 ignore next 3 */ - static get [PUBLIC_MEMBERS] () { - throw new Error(`"static get [PUBLIC_MEMBERS]()" is not implemented on ${this.name}`) - } - - /* c8 ignore next 3 */ - static get [PRIVATE_MEMBERS] () { - throw new Error(`"static get [PRIVATE_MEMBERS]()" is not implemented on ${this.name}`) - } -} - -module.exports = Key diff --git a/lib/jwk/key/ec.js b/lib/jwk/key/ec.js deleted file mode 100644 index 0a5848a4db..0000000000 --- a/lib/jwk/key/ec.js +++ /dev/null @@ -1,110 +0,0 @@ -const { generateKeyPairSync, generateKeyPair: async } = require('crypto') -const { promisify } = require('util') - -const { - THUMBPRINT_MATERIAL, JWK_MEMBERS, PUBLIC_MEMBERS, - PRIVATE_MEMBERS, KEY_MANAGEMENT_DECRYPT, KEY_MANAGEMENT_ENCRYPT -} = require('../../help/consts') -const { EC_CURVES } = require('../../registry') -const { keyObjectSupported } = require('../../help/runtime_support') -const { createPublicKey, createPrivateKey } = require('../../help/key_object') - -const errors = require('../../errors') - -const Key = require('./base') - -const generateKeyPair = promisify(async) - -const EC_PUBLIC = new Set(['crv', 'x', 'y']) -Object.freeze(EC_PUBLIC) -const EC_PRIVATE = new Set([...EC_PUBLIC, 'd']) -Object.freeze(EC_PRIVATE) - -// Elliptic Curve Key Type -class ECKey extends Key { - constructor (...args) { - super(...args) - this[JWK_MEMBERS]() - Object.defineProperty(this, 'kty', { value: 'EC', enumerable: true }) - if (!EC_CURVES.has(this.crv)) { - throw new errors.JOSENotSupported('unsupported EC key curve') - } - } - - static get [PUBLIC_MEMBERS] () { - return EC_PUBLIC - } - - static get [PRIVATE_MEMBERS] () { - return EC_PRIVATE - } - - // https://tc39.github.io/ecma262/#sec-ordinaryownpropertykeys no need for any special - // JSON.stringify handling in V8 - [THUMBPRINT_MATERIAL] () { - return { crv: this.crv, kty: 'EC', x: this.x, y: this.y } - } - - [KEY_MANAGEMENT_ENCRYPT] () { - return this.algorithms('deriveKey') - } - - [KEY_MANAGEMENT_DECRYPT] () { - if (this.public) { - return new Set() - } - return this.algorithms('deriveKey') - } - - static async generate (crv = 'P-256', privat = true) { - if (!EC_CURVES.has(crv)) { - throw new errors.JOSENotSupported(`unsupported EC key curve: ${crv}`) - } - - let privateKey, publicKey - - if (keyObjectSupported) { - ({ privateKey, publicKey } = await generateKeyPair('ec', { namedCurve: crv })) - return privat ? privateKey : publicKey - } - - ({ privateKey, publicKey } = await generateKeyPair('ec', { - namedCurve: crv, - publicKeyEncoding: { type: 'spki', format: 'pem' }, - privateKeyEncoding: { type: 'pkcs8', format: 'pem' } - })) - - if (privat) { - return createPrivateKey(privateKey) - } else { - return createPublicKey(publicKey) - } - } - - static generateSync (crv = 'P-256', privat = true) { - if (!EC_CURVES.has(crv)) { - throw new errors.JOSENotSupported(`unsupported EC key curve: ${crv}`) - } - - let privateKey, publicKey - - if (keyObjectSupported) { - ({ privateKey, publicKey } = generateKeyPairSync('ec', { namedCurve: crv })) - return privat ? privateKey : publicKey - } - - ({ privateKey, publicKey } = generateKeyPairSync('ec', { - namedCurve: crv, - publicKeyEncoding: { type: 'spki', format: 'pem' }, - privateKeyEncoding: { type: 'pkcs8', format: 'pem' } - })) - - if (privat) { - return createPrivateKey(privateKey) - } else { - return createPublicKey(publicKey) - } - } -} - -module.exports = ECKey diff --git a/lib/jwk/key/embedded.jwk.js b/lib/jwk/key/embedded.jwk.js deleted file mode 100644 index dd7f59ff55..0000000000 --- a/lib/jwk/key/embedded.jwk.js +++ /dev/null @@ -1,27 +0,0 @@ -const { inspect } = require('util') - -const Key = require('./base') - -class EmbeddedJWK extends Key { - constructor () { - super({ type: 'embedded' }) - Object.defineProperties(this, { - kid: { value: undefined }, - kty: { value: undefined }, - thumbprint: { value: undefined }, - toJWK: { value: undefined }, - toPEM: { value: undefined } - }) - } - - /* c8 ignore next 3 */ - [inspect.custom] () { - return 'Embedded.JWK {}' - } - - algorithms () { - return new Set() - } -} - -module.exports = new EmbeddedJWK() diff --git a/lib/jwk/key/embedded.x5c.js b/lib/jwk/key/embedded.x5c.js deleted file mode 100644 index 48cfb106fe..0000000000 --- a/lib/jwk/key/embedded.x5c.js +++ /dev/null @@ -1,27 +0,0 @@ -const { inspect } = require('util') - -const Key = require('./base') - -class EmbeddedX5C extends Key { - constructor () { - super({ type: 'embedded' }) - Object.defineProperties(this, { - kid: { value: undefined }, - kty: { value: undefined }, - thumbprint: { value: undefined }, - toJWK: { value: undefined }, - toPEM: { value: undefined } - }) - } - - /* c8 ignore next 3 */ - [inspect.custom] () { - return 'Embedded.X5C {}' - } - - algorithms () { - return new Set() - } -} - -module.exports = new EmbeddedX5C() diff --git a/lib/jwk/key/none.js b/lib/jwk/key/none.js deleted file mode 100644 index eb53316bd0..0000000000 --- a/lib/jwk/key/none.js +++ /dev/null @@ -1,34 +0,0 @@ -const { inspect } = require('util') - -const Key = require('./base') - -class NoneKey extends Key { - constructor () { - super({ type: 'unsecured' }, { alg: 'none' }) - Object.defineProperties(this, { - kid: { value: undefined }, - kty: { value: undefined }, - thumbprint: { value: undefined }, - toJWK: { value: undefined }, - toPEM: { value: undefined } - }) - } - - /* c8 ignore next 3 */ - [inspect.custom] () { - return 'None {}' - } - - algorithms (operation) { - switch (operation) { - case 'sign': - case 'verify': - case undefined: - return new Set(['none']) - default: - return new Set() - } - } -} - -module.exports = new NoneKey() diff --git a/lib/jwk/key/oct.js b/lib/jwk/key/oct.js deleted file mode 100644 index 9bb9567122..0000000000 --- a/lib/jwk/key/oct.js +++ /dev/null @@ -1,103 +0,0 @@ -const { randomBytes } = require('crypto') - -const { createSecretKey } = require('../../help/key_object') -const base64url = require('../../help/base64url') -const { - THUMBPRINT_MATERIAL, PUBLIC_MEMBERS, PRIVATE_MEMBERS, - KEY_MANAGEMENT_DECRYPT, KEY_MANAGEMENT_ENCRYPT, KEYOBJECT -} = require('../../help/consts') - -const Key = require('./base') - -const OCT_PUBLIC = new Set() -Object.freeze(OCT_PUBLIC) -const OCT_PRIVATE = new Set(['k']) -Object.freeze(OCT_PRIVATE) - -// Octet sequence Key Type -class OctKey extends Key { - constructor (...args) { - super(...args) - Object.defineProperties(this, { - kty: { - value: 'oct', - enumerable: true - }, - length: { - value: this[KEYOBJECT] ? this[KEYOBJECT].symmetricKeySize * 8 : undefined - }, - k: { - enumerable: false, - get () { - if (this[KEYOBJECT]) { - Object.defineProperty(this, 'k', { - value: base64url.encodeBuffer(this[KEYOBJECT].export()), - configurable: false - }) - } else { - Object.defineProperty(this, 'k', { - value: undefined, - configurable: false - }) - } - - return this.k - }, - configurable: true - } - }) - } - - static get [PUBLIC_MEMBERS] () { - return OCT_PUBLIC - } - - static get [PRIVATE_MEMBERS] () { - return OCT_PRIVATE - } - - // https://tc39.github.io/ecma262/#sec-ordinaryownpropertykeys no need for any special - // JSON.stringify handling in V8 - [THUMBPRINT_MATERIAL] () { - if (!this[KEYOBJECT]) { - throw new TypeError('reference "oct" keys without "k" cannot have their thumbprint calculated') - } - return { k: this.k, kty: 'oct' } - } - - [KEY_MANAGEMENT_ENCRYPT] () { - return new Set([ - ...this.algorithms('wrapKey'), - ...this.algorithms('deriveKey') - ]) - } - - [KEY_MANAGEMENT_DECRYPT] () { - return this[KEY_MANAGEMENT_ENCRYPT]() - } - - algorithms (...args) { - if (!this[KEYOBJECT]) { - return new Set() - } - - return Key.prototype.algorithms.call(this, ...args) - } - - static async generate (...args) { - return this.generateSync(...args) - } - - static generateSync (len = 256, privat = true) { - if (!privat) { - throw new TypeError('"oct" keys cannot be generated as public') - } - if (!Number.isSafeInteger(len) || !len || len % 8 !== 0) { - throw new TypeError('invalid bit length') - } - - return createSecretKey(randomBytes(len / 8)) - } -} - -module.exports = OctKey diff --git a/lib/jwk/key/okp.js b/lib/jwk/key/okp.js deleted file mode 100644 index 4c12d2a6aa..0000000000 --- a/lib/jwk/key/okp.js +++ /dev/null @@ -1,86 +0,0 @@ -const { generateKeyPairSync, generateKeyPair: async } = require('crypto') -const { promisify } = require('util') - -const { - THUMBPRINT_MATERIAL, JWK_MEMBERS, PUBLIC_MEMBERS, - PRIVATE_MEMBERS, KEY_MANAGEMENT_DECRYPT, KEY_MANAGEMENT_ENCRYPT -} = require('../../help/consts') -const { OKP_CURVES } = require('../../registry') -const { edDSASupported } = require('../../help/runtime_support') -const errors = require('../../errors') - -const Key = require('./base') - -const generateKeyPair = promisify(async) - -const OKP_PUBLIC = new Set(['crv', 'x']) -Object.freeze(OKP_PUBLIC) -const OKP_PRIVATE = new Set([...OKP_PUBLIC, 'd']) -Object.freeze(OKP_PRIVATE) - -// Octet string key pairs Key Type -class OKPKey extends Key { - constructor (...args) { - super(...args) - this[JWK_MEMBERS]() - Object.defineProperty(this, 'kty', { value: 'OKP', enumerable: true }) - if (!OKP_CURVES.has(this.crv)) { - throw new errors.JOSENotSupported('unsupported OKP key curve') - } - } - - static get [PUBLIC_MEMBERS] () { - return OKP_PUBLIC - } - - static get [PRIVATE_MEMBERS] () { - return OKP_PRIVATE - } - - // https://tc39.github.io/ecma262/#sec-ordinaryownpropertykeys no need for any special - // JSON.stringify handling in V8 - [THUMBPRINT_MATERIAL] () { - return { crv: this.crv, kty: 'OKP', x: this.x } - } - - [KEY_MANAGEMENT_ENCRYPT] () { - return this.algorithms('deriveKey') - } - - [KEY_MANAGEMENT_DECRYPT] () { - if (this.public) { - return new Set() - } - return this.algorithms('deriveKey') - } - - static async generate (crv = 'Ed25519', privat = true) { - if (!edDSASupported) { - throw new errors.JOSENotSupported('OKP keys are not supported in your Node.js runtime version') - } - - if (!OKP_CURVES.has(crv)) { - throw new errors.JOSENotSupported(`unsupported OKP key curve: ${crv}`) - } - - const { privateKey, publicKey } = await generateKeyPair(crv.toLowerCase()) - - return privat ? privateKey : publicKey - } - - static generateSync (crv = 'Ed25519', privat = true) { - if (!edDSASupported) { - throw new errors.JOSENotSupported('OKP keys are not supported in your Node.js runtime version') - } - - if (!OKP_CURVES.has(crv)) { - throw new errors.JOSENotSupported(`unsupported OKP key curve: ${crv}`) - } - - const { privateKey, publicKey } = generateKeyPairSync(crv.toLowerCase()) - - return privat ? privateKey : publicKey - } -} - -module.exports = OKPKey diff --git a/lib/jwk/key/rsa.js b/lib/jwk/key/rsa.js deleted file mode 100644 index 210441c7a0..0000000000 --- a/lib/jwk/key/rsa.js +++ /dev/null @@ -1,117 +0,0 @@ -const { generateKeyPairSync, generateKeyPair: async } = require('crypto') -const { promisify } = require('util') - -const { - THUMBPRINT_MATERIAL, JWK_MEMBERS, PUBLIC_MEMBERS, - PRIVATE_MEMBERS, KEY_MANAGEMENT_DECRYPT, KEY_MANAGEMENT_ENCRYPT -} = require('../../help/consts') -const { keyObjectSupported } = require('../../help/runtime_support') -const { createPublicKey, createPrivateKey } = require('../../help/key_object') - -const Key = require('./base') - -const generateKeyPair = promisify(async) - -const RSA_PUBLIC = new Set(['e', 'n']) -Object.freeze(RSA_PUBLIC) -const RSA_PRIVATE = new Set([...RSA_PUBLIC, 'd', 'p', 'q', 'dp', 'dq', 'qi']) -Object.freeze(RSA_PRIVATE) - -// RSA Key Type -class RSAKey extends Key { - constructor (...args) { - super(...args) - this[JWK_MEMBERS]() - Object.defineProperties(this, { - kty: { - value: 'RSA', - enumerable: true - }, - length: { - get () { - Object.defineProperty(this, 'length', { - value: Buffer.byteLength(this.n, 'base64') * 8, - configurable: false - }) - - return this.length - }, - configurable: true - } - }) - } - - static get [PUBLIC_MEMBERS] () { - return RSA_PUBLIC - } - - static get [PRIVATE_MEMBERS] () { - return RSA_PRIVATE - } - - // https://tc39.github.io/ecma262/#sec-ordinaryownpropertykeys no need for any special - // JSON.stringify handling in V8 - [THUMBPRINT_MATERIAL] () { - return { e: this.e, kty: 'RSA', n: this.n } - } - - [KEY_MANAGEMENT_ENCRYPT] () { - return this.algorithms('wrapKey') - } - - [KEY_MANAGEMENT_DECRYPT] () { - return this.algorithms('unwrapKey') - } - - static async generate (len = 2048, privat = true) { - if (!Number.isSafeInteger(len) || len < 512 || len % 8 !== 0 || (('electron' in process.versions) && len % 128 !== 0)) { - throw new TypeError('invalid bit length') - } - - let privateKey, publicKey - - if (keyObjectSupported) { - ({ privateKey, publicKey } = await generateKeyPair('rsa', { modulusLength: len })) - return privat ? privateKey : publicKey - } - - ({ privateKey, publicKey } = await generateKeyPair('rsa', { - modulusLength: len, - publicKeyEncoding: { type: 'spki', format: 'pem' }, - privateKeyEncoding: { type: 'pkcs8', format: 'pem' } - })) - - if (privat) { - return createPrivateKey(privateKey) - } else { - return createPublicKey(publicKey) - } - } - - static generateSync (len = 2048, privat = true) { - if (!Number.isSafeInteger(len) || len < 512 || len % 8 !== 0 || (('electron' in process.versions) && len % 128 !== 0)) { - throw new TypeError('invalid bit length') - } - - let privateKey, publicKey - - if (keyObjectSupported) { - ({ privateKey, publicKey } = generateKeyPairSync('rsa', { modulusLength: len })) - return privat ? privateKey : publicKey - } - - ({ privateKey, publicKey } = generateKeyPairSync('rsa', { - modulusLength: len, - publicKeyEncoding: { type: 'spki', format: 'pem' }, - privateKeyEncoding: { type: 'pkcs8', format: 'pem' } - })) - - if (privat) { - return createPrivateKey(privateKey) - } else { - return createPublicKey(publicKey) - } - } -} - -module.exports = RSAKey diff --git a/lib/jwk/thumbprint.js b/lib/jwk/thumbprint.js deleted file mode 100644 index 6a4c7c4154..0000000000 --- a/lib/jwk/thumbprint.js +++ /dev/null @@ -1,9 +0,0 @@ -const { createHash } = require('crypto') - -const base64url = require('../help/base64url') - -const x5t = (hash, cert) => base64url.encodeBuffer(createHash(hash).update(Buffer.from(cert, 'base64')).digest()) - -module.exports.kid = components => base64url.encodeBuffer(createHash('sha256').update(JSON.stringify(components)).digest()) -module.exports.x5t = x5t.bind(undefined, 'sha1') -module.exports['x5t#S256'] = x5t.bind(undefined, 'sha256') diff --git a/lib/jwks/index.js b/lib/jwks/index.js deleted file mode 100644 index 285a2798d4..0000000000 --- a/lib/jwks/index.js +++ /dev/null @@ -1,3 +0,0 @@ -const KeyStore = require('./keystore') - -module.exports = KeyStore diff --git a/lib/jwks/keystore.js b/lib/jwks/keystore.js deleted file mode 100644 index 1af03493e0..0000000000 --- a/lib/jwks/keystore.js +++ /dev/null @@ -1,183 +0,0 @@ -const { inspect } = require('util') - -const isObject = require('../help/is_object') -const { generate, generateSync } = require('../jwk/generate') -const { USES_MAPPING } = require('../help/consts') -const { isKey, asKey: importKey } = require('../jwk') - -const keyscore = (key, { alg, use, ops }) => { - let score = 0 - - if (alg && key.alg) { - score++ - } - - if (use && key.use) { - score++ - } - - if (ops && key.key_ops) { - score++ - } - - return score -} - -class KeyStore { - constructor (...keys) { - while (keys.some(Array.isArray)) { - keys = keys.flat - ? keys.flat() - : keys.reduce((acc, val) => { - if (Array.isArray(val)) { - return [...acc, ...val] - } - - acc.push(val) - return acc - }, []) - } - if (keys.some(k => !isKey(k) || !k.kty)) { - throw new TypeError('all keys must be instances of a key instantiated by JWK.asKey') - } - - this._keys = new Set(keys) - } - - all ({ alg, kid, thumbprint, use, kty, key_ops: ops, x5t, 'x5t#S256': x5t256, crv } = {}) { - if (ops !== undefined && (!Array.isArray(ops) || !ops.length || ops.some(x => typeof x !== 'string'))) { - throw new TypeError('`key_ops` must be a non-empty array of strings') - } - - const search = { alg, use, ops } - return [...this._keys] - .filter((key) => { - let candidate = true - - if (candidate && kid !== undefined && key.kid !== kid) { - candidate = false - } - - if (candidate && thumbprint !== undefined && key.thumbprint !== thumbprint) { - candidate = false - } - - if (candidate && x5t !== undefined && key.x5t !== x5t) { - candidate = false - } - - if (candidate && x5t256 !== undefined && key['x5t#S256'] !== x5t256) { - candidate = false - } - - if (candidate && kty !== undefined && key.kty !== kty) { - candidate = false - } - - if (candidate && crv !== undefined && (key.crv !== crv)) { - candidate = false - } - - if (alg !== undefined && !key.algorithms().has(alg)) { - candidate = false - } - - if (candidate && use !== undefined && (key.use !== undefined && key.use !== use)) { - candidate = false - } - - // TODO: - if (candidate && ops !== undefined && (key.key_ops !== undefined || key.use !== undefined)) { - let keyOps - if (key.key_ops) { - keyOps = new Set(key.key_ops) - } else { - keyOps = USES_MAPPING[key.use] - } - if (ops.some(x => !keyOps.has(x))) { - candidate = false - } - } - - return candidate - }) - .sort((first, second) => keyscore(second, search) - keyscore(first, search)) - } - - get (...args) { - return this.all(...args)[0] - } - - add (key) { - if (!isKey(key) || !key.kty) { - throw new TypeError('key must be an instance of a key instantiated by JWK.asKey') - } - - this._keys.add(key) - } - - remove (key) { - if (!isKey(key)) { - throw new TypeError('key must be an instance of a key instantiated by JWK.asKey') - } - - this._keys.delete(key) - } - - toJWKS (priv = false) { - return { - keys: [...this._keys.values()].map( - key => key.toJWK(priv && (key.private || (key.secret && key.k))) - ) - } - } - - async generate (...args) { - this._keys.add(await generate(...args)) - } - - generateSync (...args) { - this._keys.add(generateSync(...args)) - } - - get size () { - return this._keys.size - } - - /* c8 ignore next 8 */ - [inspect.custom] () { - return `${this.constructor.name} ${inspect(this.toJWKS(false), { - depth: Infinity, - colors: process.stdout.isTTY, - compact: false, - sorted: true - })}` - } - - * [Symbol.iterator] () { - for (const key of this._keys) { - yield key - } - } -} - -function asKeyStore (jwks, { ignoreErrors = false, calculateMissingRSAPrimes = false } = {}) { - if (!isObject(jwks) || !Array.isArray(jwks.keys) || jwks.keys.some(k => !isObject(k) || !('kty' in k))) { - throw new TypeError('jwks must be a JSON Web Key Set formatted object') - } - - const keys = jwks.keys.map((jwk) => { - try { - return importKey(jwk, { calculateMissingRSAPrimes }) - } catch (err) { - if (!ignoreErrors) { - throw err - } - return undefined - } - }).filter(Boolean) - - return new KeyStore(...keys) -} - -module.exports = { KeyStore, asKeyStore } diff --git a/lib/jws/index.js b/lib/jws/index.js deleted file mode 100644 index 3b0662fc5f..0000000000 --- a/lib/jws/index.js +++ /dev/null @@ -1,15 +0,0 @@ -const Sign = require('./sign') -const { verify } = require('./verify') - -const single = (serialization, payload, key, protectedHeader, unprotectedHeader) => { - return new Sign(payload) - .recipient(key, protectedHeader, unprotectedHeader) - .sign(serialization) -} - -module.exports.Sign = Sign -module.exports.sign = single.bind(undefined, 'compact') -module.exports.sign.flattened = single.bind(undefined, 'flattened') -module.exports.sign.general = single.bind(undefined, 'general') - -module.exports.verify = verify diff --git a/lib/jws/serializers.js b/lib/jws/serializers.js deleted file mode 100644 index fee5303511..0000000000 --- a/lib/jws/serializers.js +++ /dev/null @@ -1,104 +0,0 @@ -const isObject = require('../help/is_object') -let validateCrit = require('../help/validate_crit') -const { JWSInvalid } = require('../errors') - -validateCrit = validateCrit.bind(undefined, JWSInvalid) - -const compactSerializer = (payload, [recipient]) => { - return `${recipient.protected}.${payload}.${recipient.signature}` -} -compactSerializer.validate = (jws, { 0: { unprotectedHeader, protectedHeader }, length }) => { - if (length !== 1 || unprotectedHeader) { - throw new JWSInvalid('JWS Compact Serialization doesn\'t support multiple recipients or JWS unprotected headers') - } - validateCrit(protectedHeader, unprotectedHeader, protectedHeader ? protectedHeader.crit : undefined) -} - -const flattenedSerializer = (payload, [recipient]) => { - const { header, signature, protected: prot } = recipient - - return { - payload, - ...prot ? { protected: prot } : undefined, - ...header ? { header } : undefined, - signature - } -} -flattenedSerializer.validate = (jws, { 0: { unprotectedHeader, protectedHeader }, length }) => { - if (length !== 1) { - throw new JWSInvalid('Flattened JWS JSON Serialization doesn\'t support multiple recipients') - } - validateCrit(protectedHeader, unprotectedHeader, protectedHeader ? protectedHeader.crit : undefined) -} - -const generalSerializer = (payload, recipients) => { - return { - payload, - signatures: recipients.map(({ header, signature, protected: prot }) => { - return { - ...prot ? { protected: prot } : undefined, - ...header ? { header } : undefined, - signature - } - }) - } -} -generalSerializer.validate = (jws, recipients) => { - let validateB64 = false - recipients.forEach(({ protectedHeader, unprotectedHeader }) => { - if (protectedHeader && !validateB64 && 'b64' in protectedHeader) { - validateB64 = true - } - validateCrit(protectedHeader, unprotectedHeader, protectedHeader ? protectedHeader.crit : undefined) - }) - - if (validateB64) { - const values = recipients.map(({ protectedHeader }) => protectedHeader && protectedHeader.b64) - if (!values.every((actual, i, [expected]) => actual === expected)) { - throw new JWSInvalid('the "b64" Header Parameter value MUST be the same for all recipients') - } - } -} - -const isJSON = (input) => { - return isObject(input) && (typeof input.payload === 'string' || Buffer.isBuffer(input.payload)) -} - -const isValidRecipient = (recipient) => { - return isObject(recipient) && typeof recipient.signature === 'string' && - (recipient.header === undefined || isObject(recipient.header)) && - (recipient.protected === undefined || typeof recipient.protected === 'string') -} - -const isMultiRecipient = (input) => { - if (Array.isArray(input.signatures) && input.signatures.every(isValidRecipient)) { - return true - } - - return false -} - -const detect = (input) => { - if (typeof input === 'string' && input.split('.').length === 3) { - return 'compact' - } - - if (isJSON(input)) { - if (isMultiRecipient(input)) { - return 'general' - } - - if (isValidRecipient(input)) { - return 'flattened' - } - } - - throw new JWSInvalid('JWS malformed or invalid serialization') -} - -module.exports = { - compact: compactSerializer, - flattened: flattenedSerializer, - general: generalSerializer, - detect -} diff --git a/lib/jws/sign.js b/lib/jws/sign.js deleted file mode 100644 index d809fd59a5..0000000000 --- a/lib/jws/sign.js +++ /dev/null @@ -1,130 +0,0 @@ -const base64url = require('../help/base64url') -const isDisjoint = require('../help/is_disjoint') -const isObject = require('../help/is_object') -const deepClone = require('../help/deep_clone') -const { JWSInvalid } = require('../errors') -const { sign } = require('../jwa') -const getKey = require('../help/get_key') - -const serializers = require('./serializers') - -const PROCESS_RECIPIENT = Symbol('PROCESS_RECIPIENT') - -class Sign { - constructor (payload) { - if (typeof payload === 'string') { - payload = base64url.encode(payload) - } else if (Buffer.isBuffer(payload)) { - payload = base64url.encodeBuffer(payload) - this._binary = true - } else if (isObject(payload)) { - payload = base64url.JSON.encode(payload) - } else { - throw new TypeError('payload argument must be a Buffer, string or an object') - } - - this._payload = payload - this._recipients = [] - } - - /* - * @public - */ - recipient (key, protectedHeader, unprotectedHeader) { - key = getKey(key) - - if (protectedHeader !== undefined && !isObject(protectedHeader)) { - throw new TypeError('protectedHeader argument must be a plain object when provided') - } - - if (unprotectedHeader !== undefined && !isObject(unprotectedHeader)) { - throw new TypeError('unprotectedHeader argument must be a plain object when provided') - } - - if (!isDisjoint(protectedHeader, unprotectedHeader)) { - throw new JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint') - } - - this._recipients.push({ - key, - protectedHeader: protectedHeader ? deepClone(protectedHeader) : undefined, - unprotectedHeader: unprotectedHeader ? deepClone(unprotectedHeader) : undefined - }) - - return this - } - - /* - * @private - */ - [PROCESS_RECIPIENT] (recipient, first) { - const { key, protectedHeader, unprotectedHeader } = recipient - - if (key.use === 'enc') { - throw new TypeError('a key with "use":"enc" is not usable for signing') - } - - const joseHeader = { - protected: protectedHeader || {}, - unprotected: unprotectedHeader || {} - } - - let alg = joseHeader.protected.alg || joseHeader.unprotected.alg - - if (!alg) { - alg = key.alg || [...key.algorithms('sign')][0] - if (recipient.protectedHeader) { - joseHeader.protected.alg = recipient.protectedHeader.alg = alg - } else { - joseHeader.protected = recipient.protectedHeader = { alg } - } - } - - if (!alg) { - throw new JWSInvalid('could not resolve a usable "alg" for a recipient') - } - - recipient.header = unprotectedHeader - recipient.protected = Object.keys(joseHeader.protected).length ? base64url.JSON.encode(joseHeader.protected) : '' - - if (first && joseHeader.protected.crit && joseHeader.protected.crit.includes('b64') && joseHeader.protected.b64 === false) { - if (this._binary) { - this._payload = base64url.decodeToBuffer(this._payload) - } else { - this._payload = base64url.decode(this._payload) - } - } - - const data = Buffer.concat([ - Buffer.from(recipient.protected || ''), - Buffer.from('.'), - Buffer.from(this._payload) - ]) - - recipient.signature = base64url.encodeBuffer(sign(alg, key, data)) - } - - /* - * @public - */ - sign (serialization) { - const serializer = serializers[serialization] - if (!serializer) { - throw new TypeError('serialization must be one of "compact", "flattened", "general"') - } - - if (!this._recipients.length) { - throw new JWSInvalid('missing recipients') - } - - serializer.validate(this, this._recipients) - - this._recipients.forEach((recipient, i) => { - this[PROCESS_RECIPIENT](recipient, i === 0) - }) - - return serializer(this._payload, this._recipients) - } -} - -module.exports = Sign diff --git a/lib/jws/verify.js b/lib/jws/verify.js deleted file mode 100644 index 6fadecc373..0000000000 --- a/lib/jws/verify.js +++ /dev/null @@ -1,202 +0,0 @@ -const { EOL } = require('os') - -const base64url = require('../help/base64url') -const isDisjoint = require('../help/is_disjoint') -const isObject = require('../help/is_object') -let validateCrit = require('../help/validate_crit') -const getKey = require('../help/get_key') -const { KeyStore } = require('../jwks') -const errors = require('../errors') -const { check, verify } = require('../jwa') -const JWK = require('../jwk') - -const { detect: resolveSerialization } = require('./serializers') - -validateCrit = validateCrit.bind(undefined, errors.JWSInvalid) -const SINGLE_RECIPIENT = new Set(['compact', 'flattened', 'preparsed']) - -/* - * @public - */ -const jwsVerify = (skipDisjointCheck, serialization, jws, key, { crit = [], complete = false, algorithms } = {}) => { - key = getKey(key, true) - - if (algorithms !== undefined && (!Array.isArray(algorithms) || algorithms.some(s => typeof s !== 'string' || !s))) { - throw new TypeError('"algorithms" option must be an array of non-empty strings') - } else if (algorithms) { - algorithms = new Set(algorithms) - } - - if (!Array.isArray(crit) || crit.some(s => typeof s !== 'string' || !s)) { - throw new TypeError('"crit" option must be an array of non-empty strings') - } - - if (!serialization) { - serialization = resolveSerialization(jws) - } - - let prot // protected header - let header // unprotected header - let payload - let signature - let alg - - // treat general format with one recipient as flattened - // skips iteration and avoids multi errors in this case - if (serialization === 'general' && jws.signatures.length === 1) { - serialization = 'flattened' - const { signatures, ...root } = jws - jws = { ...root, ...signatures[0] } - } - - let decoded - - if (SINGLE_RECIPIENT.has(serialization)) { - let parsedProt = {} - - switch (serialization) { - case 'compact': // compact serialization format - ([prot, payload, signature] = jws.split('.')) - break - case 'flattened': // flattened serialization format - ({ protected: prot, payload, signature, header } = jws) - break - case 'preparsed': { // from the JWT module - ({ decoded } = jws); - ([prot, payload, signature] = jws.token.split('.')) - break - } - } - - if (!header) { - skipDisjointCheck = true - } - - if (decoded) { - parsedProt = decoded.header - } else if (prot) { - try { - parsedProt = base64url.JSON.decode(prot) - } catch (err) { - throw new errors.JWSInvalid('could not parse JWS protected header') - } - } else { - skipDisjointCheck = skipDisjointCheck || true - } - - if (!skipDisjointCheck && !isDisjoint(parsedProt, header)) { - throw new errors.JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint') - } - - const combinedHeader = { ...parsedProt, ...header } - validateCrit(parsedProt, header, crit) - - alg = parsedProt.alg || (header && header.alg) - if (!alg) { - throw new errors.JWSInvalid('missing JWS signature algorithm') - } else if (algorithms && !algorithms.has(alg)) { - throw new errors.JOSEAlgNotWhitelisted('alg not whitelisted') - } - - if (key instanceof KeyStore) { - const keystore = key - const keys = keystore.all({ kid: combinedHeader.kid, alg: combinedHeader.alg, key_ops: ['verify'] }) - switch (keys.length) { - case 0: - throw new errors.JWKSNoMatchingKey() - case 1: - // treat the call as if a Key instance was passed in - // skips iteration and avoids multi errors in this case - key = keys[0] - break - default: { - const errs = [] - for (const key of keys) { - try { - return jwsVerify(true, serialization, jws, key, { crit, complete, algorithms: algorithms ? [...algorithms] : undefined }) - } catch (err) { - errs.push(err) - continue - } - } - - const multi = new errors.JOSEMultiError(errs) - if ([...multi].some(e => e instanceof errors.JWSVerificationFailed)) { - throw new errors.JWSVerificationFailed() - } - throw multi - } - } - } - - if (key === JWK.EmbeddedJWK) { - if (!isObject(combinedHeader.jwk)) { - throw new errors.JWSInvalid('JWS Header Parameter "jwk" must be a JSON object') - } - key = JWK.asKey(combinedHeader.jwk) - if (key.type !== 'public') { - throw new errors.JWSInvalid('JWS Header Parameter "jwk" must be a public key') - } - } else if (key === JWK.EmbeddedX5C) { - if (!Array.isArray(combinedHeader.x5c) || !combinedHeader.x5c.length || combinedHeader.x5c.some(c => typeof c !== 'string' || !c)) { - throw new errors.JWSInvalid('JWS Header Parameter "x5c" must be a JSON array of certificate value strings') - } - key = JWK.asKey( - `-----BEGIN CERTIFICATE-----${EOL}${(combinedHeader.x5c[0].match(/.{1,64}/g) || []).join(EOL)}${EOL}-----END CERTIFICATE-----`, - { x5c: combinedHeader.x5c } - ) - } - - check(key, 'verify', alg) - - const toBeVerified = Buffer.concat([ - Buffer.from(prot || ''), - Buffer.from('.'), - Buffer.isBuffer(payload) ? payload : Buffer.from(payload) - ]) - - if (!verify(alg, key, toBeVerified, base64url.decodeToBuffer(signature))) { - throw new errors.JWSVerificationFailed() - } - - if (combinedHeader.b64 === false) { - payload = Buffer.from(payload) - } else { - payload = base64url.decodeToBuffer(payload) - } - - if (complete) { - const result = { payload, key } - if (prot) result.protected = parsedProt - if (header) result.header = header - return result - } - - return payload - } - - // general serialization format - const { signatures, ...root } = jws - const errs = [] - for (const recipient of signatures) { - try { - return jwsVerify(false, 'flattened', { ...root, ...recipient }, key, { crit, complete, algorithms: algorithms ? [...algorithms] : undefined }) - } catch (err) { - errs.push(err) - continue - } - } - - const multi = new errors.JOSEMultiError(errs) - if ([...multi].some(e => e instanceof errors.JWSVerificationFailed)) { - throw new errors.JWSVerificationFailed() - } else if ([...multi].every(e => e instanceof errors.JWKSNoMatchingKey)) { - throw new errors.JWKSNoMatchingKey() - } - throw multi -} - -module.exports = { - bare: jwsVerify, - verify: jwsVerify.bind(undefined, false, undefined) -} diff --git a/lib/jwt/decode.js b/lib/jwt/decode.js deleted file mode 100644 index 022266f18a..0000000000 --- a/lib/jwt/decode.js +++ /dev/null @@ -1,30 +0,0 @@ -const base64url = require('../help/base64url') -const errors = require('../errors') - -module.exports = (token, { complete = false } = {}) => { - if (typeof token !== 'string' || !token) { - throw new TypeError('JWT must be a string') - } - - const { 0: header, 1: payload, 2: signature, length } = token.split('.') - - if (length === 5) { - throw new TypeError('encrypted JWTs cannot be decoded') - } - - if (length !== 3) { - throw new errors.JWTMalformed('JWTs must have three components') - } - - try { - const result = { - header: base64url.JSON.decode(header), - payload: base64url.JSON.decode(payload), - signature - } - - return complete ? result : result.payload - } catch (err) { - throw new errors.JWTMalformed('JWT is malformed') - } -} diff --git a/lib/jwt/index.js b/lib/jwt/index.js deleted file mode 100644 index 84d24c33b3..0000000000 --- a/lib/jwt/index.js +++ /dev/null @@ -1,16 +0,0 @@ -const decode = require('./decode') -const sign = require('./sign') -const verify = require('./verify') -const profiles = require('./profiles') - -module.exports = { - sign, - verify, - ...profiles -} - -Object.defineProperty(module.exports, 'decode', { - enumerable: false, - configurable: true, - value: decode -}) diff --git a/lib/jwt/profiles.js b/lib/jwt/profiles.js deleted file mode 100644 index 9b3b743b66..0000000000 --- a/lib/jwt/profiles.js +++ /dev/null @@ -1,168 +0,0 @@ -const { JWTClaimInvalid } = require('../errors') -const secs = require('../help/secs') -const epoch = require('../help/epoch') -const isObject = require('../help/is_object') - -const verify = require('./verify') -const { - isString, - isRequired, - isTimestamp, - isStringOrArrayOfStrings -} = require('./shared_validations') - -const isPayloadRequired = isRequired.bind(undefined, JWTClaimInvalid) -const isPayloadString = isString.bind(undefined, JWTClaimInvalid) -const isOptionString = isString.bind(undefined, TypeError) - -const defineLazyExportWithWarning = (obj, property, name, definition) => { - Object.defineProperty(obj, property, { - enumerable: true, - configurable: true, - value (...args) { - process.emitWarning( - `The ${name} API implements an IETF draft. Breaking draft implementations are included as minor versions of the jose library, therefore, the ~ semver operator should be used and close attention be payed to library changelog as well as the drafts themselves.`, - 'DraftWarning' - ) - Object.defineProperty(obj, property, { - enumerable: true, - configurable: true, - value: definition - }) - return obj[property](...args) - } - }) -} - -const validateCommonOptions = (options, profile) => { - if (!isObject(options)) { - throw new TypeError('options must be an object') - } - - if (!options.issuer) { - throw new TypeError(`"issuer" option is required to validate ${profile}`) - } - - if (!options.audience) { - throw new TypeError(`"audience" option is required to validate ${profile}`) - } -} - -module.exports = { - IdToken: { - verify: (token, key, options = {}) => { - validateCommonOptions(options, 'an ID Token') - - if ('maxAuthAge' in options) { - isOptionString(options.maxAuthAge, 'options.maxAuthAge') - } - if ('nonce' in options) { - isOptionString(options.nonce, 'options.nonce') - } - - const unix = epoch(options.now || new Date()) - const result = verify(token, key, { ...options }) - const payload = options.complete ? result.payload : result - - if (Array.isArray(payload.aud) && payload.aud.length > 1) { - isPayloadRequired(payload.azp, '"azp" claim', 'azp') - } - isPayloadRequired(payload.iat, '"iat" claim', 'iat') - isPayloadRequired(payload.sub, '"sub" claim', 'sub') - isPayloadRequired(payload.exp, '"exp" claim', 'exp') - isTimestamp(payload.auth_time, 'auth_time', !!options.maxAuthAge) - isPayloadString(payload.nonce, '"nonce" claim', 'nonce', !!options.nonce) - isPayloadString(payload.acr, '"acr" claim', 'acr') - isStringOrArrayOfStrings(payload.amr, 'amr') - - if (options.nonce && payload.nonce !== options.nonce) { - throw new JWTClaimInvalid('unexpected "nonce" claim value', 'nonce', 'check_failed') - } - - const tolerance = options.clockTolerance ? secs(options.clockTolerance) : 0 - - if (options.maxAuthAge) { - const maxAuthAgeSeconds = secs(options.maxAuthAge) - if (payload.auth_time + maxAuthAgeSeconds < unix - tolerance) { - throw new JWTClaimInvalid('"auth_time" claim timestamp check failed (too much time has elapsed since the last End-User authentication)', 'auth_time', 'check_failed') - } - } - - if (Array.isArray(payload.aud) && payload.aud.length > 1 && payload.azp !== options.audience) { - throw new JWTClaimInvalid('unexpected "azp" claim value', 'azp', 'check_failed') - } - - return result - } - }, - LogoutToken: {}, - AccessToken: {} -} - -defineLazyExportWithWarning(module.exports.LogoutToken, 'verify', 'jose.JWT.LogoutToken.verify', (token, key, options = {}) => { - validateCommonOptions(options, 'a Logout Token') - - const result = verify(token, key, { ...options }) - const payload = options.complete ? result.payload : result - - isPayloadRequired(payload.iat, '"iat" claim', 'iat') - isPayloadRequired(payload.jti, '"jti" claim', 'jti') - isPayloadString(payload.sid, '"sid" claim', 'sid') - - if (!('sid' in payload) && !('sub' in payload)) { - throw new JWTClaimInvalid('either "sid" or "sub" (or both) claims must be present') - } - - if ('nonce' in payload) { - throw new JWTClaimInvalid('"nonce" claim is prohibited', 'nonce', 'prohibited') - } - - if (!('events' in payload)) { - throw new JWTClaimInvalid('"events" claim is missing', 'events', 'missing') - } - - if (!isObject(payload.events)) { - throw new JWTClaimInvalid('"events" claim must be an object', 'events', 'invalid') - } - - if (!('http://schemas.openid.net/event/backchannel-logout' in payload.events)) { - throw new JWTClaimInvalid('"http://schemas.openid.net/event/backchannel-logout" member is missing in the "events" claim', 'events', 'invalid') - } - - if (!isObject(payload.events['http://schemas.openid.net/event/backchannel-logout'])) { - throw new JWTClaimInvalid('"http://schemas.openid.net/event/backchannel-logout" member in the "events" claim must be an object', 'events', 'invalid') - } - - return result -}) - -defineLazyExportWithWarning(module.exports.AccessToken, 'verify', 'jose.JWT.AccessToken.verify', (token, key, options = {}) => { - validateCommonOptions(options, 'a JWT Access Token') - - isOptionString(options.maxAuthAge, 'options.maxAuthAge') - - const unix = epoch(options.now || new Date()) - const typ = 'at+JWT' - const result = verify(token, key, { ...options, typ }) - const payload = options.complete ? result.payload : result - - isPayloadRequired(payload.iat, '"iat" claim', 'iat') - isPayloadRequired(payload.exp, '"exp" claim', 'exp') - isPayloadRequired(payload.sub, '"sub" claim', 'sub') - isPayloadRequired(payload.jti, '"jti" claim', 'jti') - isPayloadString(payload.client_id, '"client_id" claim', 'client_id', true) - isTimestamp(payload.auth_time, 'auth_time', !!options.maxAuthAge) - isPayloadString(payload.acr, '"acr" claim', 'acr') - isStringOrArrayOfStrings(payload.amr, 'amr') - - const tolerance = options.clockTolerance ? secs(options.clockTolerance) : 0 - - if (options.maxAuthAge) { - const maxAuthAgeSeconds = secs(options.maxAuthAge) - if (payload.auth_time + maxAuthAgeSeconds < unix - tolerance) { - throw new JWTClaimInvalid('"auth_time" claim timestamp check failed (too much time has elapsed since the last End-User authentication)', 'auth_time', 'check_failed') - } - } - - return result -}) diff --git a/lib/jwt/shared_validations.js b/lib/jwt/shared_validations.js deleted file mode 100644 index fffc4eee5d..0000000000 --- a/lib/jwt/shared_validations.js +++ /dev/null @@ -1,45 +0,0 @@ -const { JWTClaimInvalid } = require('../errors') - -const isNotString = val => typeof val !== 'string' || val.length === 0 -const isNotArrayOfStrings = val => !Array.isArray(val) || val.length === 0 || val.some(isNotString) -const isRequired = (Err, value, label, claim) => { - if (value === undefined) { - throw new Err(`${label} is missing`, claim, 'missing') - } -} -const isString = (Err, value, label, claim, required = false) => { - if (required) { - isRequired(Err, value, label, claim) - } - - if (value !== undefined && isNotString(value)) { - throw new Err(`${label} must be a string`, claim, 'invalid') - } -} -const isTimestamp = (value, label, required = false) => { - if (required && value === undefined) { - throw new JWTClaimInvalid(`"${label}" claim is missing`, label, 'missing') - } - - if (value !== undefined && (typeof value !== 'number')) { - throw new JWTClaimInvalid(`"${label}" claim must be a JSON numeric value`, label, 'invalid') - } -} -const isStringOrArrayOfStrings = (value, label, required = false) => { - if (required && value === undefined) { - throw new JWTClaimInvalid(`"${label}" claim is missing`, label, 'missing') - } - - if (value !== undefined && (isNotString(value) && isNotArrayOfStrings(value))) { - throw new JWTClaimInvalid(`"${label}" claim must be a string or array of strings`, label, 'invalid') - } -} - -module.exports = { - isNotArrayOfStrings, - isRequired, - isNotString, - isString, - isTimestamp, - isStringOrArrayOfStrings -} diff --git a/lib/jwt/sign.js b/lib/jwt/sign.js deleted file mode 100644 index 5f3416ae4c..0000000000 --- a/lib/jwt/sign.js +++ /dev/null @@ -1,94 +0,0 @@ -const isObject = require('../help/is_object') -const secs = require('../help/secs') -const epoch = require('../help/epoch') -const getKey = require('../help/get_key') -const JWS = require('../jws') - -const isString = require('./shared_validations').isString.bind(undefined, TypeError) - -const validateOptions = (options) => { - if (typeof options.iat !== 'boolean') { - throw new TypeError('options.iat must be a boolean') - } - - if (typeof options.kid !== 'boolean') { - throw new TypeError('options.kid must be a boolean') - } - - isString(options.subject, 'options.subject') - isString(options.issuer, 'options.issuer') - - if ( - options.audience !== undefined && - ( - (typeof options.audience !== 'string' || !options.audience) && - (!Array.isArray(options.audience) || options.audience.length === 0 || options.audience.some(a => !a || typeof a !== 'string')) - ) - ) { - throw new TypeError('options.audience must be a string or an array of strings') - } - - if (!isObject(options.header)) { - throw new TypeError('options.header must be an object') - } - - isString(options.algorithm, 'options.algorithm') - isString(options.expiresIn, 'options.expiresIn') - isString(options.notBefore, 'options.notBefore') - isString(options.jti, 'options.jti') - - if (options.now !== undefined && (!(options.now instanceof Date) || !options.now.getTime())) { - throw new TypeError('options.now must be a valid Date object') - } -} - -module.exports = (payload, key, options = {}) => { - if (!isObject(options)) { - throw new TypeError('options must be an object') - } - - const { - algorithm, audience, expiresIn, header = {}, iat = true, - issuer, jti, kid = true, notBefore, subject, now - } = options - - validateOptions({ - algorithm, audience, expiresIn, header, iat, issuer, jti, kid, notBefore, now, subject - }) - - if (!isObject(payload)) { - throw new TypeError('payload must be an object') - } - - let unix - if (expiresIn || notBefore || iat) { - unix = epoch(now || new Date()) - } - - payload = { - ...payload, - sub: subject || payload.sub, - aud: audience || payload.aud, - iss: issuer || payload.iss, - jti: jti || payload.jti, - iat: iat ? unix : payload.iat, - exp: expiresIn ? unix + secs(expiresIn) : payload.exp, - nbf: notBefore ? unix + secs(notBefore) : payload.nbf - } - - key = getKey(key) - - let includeKid - - if (typeof options.kid === 'boolean') { - includeKid = kid - } else { - includeKid = !key.secret - } - - return JWS.sign(JSON.stringify(payload), key, { - ...header, - alg: algorithm || header.alg, - kid: includeKid ? key.kid : header.kid - }) -} diff --git a/lib/jwt/verify.js b/lib/jwt/verify.js deleted file mode 100644 index db341603e0..0000000000 --- a/lib/jwt/verify.js +++ /dev/null @@ -1,186 +0,0 @@ -const isObject = require('../help/is_object') -const epoch = require('../help/epoch') -const secs = require('../help/secs') -const getKey = require('../help/get_key') -const { bare: verify } = require('../jws/verify') -const { JWTClaimInvalid, JWTExpired } = require('../errors') - -const { - isString, - isNotString, - isNotArrayOfStrings, - isTimestamp, - isStringOrArrayOfStrings -} = require('./shared_validations') -const decode = require('./decode') - -const isPayloadString = isString.bind(undefined, JWTClaimInvalid) -const isOptionString = isString.bind(undefined, TypeError) - -const normalizeTyp = (value) => value.toLowerCase().replace(/^application\//, '') - -const validateOptions = ({ - algorithms, audience, clockTolerance, complete = false, crit, ignoreExp = false, - ignoreIat = false, ignoreNbf = false, issuer, jti, maxTokenAge, now = new Date(), - subject, typ -}) => { - if (typeof complete !== 'boolean') { - throw new TypeError('options.complete must be a boolean') - } - - if (typeof ignoreExp !== 'boolean') { - throw new TypeError('options.ignoreExp must be a boolean') - } - - if (typeof ignoreNbf !== 'boolean') { - throw new TypeError('options.ignoreNbf must be a boolean') - } - - if (typeof ignoreIat !== 'boolean') { - throw new TypeError('options.ignoreIat must be a boolean') - } - - isOptionString(maxTokenAge, 'options.maxTokenAge') - isOptionString(subject, 'options.subject') - isOptionString(jti, 'options.jti') - isOptionString(clockTolerance, 'options.clockTolerance') - isOptionString(typ, 'options.typ') - - if (issuer !== undefined && (isNotString(issuer) && isNotArrayOfStrings(issuer))) { - throw new TypeError('options.issuer must be a string or an array of strings') - } - - if (audience !== undefined && (isNotString(audience) && isNotArrayOfStrings(audience))) { - throw new TypeError('options.audience must be a string or an array of strings') - } - - if (algorithms !== undefined && isNotArrayOfStrings(algorithms)) { - throw new TypeError('options.algorithms must be an array of strings') - } - - if (!(now instanceof Date) || !now.getTime()) { - throw new TypeError('options.now must be a valid Date object') - } - - if (ignoreIat && maxTokenAge !== undefined) { - throw new TypeError('options.ignoreIat and options.maxTokenAge cannot used together') - } - - if (crit !== undefined && isNotArrayOfStrings(crit)) { - throw new TypeError('options.crit must be an array of strings') - } - - return { - algorithms, - audience, - clockTolerance, - complete, - crit, - ignoreExp, - ignoreIat, - ignoreNbf, - issuer, - jti, - maxTokenAge, - now, - subject, - typ - } -} - -const validateTypes = ({ header, payload }, options) => { - isPayloadString(header.alg, '"alg" header parameter', 'alg', true) - - isTimestamp(payload.iat, 'iat', !!options.maxTokenAge) - isTimestamp(payload.exp, 'exp') - isTimestamp(payload.nbf, 'nbf') - isPayloadString(payload.jti, '"jti" claim', 'jti', !!options.jti) - isStringOrArrayOfStrings(payload.iss, 'iss', !!options.issuer) - isPayloadString(payload.sub, '"sub" claim', 'sub', !!options.subject) - isStringOrArrayOfStrings(payload.aud, 'aud', !!options.audience) - isPayloadString(header.typ, '"typ" header parameter', 'typ', !!options.typ) -} - -const checkAudiencePresence = (audPayload, audOption) => { - if (typeof audPayload === 'string') { - return audOption.includes(audPayload) - } - - // Each principal intended to process the JWT MUST - // identify itself with a value in the audience claim - audPayload = new Set(audPayload) - return audOption.some(Set.prototype.has.bind(audPayload)) -} - -module.exports = (token, key, options = {}) => { - if (!isObject(options)) { - throw new TypeError('options must be an object') - } - - const { - algorithms, audience, clockTolerance, complete, crit, ignoreExp, ignoreIat, ignoreNbf, issuer, - jti, maxTokenAge, now, subject, typ - } = options = validateOptions(options) - - const decoded = decode(token, { complete: true }) - key = getKey(key, true) - - if (complete) { - ({ key } = verify(true, 'preparsed', { decoded, token }, key, { crit, algorithms, complete: true })) - decoded.key = key - } else { - verify(true, 'preparsed', { decoded, token }, key, { crit, algorithms }) - } - - const unix = epoch(now) - validateTypes(decoded, options) - - if (issuer && (typeof decoded.payload.iss !== 'string' || !(typeof issuer === 'string' ? [issuer] : issuer).includes(decoded.payload.iss))) { - throw new JWTClaimInvalid('unexpected "iss" claim value', 'iss', 'check_failed') - } - - if (subject && decoded.payload.sub !== subject) { - throw new JWTClaimInvalid('unexpected "sub" claim value', 'sub', 'check_failed') - } - - if (jti && decoded.payload.jti !== jti) { - throw new JWTClaimInvalid('unexpected "jti" claim value', 'jti', 'check_failed') - } - - if (audience && !checkAudiencePresence(decoded.payload.aud, typeof audience === 'string' ? [audience] : audience)) { - throw new JWTClaimInvalid('unexpected "aud" claim value', 'aud', 'check_failed') - } - - if (typ && normalizeTyp(decoded.header.typ) !== normalizeTyp(typ)) { - throw new JWTClaimInvalid('unexpected "typ" JWT header value', 'typ', 'check_failed') - } - - const tolerance = clockTolerance ? secs(clockTolerance) : 0 - - if (!ignoreIat && !('exp' in decoded.payload) && 'iat' in decoded.payload && decoded.payload.iat > unix + tolerance) { - throw new JWTClaimInvalid('"iat" claim timestamp check failed (it should be in the past)', 'iat', 'check_failed') - } - - if (!ignoreNbf && 'nbf' in decoded.payload && decoded.payload.nbf > unix + tolerance) { - throw new JWTClaimInvalid('"nbf" claim timestamp check failed', 'nbf', 'check_failed') - } - - if (!ignoreExp && 'exp' in decoded.payload && decoded.payload.exp <= unix - tolerance) { - throw new JWTExpired('"exp" claim timestamp check failed', 'exp', 'check_failed') - } - - if (maxTokenAge) { - const age = unix - decoded.payload.iat - const max = secs(maxTokenAge) - - if (age - tolerance > max) { - throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', 'iat', 'check_failed') - } - - if (age < 0 - tolerance) { - throw new JWTClaimInvalid('"iat" claim timestamp check failed (it should be in the past)', 'iat', 'check_failed') - } - } - - return complete ? decoded : decoded.payload -} diff --git a/lib/registry/ec_curves.js b/lib/registry/ec_curves.js deleted file mode 100644 index c03d96abc0..0000000000 --- a/lib/registry/ec_curves.js +++ /dev/null @@ -1,21 +0,0 @@ -const { getCurves } = require('crypto') - -const curves = new Set() - -if (getCurves().includes('prime256v1')) { - curves.add('P-256') -} - -if (getCurves().includes('secp256k1')) { - curves.add('secp256k1') -} - -if (getCurves().includes('secp384r1')) { - curves.add('P-384') -} - -if (getCurves().includes('secp521r1')) { - curves.add('P-521') -} - -module.exports = curves diff --git a/lib/registry/ecdh_derive_lengths.js b/lib/registry/ecdh_derive_lengths.js deleted file mode 100644 index c08549c45f..0000000000 --- a/lib/registry/ecdh_derive_lengths.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = new Map() diff --git a/lib/registry/index.js b/lib/registry/index.js deleted file mode 100644 index 70558d2bc2..0000000000 --- a/lib/registry/index.js +++ /dev/null @@ -1,17 +0,0 @@ -const EC_CURVES = require('./ec_curves') -const IVLENGTHS = require('./iv_lengths') -const JWA = require('./jwa') -const JWK = require('./jwk') -const KEYLENGTHS = require('./key_lengths') -const OKP_CURVES = require('./okp_curves') -const ECDH_DERIVE_LENGTHS = require('./ecdh_derive_lengths') - -module.exports = { - EC_CURVES, - ECDH_DERIVE_LENGTHS, - IVLENGTHS, - JWA, - JWK, - KEYLENGTHS, - OKP_CURVES -} diff --git a/lib/registry/iv_lengths.js b/lib/registry/iv_lengths.js deleted file mode 100644 index 51229f129c..0000000000 --- a/lib/registry/iv_lengths.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = new Map([ - ['A128CBC-HS256', 128], - ['A128GCM', 96], - ['A128GCMKW', 96], - ['A192CBC-HS384', 128], - ['A192GCM', 96], - ['A192GCMKW', 96], - ['A256CBC-HS512', 128], - ['A256GCM', 96], - ['A256GCMKW', 96] -]) diff --git a/lib/registry/jwa.js b/lib/registry/jwa.js deleted file mode 100644 index dea7dd1267..0000000000 --- a/lib/registry/jwa.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - sign: new Map(), - verify: new Map(), - keyManagementEncrypt: new Map(), - keyManagementDecrypt: new Map(), - encrypt: new Map(), - decrypt: new Map() -} diff --git a/lib/registry/jwk.js b/lib/registry/jwk.js deleted file mode 100644 index b4dd4d291f..0000000000 --- a/lib/registry/jwk.js +++ /dev/null @@ -1,38 +0,0 @@ -module.exports = { - oct: { - decrypt: {}, - deriveKey: {}, - encrypt: {}, - sign: {}, - unwrapKey: {}, - verify: {}, - wrapKey: {} - }, - EC: { - decrypt: {}, - deriveKey: {}, - encrypt: {}, - sign: {}, - unwrapKey: {}, - verify: {}, - wrapKey: {} - }, - RSA: { - decrypt: {}, - deriveKey: {}, - encrypt: {}, - sign: {}, - unwrapKey: {}, - verify: {}, - wrapKey: {} - }, - OKP: { - decrypt: {}, - deriveKey: {}, - encrypt: {}, - sign: {}, - unwrapKey: {}, - verify: {}, - wrapKey: {} - } -} diff --git a/lib/registry/key_lengths.js b/lib/registry/key_lengths.js deleted file mode 100644 index fc3c1d8dab..0000000000 --- a/lib/registry/key_lengths.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = new Map([ - ['A128CBC-HS256', 256], - ['A128GCM', 128], - ['A192CBC-HS384', 384], - ['A192GCM', 192], - ['A256CBC-HS512', 512], - ['A256GCM', 256] -]) diff --git a/lib/registry/okp_curves.js b/lib/registry/okp_curves.js deleted file mode 100644 index 8406598d42..0000000000 --- a/lib/registry/okp_curves.js +++ /dev/null @@ -1,9 +0,0 @@ -const curves = new Set(['Ed25519']) - -if (!('electron' in process.versions)) { - curves.add('Ed448') - curves.add('X25519') - curves.add('X448') -} - -module.exports = curves diff --git a/package.json b/package.json index f4c76a045d..4640d1501c 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,8 @@ { "name": "jose", "version": "2.0.3", - "description": "JSON Web Almost Everything - JWA, JWS, JWE, JWK, JWT, JWKS for Node.js with minimal dependencies", + "description": "JSON Web Almost Everything - JWA, JWS, JWE, JWK, JWT, JWKS with no dependencies", "keywords": [ - "access token", - "access_token", "compact", "decode", "decrypt", @@ -16,9 +14,7 @@ "embedded", "encrypt", "flattened", - "general", - "id token", - "id_token", + "isomorphic", "jose", "json web token", "jsonwebtoken", @@ -28,8 +24,6 @@ "jwks", "jws", "jwt", - "logout token", - "logout_token", "oct", "okp", "payload", @@ -37,36 +31,429 @@ "secp256k1", "sign", "signature", + "universal", "validate", - "verify" + "verify", + "webcrypto" ], "homepage": "https://github.com/panva/jose", "repository": "panva/jose", - "funding": "https://github.com/sponsors/panva", + "funding": { + "url": "https://github.com/sponsors/panva" + }, "license": "MIT", "author": "Filip Skokan ", + "imports": { + "#dist/jwe/compact/decrypt": { + "import": "./dist/node/esm/jwe/compact/decrypt.js", + "require": "./dist/node/cjs/jwe/compact/decrypt.js" + }, + "#dist/webcrypto/jwe/compact/decrypt": { + "import": "./dist/node/webcrypto/esm/jwe/compact/decrypt.js", + "require": "./dist/node/webcrypto/cjs/jwe/compact/decrypt.js" + }, + "#dist/jwe/compact/encrypt": { + "import": "./dist/node/esm/jwe/compact/encrypt.js", + "require": "./dist/node/cjs/jwe/compact/encrypt.js" + }, + "#dist/webcrypto/jwe/compact/encrypt": { + "import": "./dist/node/webcrypto/esm/jwe/compact/encrypt.js", + "require": "./dist/node/webcrypto/cjs/jwe/compact/encrypt.js" + }, + "#dist/jwe/flattened/decrypt": { + "import": "./dist/node/esm/jwe/flattened/decrypt.js", + "require": "./dist/node/cjs/jwe/flattened/decrypt.js" + }, + "#dist/webcrypto/jwe/flattened/decrypt": { + "import": "./dist/node/webcrypto/esm/jwe/flattened/decrypt.js", + "require": "./dist/node/webcrypto/cjs/jwe/flattened/decrypt.js" + }, + "#dist/jwe/flattened/encrypt": { + "import": "./dist/node/esm/jwe/flattened/encrypt.js", + "require": "./dist/node/cjs/jwe/flattened/encrypt.js" + }, + "#dist/webcrypto/jwe/flattened/encrypt": { + "import": "./dist/node/webcrypto/esm/jwe/flattened/encrypt.js", + "require": "./dist/node/webcrypto/cjs/jwe/flattened/encrypt.js" + }, + "#dist/jwk/embedded": { + "import": "./dist/node/esm/jwk/embedded.js", + "require": "./dist/node/cjs/jwk/embedded.js" + }, + "#dist/webcrypto/jwk/embedded": { + "import": "./dist/node/webcrypto/esm/jwk/embedded.js", + "require": "./dist/node/webcrypto/cjs/jwk/embedded.js" + }, + "#dist/jwk/parse": { + "import": "./dist/node/esm/jwk/parse.js", + "require": "./dist/node/cjs/jwk/parse.js" + }, + "#dist/webcrypto/jwk/parse": { + "import": "./dist/node/webcrypto/esm/jwk/parse.js", + "require": "./dist/node/webcrypto/cjs/jwk/parse.js" + }, + "#dist/jwk/thumbprint": { + "import": "./dist/node/esm/jwk/thumbprint.js", + "require": "./dist/node/cjs/jwk/thumbprint.js" + }, + "#dist/webcrypto/jwk/thumbprint": { + "import": "./dist/node/webcrypto/esm/jwk/thumbprint.js", + "require": "./dist/node/webcrypto/cjs/jwk/thumbprint.js" + }, + "#dist/jwks/remote": { + "import": "./dist/node/esm/jwks/remote.js", + "require": "./dist/node/cjs/jwks/remote.js" + }, + "#dist/webcrypto/jwks/remote": { + "import": "./dist/node/webcrypto/esm/jwks/remote.js", + "require": "./dist/node/webcrypto/cjs/jwks/remote.js" + }, + "#dist/jws/compact/sign": { + "import": "./dist/node/esm/jws/compact/sign.js", + "require": "./dist/node/cjs/jws/compact/sign.js" + }, + "#dist/webcrypto/jws/compact/sign": { + "import": "./dist/node/webcrypto/esm/jws/compact/sign.js", + "require": "./dist/node/webcrypto/cjs/jws/compact/sign.js" + }, + "#dist/jws/compact/verify": { + "import": "./dist/node/esm/jws/compact/verify.js", + "require": "./dist/node/cjs/jws/compact/verify.js" + }, + "#dist/webcrypto/jws/compact/verify": { + "import": "./dist/node/webcrypto/esm/jws/compact/verify.js", + "require": "./dist/node/webcrypto/cjs/jws/compact/verify.js" + }, + "#dist/jws/flattened/sign": { + "import": "./dist/node/esm/jws/flattened/sign.js", + "require": "./dist/node/cjs/jws/flattened/sign.js" + }, + "#dist/webcrypto/jws/flattened/sign": { + "import": "./dist/node/webcrypto/esm/jws/flattened/sign.js", + "require": "./dist/node/webcrypto/cjs/jws/flattened/sign.js" + }, + "#dist/jws/flattened/verify": { + "import": "./dist/node/esm/jws/flattened/verify.js", + "require": "./dist/node/cjs/jws/flattened/verify.js" + }, + "#dist/webcrypto/jws/flattened/verify": { + "import": "./dist/node/webcrypto/esm/jws/flattened/verify.js", + "require": "./dist/node/webcrypto/cjs/jws/flattened/verify.js" + }, + "#dist/jwt/decrypt": { + "import": "./dist/node/esm/jwt/decrypt.js", + "require": "./dist/node/cjs/jwt/decrypt.js" + }, + "#dist/webcrypto/jwt/decrypt": { + "import": "./dist/node/webcrypto/esm/jwt/decrypt.js", + "require": "./dist/node/webcrypto/cjs/jwt/decrypt.js" + }, + "#dist/jwt/encrypt": { + "import": "./dist/node/esm/jwt/encrypt.js", + "require": "./dist/node/cjs/jwt/encrypt.js" + }, + "#dist/webcrypto/jwt/encrypt": { + "import": "./dist/node/webcrypto/esm/jwt/encrypt.js", + "require": "./dist/node/webcrypto/cjs/jwt/encrypt.js" + }, + "#dist/jwt/sign": { + "import": "./dist/node/esm/jwt/sign.js", + "require": "./dist/node/cjs/jwt/sign.js" + }, + "#dist/webcrypto/jwt/sign": { + "import": "./dist/node/webcrypto/esm/jwt/sign.js", + "require": "./dist/node/webcrypto/cjs/jwt/sign.js" + }, + "#dist/jwt/unsecured": { + "import": "./dist/node/esm/jwt/unsecured.js", + "require": "./dist/node/cjs/jwt/unsecured.js" + }, + "#dist/webcrypto/jwt/unsecured": { + "import": "./dist/node/webcrypto/esm/jwt/unsecured.js", + "require": "./dist/node/webcrypto/cjs/jwt/unsecured.js" + }, + "#dist/jwt/verify": { + "import": "./dist/node/esm/jwt/verify.js", + "require": "./dist/node/cjs/jwt/verify.js" + }, + "#dist/webcrypto/jwt/verify": { + "import": "./dist/node/webcrypto/esm/jwt/verify.js", + "require": "./dist/node/webcrypto/cjs/jwt/verify.js" + }, + "#dist/util/base64url": { + "import": "./dist/node/esm/util/base64url.js", + "require": "./dist/node/cjs/util/base64url.js" + }, + "#dist/webcrypto/util/base64url": { + "import": "./dist/node/webcrypto/esm/util/base64url.js", + "require": "./dist/node/webcrypto/cjs/util/base64url.js" + }, + "#dist/util/errors": { + "import": "./dist/node/esm/util/errors.js", + "require": "./dist/node/cjs/util/errors.js" + }, + "#dist/webcrypto/util/errors": { + "import": "./dist/node/webcrypto/esm/util/errors.js", + "require": "./dist/node/webcrypto/cjs/util/errors.js" + }, + "#dist/util/generate_key_pair": { + "import": "./dist/node/esm/util/generate_key_pair.js", + "require": "./dist/node/cjs/util/generate_key_pair.js" + }, + "#dist/webcrypto/util/generate_key_pair": { + "import": "./dist/node/webcrypto/esm/util/generate_key_pair.js", + "require": "./dist/node/webcrypto/cjs/util/generate_key_pair.js" + }, + "#dist/util/generate_secret": { + "import": "./dist/node/esm/util/generate_secret.js", + "require": "./dist/node/cjs/util/generate_secret.js" + }, + "#dist/webcrypto/util/generate_secret": { + "import": "./dist/node/webcrypto/esm/util/generate_secret.js", + "require": "./dist/node/webcrypto/cjs/util/generate_secret.js" + }, + "#dist/util/random": { + "import": "./dist/node/esm/util/random.js", + "require": "./dist/node/cjs/util/random.js" + }, + "#dist/webcrypto/util/random": { + "import": "./dist/node/webcrypto/esm/util/random.js", + "require": "./dist/node/webcrypto/cjs/util/random.js" + } + }, "exports": { - ".": { - "import": "./lib/index.mjs", - "require": "./lib/index.js" + "./jwe/compact/decrypt": { + "browser": "./dist/browser/jwe/compact/decrypt.js", + "import": "./dist/node/esm/jwe/compact/decrypt.js", + "require": "./dist/node/cjs/jwe/compact/decrypt.js" + }, + "./webcrypto/jwe/compact/decrypt": { + "import": "./dist/node/webcrypto/esm/jwe/compact/decrypt.js", + "require": "./dist/node/webcrypto/cjs/jwe/compact/decrypt.js" + }, + "./jwe/compact/encrypt": { + "browser": "./dist/browser/jwe/compact/encrypt.js", + "import": "./dist/node/esm/jwe/compact/encrypt.js", + "require": "./dist/node/cjs/jwe/compact/encrypt.js" }, - "./": "./" + "./webcrypto/jwe/compact/encrypt": { + "import": "./dist/node/webcrypto/esm/jwe/compact/encrypt.js", + "require": "./dist/node/webcrypto/cjs/jwe/compact/encrypt.js" + }, + "./jwe/flattened/decrypt": { + "browser": "./dist/browser/jwe/flattened/decrypt.js", + "import": "./dist/node/esm/jwe/flattened/decrypt.js", + "require": "./dist/node/cjs/jwe/flattened/decrypt.js" + }, + "./webcrypto/jwe/flattened/decrypt": { + "import": "./dist/node/webcrypto/esm/jwe/flattened/decrypt.js", + "require": "./dist/node/webcrypto/cjs/jwe/flattened/decrypt.js" + }, + "./jwe/flattened/encrypt": { + "browser": "./dist/browser/jwe/flattened/encrypt.js", + "import": "./dist/node/esm/jwe/flattened/encrypt.js", + "require": "./dist/node/cjs/jwe/flattened/encrypt.js" + }, + "./webcrypto/jwe/flattened/encrypt": { + "import": "./dist/node/webcrypto/esm/jwe/flattened/encrypt.js", + "require": "./dist/node/webcrypto/cjs/jwe/flattened/encrypt.js" + }, + "./jwk/embedded": { + "browser": "./dist/browser/jwk/embedded.js", + "import": "./dist/node/esm/jwk/embedded.js", + "require": "./dist/node/cjs/jwk/embedded.js" + }, + "./webcrypto/jwk/embedded": { + "import": "./dist/node/webcrypto/esm/jwk/embedded.js", + "require": "./dist/node/webcrypto/cjs/jwk/embedded.js" + }, + "./jwk/parse": { + "browser": "./dist/browser/jwk/parse.js", + "import": "./dist/node/esm/jwk/parse.js", + "require": "./dist/node/cjs/jwk/parse.js" + }, + "./webcrypto/jwk/parse": { + "import": "./dist/node/webcrypto/esm/jwk/parse.js", + "require": "./dist/node/webcrypto/cjs/jwk/parse.js" + }, + "./jwk/thumbprint": { + "browser": "./dist/browser/jwk/thumbprint.js", + "import": "./dist/node/esm/jwk/thumbprint.js", + "require": "./dist/node/cjs/jwk/thumbprint.js" + }, + "./webcrypto/jwk/thumbprint": { + "import": "./dist/node/webcrypto/esm/jwk/thumbprint.js", + "require": "./dist/node/webcrypto/cjs/jwk/thumbprint.js" + }, + "./jwks/remote": { + "browser": "./dist/browser/jwks/remote.js", + "import": "./dist/node/esm/jwks/remote.js", + "require": "./dist/node/cjs/jwks/remote.js" + }, + "./webcrypto/jwks/remote": { + "import": "./dist/node/webcrypto/esm/jwks/remote.js", + "require": "./dist/node/webcrypto/cjs/jwks/remote.js" + }, + "./jws/compact/sign": { + "browser": "./dist/browser/jws/compact/sign.js", + "import": "./dist/node/esm/jws/compact/sign.js", + "require": "./dist/node/cjs/jws/compact/sign.js" + }, + "./webcrypto/jws/compact/sign": { + "import": "./dist/node/webcrypto/esm/jws/compact/sign.js", + "require": "./dist/node/webcrypto/cjs/jws/compact/sign.js" + }, + "./jws/compact/verify": { + "browser": "./dist/browser/jws/compact/verify.js", + "import": "./dist/node/esm/jws/compact/verify.js", + "require": "./dist/node/cjs/jws/compact/verify.js" + }, + "./webcrypto/jws/compact/verify": { + "import": "./dist/node/webcrypto/esm/jws/compact/verify.js", + "require": "./dist/node/webcrypto/cjs/jws/compact/verify.js" + }, + "./jws/flattened/sign": { + "browser": "./dist/browser/jws/flattened/sign.js", + "import": "./dist/node/esm/jws/flattened/sign.js", + "require": "./dist/node/cjs/jws/flattened/sign.js" + }, + "./webcrypto/jws/flattened/sign": { + "import": "./dist/node/webcrypto/esm/jws/flattened/sign.js", + "require": "./dist/node/webcrypto/cjs/jws/flattened/sign.js" + }, + "./jws/flattened/verify": { + "browser": "./dist/browser/jws/flattened/verify.js", + "import": "./dist/node/esm/jws/flattened/verify.js", + "require": "./dist/node/cjs/jws/flattened/verify.js" + }, + "./webcrypto/jws/flattened/verify": { + "import": "./dist/node/webcrypto/esm/jws/flattened/verify.js", + "require": "./dist/node/webcrypto/cjs/jws/flattened/verify.js" + }, + "./jwt/decrypt": { + "browser": "./dist/browser/jwt/decrypt.js", + "import": "./dist/node/esm/jwt/decrypt.js", + "require": "./dist/node/cjs/jwt/decrypt.js" + }, + "./webcrypto/jwt/decrypt": { + "import": "./dist/node/webcrypto/esm/jwt/decrypt.js", + "require": "./dist/node/webcrypto/cjs/jwt/decrypt.js" + }, + "./jwt/encrypt": { + "browser": "./dist/browser/jwt/encrypt.js", + "import": "./dist/node/esm/jwt/encrypt.js", + "require": "./dist/node/cjs/jwt/encrypt.js" + }, + "./webcrypto/jwt/encrypt": { + "import": "./dist/node/webcrypto/esm/jwt/encrypt.js", + "require": "./dist/node/webcrypto/cjs/jwt/encrypt.js" + }, + "./jwt/sign": { + "browser": "./dist/browser/jwt/sign.js", + "import": "./dist/node/esm/jwt/sign.js", + "require": "./dist/node/cjs/jwt/sign.js" + }, + "./webcrypto/jwt/sign": { + "import": "./dist/node/webcrypto/esm/jwt/sign.js", + "require": "./dist/node/webcrypto/cjs/jwt/sign.js" + }, + "./jwt/unsecured": { + "browser": "./dist/browser/jwt/unsecured.js", + "import": "./dist/node/esm/jwt/unsecured.js", + "require": "./dist/node/cjs/jwt/unsecured.js" + }, + "./webcrypto/jwt/unsecured": { + "import": "./dist/node/webcrypto/esm/jwt/unsecured.js", + "require": "./dist/node/webcrypto/cjs/jwt/unsecured.js" + }, + "./jwt/verify": { + "browser": "./dist/browser/jwt/verify.js", + "import": "./dist/node/esm/jwt/verify.js", + "require": "./dist/node/cjs/jwt/verify.js" + }, + "./webcrypto/jwt/verify": { + "import": "./dist/node/webcrypto/esm/jwt/verify.js", + "require": "./dist/node/webcrypto/cjs/jwt/verify.js" + }, + "./util/base64url": { + "browser": "./dist/browser/util/base64url.js", + "import": "./dist/node/esm/util/base64url.js", + "require": "./dist/node/cjs/util/base64url.js" + }, + "./webcrypto/util/base64url": { + "import": "./dist/node/webcrypto/esm/util/base64url.js", + "require": "./dist/node/webcrypto/cjs/util/base64url.js" + }, + "./util/errors": { + "browser": "./dist/browser/util/errors.js", + "import": "./dist/node/esm/util/errors.js", + "require": "./dist/node/cjs/util/errors.js" + }, + "./webcrypto/util/errors": { + "import": "./dist/node/webcrypto/esm/util/errors.js", + "require": "./dist/node/webcrypto/cjs/util/errors.js" + }, + "./util/generate_key_pair": { + "browser": "./dist/browser/util/generate_key_pair.js", + "import": "./dist/node/esm/util/generate_key_pair.js", + "require": "./dist/node/cjs/util/generate_key_pair.js" + }, + "./webcrypto/util/generate_key_pair": { + "import": "./dist/node/webcrypto/esm/util/generate_key_pair.js", + "require": "./dist/node/webcrypto/cjs/util/generate_key_pair.js" + }, + "./util/generate_secret": { + "browser": "./dist/browser/util/generate_secret.js", + "import": "./dist/node/esm/util/generate_secret.js", + "require": "./dist/node/cjs/util/generate_secret.js" + }, + "./webcrypto/util/generate_secret": { + "import": "./dist/node/webcrypto/esm/util/generate_secret.js", + "require": "./dist/node/webcrypto/cjs/util/generate_secret.js" + }, + "./util/random": { + "browser": "./dist/browser/util/random.js", + "import": "./dist/node/esm/util/random.js", + "require": "./dist/node/cjs/util/random.js" + }, + "./webcrypto/util/random": { + "import": "./dist/node/webcrypto/esm/util/random.js", + "require": "./dist/node/webcrypto/cjs/util/random.js" + } }, - "main": "lib/index.js", - "types": "types/index.d.ts", "files": [ - "lib/**/*.js", - "lib/**/*.mjs", - "LICENSE_THIRD_PARTY", - "types/index.d.ts" + "dist/**/*.js", + "src/**/*.d.ts", + "src/**/*.ts", + "!src/runtime/*.ts", + "src/runtime/interfaces.d.ts" ], "scripts": { - "coverage": "c8 ava", - "lint": "standard", - "lint-fix": "standard --fix", - "lint-ts": "npx typescript@~3.6.0 --build types", - "test": "ava", - "watch": "ava --watch" + "build": "tsc", + "build-all": "run-s clear build:*", + "build:browser": "run-s runtime-browser lint 'build -- -p ./tsconfig/browser.json' && echo '{\"type\": \"module\"}'> dist/browser/package.json", + "build:node-cjs": "run-s runtime-node lint 'build -- -p ./tsconfig/node-cjs.json'", + "build:node-esm": "run-s runtime-node lint 'build -- -p ./tsconfig/node-esm.json' && echo '{\"type\": \"module\"}'> dist/node/esm/package.json", + "build:node-webcrypto-cjs": "run-s runtime-node-webcrypto && run-s 'build -- -p ./tsconfig/node-webcrypto-cjs.json'", + "build:node-webcrypto-esm": "run-s runtime-node-webcrypto && run-s 'build -- -p ./tsconfig/node-webcrypto-esm.json' && echo '{\"type\": \"module\"}'> dist/node/webcrypto/esm/package.json", + "clear": "rm -rf dist", + "coverage": "npm run-script runtime-node && c8 npm run-script test", + "coverage-webcrypto": "npm run-script runtime-node-webcrypto && c8 npm run-script test-webcrypto", + "docs": "run-s docs:*", + "docs:generate": "npx typedoc --disableOutputCheck --excludeNotExported --excludePrivate --excludeProtected --gitRevision main --readme none --listInvalidSymbolLinks --plugin typedoc-plugin-markdown --out docs --includeDeclarations --excludeExternals --tsconfig ./tsconfig/browser.json --mode modules src/types.d.ts src/jwt/*.ts src/jwe/**/*.ts src/jws/**/*.ts src/jwk/*.ts src/jwks/*.ts src/util/*.ts --hideProjectName --hideGenerator --allReflectionsHaveOwnDocument --hideBreadcrumbs", + "lint": "eslint --config ./src/.eslintrc.json ./src", + "runtime-browser": "run-s runtime:clear runtime:browser:* runtime:refs", + "runtime-node": "run-s runtime:clear runtime:node:* runtime:refs", + "runtime-node-webcrypto": "run-s runtime:clear runtime:browser:* && cp ./src/runtime/node/webcrypto.ts ./src/runtime/ && cp ./src/runtime/node/fetch.ts ./src/runtime/ && cp ./src/runtime/node/base64url.ts ./src/runtime/ && cp ./src/runtime/node/zlib.ts ./src/runtime/ && run-s runtime:refs", + "runtime:browser:copy": "cp ./src/runtime/browser/*.ts ./src/runtime", + "runtime:clear": "run-s -s runtime:find | xargs -0 rm -f", + "runtime:find": "find src/runtime -not -name 'interfaces.d.ts' -maxdepth 1 -type f -print0", + "runtime:node:copy": "cp ./src/runtime/node/*.ts ./src/runtime", + "runtime:refs": "run-s -s runtime:find | xargs -0 sed -i '' -e \"s/'\\.\\.\\//'\\.\\//g\" -e \"s/'\\.\\/\\.\\./'../g\"", + "test": "npm run-script test-rollup && ava", + "test-browser": "webpack && karma start", + "test-rollup": "rm -rf test/cjs && find test -type f -name '*.mjs' -print0 | xargs -0 rollup --silent --no-interop --preserveModules --format cjs --dir test/cjs", + "test-webcrypto": "WEBCRYPTO=true npm test" }, "husky": { "hooks": { @@ -78,29 +465,46 @@ "@commitlint/config-conventional" ] }, - "ava": { - "babel": false, - "compileEnhancements": false, - "files": [ - "test/**/*.test.js" - ] - }, - "dependencies": { - "@panva/asn1.js": "^1.0.0" - }, "devDependencies": { - "@commitlint/cli": "^11.0.0", - "@commitlint/config-conventional": "^11.0.0", - "ava": "^2.4.0", + "@types/node": "^14.14.2", + "@typescript-eslint/eslint-plugin": "^4.5.0", + "ava": "^3.13.0", + "bowser": "^2.11.0", "c8": "^7.3.5", - "husky": "^4.3.0", - "standard": "^16.0.0" + "eslint": "^7.12.0", + "eslint-config-airbnb-base": "^14.2.0", + "eslint-config-airbnb-typescript": "^12.0.0", + "eslint-config-prettier": "^6.14.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-jsdoc": "^30.7.3", + "glob": "^7.1.6", + "karma": "^5.2.3", + "karma-browserstack-launcher": "^1.6.0", + "karma-qunit": "^4.1.1", + "nock": "^13.0.4", + "npm-run-all": "^4.1.5", + "prettier": "^2.1.2", + "qunit": "^2.12.0", + "rollup": "^2.33.1", + "timekeeper": "^2.2.0", + "typedoc": "0.19.2", + "typedoc-plugin-markdown": "3.0.11", + "typescript": "~4.0.3", + "webpack": "^5.4.0", + "webpack-cli": "^4.2.0" }, - "engines": { - "node": ">=10.13.0 < 13 || >=13.7.0" + "c8": { + "src": "./src", + "reporter": [ + "lcov", + "text-summary" + ] }, "standard-version": { + "commit-all": true, "scripts": { + "prerelease": "npm run-script build-all", + "postbump": "node ./tools/docs.postbump.js", "postchangelog": "sed -i '' -e 's/### \\[/## [/g' CHANGELOG.md" }, "types": [ @@ -138,5 +542,15 @@ "hidden": true } ] + }, + "typesVersions": { + "*": { + "webcrypto/*": [ + "./src/*" + ], + "*": [ + "./src/*" + ] + } } } diff --git a/src/.eslintrc.json b/src/.eslintrc.json new file mode 100644 index 0000000000..df09868ee8 --- /dev/null +++ b/src/.eslintrc.json @@ -0,0 +1,38 @@ +{ + "plugins": ["jsdoc"], + "extends": ["airbnb-typescript/base", "prettier"], + "parserOptions": { + "project": "./tsconfig/browser.json" + }, + "rules": { + "no-underscore-dangle": "off", + "no-bitwise": "off", + "no-plusplus": "off", + "@typescript-eslint/indent": "off", + "@typescript-eslint/semi": "off", + "@typescript-eslint/no-extra-semi": "off", + "import/prefer-default-export": "off", + "jsdoc/check-access": 2, + "jsdoc/check-alignment": 2, + "jsdoc/check-indentation": 2, + "jsdoc/check-param-names": 2, + "jsdoc/check-property-names": 2, + "jsdoc/check-tag-names": 2, + "jsdoc/check-types": 2, + "jsdoc/empty-tags": 2, + "jsdoc/newline-after-description": 2, + "jsdoc/no-bad-blocks": 2, + "jsdoc/no-types": 2, + "jsdoc/require-description-complete-sentence": [1, { "abbreviations": ["e.g.", "i.e."] }], + "jsdoc/require-description": [2, { "checkConstructors": false }], + "jsdoc/require-hyphen-before-param-description": [2, "never"], + "jsdoc/require-param-description": 2, + "jsdoc/require-param-name": 2, + "jsdoc/require-param": 2, + "jsdoc/valid-types": 2 + }, + "globals": { + "window": "readonly" + }, + "ignorePatterns": ["src/runtime/*/*.ts", "src/runtime/webcrypto.ts", "dist"] +} diff --git a/src/.prettierrc.json b/src/.prettierrc.json new file mode 100644 index 0000000000..3c9a291efe --- /dev/null +++ b/src/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "trailingComma": "all", + "singleQuote": true, + "printWidth": 100, + "semi": false +} diff --git a/src/jwe/compact/decrypt.ts b/src/jwe/compact/decrypt.ts new file mode 100644 index 0000000000..fa814779fa --- /dev/null +++ b/src/jwe/compact/decrypt.ts @@ -0,0 +1,93 @@ +import decrypt from '../flattened/decrypt.js' +import { JWEInvalid } from '../../util/errors.js' +import type { + KeyLike, + DecryptOptions, + JWEHeaderParameters, + GetKeyFunction, + FlattenedJWE, + CompactDecryptResult, +} from '../../types.d' + +/** + * Interface for Compact JWE Decryption dynamic key resolution. + * No token components have been verified at the time of this function call. + */ +export interface CompactDecryptGetKey extends GetKeyFunction {} + +/** + * Decrypts a Compact JWE. + * + * @param jwe Compact JWE. + * @param key Private Key or Secret, or a function resolving one, to decrypt the JWE with. + * @param options JWE Decryption options. + * + * @example + * ``` + * // ESM import + * import compactDecrypt from 'jose/jwe/compact/decrypt' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: compactDecrypt } = require('jose/jwe/compact/decrypt') + * ``` + * + * @example + * ``` + * // usage + * import parseJwk from 'jose/jwk/parse' + * + * const decoder = new TextDecoder() + * const jwe = 'eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIn0.nyQ19eq9ogh9wA7fFtnI2oouzy5_8b5DeLkoRMfi2yijgfTs2zEnayCEofz_qhnL-nwszabd9qUeHv0-IwvhhJJS7GUJOU3ikiIe42qcIAFme1A_Fo9CTxw4XTOy-I5qanl8So91u6hwfyN1VxAqVLsSE7_23EC-gfGEg_5znew9PyXXsOIE-K_HH7IQowRrlZ1X_bM_Liu53RzDpLDvRz59mp3S8L56YqpM8FexFGTGpEaoTcEIst375qncYt3-79IVR7gZN1RWsWgjPatfvVbnh74PglQcATSf3UUhaW0OAKn6q7r3PDx6DIKQ35bgHQg5QopuN00eIfLQL2trGw.W3grIVj5HVuAb76X.6PcuDe5D6ttWFYyv0oqqdDXfI2R8wBg1F2Q80UUA_Gv8eEimNWfxIWdLxrjzgQGSvIhxmFKuLM0.a93_Ug3uZHuczj70Zavx8Q' + * const privateKey = await parseJwk({ + * e: 'AQAB', + * n: 'qpzYkTGRKSUcd12hZaJnYEKVLfdEsqu6HBAxZgRSvzLFj_zTSAEXjbf3fX47MPEHRw8NDcEXPjVOz84t4FTXYF2w2_LGWfp_myjV8pR6oUUncJjS7DhnUmTG5bpuK2HFXRMRJYz_iNR48xRJPMoY84jrnhdIFx8Tqv6w4ZHVyEvcvloPgwG3UjLidP6jmqbTiJtidVLnpQJRuFNFQJiluQXBZ1nOLC7raQshu7L9y0IatVU7vf0BPnmuSkcNNvmQkSta6ODQBPaL5-o5SW8H37vQjPDkrlJpreViNa3jqP5DB5HYUO-DMh4FegRv9gZWLDEvXpSd9A13YXCa9Q8K_w', + * d: 'YAfYfiEAK8CPvUAeUC6RMUVI4o6DRG4UWydiJqHYUXYqbVlJMwYqU8Jws1oRxwJjrkNyfYNpqcInkh_jApm-gKc7nRGRQ6QTnynlAp1ASPW7tUzPq9YzkdTXfwboa9KkXDcXN6OdUU8GpQuODYFTegBfXqSMFzeOwniI5u5G_m2I6YU1zU4x7dxaKhPSK2mJ1v-tJu88j855DYIY0AiX5uf_oa0CgaqyOOY3LaxGjV0FxrkAzYluHfQef7ux-1ocXD1aUrdj3owk48ZVEb2o-V1bMLtk415ngS-u89bABHuJ50-gIwpO-y7ofe6ik4fAd9NfD8PVKHHsrNYbC5FdAQ', + * p: '4WlvPw4Vf-mHzoqem_2VUf7hMiLEM5sl_th-CZyA0dowhEnNBJPtaqCz2k_6_ECKZ5C-KoT-EmQOBILQFJtR9SOs6fI9yZGL1OpbjGNKpWzym8iQrFcKAhFvQ_hG7Fkwz6_yRV5fKnOWSD78Rk6wuOTaXqwJS7uljvrn7SmRFpE', + * q: 'wcO_PHrkHazbqDgBVvTDaMXJ7W5l0RTxhrOsU6qGCLp367Zc2F9BwPAlMy9KKMhf9RLxgv32lGqWxVh3WQ1GSJqswSIKhfAOzmuTDjlYxqrte_TMcaVDxtRuO8Bxp5A8Y7i3VxQ_Rjfa04QLxJfiRdap4UamYWco25WKH4rkcI8', + * dp: 'rWynEIZPeEg-GmSAP1fMqHdG34HsHiBCDV6XKeHlIo-SQFVfjSQax6y4c0CRw74MPj4YcTI9H_0m48WZPiF53vcBtESR0SFPyhI9OTezWK8HwV-AH3gf1ROA3XSJbJH6ge_GoCRJZ6nid9ct1RH52WcJs0j9Je1LJURZaBhQ7mE', + * dq: 'tYrMc0ME1dTuHQcUIj_Dkje2gLGtzZ6cyMMw01byq9zhnMRI6yUcu0OE5xcImXtbhIfSJhQCYn4XcyD2-UWZs07QS0e0qlcH2Fkr9-i9B66AQWJT5qqb_P9tpKgjFIbsPdaEWJ8MxaJxcTnHuNNBWoPMuNfz7VC1FD9goTsF23s', + * qi: 'qAZmEWhWcDgW_pQZA5e7r185-sOnNPAW53y16QKh5wNThGjpUl7OvePZWY59ekd6PYwvkloNIRki6mLskP9NZ73CsAdZknSAPaAmBuNGYDabtObcigQDPFQ5DeqyAdRUrim66eN7whE5mf_XgOwVAx3-9PtfHvvmTTNezHfoZdo', + * kty: 'RSA' + * }, 'RSA-OAEP-256') + * + * const { plaintext, protectedHeader } = await compactDecrypt(jwe, privateKey) + * + * console.log(protectedHeader) + * console.log(decoder.decode(plaintext)) + * ``` + */ +export default async function compactDecrypt( + jwe: string, + key: KeyLike | CompactDecryptGetKey, + options?: DecryptOptions, +): Promise { + if (typeof jwe !== 'string') { + throw new JWEInvalid('Compact JWE must be a string') + } + const { 0: protectedHeader, 1: encryptedKey, 2: iv, 3: ciphertext, 4: tag, length } = jwe.split( + '.', + ) + + if (length !== 5) { + throw new JWEInvalid('Invalid Compact JWE') + } + + const decrypted = await decrypt( + { + ciphertext, + iv, + protected: protectedHeader, + tag, + ...(encryptedKey ? { encrypted_key: encryptedKey } : undefined), + }, + key as Parameters[1], + options, + ) + + return { plaintext: decrypted.plaintext, protectedHeader: decrypted.protectedHeader! } +} + +export type { KeyLike, DecryptOptions } diff --git a/src/jwe/compact/encrypt.ts b/src/jwe/compact/encrypt.ts new file mode 100644 index 0000000000..45a4d5bbe1 --- /dev/null +++ b/src/jwe/compact/encrypt.ts @@ -0,0 +1,115 @@ +import FlattenedEncrypt from '../flattened/encrypt.js' +import type { + KeyLike, + JWEKeyManagementHeaderParameters, + JWEHeaderParameters, + EncryptOptions, +} from '../../types.d' + +/** + * The CompactEncrypt class is a utility for creating Compact JWE strings. + * + * @example + * ``` + * // ESM import + * import CompactEncrypt from 'jose/jwe/compact/encrypt' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: CompactEncrypt } = require('jose/jwe/compact/encrypt') + * ``` + * + * @example + * ``` + * // usage + * import parseJwk from 'jose/jwk/parse' + * + * const encoder = new TextEncoder() + * + * const publicKey = await parseJwk({ + * e: 'AQAB', + * n: 'qpzYkTGRKSUcd12hZaJnYEKVLfdEsqu6HBAxZgRSvzLFj_zTSAEXjbf3fX47MPEHRw8NDcEXPjVOz84t4FTXYF2w2_LGWfp_myjV8pR6oUUncJjS7DhnUmTG5bpuK2HFXRMRJYz_iNR48xRJPMoY84jrnhdIFx8Tqv6w4ZHVyEvcvloPgwG3UjLidP6jmqbTiJtidVLnpQJRuFNFQJiluQXBZ1nOLC7raQshu7L9y0IatVU7vf0BPnmuSkcNNvmQkSta6ODQBPaL5-o5SW8H37vQjPDkrlJpreViNa3jqP5DB5HYUO-DMh4FegRv9gZWLDEvXpSd9A13YXCa9Q8K_w', + * kty: 'RSA' + * }, 'RSA-OAEP-256') + * + * const jwe = await new CompactEncrypt(encoder.encode('It’s a dangerous business, Frodo, going out your door.')) + * .setProtectedHeader({ alg: 'RSA-OAEP-256', enc: 'A256GCM' }) + * .encrypt(publicKey) + * + * console.log(jwe) + * ``` + */ +export default class CompactEncrypt { + private _flattened: FlattenedEncrypt + + /** + * @param plaintext Binary representation of the plaintext to encrypt. + */ + constructor(plaintext: Uint8Array) { + this._flattened = new FlattenedEncrypt(plaintext) + } + + /** + * Sets a content encryption key to use, by default a random suitable one + * is generated for the JWE enc" (Encryption Algorithm) Header Parameter. + * You do not need to invoke this method, it is only really intended for + * test and vector validation purposes. + * + * @param cek JWE Content Encryption Key. + */ + setContentEncryptionKey(cek: Uint8Array) { + this._flattened.setContentEncryptionKey(cek) + return this + } + + /** + * Sets the JWE Initialization Vector to use for content encryption, by default + * a random suitable one is generated for the JWE enc" (Encryption Algorithm) + * Header Parameter. You do not need to invoke this method, it is only really + * intended for test and vector validation purposes. + * + * @param iv JWE Initialization Vector. + */ + setInitializationVector(iv: Uint8Array) { + this._flattened.setInitializationVector(iv) + return this + } + + /** + * Sets the JWE Protected Header on the CompactEncrypt object. + * + * @param protectedHeader JWE Protected Header object. + */ + setProtectedHeader(protectedHeader: JWEHeaderParameters) { + this._flattened.setProtectedHeader(protectedHeader) + return this + } + + /** + * Sets the JWE Key Management parameters to be used when encrypting the Content + * Encryption Key. You do not need to invoke this method, it is only really + * intended for test and vector validation purposes. + * + * @param parameters JWE Key Management parameters. + */ + setKeyManagementParameters(parameters: JWEKeyManagementHeaderParameters) { + this._flattened.setKeyManagementParameters(parameters) + return this + } + + /** + * Encrypts and resolves the value of the Compact JWE string. + * + * @param key Public Key or Secret to encrypt the JWE with. + * @param options JWE Encryption options. + */ + async encrypt(key: KeyLike, options?: EncryptOptions): Promise { + const jwe = await this._flattened.encrypt(key, options) + + return [jwe.protected, jwe.encrypted_key, jwe.iv, jwe.ciphertext, jwe.tag].join('.') + } +} + +export type { KeyLike, JWEKeyManagementHeaderParameters, JWEHeaderParameters } diff --git a/src/jwe/flattened/decrypt.ts b/src/jwe/flattened/decrypt.ts new file mode 100644 index 0000000000..9b50b22e53 --- /dev/null +++ b/src/jwe/flattened/decrypt.ts @@ -0,0 +1,255 @@ +import { JOSEAlgNotAllowed, JOSENotSupported, JWEInvalid } from '../../util/errors.js' +import isDisjoint from '../../lib/is_disjoint.js' +import isObject from '../../lib/is_object.js' + +import { decode as base64url } from '../../runtime/base64url.js' +import decrypt from '../../runtime/decrypt.js' +import { inflate } from '../../runtime/zlib.js' +import decryptKeyManagement from '../../lib/decrypt_key_management.js' + +import type { + FlattenedDecryptResult, + KeyLike, + FlattenedJWE, + JWEHeaderParameters, + DecryptOptions, + GetKeyFunction, +} from '../../types.d' +import { encoder, decoder, concat } from '../../lib/buffer_utils.js' +import cekFactory from '../../lib/cek.js' +import random from '../../runtime/random.js' +import validateCrit from '../../lib/validate_crit.js' +import validateAlgorithms from '../../lib/validate_algorithms.js' + +const generateCek = cekFactory(random) +const checkCrit = validateCrit.bind(undefined, JWEInvalid, new Map()) +const checkAlgOption = validateAlgorithms.bind(undefined, 'keyManagementAlgorithms') +const checkEncOption = validateAlgorithms.bind(undefined, 'contentEncryptionAlgorithms') + +/** + * Interface for Flattened JWE Decryption dynamic key resolution. + * No token components have been verified at the time of this function call. + */ +export interface FlattenedDecryptGetKey + extends GetKeyFunction {} + +/** + * Decrypts a Flattened JWE. + * + * @param jwe Flattened JWE. + * @param key Public Key or Secret, or a function resolving one, to decrypt the JWE with. + * @param options JWE Decryption options. + * + * @example + * ``` + * // ESM import + * import flattenedDecrypt from 'jose/jwe/flattened/decrypt' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: flattenedDecrypt } = require('jose/jwe/flattened/decrypt') + * ``` + * + * @example + * ``` + * // usage + * import parseJwk from 'jose/jwk/parse' + * + * const decoder = new TextDecoder() + * const jwe = { + * ciphertext: '9EzjFISUyoG-ifC2mSihfP0DPC80yeyrxhTzKt1C_VJBkxeBG0MI4Te61Pk45RAGubUvBpU9jm4', + * iv: '8Fy7A_IuoX5VXG9s', + * tag: 'W76IYV6arGRuDSaSyWrQNg', + * encrypted_key: 'Z6eD4UK_yFb5ZoKvKkGAdqywEG_m0e4IYo0x8Vf30LAMJcsc-_zSgIeiF82teZyYi2YYduHKoqImk7MRnoPZOlEs0Q5BNK1OgBmSOhCE8DFyqh9Zh48TCTP6lmBQ52naqoUJFMtHzu-0LwZH26hxos0GP3Dt19O379MJB837TdKKa87skq0zHaVLAquRHOBF77GI54Bc7O49d8aOrSu1VEFGMThlW2caspPRiTSePDMDPq7_WGk50izRhB3Asl9wmP9wEeaTrkJKRnQj5ips1SAZ1hDBsqEQKKukxP1HtdcopHV5_qgwU8Hjm5EwSLMluMQuiE6hwlkXGOujZLVizA', + * aad: 'VGhlIEZlbGxvd3NoaXAgb2YgdGhlIFJpbmc', + * protected: 'eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIn0' + * } + * const privateKey = await parseJwk({ + * e: 'AQAB', + * n: 'qpzYkTGRKSUcd12hZaJnYEKVLfdEsqu6HBAxZgRSvzLFj_zTSAEXjbf3fX47MPEHRw8NDcEXPjVOz84t4FTXYF2w2_LGWfp_myjV8pR6oUUncJjS7DhnUmTG5bpuK2HFXRMRJYz_iNR48xRJPMoY84jrnhdIFx8Tqv6w4ZHVyEvcvloPgwG3UjLidP6jmqbTiJtidVLnpQJRuFNFQJiluQXBZ1nOLC7raQshu7L9y0IatVU7vf0BPnmuSkcNNvmQkSta6ODQBPaL5-o5SW8H37vQjPDkrlJpreViNa3jqP5DB5HYUO-DMh4FegRv9gZWLDEvXpSd9A13YXCa9Q8K_w', + * d: 'YAfYfiEAK8CPvUAeUC6RMUVI4o6DRG4UWydiJqHYUXYqbVlJMwYqU8Jws1oRxwJjrkNyfYNpqcInkh_jApm-gKc7nRGRQ6QTnynlAp1ASPW7tUzPq9YzkdTXfwboa9KkXDcXN6OdUU8GpQuODYFTegBfXqSMFzeOwniI5u5G_m2I6YU1zU4x7dxaKhPSK2mJ1v-tJu88j855DYIY0AiX5uf_oa0CgaqyOOY3LaxGjV0FxrkAzYluHfQef7ux-1ocXD1aUrdj3owk48ZVEb2o-V1bMLtk415ngS-u89bABHuJ50-gIwpO-y7ofe6ik4fAd9NfD8PVKHHsrNYbC5FdAQ', + * p: '4WlvPw4Vf-mHzoqem_2VUf7hMiLEM5sl_th-CZyA0dowhEnNBJPtaqCz2k_6_ECKZ5C-KoT-EmQOBILQFJtR9SOs6fI9yZGL1OpbjGNKpWzym8iQrFcKAhFvQ_hG7Fkwz6_yRV5fKnOWSD78Rk6wuOTaXqwJS7uljvrn7SmRFpE', + * q: 'wcO_PHrkHazbqDgBVvTDaMXJ7W5l0RTxhrOsU6qGCLp367Zc2F9BwPAlMy9KKMhf9RLxgv32lGqWxVh3WQ1GSJqswSIKhfAOzmuTDjlYxqrte_TMcaVDxtRuO8Bxp5A8Y7i3VxQ_Rjfa04QLxJfiRdap4UamYWco25WKH4rkcI8', + * dp: 'rWynEIZPeEg-GmSAP1fMqHdG34HsHiBCDV6XKeHlIo-SQFVfjSQax6y4c0CRw74MPj4YcTI9H_0m48WZPiF53vcBtESR0SFPyhI9OTezWK8HwV-AH3gf1ROA3XSJbJH6ge_GoCRJZ6nid9ct1RH52WcJs0j9Je1LJURZaBhQ7mE', + * dq: 'tYrMc0ME1dTuHQcUIj_Dkje2gLGtzZ6cyMMw01byq9zhnMRI6yUcu0OE5xcImXtbhIfSJhQCYn4XcyD2-UWZs07QS0e0qlcH2Fkr9-i9B66AQWJT5qqb_P9tpKgjFIbsPdaEWJ8MxaJxcTnHuNNBWoPMuNfz7VC1FD9goTsF23s', + * qi: 'qAZmEWhWcDgW_pQZA5e7r185-sOnNPAW53y16QKh5wNThGjpUl7OvePZWY59ekd6PYwvkloNIRki6mLskP9NZ73CsAdZknSAPaAmBuNGYDabtObcigQDPFQ5DeqyAdRUrim66eN7whE5mf_XgOwVAx3-9PtfHvvmTTNezHfoZdo', + * kty: 'RSA' + * }, 'RSA-OAEP-256') + * + * const { + * plaintext, + * protectedHeader, + * additionalAuthenticatedData + * } = await flattenedDecrypt(jwe, privateKey) + * + * console.log(protectedHeader) + * console.log(decoder.decode(plaintext)) + * console.log(decoder.decode(additionalAuthenticatedData)) + * ``` + */ +export default async function flattenedDecrypt( + jwe: FlattenedJWE, + key: KeyLike | FlattenedDecryptGetKey, + options?: DecryptOptions, +): Promise { + if (!isObject(jwe)) { + throw new JWEInvalid('Flattened JWE must be an object') + } + + if (!('protected' in jwe) && !('header' in jwe) && !('unprotected' in jwe)) { + throw new JWEInvalid('JOSE Header missing') + } + + if (!('iv' in jwe) || typeof jwe.iv !== 'string') { + throw new JWEInvalid('JWE Initialization Vector missing or incorrect type') + } + + if (!('ciphertext' in jwe) || typeof jwe.ciphertext !== 'string') { + throw new JWEInvalid('JWE Ciphertext missing or incorrect type') + } + + if (!('tag' in jwe) || typeof jwe.tag !== 'string') { + throw new JWEInvalid('JWE Authentication Tag missing or incorrect type') + } + + if ('protected' in jwe && typeof jwe.protected !== 'string') { + throw new JWEInvalid('JWE Protected Header incorrect type') + } + + if ('encrypted_key' in jwe && typeof jwe.encrypted_key !== 'string') { + throw new JWEInvalid('JWE Encrypted Key incorrect type') + } + + if ('aad' in jwe && typeof jwe.aad !== 'string') { + throw new JWEInvalid('JWE AAD incorrect type') + } + + if ('header' in jwe && !isObject(jwe.header)) { + throw new JWEInvalid('JWE Shared Unprotected Header incorrect type') + } + + if ('unprotected' in jwe && !isObject(jwe.unprotected)) { + throw new JWEInvalid('JWE Per-Recipient Unprotected Header incorrect type') + } + + let parsedProt!: JWEHeaderParameters + if (jwe.protected) { + const protectedHeader = base64url(jwe.protected) + parsedProt = JSON.parse(decoder.decode(protectedHeader)) + } + if (!isDisjoint(parsedProt, jwe.header, jwe.unprotected)) { + throw new JWEInvalid( + 'JWE Protected, JWE Unprotected Header, and JWE Per-Recipient Unprotected Header Parameter names must be disjoint', + ) + } + + const joseHeader: JWEHeaderParameters = { + ...parsedProt, + ...jwe.header, + ...jwe.unprotected, + } + + checkCrit(parsedProt, joseHeader) + + if ('zip' in joseHeader) { + if (!parsedProt || !parsedProt.zip) { + throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected') + } + + if (joseHeader.zip !== 'DEF') { + throw new JOSENotSupported( + 'unsupported JWE "zip" (Compression Algorithm) Header Parameter value', + ) + } + } + + const { alg, enc } = joseHeader + + if (!alg) { + throw new JWEInvalid('missing JWE Algorithm (alg) in JWE Header') + } + + if (!enc) { + throw new JWEInvalid('missing JWE Encryption Algorithm (enc) in JWE Header') + } + + const keyManagementAlgorithms = options && checkAlgOption(options.keyManagementAlgorithms) + const contentEncryptionAlgorithms = options && checkEncOption(options.contentEncryptionAlgorithms) + + if (keyManagementAlgorithms && !keyManagementAlgorithms.has(alg)) { + throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter not allowed') + } + + if (contentEncryptionAlgorithms && !contentEncryptionAlgorithms.has(enc)) { + throw new JOSEAlgNotAllowed('"enc" (Encryption Algorithm) Header Parameter not allowed') + } + + let encryptedKey!: Uint8Array + if ('encrypted_key' in jwe) { + encryptedKey = base64url(jwe.encrypted_key!) + } + + if (typeof key === 'function') { + // eslint-disable-next-line no-param-reassign + key = await key(parsedProt, jwe) + } + + let cek: KeyLike + try { + cek = await decryptKeyManagement(alg, key, encryptedKey, joseHeader) + } catch (err) { + if (err instanceof TypeError) { + throw err + } + // https://tools.ietf.org/html/rfc7516#section-11.5 + // To mitigate the attacks described in RFC 3218, the + // recipient MUST NOT distinguish between format, padding, and length + // errors of encrypted keys. It is strongly recommended, in the event + // of receiving an improperly formatted key, that the recipient + // substitute a randomly generated CEK and proceed to the next step, to + // mitigate timing attacks. + cek = await generateCek(enc) + } + + const iv = base64url(jwe.iv) + const tag = base64url(jwe.tag) + + const protectedHeader: Uint8Array = encoder.encode(jwe.protected || '') + let additionalData: Uint8Array + + if ('aad' in jwe) { + additionalData = concat(protectedHeader, encoder.encode('.'), encoder.encode(jwe.aad)) + } else { + additionalData = protectedHeader + } + + let plaintext = await decrypt(enc, cek, base64url(jwe.ciphertext), iv, tag, additionalData) + + if (joseHeader.zip === 'DEF') { + plaintext = await (options?.inflateRaw || inflate)(plaintext) + } + + const result: FlattenedDecryptResult = { plaintext } + + if ('protected' in jwe) { + result.protectedHeader = parsedProt + } + + if ('aad' in jwe) { + result.additionalAuthenticatedData = base64url(jwe.aad!) + } + + if ('unprotected' in jwe) { + result.sharedUnprotectedHeader = jwe.unprotected + } + + if ('header' in jwe) { + result.unprotectedHeader = jwe.header + } + + return result +} + +export type { KeyLike, FlattenedJWE, JWEHeaderParameters, DecryptOptions } diff --git a/src/jwe/flattened/encrypt.ts b/src/jwe/flattened/encrypt.ts new file mode 100644 index 0000000000..3a0b28f37d --- /dev/null +++ b/src/jwe/flattened/encrypt.ts @@ -0,0 +1,324 @@ +import type { + KeyLike, + FlattenedJWE, + JWEHeaderParameters, + JWEKeyManagementHeaderParameters, + EncryptOptions, +} from '../../types.d' +import type { JWEKeyManagementHeaderResults } from '../../types.i.d' +import ivFactory from '../../lib/iv.js' +import { encode as base64url } from '../../runtime/base64url.js' +import random from '../../runtime/random.js' +import encrypt from '../../runtime/encrypt.js' +import { deflate } from '../../runtime/zlib.js' +import encryptKeyManagement from '../../lib/encrypt_key_management.js' + +import { JOSENotSupported, JWEInvalid } from '../../util/errors.js' +import isDisjoint from '../../lib/is_disjoint.js' +import { encoder, decoder, concat } from '../../lib/buffer_utils.js' +import validateCrit from '../../lib/validate_crit.js' + +const generateIv = ivFactory(random) +const checkCrit = validateCrit.bind(undefined, JWEInvalid, new Map()) + +/** + * The FlattenedEncrypt class is a utility for creating Flattened JWE + * objects. + * + * @example + * ``` + * // ESM import + * import FlattenedEncrypt from 'jose/jwe/flattened/encrypt' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: FlattenedEncrypt } = require('jose/jwe/flattened/encrypt') + * ``` + * + * @example + * ``` + * // usage + * import parseJwk from 'jose/jwk/parse' + * + * const encoder = new TextEncoder() + * const publicKey = await parseJwk({ + * e: 'AQAB', + * n: 'qpzYkTGRKSUcd12hZaJnYEKVLfdEsqu6HBAxZgRSvzLFj_zTSAEXjbf3fX47MPEHRw8NDcEXPjVOz84t4FTXYF2w2_LGWfp_myjV8pR6oUUncJjS7DhnUmTG5bpuK2HFXRMRJYz_iNR48xRJPMoY84jrnhdIFx8Tqv6w4ZHVyEvcvloPgwG3UjLidP6jmqbTiJtidVLnpQJRuFNFQJiluQXBZ1nOLC7raQshu7L9y0IatVU7vf0BPnmuSkcNNvmQkSta6ODQBPaL5-o5SW8H37vQjPDkrlJpreViNa3jqP5DB5HYUO-DMh4FegRv9gZWLDEvXpSd9A13YXCa9Q8K_w', + * kty: 'RSA' + * }, 'RSA-OAEP-256') + * + * const jwe = await new FlattenedEncrypt(encoder.encode('It’s a dangerous business, Frodo, going out your door.')) + * .setProtectedHeader({ alg: 'RSA-OAEP-256', enc: 'A256GCM' }) + * .setAdditionalAuthenticatedData(encoder.encode('The Fellowship of the Ring')) + * .encrypt(publicKey) + * + * console.log(jwe) + * ``` + */ +export default class FlattenedEncrypt { + private _plaintext: Uint8Array + + private _protectedHeader!: JWEHeaderParameters + + private _sharedUnprotectedHeader!: JWEHeaderParameters + + private _unprotectedHeader!: JWEHeaderParameters + + private _aad!: Uint8Array + + private _cek!: Uint8Array + + private _iv!: Uint8Array + + private _keyManagementParameters!: JWEKeyManagementHeaderParameters + + /** + * @param plaintext Binary representation of the plaintext to encrypt. + */ + constructor(plaintext: Uint8Array) { + this._plaintext = plaintext + } + + /** + * Sets the JWE Key Management parameters to be used when encrypting. + * Use of this is method is really only needed for ECDH-ES based algorithms + * when utilizing the Agreement PartyUInfo or Agreement PartyVInfo parameters. + * Other parameters will always be randomly generated when needed and missing. + * + * @param parameters JWE Key Management parameters. + */ + setKeyManagementParameters(parameters: JWEKeyManagementHeaderParameters) { + if (this._keyManagementParameters) { + throw new TypeError('setKeyManagementParameters can only be called once') + } + this._keyManagementParameters = parameters + return this + } + + /** + * Sets the JWE Protected Header on the FlattenedEncrypt object. + * + * @param protectedHeader JWE Protected Header. + */ + setProtectedHeader(protectedHeader: JWEHeaderParameters) { + if (this._protectedHeader) { + throw new TypeError('setProtectedHeader can only be called once') + } + this._protectedHeader = protectedHeader + return this + } + + /** + * Sets the JWE Shared Unprotected Header on the FlattenedEncrypt object. + * + * @param sharedUnprotectedHeader JWE Shared Unprotected Header. + */ + setSharedUnprotectedHeader(sharedUnprotectedHeader: JWEHeaderParameters) { + if (this._sharedUnprotectedHeader) { + throw new TypeError('setSharedUnprotectedHeader can only be called once') + } + this._sharedUnprotectedHeader = sharedUnprotectedHeader + return this + } + + /** + * Sets the JWE Per-Recipient Unprotected Header on the FlattenedEncrypt object. + * + * @param unprotectedHeader JWE Per-Recipient Unprotected Header. + */ + setUnprotectedHeader(unprotectedHeader: JWEHeaderParameters) { + if (this._unprotectedHeader) { + throw new TypeError('setUnprotectedHeader can only be called once') + } + this._unprotectedHeader = unprotectedHeader + return this + } + + /** + * Sets the Additional Authenticated Data on the FlattenedEncrypt object. + * + * @param aad Additional Authenticated Data. + */ + setAdditionalAuthenticatedData(aad: Uint8Array) { + this._aad = aad + return this + } + + /** + * Sets a content encryption key to use, by default a random suitable one + * is generated for the JWE enc" (Encryption Algorithm) Header Parameter. + * You do not need to invoke this method, it is only really intended for + * test and vector validation purposes. + * + * @param cek JWE Content Encryption Key. + */ + setContentEncryptionKey(cek: Uint8Array) { + if (this._cek) { + throw new TypeError('setContentEncryptionKey can only be called once') + } + this._cek = cek + return this + } + + /** + * Sets the JWE Initialization Vector to use for content encryption, by default + * a random suitable one is generated for the JWE enc" (Encryption Algorithm) + * Header Parameter. You do not need to invoke this method, it is only really + * intended for test and vector validation purposes. + * + * @param iv JWE Initialization Vector. + */ + setInitializationVector(iv: Uint8Array) { + if (this._iv) { + throw new TypeError('setInitializationVector can only be called once') + } + this._iv = iv + return this + } + + /** + * Encrypts and resolves the value of the Flattened JWE object. + * + * @param key Public Key or Secret to encrypt the JWE with. + * @param options JWE Encryption options. + */ + async encrypt(key: KeyLike, options?: EncryptOptions) { + if (!this._protectedHeader && !this._unprotectedHeader && !this._sharedUnprotectedHeader) { + throw new JWEInvalid( + 'either setProtectedHeader, setUnprotectedHeader, or sharedUnprotectedHeader must be called before #encrypt()', + ) + } + + if ( + !isDisjoint(this._protectedHeader, this._unprotectedHeader, this._sharedUnprotectedHeader) + ) { + throw new JWEInvalid( + 'JWE Shared Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint', + ) + } + + const joseHeader: JWEHeaderParameters = { + ...this._protectedHeader, + ...this._unprotectedHeader, + ...this._sharedUnprotectedHeader, + } + + checkCrit(this._protectedHeader, joseHeader) + + if ('zip' in joseHeader) { + if (!this._protectedHeader || !this._protectedHeader.zip) { + throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected') + } + + if (joseHeader.zip !== 'DEF') { + throw new JOSENotSupported( + 'unsupported JWE "zip" (Compression Algorithm) Header Parameter value', + ) + } + } + + const { alg, enc } = joseHeader + + if (!alg) { + throw new JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing') + } + + if (!enc) { + throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing') + } + + let encryptedKey: Uint8Array | undefined + + if (alg === 'dir') { + if (this._cek) { + throw new TypeError('setContentEncryptionKey cannot be called when using Direct Encryption') + } + } else if (alg === 'ECDH-ES') { + if (this._cek) { + throw new TypeError( + 'setContentEncryptionKey cannot be called when using Direct Key Agreement', + ) + } + } + + let cek: KeyLike + { + let parameters: JWEKeyManagementHeaderResults | undefined + ;({ cek, encryptedKey, parameters } = await encryptKeyManagement( + alg, + enc, + key, + this._cek, + this._keyManagementParameters, + )) + + if (parameters) { + if (!this._protectedHeader) { + this.setProtectedHeader(parameters) + } else { + this._protectedHeader = { ...this._protectedHeader, ...parameters } + } + } + } + + this._iv ||= await generateIv(enc) + + let additionalData: Uint8Array + let protectedHeader: Uint8Array + let aadMember: string | undefined + if (this._protectedHeader) { + protectedHeader = encoder.encode(base64url(JSON.stringify(this._protectedHeader))) + } else { + protectedHeader = encoder.encode('') + } + + if (this._aad) { + aadMember = base64url(this._aad) + additionalData = concat(protectedHeader, encoder.encode('.'), encoder.encode(aadMember)) + } else { + additionalData = protectedHeader + } + + let ciphertext: Uint8Array + let tag: Uint8Array + + if (joseHeader.zip === 'DEF') { + const deflated = await (options?.deflateRaw || deflate)(this._plaintext) + ;({ ciphertext, tag } = await encrypt(enc, deflated, cek, this._iv, additionalData)) + } else { + ;({ ciphertext, tag } = await encrypt(enc, this._plaintext, cek, this._iv, additionalData)) + } + + const jwe: FlattenedJWE = { + ciphertext: base64url(ciphertext), + iv: base64url(this._iv), + tag: base64url(tag), + } + + if (encryptedKey) { + jwe.encrypted_key = base64url(encryptedKey) + } + + if (aadMember) { + jwe.aad = aadMember + } + + if (this._protectedHeader) { + jwe.protected = decoder.decode(protectedHeader) + } + + if (this._sharedUnprotectedHeader) { + jwe.unprotected = this._sharedUnprotectedHeader + } + + if (this._unprotectedHeader) { + jwe.header = this._unprotectedHeader + } + + return jwe + } +} + +export type { KeyLike, FlattenedJWE, JWEHeaderParameters, JWEKeyManagementHeaderParameters } diff --git a/src/jwk/embedded.ts b/src/jwk/embedded.ts new file mode 100644 index 0000000000..71dafdc6db --- /dev/null +++ b/src/jwk/embedded.ts @@ -0,0 +1,64 @@ +/* eslint-disable jsdoc/require-param */ +import type { KeyObject } from 'crypto' +import { FlattenedJWSInput, JWSHeaderParameters } from '../types.d' +import parseJwk from './parse.js' +import isObject from '../lib/is_object.js' +import { JWSInvalid } from '../util/errors.js' + +/** + * EmbeddedJWK is an implementation of a GetKeyFunction intended to be used with the + * JWS/JWT verify operations whenever you need to opt-in to verify signatures with + * a public key embedded in the token's "jwk" (JSON Web Key) Header Parameter. + * It is recommended to combine this with the verify algorithms option to whitelist + * JWS algorithms to accept. + * + * @example + * ``` + * // ESM import + * import EmbeddedJWK from 'jose/jwk/embedded' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: EmbeddedJWK } = require('jose/jwk/embedded') + * ``` + * + * @example + * ``` + * // usage + * import jwtVerify from 'jose/jwt/verify' + * + * const jwt = 'eyJqd2siOnsiY3J2IjoiUC0yNTYiLCJ4IjoiVU05ZzVuS25aWFlvdldBbE03NmNMejl2VG96UmpfX0NIVV9kT2wtZ09vRSIsInkiOiJkczhhZVF3MWwyY0RDQTdiQ2tPTnZ3REtwWEFidFhqdnFDbGVZSDhXc19VIiwia3R5IjoiRUMifSwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJ1cm46ZXhhbXBsZTppc3N1ZXIiLCJhdWQiOiJ1cm46ZXhhbXBsZTphdWRpZW5jZSIsImlhdCI6MTYwNDU4MDc5NH0.60boak3_dErnW47ZPty1C0nrjeVq86EN_eK0GOq6K8w2OA0thKoBxFK4j-NuU9yZ_A9UKGxPT_G87DladBaV9g' + * + * const { payload, protectedHeader } = await jwtVerify(jwt, EmbeddedJWK, { + * issuer: 'urn:example:issuer', + * audience: 'urn:example:audience' + * }) + * + * console.log(protectedHeader) + * console.log(payload) + * ``` + */ +export default async function EmbeddedJWK( + protectedHeader: JWSHeaderParameters, + token: FlattenedJWSInput, +) { + const combinedHeader = { + ...protectedHeader, + ...token.header, + } + if (!isObject(combinedHeader.jwk)) { + throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a JSON object') + } + + const key = (await parseJwk(combinedHeader.jwk!, combinedHeader.alg!, true)) as + | CryptoKey + | KeyObject + + if (key.type !== 'public') { + throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a public key') + } + + return key +} diff --git a/src/jwk/parse.ts b/src/jwk/parse.ts new file mode 100644 index 0000000000..c45fccb783 --- /dev/null +++ b/src/jwk/parse.ts @@ -0,0 +1,95 @@ +import { decode as base64url } from '../runtime/base64url.js' +import asKeyObject from '../runtime/jwk_to_key.js' +import { JOSENotSupported } from '../util/errors.js' +import isObject from '../lib/is_object.js' +import type { JWK, KeyLike } from '../types.js' + +/** + * Converts a JWK to a runtime-specific key representation. Either JWK "alg" (Algorithm) + * Parameter must be present or the optional "alg" argument. When running on a platform + * using [Web Cryptography API](https://www.w3.org/TR/WebCryptoAPI/) the jwk parameters + * "use", "key_ops", and "ext" are also used in the resulting `CryptoKey`. + * + * @param jwk JSON Web Key. + * @param alg JSON Web Algorithm identifier to be used with the converted key. + * Default is the "alg" property on the JWK. + * @param octAsKeyObject Forces a symmetric key to be converted to a KeyObject or + * CryptoKey. Default is true unless JWK "ext" (Extractable) is true. + * + * @example + * ``` + * // ESM import + * import parseJwk from 'jose/jwk/parse' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: parseJwk } = require('jose/jwk/parse') + * ``` + * + * @example + * ``` + * // usage + * const ecPrivateKey = await parseJwk({ + * alg: 'ES256', + * crv: 'P-256', + * kty: 'EC', + * d: 'VhsfgSRKcvHCGpLyygMbO_YpXc7bVKwi12KQTE4yOR4', + * x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', + * y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' + * }) + * + * const rsaPublicKey = await parseJwk({ + * kty: 'RSA', + * e: 'AQAB', + * n: '12oBZRhCiZFJLcPg59LkZZ9mdhSMTKAQZYq32k_ti5SBB6jerkh-WzOMAO664r_qyLkqHUSp3u5SbXtseZEpN3XPWGKSxjsy-1JyEFTdLSYe6f9gfrmxkUF_7DTpq0gn6rntP05g2-wFW50YO7mosfdslfrTJYWHFhJALabAeYirYD7-9kqq9ebfFMF4sRRELbv9oi36As6Q9B3Qb5_C1rAzqfao_PCsf9EPsTZsVVVkA5qoIAr47lo1ipfiBPxUCCNSdvkmDTYgvvRm6ZoMjFbvOtgyts55fXKdMWv7I9HMD5HwE9uW839PWA514qhbcIsXEYSFMPMV6fnlsiZvQQ' + * }, 'PS256') + * ``` + */ +export default async function parseJwk( + jwk: JWK, + alg?: string, + octAsKeyObject?: boolean, +): Promise { + if (!isObject(jwk)) { + throw new TypeError('JWK must be an object') + } + + // eslint-disable-next-line no-param-reassign + alg ||= jwk.alg + + if (typeof alg !== 'string' || !alg) { + throw new TypeError('"alg" argument is required when "jwk.alg" is not present') + } + + switch (jwk.kty) { + case 'oct': + if (typeof jwk.k !== 'string' || !jwk.k) { + throw new TypeError('missing "k" (Key Value) Parameter value') + } + + // eslint-disable-next-line no-param-reassign, eqeqeq + octAsKeyObject ??= jwk.ext !== true + + if (octAsKeyObject) { + return asKeyObject({ ...jwk, alg, ext: false }) + } + + return base64url(jwk.k) + case 'RSA': + if ('oth' in jwk) { + throw new JOSENotSupported( + 'RSA JWK "oth" (Other Primes Info) Parameter value is unsupported', + ) + } + // eslint-disable-next-line no-fallthrough + case 'EC': + case 'OKP': + return asKeyObject({ ...jwk, alg }) + default: + throw new JOSENotSupported('unsupported "kty" (Key Type) Parameter value') + } +} + +export type { KeyLike, JWK } diff --git a/src/jwk/thumbprint.ts b/src/jwk/thumbprint.ts new file mode 100644 index 0000000000..e1104d8dab --- /dev/null +++ b/src/jwk/thumbprint.ts @@ -0,0 +1,85 @@ +import { JOSENotSupported, JWKInvalid } from '../util/errors.js' + +import digest from '../runtime/digest.js' +import { encode as base64url } from '../runtime/base64url.js' +import { encoder } from '../lib/buffer_utils.js' +import type { JWK } from '../types.d' +import isObject from '../lib/is_object.js' + +const check = (value: any, description: string) => { + if (typeof value !== 'string' || !value) { + throw new JWKInvalid(`${description} missing or invalid`) + } +} + +/** + * Calculates a base64url-encoded JSON Web Key (JWK) Thumbprint as per + * [RFC7638](https://tools.ietf.org/html/rfc7638). + * + * @param jwk JSON Web Key. + * @param digestAlgorithm Digest Algorithm to use for calculating the thumbprint. + * Default is sha256. Accepted is "sha256", "sha384", "sha512". + * + * @example + * ``` + * // ESM import + * import calculateThumbprint from 'jose/jwk/thumbprint' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: calculateThumbprint } = require('jose/jwk/thumbprint') + * ``` + * + * @example + * ``` + * // usage + * const thumbprint = await calculateThumbprint({ + * kty: 'RSA', + * e: 'AQAB', + * n: '12oBZRhCiZFJLcPg59LkZZ9mdhSMTKAQZYq32k_ti5SBB6jerkh-WzOMAO664r_qyLkqHUSp3u5SbXtseZEpN3XPWGKSxjsy-1JyEFTdLSYe6f9gfrmxkUF_7DTpq0gn6rntP05g2-wFW50YO7mosfdslfrTJYWHFhJALabAeYirYD7-9kqq9ebfFMF4sRRELbv9oi36As6Q9B3Qb5_C1rAzqfao_PCsf9EPsTZsVVVkA5qoIAr47lo1ipfiBPxUCCNSdvkmDTYgvvRm6ZoMjFbvOtgyts55fXKdMWv7I9HMD5HwE9uW839PWA514qhbcIsXEYSFMPMV6fnlsiZvQQ' + * }) + * + * console.log(thumbprint) + * ``` + */ +export default async function calculateThumbprint( + jwk: JWK, + digestAlgorithm: 'sha256' | 'sha384' | 'sha512' = 'sha256', +): Promise { + if (!isObject(jwk)) { + throw new TypeError('JWK must be an object') + } + + let components: JWK + switch (jwk.kty) { + case 'EC': + check(jwk.crv, '"crv" (Curve) Parameter') + check(jwk.x, '"x" (X Coordinate) Parameter') + check(jwk.y, '"y" (Y Coordinate) Parameter') + components = { crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y } + break + case 'OKP': + check(jwk.crv, '"crv" (Subtype of Key Pair) Parameter') + check(jwk.x, '"x" (Public Key) Parameter') + components = { crv: jwk.crv, kty: jwk.kty, x: jwk.x } + break + case 'RSA': + check(jwk.e, '"e" (Exponent) Parameter') + check(jwk.n, '"n" (Modulus) Parameter') + components = { e: jwk.e, kty: jwk.kty, n: jwk.n } + break + case 'oct': + check(jwk.k, '"k" (Key Value) Parameter') + components = { k: jwk.k, kty: jwk.kty } + break + default: + throw new JOSENotSupported('"kty" (Key Type) Parameter missing or unsupported') + } + + const data = encoder.encode(JSON.stringify(components)) + return base64url(await digest(digestAlgorithm, data)) +} + +export type { JWK } diff --git a/src/jwks/remote.ts b/src/jwks/remote.ts new file mode 100644 index 0000000000..236225f15a --- /dev/null +++ b/src/jwks/remote.ts @@ -0,0 +1,239 @@ +import type { KeyObject } from 'crypto' + +import type { JWSHeaderParameters, JWK, FlattenedJWSInput, GetKeyFunction } from '../types.d' +import parseJWK from '../jwk/parse.js' +import { + JWKSInvalid, + JOSENotSupported, + JWKSNoMatchingKey, + JWKSMultipleMatchingKeys, +} from '../util/errors.js' +import fetchJson from '../runtime/fetch.js' + +function getKtyFromAlg(alg: string) { + switch (alg.substr(0, 2)) { + case 'RS': + case 'PS': + return 'RSA' + case 'ES': + return 'EC' + case 'Ed': + return 'OKP' + default: + throw new JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set') + } +} + +interface Cache { + [alg: string]: KeyObject | CryptoKey +} + +/** + * Options for the remote JSON Web Key Set. + */ +export interface RemoteJWKSetOptions { + /** + * Timeout for the HTTP request. When reached the request will be + * aborted and the verification will fail. Default is 5000. + */ + timeoutDuration?: number + + /** + * Duration for which no more HTTP requests will be triggered + * after a previous successful fetch. Default is 30000. + */ + cooldownDuration?: number +} + +class RemoteJWKSet { + private _url: URL + + private _timeoutDuration: number + + private _cooldownDuration: number + + private _cooldownStarted?: number + + private _jwks?: { keys: JWK[] } + + private _cached: WeakMap = new WeakMap() + + private _pendingFetch?: ReturnType + + constructor(url: URL, options?: RemoteJWKSetOptions) { + if (!(url instanceof URL)) { + throw new TypeError('url must be an instance of URL') + } + this._url = new URL(url.href) + this._timeoutDuration = + typeof options?.timeoutDuration === 'number' ? options?.timeoutDuration : 5000 + this._cooldownDuration = + typeof options?.cooldownDuration === 'number' ? options?.cooldownDuration : 30000 + } + + coolingDown() { + if (typeof this._cooldownStarted === 'undefined') { + return false + } + + return Date.now() < this._cooldownStarted + this._cooldownDuration + } + + async getKey(protectedHeader: JWSHeaderParameters): Promise { + if (!this._jwks) { + await this.reload() + } + + const candidates = this._jwks!.keys.filter((jwk) => { + // filter keys based on the mapping of signature algorithms to Key Type + let candidate = jwk.kty === getKtyFromAlg(protectedHeader.alg!) + + // filter keys based on the JWK Key ID in the header + if (candidate && typeof protectedHeader.kid === 'string') { + candidate = protectedHeader.kid === jwk.kid + } + + // filter keys based on the key's declared Algorithm + if (candidate && typeof jwk.alg === 'string') { + candidate = protectedHeader.alg! === jwk.alg + } + + // filter keys based on the key's declared Public Key Use + if (candidate && typeof jwk.use === 'string') { + candidate = jwk.use === 'sig' + } + + // filter keys based on the key's declared Key Operations + if (candidate && Array.isArray(jwk.key_ops)) { + candidate = jwk.key_ops.includes('verify') + } + + // filter out non-applicable OKP Sub Types + if (candidate && protectedHeader.alg! === 'EdDSA') { + candidate = ['Ed25519', 'Ed448'].includes(jwk.crv!) + } + + // filter out non-applicable EC curves + if (candidate) { + switch (protectedHeader.alg!) { + case 'ES256': + candidate = jwk.crv === 'P-256' + break + case 'ES256K': + candidate = jwk.crv === 'secp256k1' + break + case 'ES384': + candidate = jwk.crv === 'P-384' + break + case 'ES512': + candidate = jwk.crv === 'P-521' + break + default: + } + } + + return candidate + }) + + const { 0: jwk, length } = candidates + + if (length === 0) { + if (this.coolingDown() === false) { + await this.reload() + return this.getKey(protectedHeader) + } + throw new JWKSNoMatchingKey() + } else if (length !== 1) { + throw new JWKSMultipleMatchingKeys() + } + + if (!this._cached.has(jwk)) { + this._cached.set(jwk, {}) + } + + const cached = this._cached.get(jwk)! + if (!(protectedHeader.alg! in cached)) { + const keyObject = (await parseJWK({ ...jwk, alg: protectedHeader.alg! })) as + | KeyObject + | CryptoKey + + if (keyObject.type !== 'public') { + throw new JWKSInvalid('JSON Web Key Set members must be public keys') + } + + cached[protectedHeader.alg!] = keyObject + } + + return cached[protectedHeader.alg!] + } + + async reload() { + if (!this._pendingFetch) { + this._pendingFetch = fetchJson(this._url, this._timeoutDuration) + .then((json: { keys: object[] }) => { + if ( + typeof json !== 'object' || + !json || + !('keys' in json) || + !Array.isArray(json.keys) || + json.keys.some((key: object) => typeof key !== 'object' || !key) + ) { + throw new JWKSInvalid('JSON Web Key Set malformed') + } + this._jwks = json + this._cooldownStarted = Date.now() + this._pendingFetch = undefined + }) + .catch((err) => { + this._pendingFetch = undefined + throw err + }) + } + + await this._pendingFetch + } +} + +/** + * Returns a function that resolves to a key object downloaded from a + * remote endpoint returning a JSON Web Key Set, that is, for example, + * an OAuth 2.0 or OIDC jwks_uri. Only a single public key must match + * the selection process. + * + * @example + * ``` + * // ESM import + * import createRemoteJWKSet from 'jose/jwks/remote' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: createRemoteJWKSet } = require('jose/jwks/remote') + * ``` + * + * @example + * ``` + * // usage + * import jwtVerify from 'jose/jwt/verify' + * + * const JWKS = createRemoteJWKSet(new URL('https://www.googleapis.com/oauth2/v3/certs')) + * + * const { payload, protectedHeader } = await jwtVerify(jwt, JWKS, { + * issuer: 'urn:example:issuer', + * audience: 'urn:example:audience' + * }) + * console.log(protectedHeader) + * console.log(payload) + * ``` + * + * @param url URL to fetch the JSON Web Key Set from. + * @param options Options for the remote JSON Web Key Set. + */ +export default function createRemoteJWKSet( + url: URL, + options?: RemoteJWKSetOptions, +): GetKeyFunction { + const set = new RemoteJWKSet(url, options) + return set.getKey.bind(set) +} diff --git a/src/jws/compact/sign.ts b/src/jws/compact/sign.ts new file mode 100644 index 0000000000..21d6721e43 --- /dev/null +++ b/src/jws/compact/sign.ts @@ -0,0 +1,79 @@ +/* eslint-disable no-underscore-dangle */ + +import FlattenedSign from '../flattened/sign.js' +import type { JWSHeaderParameters, KeyLike } from '../../types.d' + +/** + * The CompactSign class is a utility for creating Compact JWS strings. + * + * @example + * ``` + * // ESM import + * import CompactSign from 'jose/jws/compact/sign' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: CompactSign } = require('jose/jws/compact/sign') + * ``` + * + * @example + * ``` + * // usage + * import parseJwk from 'jose/jwk/parse' + * + * const encoder = new TextEncoder() + * const privateKey = await parseJwk({ + * alg: 'ES256', + * crv: 'P-256', + * kty: 'EC', + * d: 'VhsfgSRKcvHCGpLyygMbO_YpXc7bVKwi12KQTE4yOR4', + * x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', + * y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' + * }) + * + * const jws = await new CompactSign(encoder.encode('It’s a dangerous business, Frodo, going out your door.')) + * .setProtectedHeader({ alg: 'ES256' }) + * .sign(privateKey) + * + * console.log(jws) + * ``` + */ +export default class CompactSign { + private _flattened: FlattenedSign + + /** + * @param payload Binary representation of the payload to sign. + */ + constructor(payload: Uint8Array) { + this._flattened = new FlattenedSign(payload) + } + + /** + * Sets the JWS Protected Header on the Sign object. + * + * @param protectedHeader JWS Protected Header. + */ + setProtectedHeader(protectedHeader: JWSHeaderParameters) { + this._flattened.setProtectedHeader(protectedHeader) + return this + } + + /** + * Signs and resolves the value of the Compact JWS string. + * + * @param key Private Key or Secret to sign the JWS with. + */ + async sign(key: KeyLike): Promise { + const jws = await this._flattened.sign(key) + + if (jws.payload === undefined) { + throw new TypeError('use the flattened module for creating JWS with b64: false') + } + + return `${jws.protected}.${jws.payload}.${jws.signature}` + } +} + +export type { JWSHeaderParameters, KeyLike } diff --git a/src/jws/compact/verify.ts b/src/jws/compact/verify.ts new file mode 100644 index 0000000000..2106e28900 --- /dev/null +++ b/src/jws/compact/verify.ts @@ -0,0 +1,82 @@ +import verify from '../flattened/verify.js' +import { JWSInvalid } from '../../util/errors.js' +import type { + CompactVerifyResult, + FlattenedJWSInput, + GetKeyFunction, + JWSHeaderParameters, + KeyLike, + VerifyOptions, +} from '../../types.d' + +/** + * Interface for Compact JWS Verification dynamic key resolution. + * No token components have been verified at the time of this function call. + */ +export interface CompactVerifyGetKey + extends GetKeyFunction {} + +/** + * Verifies the signature and format of and afterwards decodes the Compact JWS. + * + * @param jws Compact JWS. + * @param key Key, or a function resolving a key, to verify the JWS with. + * @param options JWS Verify options. + * + * @example + * ``` + * // ESM import + * import compactVerify from 'jose/jws/compact/verify' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: compactVerify } = require('jose/jws/compact/verify') + * ``` + * + * @example + * ``` + * // usage + * import parseJwk from 'jose/jwk/parse' + * + * const decoder = new TextDecoder() + * const jws = 'eyJhbGciOiJFUzI1NiJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4.kkAs_gPPxWMI3rHuVlxHaTPfDWDoqdI8jSvuSmqV-8IHIWXg9mcAeC9ggV-45ZHRbiRJ3obUIFo1rHphPA5URg' + * const publicKey = await parseJwk({ + * alg: 'ES256', + * crv: 'P-256', + * kty: 'EC', + * x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', + * y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' + * }) + * + * const { payload, protectedHeader } = await compactVerify(jws, publicKey) + * + * console.log(protectedHeader) + * console.log(decoder.decode(payload)) + * ``` + */ +export default async function compactVerify( + jws: string, + key: KeyLike | CompactVerifyGetKey, + options?: VerifyOptions, +): Promise { + if (typeof jws !== 'string') { + throw new JWSInvalid('Compact JWS must be a string') + } + const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split('.') + + if (length !== 3) { + throw new JWSInvalid('Invalid Compact JWS') + } + + const verified = await verify( + { payload, protected: protectedHeader, signature }, + key as Parameters[1], + options, + ) + + return { payload: verified.payload, protectedHeader: verified.protectedHeader! } +} + +export type { KeyLike, VerifyOptions } diff --git a/src/jws/flattened/sign.ts b/src/jws/flattened/sign.ts new file mode 100644 index 0000000000..f4990a226e --- /dev/null +++ b/src/jws/flattened/sign.ts @@ -0,0 +1,170 @@ +/* eslint-disable no-underscore-dangle */ + +import isDisjoint from '../../lib/is_disjoint.js' +import { JWSInvalid } from '../../util/errors.js' +import { encoder, decoder, concat } from '../../lib/buffer_utils.js' + +import { encode as base64url } from '../../runtime/base64url.js' +import sign from '../../runtime/sign.js' +import type { KeyLike, FlattenedJWS, JWSHeaderParameters } from '../../types.d' +import checkKeyType from '../../lib/check_key_type.js' +import validateCrit from '../../lib/validate_crit.js' + +const checkExtensions = validateCrit.bind(undefined, JWSInvalid, new Map([['b64', true]])) + +/** + * The FlattenedSign class is a utility for creating Flattened JWS objects. + * + * @example + * ``` + * // ESM import + * import FlattenedSign from 'jose/jws/flattened/sign' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: FlattenedSign } = require('jose/jws/flattened/sign') + * ``` + * + * @example + * ``` + * // usage + * import parseJwk from 'jose/jwk/parse' + * + * const encoder = new TextEncoder() + * const privateKey = await parseJwk({ + * alg: 'ES256', + * crv: 'P-256', + * kty: 'EC', + * d: 'VhsfgSRKcvHCGpLyygMbO_YpXc7bVKwi12KQTE4yOR4', + * x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', + * y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' + * }) + * + * const jws = await new FlattenedSign(encoder.encode('It’s a dangerous business, Frodo, going out your door.')) + * .setProtectedHeader({ alg: 'ES256' }) + * .sign(privateKey) + * console.log(jws) + * ``` + */ +export default class FlattenedSign { + private _payload: Uint8Array + + private _protectedHeader!: JWSHeaderParameters + + private _unprotectedHeader!: JWSHeaderParameters + + /** + * @param payload Binary representation of the payload to sign. + */ + constructor(payload: Uint8Array) { + this._payload = payload + } + + /** + * Sets the JWS Protected Header on the FlattenedSign object. + * + * @param protectedHeader JWS Protected Header. + */ + setProtectedHeader(protectedHeader: JWSHeaderParameters) { + if (this._protectedHeader) { + throw new TypeError('setProtectedHeader can only be called once') + } + this._protectedHeader = protectedHeader + return this + } + + /** + * Sets the JWS Unprotected Header on the FlattenedSign object. + * + * @param unprotectedHeader JWS Unprotected Header. + */ + setUnprotectedHeader(unprotectedHeader: JWSHeaderParameters) { + if (this._unprotectedHeader) { + throw new TypeError('setUnprotectedHeader can only be called once') + } + this._unprotectedHeader = unprotectedHeader + return this + } + + /** + * Signs and resolves the value of the Flattened JWS object. + * + * @param key Private Key or Secret to sign the JWS with. + */ + async sign(key: KeyLike): Promise { + if (!this._protectedHeader && !this._unprotectedHeader) { + throw new JWSInvalid( + 'either setProtectedHeader or setUnprotectedHeader must be called before #sign()', + ) + } + + if (!isDisjoint(this._protectedHeader, this._unprotectedHeader)) { + throw new JWSInvalid( + 'JWS Protected and JWS Unprotected Header Parameter names must be disjoint', + ) + } + + const joseHeader: JWSHeaderParameters = { + ...this._protectedHeader, + ...this._unprotectedHeader, + } + + const extensions = checkExtensions(this._protectedHeader, joseHeader) + + let b64: boolean = true + if (extensions.has('b64')) { + b64 = this._protectedHeader.b64! + if (typeof b64 !== 'boolean') { + throw new JWSInvalid( + 'The "b64" (base64url-encode payload) Header Parameter must be a boolean', + ) + } + } + + const { alg } = joseHeader + + if (!alg) { + throw new JWSInvalid('missing JWS signature algorithm in JWS Header') + } + + checkKeyType(alg, key) + + let payload = this._payload + if (b64) { + payload = encoder.encode(base64url(payload)) + } + + let protectedHeader: Uint8Array + if (this._protectedHeader) { + protectedHeader = encoder.encode(base64url(JSON.stringify(this._protectedHeader))) + } else { + protectedHeader = encoder.encode('') + } + + const data = concat(protectedHeader, encoder.encode('.'), payload) + + const signature = await sign(alg, key, data) + + const jws: FlattenedJWS = { + signature: base64url(signature), + } + + if (b64) { + jws.payload = decoder.decode(payload) + } + + if (this._unprotectedHeader) { + jws.header = this._unprotectedHeader + } + + if (this._protectedHeader) { + jws.protected = decoder.decode(protectedHeader) + } + + return jws + } +} + +export type { KeyLike, FlattenedJWS, JWSHeaderParameters } diff --git a/src/jws/flattened/verify.ts b/src/jws/flattened/verify.ts new file mode 100644 index 0000000000..8df2f3100f --- /dev/null +++ b/src/jws/flattened/verify.ts @@ -0,0 +1,193 @@ +import { JOSEAlgNotAllowed, JWSInvalid, JWSSignatureVerificationFailed } from '../../util/errors.js' +import { concat, encoder, decoder } from '../../lib/buffer_utils.js' +import isDisjoint from '../../lib/is_disjoint.js' +import isObject from '../../lib/is_object.js' +import checkKeyType from '../../lib/check_key_type.js' + +import { decode as base64url } from '../../runtime/base64url.js' +import verify from '../../runtime/verify.js' +import validateCrit from '../../lib/validate_crit.js' +import validateAlgorithms from '../../lib/validate_algorithms.js' + +import type { + FlattenedVerifyResult, + KeyLike, + FlattenedJWSInput, + JWSHeaderParameters, + VerifyOptions, + GetKeyFunction, +} from '../../types.d' + +const checkExtensions = validateCrit.bind(undefined, JWSInvalid, new Map([['b64', true]])) +const checkAlgOption = validateAlgorithms.bind(undefined, 'algorithms') + +/** + * Interface for Flattened JWS Verification dynamic key resolution. + * No token components have been verified at the time of this function call. + */ +export interface FlattenedVerifyGetKey + extends GetKeyFunction {} + +/** + * Verifies the signature and format of and afterwards decodes the Flattened JWS. + * + * @param jws Flattened JWS. + * @param key Key, or a function resolving a key, to verify the JWS with. + * @param options JWS Verify options. + * + * @example + * ``` + * // ESM import + * import flattenedVerify from 'jose/jws/flattened/verify' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: flattenedVerify } = require('jose/jws/flattened/verify') + * ``` + * + * @example + * ``` + * // usage + * import parseJwk from 'jose/jwk/parse' + * + * const decoder = new TextDecoder() + * const jws = { + * signature: 'FVVOXwj6kD3DqdfD9yYqfT2W9jv-Nop4kOehp_DeDGNB5dQNSPRvntBY6xH3uxlCxE8na9d_kyhYOcanpDJ0EA', + * payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4', + * protected: 'eyJhbGciOiJFUzI1NiJ9' + * } + * const publicKey = await parseJwk({ + * alg: 'ES256', + * crv: 'P-256', + * kty: 'EC', + * x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', + * y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' + * }) + * + * const { payload, protectedHeader } = await flattenedVerify(jws, publicKey) + * + * console.log(protectedHeader) + * console.log(decoder.decode(payload)) + * ``` + */ +export default async function flattenedVerify( + jws: FlattenedJWSInput, + key: KeyLike | FlattenedVerifyGetKey, + options?: VerifyOptions, +): Promise { + if (!isObject(jws)) { + throw new JWSInvalid('Flattened JWS must be an object') + } + + if (!('protected' in jws) && !('header' in jws)) { + throw new JWSInvalid('Flattened JWS must have either of the "protected" or "header" members') + } + + if ('protected' in jws && typeof jws.protected !== 'string') { + throw new JWSInvalid('JWS Protected Header incorrect type') + } + + if (!('payload' in jws)) { + throw new JWSInvalid('JWS Payload missing') + } + + if (!('signature' in jws) || typeof jws.signature !== 'string') { + throw new JWSInvalid('JWS Signature missing or incorrect type') + } + + if ('header' in jws && !isObject(jws.header)) { + throw new JWSInvalid('JWS Unprotected Header incorrect type') + } + + let parsedProt: JWSHeaderParameters = {} + if (jws.protected) { + const protectedHeader = base64url(jws.protected) + parsedProt = JSON.parse(decoder.decode(protectedHeader)) + } + if (!isDisjoint(parsedProt, jws.header)) { + throw new JWSInvalid( + 'JWS Protected and JWS Unprotected Header Parameter names must be disjoint', + ) + } + + const joseHeader: JWSHeaderParameters = { + ...parsedProt, + ...jws.header, + } + + const extensions = checkExtensions(parsedProt, joseHeader) + + let b64: boolean = true + if (extensions.has('b64')) { + b64 = parsedProt.b64! + if (typeof b64 !== 'boolean') { + throw new JWSInvalid( + 'The "b64" (base64url-encode payload) Header Parameter must be a boolean', + ) + } + } + + const { alg } = joseHeader + + if (!alg) { + throw new JWSInvalid('missing JWS signature algorithm in JWS Header') + } + + const algorithms = options && checkAlgOption(options.algorithms) + + if (algorithms && !algorithms.has(alg)) { + throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter not allowed') + } + + if (b64) { + if (typeof jws.payload !== 'string') { + throw new JWSInvalid('JWS Payload must be a string') + } + } else if (typeof jws.payload !== 'string' && !(jws.payload instanceof Uint8Array)) { + throw new JWSInvalid('JWS Payload must be a string or an Uint8Array instance') + } + + if (typeof key === 'function') { + // eslint-disable-next-line no-param-reassign + key = await key(parsedProt, jws) + } + + checkKeyType(alg, key) + + const data = concat( + encoder.encode(jws.protected || ''), + encoder.encode('.'), + typeof jws.payload === 'string' ? encoder.encode(jws.payload) : jws.payload, + ) + const signature = base64url(jws.signature) + const verified = await verify(alg, key, signature, data) + + if (!verified) { + throw new JWSSignatureVerificationFailed() + } + + let payload: Uint8Array + if (b64) { + payload = base64url(jws.payload) + } else if (typeof jws.payload === 'string') { + payload = encoder.encode(jws.payload) + } else { + payload = jws.payload + } + + const result: FlattenedVerifyResult = { payload } + + if ('protected' in jws) { + result.protectedHeader = parsedProt + } + + if ('header' in jws) { + result.unprotectedHeader = jws.header + } + + return result +} + +export type { KeyLike, FlattenedJWSInput, GetKeyFunction, JWSHeaderParameters, VerifyOptions } diff --git a/src/jwt/decrypt.ts b/src/jwt/decrypt.ts new file mode 100644 index 0000000000..49c3386c7b --- /dev/null +++ b/src/jwt/decrypt.ts @@ -0,0 +1,105 @@ +import decrypt from '../jwe/compact/decrypt.js' +import type { + KeyLike, + DecryptOptions, + JWTPayload, + JWTClaimVerificationOptions, + GetKeyFunction, + JWEHeaderParameters, + FlattenedJWE, + JWTDecryptResult, +} from '../types.d' +import jwtPayload from '../lib/jwt_claims_set.js' +import { JWTClaimValidationFailed } from '../util/errors.js' + +/** + * Combination of JWE Decryption options and JWT Claims Set verification options. + */ +interface JWTDecryptOptions extends DecryptOptions, JWTClaimVerificationOptions {} + +/** + * Interface for JWT Decryption dynamic key resolution. + * No token components have been verified at the time of this function call. + */ +export interface JWTDecryptGetKey extends GetKeyFunction {} + +/** + * Verifies the JWT format (to be a JWE Compact format), decrypts the ciphertext, validates the JWT Claims Set. + * + * @param jwt JSON Web Token value (encoded as JWE). + * @param key Private Key or Secret, or a function resolving one, to decrypt and verify the JWT with. + * @param options JWT Decryption and JWT Claims Set validation options. + * + * @example + * ``` + * // ESM import + * import jwtDecrypt from 'jose/jwt/decrypt' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: jwtDecrypt } = require('jose/jwt/decrypt') + * ``` + * + * @example + * ``` + * // usage + * const jwt = 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..KVcNLqK-3-8ZkYIC.xSwF4VxO0kUMUD2W-cifsNUxnr-swyBq-nADBptyt6y9n79-iNc5b0AALJpRwc0wwDkJw8hNOMjApNUTMsK9b-asToZ3DXFMvwfJ6n1aWefvd7RsoZ2LInWFfVAuttJDzoGB.uuexQoWHwrLMEYRElT8pBQ' + * const secretKey = Uint8Array.from([ + * 206, 203, 53, 165, 235, 214, 153, 188, + * 248, 225, 1, 132, 105, 204, 75, 42, + * 186, 185, 24, 223, 136, 66, 116, 59, + * 183, 155, 52, 52, 101, 167, 201, 85 + * ]) + * + * const { payload, protectedHeader } = await jwtDecrypt(jwt, secretKey, { + * issuer: 'urn:example:issuer', + * audience: 'urn:example:audience' + * }) + * + * console.log(protectedHeader) + * console.log(payload) + * ``` + */ +export default async function jwtDecrypt( + jwt: string, + key: KeyLike | JWTDecryptGetKey, + options?: JWTDecryptOptions, +): Promise { + const decrypted = await decrypt(jwt, key, options) + const payload = jwtPayload(decrypted.protectedHeader, decrypted.plaintext, options) + + const { protectedHeader } = decrypted + + if ('iss' in protectedHeader && protectedHeader.iss !== payload.iss) { + throw new JWTClaimValidationFailed( + 'replicated "iss" claim header parameter mismatch', + 'iss', + 'mismatch', + ) + } + + if ('sub' in protectedHeader && protectedHeader.sub !== payload.sub) { + throw new JWTClaimValidationFailed( + 'replicated "sub" claim header parameter mismatch', + 'sub', + 'mismatch', + ) + } + + if ( + 'aud' in protectedHeader && + JSON.stringify(protectedHeader.aud) !== JSON.stringify(payload.aud) + ) { + throw new JWTClaimValidationFailed( + 'replicated "aud" claim header parameter mismatch', + 'aud', + 'mismatch', + ) + } + + return { payload, protectedHeader } +} + +export type { KeyLike, DecryptOptions, JWTPayload, JWTDecryptOptions } diff --git a/src/jwt/encrypt.ts b/src/jwt/encrypt.ts new file mode 100644 index 0000000000..cb1aaed5fe --- /dev/null +++ b/src/jwt/encrypt.ts @@ -0,0 +1,185 @@ +/* eslint-disable no-underscore-dangle */ + +import CompactEncrypt from '../jwe/compact/encrypt.js' +import { + EncryptOptions, + JWEHeaderParameters, + JWEKeyManagementHeaderParameters, + JWTPayload, + KeyLike, +} from '../types.d' +import { encoder } from '../lib/buffer_utils.js' +import ProduceJWT from '../lib/jwt_producer.js' + +/** + * The EncryptJWT class is a utility for creating Compact JWE formatted JWT strings. + * + * @example + * ``` + * // ESM import + * import EncryptJWT from 'jose/jwt/encrypt' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: EncryptJWT } = require('jose/jwt/encrypt') + * ``` + * + * @example + * ``` + * // usage + * const secretKey = Uint8Array.from([ + * 206, 203, 53, 165, 235, 214, 153, 188, + * 248, 225, 1, 132, 105, 204, 75, 42, + * 186, 185, 24, 223, 136, 66, 116, 59, + * 183, 155, 52, 52, 101, 167, 201, 85 + * ]) + * const jwt = await new EncryptJWT({ 'urn:example:claim': true }) + * .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' }) + * .setIssuedAt() + * .setIssuer('urn:example:issuer') + * .setAudience('urn:example:audience') + * .setExpirationTime('2h') + * .encrypt(secretKey) + * + * console.log(jwt) + * ``` + */ +export default class EncryptJWT extends ProduceJWT { + private _cek!: Uint8Array + + private _iv!: Uint8Array + + private _keyManagementParameters!: JWEKeyManagementHeaderParameters + + private _protectedHeader!: JWEHeaderParameters + + private _replicateIssuerAsHeader!: boolean + + private _replicateSubjectAsHeader!: boolean + + private _replicateAudienceAsHeader!: boolean + + /** + * Sets the JWE Protected Header on the EncryptJWT object. + * + * @param protectedHeader JWE Protected Header. + * Must contain an "alg" (JWE Algorithm) and "enc" (JWE + * Encryption Algorithm) properties. + */ + setProtectedHeader(protectedHeader: JWEHeaderParameters) { + if (this._protectedHeader) { + throw new TypeError('setProtectedHeader can only be called once') + } + this._protectedHeader = protectedHeader + return this + } + + /** + * Sets the JWE Key Management parameters to be used when encrypting. + * Use of this is method is really only needed for ECDH-ES based algorithms + * when utilizing the Agreement PartyUInfo or Agreement PartyVInfo parameters. + * Other parameters will always be randomly generated when needed and missing. + * + * @param parameters JWE Key Management parameters. + */ + setKeyManagementParameters(parameters: JWEKeyManagementHeaderParameters) { + if (this._keyManagementParameters) { + throw new TypeError('setKeyManagementParameters can only be called once') + } + this._keyManagementParameters = parameters + return this + } + + /** + * Sets a content encryption key to use, by default a random suitable one + * is generated for the JWE enc" (Encryption Algorithm) Header Parameter. + * You do not need to invoke this method, it is only really intended for + * test and vector validation purposes. + * + * @param cek JWE Content Encryption Key. + */ + setContentEncryptionKey(cek: Uint8Array) { + if (this._cek) { + throw new TypeError('setContentEncryptionKey can only be called once') + } + this._cek = cek + return this + } + + /** + * Sets the JWE Initialization Vector to use for content encryption, by default + * a random suitable one is generated for the JWE enc" (Encryption Algorithm) + * Header Parameter. You do not need to invoke this method, it is only really + * intended for test and vector validation purposes. + * + * @param iv JWE Initialization Vector. + */ + setInitializationVector(iv: Uint8Array) { + if (this._iv) { + throw new TypeError('setInitializationVector can only be called once') + } + this._iv = iv + return this + } + + /** + * Replicates the "iss" (Issuer) Claim as a JWE Protected Header Parameter as per + * [RFC7519#section-5.3](https://tools.ietf.org/html/rfc7519#section-5.3). + */ + replicateIssuerAsHeader() { + this._replicateIssuerAsHeader = true + return this + } + + /** + * Replicates the "sub" (Subject) Claim as a JWE Protected Header Parameter as per + * [RFC7519#section-5.3](https://tools.ietf.org/html/rfc7519#section-5.3). + */ + replicateSubjectAsHeader() { + this._replicateSubjectAsHeader = true + return this + } + + /** + * Replicates the "aud" (Audience) Claim as a JWE Protected Header Parameter as per + * [RFC7519#section-5.3](https://tools.ietf.org/html/rfc7519#section-5.3). + */ + replicateAudienceAsHeader() { + this._replicateAudienceAsHeader = true + return this + } + + /** + * Encrypts and returns the JWT. + * + * @param key Public Key or Secret to encrypt the JWT with. + * @param options JWE Encryption options. + */ + async encrypt(key: KeyLike, options?: EncryptOptions): Promise { + const enc = new CompactEncrypt(encoder.encode(JSON.stringify(this._payload))) + if (this._replicateIssuerAsHeader) { + this._protectedHeader = { ...this._protectedHeader, iss: this._payload.iss } + } + if (this._replicateSubjectAsHeader) { + this._protectedHeader = { ...this._protectedHeader, sub: this._payload.sub } + } + if (this._replicateAudienceAsHeader) { + this._protectedHeader = { ...this._protectedHeader, aud: this._payload.aud } + } + enc.setProtectedHeader(this._protectedHeader) + if (this._iv) { + enc.setInitializationVector(this._iv) + } + if (this._cek) { + enc.setContentEncryptionKey(this._cek) + } + if (this._keyManagementParameters) { + enc.setKeyManagementParameters(this._keyManagementParameters) + } + return enc.encrypt(key, options) + } +} + +export type { JWEHeaderParameters, JWTPayload, KeyLike } diff --git a/src/jwt/sign.ts b/src/jwt/sign.ts new file mode 100644 index 0000000000..5d92cbd542 --- /dev/null +++ b/src/jwt/sign.ts @@ -0,0 +1,77 @@ +/* eslint-disable no-underscore-dangle */ + +import CompactSign from '../jws/compact/sign.js' +import { JWTInvalid } from '../util/errors.js' +import { JWSHeaderParameters, JWTPayload, KeyLike } from '../types.d' +import { encoder } from '../lib/buffer_utils.js' +import ProduceJWT from '../lib/jwt_producer.js' + +/** + * The SignJWT class is a utility for creating Compact JWS formatted JWT strings. + * + * @example + * ``` + * // ESM import + * import SignJWT from 'jose/jwt/sign' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: SignJWT } = require('jose/jwt/sign') + * ``` + * + * @example + * ``` + * // usage + * import parseJwk from 'jose/jwk/parse' + * + * const privateKey = await parseJwk({ + * alg: 'ES256', + * crv: 'P-256', + * kty: 'EC', + * d: 'VhsfgSRKcvHCGpLyygMbO_YpXc7bVKwi12KQTE4yOR4', + * x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', + * y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' + * }) + * + * const jwt = await new SignJWT({ 'urn:example:claim': true }) + * .setProtectedHeader({ alg: 'ES256' }) + * .setIssuedAt() + * .setIssuer('urn:example:issuer') + * .setAudience('urn:example:audience') + * .setExpirationTime('2h') + * .sign(privateKey) + * + * console.log(jwt) + * ``` + */ +export default class SignJWT extends ProduceJWT { + private _protectedHeader!: JWSHeaderParameters + + /** + * Sets the JWS Protected Header on the SignJWT object. + * + * @param protectedHeader JWS Protected Header. + */ + setProtectedHeader(protectedHeader: JWSHeaderParameters) { + this._protectedHeader = protectedHeader + return this + } + + /** + * Signs and returns the JWT. + * + * @param key Private Key or Secret to sign the JWT with. + */ + async sign(key: KeyLike): Promise { + const sig = new CompactSign(encoder.encode(JSON.stringify(this._payload))) + sig.setProtectedHeader(this._protectedHeader) + if (this._protectedHeader.crit?.includes('b64') && this._protectedHeader.b64 === false) { + throw new JWTInvalid('JWTs MUST NOT use unencoded payload') + } + return sig.sign(key) + } +} + +export type { JWSHeaderParameters, JWTPayload, KeyLike } diff --git a/src/jwt/unsecured.ts b/src/jwt/unsecured.ts new file mode 100644 index 0000000000..40a51a9f74 --- /dev/null +++ b/src/jwt/unsecured.ts @@ -0,0 +1,104 @@ +/* eslint-disable no-underscore-dangle */ + +import { JWSHeaderParameters, JWTClaimVerificationOptions, JWTPayload } from '../types.d' +import { decoder } from '../lib/buffer_utils.js' +import * as base64url from '../runtime/base64url.js' +import { JWTInvalid } from '../util/errors.js' +import jwtPayload from '../lib/jwt_claims_set.js' +import ProduceJWT from '../lib/jwt_producer.js' + +/** + * The UnsecuredJWT class is a utility for creating `{ "alg": "none" }` Unsecured JWTs. + * + * @example + * ``` + * // ESM import + * import UnsecuredJWT from 'jose/jwt/unsecured' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: UnsecuredJWT } = require('jose/jwt/unsecured') + * ``` + * + * @example + * ``` + * // encoding + * + * const unsecuredJwt = new UnsecuredJWT({ 'urn:example:claim': true }) + * .setIssuedAt() + * .setIssuer('urn:example:issuer') + * .setAudience('urn:example:audience') + * .setExpirationTime('2h') + * .encode() + * + * console.log(unsecuredJwt) + * ``` + * + * @example + * ``` + * // decoding + * + * const payload = new UnsecuredJWT.decode(jwt, { + * issuer: 'urn:example:issuer', + * audience: 'urn:example:audience' + * }) + * + * console.log(payload) + * ``` + */ +export default class UnsecuredJWT extends ProduceJWT { + /** + * Encodes the Unsecured JWT. + */ + encode(): string { + const header = base64url.encode(JSON.stringify({ alg: 'none' })) + const payload = base64url.encode(JSON.stringify(this._payload)) + + return `${header}.${payload}.` + } + + /** + * Decodes an unsecured JWT. + * + * @param jwt Unsecured JWT to decode the payload of. + * @param options JWT Claims Set validation options. + * + * @example + * ``` + * // decoding + * const { payload, header } = UnsecuredJWT.decode(unsecuredJwt) + * + * console.log(header) + * console.log(payload) + * ``` + */ + static decode( + jwt: string, + options?: JWTClaimVerificationOptions, + ): { payload: JWTPayload; header: JWSHeaderParameters } { + if (typeof jwt !== 'string') { + throw new JWTInvalid('Unsecured JWT must be a string') + } + const { 0: encodedHeader, 1: encodedPayload, 2: signature, length } = jwt.split('.') + + if (length !== 3 || signature !== '') { + throw new JWTInvalid('Invalid Unsecured JWT') + } + + let header: JWSHeaderParameters + try { + header = JSON.parse(decoder.decode(base64url.decode(encodedHeader))) + if (header.alg !== 'none') throw new Error() + } catch { + throw new JWTInvalid('Invalid Unsecured JWT') + } + + const payload = jwtPayload(header, base64url.decode(encodedPayload), options) + + return { payload, header } + } +} + +export type { JWSHeaderParameters, JWTPayload } diff --git a/src/jwt/verify.ts b/src/jwt/verify.ts new file mode 100644 index 0000000000..8c2a2b0364 --- /dev/null +++ b/src/jwt/verify.ts @@ -0,0 +1,76 @@ +import verify from '../jws/compact/verify.js' +import type { + KeyLike, + VerifyOptions, + JWTPayload, + JWTClaimVerificationOptions, + JWSHeaderParameters, + GetKeyFunction, + FlattenedJWSInput, + JWTVerifyResult, +} from '../types.d' +import jwtPayload from '../lib/jwt_claims_set.js' + +/** + * Combination of JWS Verification options and JWT Claims Set verification options. + */ +interface JWTVerifyOptions extends VerifyOptions, JWTClaimVerificationOptions {} + +/** + * Interface for JWT Verification dynamic key resolution. + * No token components have been verified at the time of this function call. + */ +export interface JWTVerifyGetKey extends GetKeyFunction {} + +/** + * Verifies the JWT format (to be a JWS Compact format), verifies the JWS signature, validates the JWT Claims Set. + * + * @param jwt JSON Web Token value (encoded as JWS). + * @param key Key, or a function resolving a key, to verify the JWT with. + * @param options JWT Decryption and JWT Claims Set validation options. + * + * @example + * ``` + * // ESM import + * import jwtVerify from 'jose/jwt/verify' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: jwtVerify } = require('jose/jwt/verify') + * ``` + * + * @example + * ``` + * // usage + * import parseJwk from 'jose/jwk/parse' + * + * const jwt = 'eyJhbGciOiJFUzI1NiJ9.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6dHJ1ZSwiaWF0IjoxNjA0MzE1MDc0LCJpc3MiOiJ1cm46ZXhhbXBsZTppc3N1ZXIiLCJhdWQiOiJ1cm46ZXhhbXBsZTphdWRpZW5jZSJ9.hx1nOfAT5LlXuzu8O-bhjXBGpklWDt2EsHw7-MDn49NrnwvVsstNhEnkW2ddauB7eSikFtUNeumLpFI9CWDBsg' + * const publicKey = await parseJwk({ + * alg: 'ES256', + * crv: 'P-256', + * kty: 'EC', + * x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', + * y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' + * }) + * const { payload, protectedHeader } = await jwtVerify(jwt, publicKey, { + * issuer: 'urn:example:issuer', + * audience: 'urn:example:audience' + * }) + * + * console.log(protectedHeader) + * console.log(payload) + * ``` + */ +export default async function jwtVerify( + jwt: string, + key: KeyLike | JWTVerifyGetKey, + options?: JWTVerifyOptions, +): Promise { + const verified = await verify(jwt, key, options) + const payload = jwtPayload(verified.protectedHeader, verified.payload, options) + return { payload, protectedHeader: verified.protectedHeader } +} + +export type { KeyLike, JWTPayload, JWTVerifyOptions, JWSHeaderParameters, GetKeyFunction } diff --git a/src/lib/buffer_utils.ts b/src/lib/buffer_utils.ts new file mode 100644 index 0000000000..5913544f0c --- /dev/null +++ b/src/lib/buffer_utils.ts @@ -0,0 +1,66 @@ +/* eslint-disable no-await-in-loop */ + +export const encoder = new TextEncoder() +export const decoder = new TextDecoder() + +const MAX_INT32 = 2 ** 32 + +export function concat(...buffers: Uint8Array[]): Uint8Array { + const size = buffers.reduce((acc, { length }) => acc + length, 0) + const buf = new Uint8Array(size) + let i = 0 + buffers.forEach((buffer) => { + buf.set(buffer, i) + i += buffer.length + }) + return buf +} + +export function p2s(alg: string, p2sInput: Uint8Array) { + return concat(encoder.encode(alg), new Uint8Array([0]), p2sInput) +} + +function writeUInt32BE(buf: Uint8Array, value: number, offset?: number) { + if (value < 0 || value >= MAX_INT32) { + throw new RangeError(`value must be >= 0 and <= ${MAX_INT32 - 1}. Received ${value}`) + } + buf.set([value >>> 24, value >>> 16, value >>> 8, value & 0xff], offset) +} + +export function uint64be(value: number) { + const high = Math.floor(value / MAX_INT32) + const low = value % MAX_INT32 + const buf = new Uint8Array(8) + writeUInt32BE(buf, high, 0) + writeUInt32BE(buf, low, 4) + return buf +} + +export function uint32be(value: number) { + const buf = new Uint8Array(4) + writeUInt32BE(buf, value) + return buf +} + +export function lengthAndInput(input: Uint8Array) { + return concat(uint32be(input.length), input) +} + +export async function concatKdf(digest: any, secret: Uint8Array, bits: number, value: Uint8Array) { + const iterations = Math.ceil((bits >> 3) / 32) + let res!: Uint8Array + + for (let iter = 1; iter <= iterations; iter++) { + const buf = new Uint8Array(4 + secret.length + value.length) + buf.set(uint32be(iter)) + buf.set(secret, 4) + buf.set(value, 4 + secret.length) + if (!res) { + res = await digest(buf) + } else { + res = concat(res, await digest(buf)) + } + } + res = res.slice(0, bits >> 3) + return res +} diff --git a/src/lib/cek.ts b/src/lib/cek.ts new file mode 100644 index 0000000000..7d587dcd5b --- /dev/null +++ b/src/lib/cek.ts @@ -0,0 +1,24 @@ +import type { AsyncOrSync } from '../types.i.d' +import { JOSENotSupported } from '../util/errors.js' + +const bitLengths = new Map([ + ['A128CBC-HS256', 256], + ['A128GCM', 128], + ['A192CBC-HS384', 384], + ['A192GCM', 192], + ['A256CBC-HS512', 512], + ['A256GCM', 256], +]) + +const factory = (random: (array: Uint8Array) => AsyncOrSync) => ( + alg: string, +): AsyncOrSync => { + const bitLength = bitLengths.get(alg) + if (!bitLength) { + throw new JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`) + } + + return random(new Uint8Array(bitLength >> 3)) +} +export default factory +export { bitLengths } diff --git a/src/lib/check_iv_length.ts b/src/lib/check_iv_length.ts new file mode 100644 index 0000000000..9124373d5b --- /dev/null +++ b/src/lib/check_iv_length.ts @@ -0,0 +1,10 @@ +import { JWEInvalid } from '../util/errors.js' +import { bitLengths } from './iv.js' + +const checkIvLength = (enc: string, iv: Uint8Array) => { + if (iv.length << 3 !== bitLengths.get(enc)) { + throw new JWEInvalid('Invalid Initialization Vector length') + } +} + +export default checkIvLength diff --git a/src/lib/check_key_type.ts b/src/lib/check_key_type.ts new file mode 100644 index 0000000000..a5db395f95 --- /dev/null +++ b/src/lib/check_key_type.ts @@ -0,0 +1,30 @@ +import type { KeyLike } from '../types.d' + +const checkKeyType = (alg: string, key: KeyLike): void => { + if ( + alg.startsWith('HS') || + alg === 'dir' || + alg.startsWith('PBES2') || + alg.match(/^A\d{3}(?:GCM)KW$/) + ) { + if (key instanceof Uint8Array || key.type === 'secret') { + return + } + + throw new TypeError( + 'CryptoKey or KeyObject instances for symmetric algorithms must be of type "secret"', + ) + } + + if (key instanceof Uint8Array) { + throw new TypeError('CryptoKey or KeyObject instances must be used for asymmetric algorithms') + } + + if (key.type === 'secret') { + throw new TypeError( + 'CryptoKey or KeyObject instances for asymmetric algorithms must not be of type "secret"', + ) + } +} + +export default checkKeyType diff --git a/src/lib/check_p2s.ts b/src/lib/check_p2s.ts new file mode 100644 index 0000000000..8e267cd396 --- /dev/null +++ b/src/lib/check_p2s.ts @@ -0,0 +1,7 @@ +import { JWEInvalid } from '../util/errors.js' + +export default function checkP2s(p2s: Uint8Array) { + if (!(p2s instanceof Uint8Array) || p2s.length < 8) { + throw new JWEInvalid('PBES2 Salt Input must be 8 or more octets') + } +} diff --git a/src/lib/decrypt_key_management.ts b/src/lib/decrypt_key_management.ts new file mode 100644 index 0000000000..ff384a283f --- /dev/null +++ b/src/lib/decrypt_key_management.ts @@ -0,0 +1,119 @@ +import type { JWEHeaderParameters, KeyLike } from '../types.d' +import type { JWEKeyManagementHeaderResults } from '../types.i.d' +import { JOSENotSupported, JWEInvalid } from '../util/errors.js' +import { unwrap as aesKw } from '../runtime/aeskw.js' +import * as ECDH from '../runtime/ecdhes.js' +import { decrypt as pbes2Kw } from '../runtime/pbes2kw.js' +import { decrypt as rsaEs } from '../runtime/rsaes.js' +import { unwrap as aesGcmKw } from '../runtime/aesgcmkw.js' +import { decode as base64url } from '../runtime/base64url.js' +import { bitLengths as cekLengths } from '../lib/cek.js' + +function assertEnryptedKey(encryptedKey: any) { + if (!encryptedKey) { + throw new JWEInvalid('JWE Encrypted Key missing') + } +} + +function assertHeaderParameter(joseHeader: object, parameter: string, name: string) { + if (!(parameter in joseHeader)) { + throw new JWEInvalid(`JOSE Header ${name} (${parameter}) missing`) + } +} + +async function decryptKeyManagement( + alg: string, + key: KeyLike, + encryptedKey: Uint8Array | undefined, + joseHeader: JWEKeyManagementHeaderResults & JWEHeaderParameters, +): Promise { + switch (alg) { + case 'dir': { + // Direct Encryption + if (encryptedKey !== undefined) { + throw new JWEInvalid('Encountered unexpected JWE Encrypted Key') + } + return key + } + case 'ECDH-ES': + // Direct Key Agreement + if (encryptedKey !== undefined) { + throw new JWEInvalid('Encountered unexpected JWE Encrypted Key') + } + // eslint-disable-next-line no-fallthrough + case 'ECDH-ES+A128KW': + case 'ECDH-ES+A192KW': + case 'ECDH-ES+A256KW': { + // Direct Key Agreement + assertHeaderParameter(joseHeader, 'epk', 'Ephemeral Public Key') + if (!ECDH.ecdhAllowed(key)) { + throw new JOSENotSupported('ECDH not allowed or unsupported by your javascript runtime') + } + const ephemeralKey = await ECDH.publicJwkToEphemeralKey(joseHeader.epk!) + let partyUInfo!: Uint8Array + let partyVInfo!: Uint8Array + if (joseHeader.apu) partyUInfo = base64url(joseHeader.apu) + if (joseHeader.apv) partyVInfo = base64url(joseHeader.apv) + const sharedSecret = await ECDH.deriveKey( + ephemeralKey, + key, + alg === 'ECDH-ES' ? joseHeader.enc! : alg, + parseInt(alg.substr(-5, 3), 10) || (cekLengths.get(joseHeader.enc!) as number), + partyUInfo, + partyVInfo, + ) + + if (alg === 'ECDH-ES') { + return sharedSecret + } + + // Key Agreement with Key Wrapping + assertEnryptedKey(encryptedKey) + const kwAlg = alg.substr(-6) + return aesKw(kwAlg, sharedSecret, encryptedKey!) + } + case 'RSA1_5': + case 'RSA-OAEP': + case 'RSA-OAEP-256': + case 'RSA-OAEP-384': + case 'RSA-OAEP-512': { + // Key Encryption (RSA) + assertEnryptedKey(encryptedKey) + return rsaEs(alg, key, encryptedKey!) + } + case 'PBES2-HS256+A128KW': + case 'PBES2-HS384+A192KW': + case 'PBES2-HS512+A256KW': { + // Key Encryption (PBES2) + assertEnryptedKey(encryptedKey) + assertHeaderParameter(joseHeader, 'p2c', 'PBES2 Count') + assertHeaderParameter(joseHeader, 'p2s', 'PBES2 Salt') + const { p2c } = joseHeader + const p2s = base64url(joseHeader.p2s!) + return pbes2Kw(alg, key, encryptedKey!, p2c!, p2s) + } + case 'A128KW': + case 'A192KW': + case 'A256KW': { + // Key Wrapping (AES KW) + assertEnryptedKey(encryptedKey) + return aesKw(alg, key, encryptedKey!) + } + case 'A128GCMKW': + case 'A192GCMKW': + case 'A256GCMKW': { + // Key Wrapping (AES GCM KW) + assertEnryptedKey(encryptedKey) + assertHeaderParameter(joseHeader, 'iv', 'Initialization Vector') + assertHeaderParameter(joseHeader, 'tag', 'Authentication Tag') + const iv = base64url(joseHeader.iv!) + const tag = base64url(joseHeader.tag!) + return aesGcmKw(alg, key, encryptedKey!, iv, tag) + } + default: { + throw new JOSENotSupported(`alg ${alg} is unsupported`) + } + } +} + +export default decryptKeyManagement diff --git a/src/lib/encrypt_key_management.ts b/src/lib/encrypt_key_management.ts new file mode 100644 index 0000000000..9eeabda3d8 --- /dev/null +++ b/src/lib/encrypt_key_management.ts @@ -0,0 +1,115 @@ +import type { KeyLike, JWEKeyManagementHeaderParameters } from '../types.d' +import type { JWEKeyManagementHeaderResults } from '../types.i.d' +import cekFactory, { bitLengths as cekLengths } from '../lib/cek.js' +import { JOSENotSupported } from '../util/errors.js' +import random from '../runtime/random.js' +import { wrap as aesKw } from '../runtime/aeskw.js' +import * as ECDH from '../runtime/ecdhes.js' +import { encrypt as pbes2Kw } from '../runtime/pbes2kw.js' +import { encrypt as rsaEs } from '../runtime/rsaes.js' +import { wrap as aesGcmKw } from '../runtime/aesgcmkw.js' +import { encode as base64url } from '../runtime/base64url.js' + +const generateCek = cekFactory(random) + +async function encryptKeyManagement( + alg: string, + enc: string, + key: KeyLike, + providedCek?: Uint8Array, + providedParameters: JWEKeyManagementHeaderParameters = {}, +): Promise<{ + cek: KeyLike + encryptedKey?: Uint8Array + parameters?: JWEKeyManagementHeaderResults +}> { + let encryptedKey: Uint8Array | undefined + let parameters: JWEKeyManagementHeaderResults | undefined + let cek: KeyLike + + switch (alg) { + case 'dir': { + // Direct Encryption + cek = key + break + } + case 'ECDH-ES': + case 'ECDH-ES+A128KW': + case 'ECDH-ES+A192KW': + case 'ECDH-ES+A256KW': { + // Direct Key Agreement + if (!ECDH.ecdhAllowed(key)) { + throw new JOSENotSupported('ECDH not allowed or unsupported by your javascript runtime') + } + const { apu, apv } = providedParameters + let { epk: ephemeralKey } = providedParameters + ephemeralKey ||= await ECDH.generateEpk(key) + const epk = await ECDH.ephemeralKeyToPublicJWK(ephemeralKey) + const sharedSecret = await ECDH.deriveKey( + key, + ephemeralKey, + alg === 'ECDH-ES' ? enc : alg, + parseInt(alg.substr(-5, 3), 10) || (cekLengths.get(enc) as number), + apu, + apv, + ) + parameters = { epk } + if (apu) parameters.apu = base64url(apu) + if (apv) parameters.apv = base64url(apv) + + if (alg === 'ECDH-ES') { + cek = sharedSecret + break + } + + // Key Agreement with Key Wrapping + cek = providedCek || (await generateCek(enc)) + const kwAlg = alg.substr(-6) + encryptedKey = await aesKw(kwAlg, sharedSecret, cek) + break + } + case 'RSA1_5': + case 'RSA-OAEP': + case 'RSA-OAEP-256': + case 'RSA-OAEP-384': + case 'RSA-OAEP-512': { + // Key Encryption (RSA) + cek = providedCek || (await generateCek(enc)) + encryptedKey = await rsaEs(alg, key, cek) + break + } + case 'PBES2-HS256+A128KW': + case 'PBES2-HS384+A192KW': + case 'PBES2-HS512+A256KW': { + // Key Encryption (PBES2) + cek = providedCek || (await generateCek(enc)) + const { p2c, p2s } = providedParameters + ;({ encryptedKey, ...parameters } = await pbes2Kw(alg, key, cek, p2c, p2s)) + break + } + case 'A128KW': + case 'A192KW': + case 'A256KW': { + // Key Wrapping (AES KW) + cek = providedCek || (await generateCek(enc)) + encryptedKey = await aesKw(alg, key, cek) + break + } + case 'A128GCMKW': + case 'A192GCMKW': + case 'A256GCMKW': { + // Key Wrapping (AES GCM KW) + cek = providedCek || (await generateCek(enc)) + const { iv } = providedParameters + ;({ encryptedKey, ...parameters } = await aesGcmKw(alg, key, cek, iv)) + break + } + default: { + throw new JOSENotSupported(`alg ${alg} is unsupported`) + } + } + + return { cek, encryptedKey, parameters } +} + +export default encryptKeyManagement diff --git a/src/lib/epoch.ts b/src/lib/epoch.ts new file mode 100644 index 0000000000..616795a52e --- /dev/null +++ b/src/lib/epoch.ts @@ -0,0 +1 @@ +export default (date: Date) => Math.floor(date.getTime() / 1000) diff --git a/src/lib/is_disjoint.ts b/src/lib/is_disjoint.ts new file mode 100644 index 0000000000..5fc8df6236 --- /dev/null +++ b/src/lib/is_disjoint.ts @@ -0,0 +1,29 @@ +/* eslint-disable no-restricted-syntax */ +/* eslint-disable no-continue */ + +const isDisjoint = (...headers: Array) => { + const sources = headers.filter(Boolean) as Array + + if (sources.length === 0 || sources.length === 1) { + return true + } + + let acc!: Set + for (const header of sources) { + const parameters = Object.keys(header) + if (!acc || acc.size === 0) { + acc = new Set(parameters) + continue + } + + for (const parameter of parameters) { + if (acc.has(parameter)) { + return false + } + acc.add(parameter) + } + } + + return true +} +export default isDisjoint diff --git a/src/lib/is_object.ts b/src/lib/is_object.ts new file mode 100644 index 0000000000..73c68ed826 --- /dev/null +++ b/src/lib/is_object.ts @@ -0,0 +1,3 @@ +export default function isObject(input: any): boolean { + return !!input && input.constructor === Object +} diff --git a/src/lib/iv.ts b/src/lib/iv.ts new file mode 100644 index 0000000000..5d85035281 --- /dev/null +++ b/src/lib/iv.ts @@ -0,0 +1,28 @@ +import type { AsyncOrSync } from '../types.i.d' +import { JOSENotSupported } from '../util/errors.js' + +const bitLengths = new Map([ + ['A128CBC-HS256', 128], + ['A128GCM', 96], + ['A128GCMKW', 96], + ['A192CBC-HS384', 128], + ['A192GCM', 96], + ['A192GCMKW', 96], + ['A256CBC-HS512', 128], + ['A256GCM', 96], + ['A256GCMKW', 96], +]) + +const factory = (random: (array: Uint8Array) => AsyncOrSync) => ( + alg: string, +): AsyncOrSync => { + const bitLength = bitLengths.get(alg) + if (!bitLength) { + throw new JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`) + } + + return random(new Uint8Array(bitLength >> 3)) +} + +export default factory +export { bitLengths } diff --git a/src/lib/jwt_claims_set.ts b/src/lib/jwt_claims_set.ts new file mode 100644 index 0000000000..71ba367444 --- /dev/null +++ b/src/lib/jwt_claims_set.ts @@ -0,0 +1,143 @@ +import type { + JWTPayload, + JWTClaimVerificationOptions, + JWEHeaderParameters, + JWSHeaderParameters, +} from '../types.d' +import { JWTClaimValidationFailed, JWTExpired, JWTInvalid } from '../util/errors.js' +import { decoder } from './buffer_utils.js' +import epoch from './epoch.js' +import secs from './secs.js' + +const normalizeTyp = (value: string) => value.toLowerCase().replace(/^application\//, '') + +const checkAudiencePresence = (audPayload: any, audOption: string[]) => { + if (typeof audPayload === 'string') { + return audOption.includes(audPayload) + } + + // Each principal intended to process the JWT MUST + // identify itself with a value in the audience claim + return audOption.some(Set.prototype.has.bind(new Set(audPayload))) +} + +export default ( + protectedHeader: JWEHeaderParameters | JWSHeaderParameters, + encodedPayload: Uint8Array, + options: JWTClaimVerificationOptions = {}, +) => { + const { typ } = options + if ( + typ && + (typeof protectedHeader!.typ !== 'string' || + normalizeTyp(protectedHeader!.typ) !== normalizeTyp(typ)) + ) { + throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', 'typ', 'check_failed') + } + + let payload!: JWTPayload + try { + payload = JSON.parse(decoder.decode(encodedPayload)) + } catch { + // + } + + if (typeof payload !== 'object' || !payload || Array.isArray(payload)) { + throw new JWTInvalid('JWT Claims Set must be a top-level JSON object') + } + + const { issuer } = options + if (issuer && !(typeof issuer === 'string' ? [issuer] : issuer).includes(payload.iss!)) { + throw new JWTClaimValidationFailed('unexpected "iss" claim value', 'iss', 'check_failed') + } + + const { subject } = options + if (subject && payload.sub !== subject) { + throw new JWTClaimValidationFailed('unexpected "sub" claim value', 'sub', 'check_failed') + } + + const { audience } = options + if ( + audience && + !checkAudiencePresence(payload.aud, typeof audience === 'string' ? [audience] : audience) + ) { + throw new JWTClaimValidationFailed('unexpected "aud" claim value', 'aud', 'check_failed') + } + + let tolerance: number + switch (typeof options.clockTolerance) { + case 'string': + tolerance = secs(options.clockTolerance) + break + case 'number': + tolerance = options.clockTolerance + break + case 'undefined': + tolerance = 0 + break + default: + throw new TypeError('invalid clockTolerance option type') + } + + const { currentDate } = options + const now = epoch(currentDate || new Date()) + + if ('iat' in payload || options.maxTokenAge) { + if (typeof payload.iat !== 'number') { + throw new JWTClaimValidationFailed('"iat" claim must be a number', 'iat', 'invalid') + } + if (!('exp' in payload) && payload.iat > now + tolerance) { + throw new JWTClaimValidationFailed( + '"iat" claim timestamp check failed (it should be in the past)', + 'iat', + 'check_failed', + ) + } + } + + if ('nbf' in payload) { + if (typeof payload.nbf !== 'number') { + throw new JWTClaimValidationFailed('"nbf" claim must be a number', 'nbf', 'invalid') + } + if (payload.nbf > now + tolerance) { + throw new JWTClaimValidationFailed( + '"nbf" claim timestamp check failed', + 'nbf', + 'check_failed', + ) + } + } + + if ('exp' in payload) { + if (typeof payload.exp !== 'number') { + throw new JWTClaimValidationFailed('"exp" claim must be a number', 'exp', 'invalid') + } + if (payload.exp <= now - tolerance) { + throw new JWTExpired('"exp" claim timestamp check failed', 'exp', 'check_failed') + } + } + + if (options.maxTokenAge) { + const age = now - payload.iat! + const max = + typeof options.maxTokenAge === 'number' ? options.maxTokenAge : secs(options.maxTokenAge) + + if (age - tolerance > max) { + throw new JWTExpired( + '"iat" claim timestamp check failed (too far in the past)', + 'iat', + 'check_failed', + ) + } + + if (age < 0 - tolerance) { + throw new JWTClaimValidationFailed( + '"iat" claim timestamp check failed (it should be in the past)', + 'iat', + 'check_failed', + ) + } + } + + return payload +} diff --git a/src/lib/jwt_producer.ts b/src/lib/jwt_producer.ts new file mode 100644 index 0000000000..83fdf4b260 --- /dev/null +++ b/src/lib/jwt_producer.ts @@ -0,0 +1,108 @@ +import type { JWTPayload } from '../types.d' +import epoch from './epoch.js' +import isObject from './is_object.js' +import secs from './secs.js' + +/** + * Generic class for JWT producing. + */ +export default class ProduceJWT { + protected _payload!: JWTPayload + + /** + * @param payload The JWT Claims Set object. + */ + constructor(payload: JWTPayload) { + if (!isObject(payload)) { + throw new TypeError('JWT Claims Set MUST be an object') + } + this._payload = payload + } + + /** + * Set "iss" (Issuer) Claim. + * + * @param issuer "Issuer" Claim value to set on the JWT Claims Set. + */ + setIssuer(issuer: string) { + this._payload = { ...this._payload, iss: issuer } + return this + } + + /** + * Set "sub" (Subject) Claim. + * + * @param subject "sub" (Subject) Claim value to set on the JWT Claims Set. + */ + setSubject(subject: string) { + this._payload = { ...this._payload, sub: subject } + return this + } + + /** + * Set "aud" (Audience) Claim. + * + * @param audience "aud" (Audience) Claim value to set on the JWT Claims Set. + */ + setAudience(audience: string | string[]) { + this._payload = { ...this._payload, aud: audience } + return this + } + + /** + * Set "jti" (JWT ID) Claim. + * + * @param jwtId "jti" (JWT ID) Claim value to set on the JWT Claims Set. + */ + setJti(jwtId: string) { + this._payload = { ...this._payload, jti: jwtId } + return this + } + + /** + * Set "nbf" (Not Before) Claim. + * + * @param input "nbf" (Not Before) Claim value to set on the JWT Claims Set. + * When number is passed that is used as a value, when string is passed + * it is resolved to a time span and added to the current timestamp. + */ + setNotBefore(input: number | string) { + if (typeof input === 'number') { + this._payload = { ...this._payload, nbf: input } + } else { + this._payload = { ...this._payload, nbf: epoch(new Date()) + secs(input) } + } + return this + } + + /** + * Set "exp" (Expiration Time) Claim. + * + * @param input "exp" (Expiration Time) Claim value to set on the JWT Claims Set. + * When number is passed that is used as a value, when string is passed + * it is resolved to a time span and added to the current timestamp. + */ + setExpirationTime(input: number | string) { + if (typeof input === 'number') { + this._payload = { ...this._payload, exp: input } + } else { + this._payload = { ...this._payload, exp: epoch(new Date()) + secs(input) } + } + return this + } + + /** + * Set "iat" (Issued At) Claim. + * + * @param input "iat" (Issued At) Claim value to set on the JWT Claims Set. + * Default is current timestamp. + */ + setIssuedAt(input?: number) { + if (typeof input === 'undefined') { + this._payload = { ...this._payload, iat: epoch(new Date()) } + } else { + this._payload = { ...this._payload, iat: input } + } + return this + } +} diff --git a/lib/help/secs.js b/src/lib/secs.ts similarity index 86% rename from lib/help/secs.js rename to src/lib/secs.ts index a17b09a5a6..1e51f2741f 100644 --- a/lib/help/secs.js +++ b/src/lib/secs.ts @@ -6,7 +6,8 @@ const year = day * 365.25 const REGEX = /^(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)$/i -module.exports = (str) => { +// eslint-disable-next-line consistent-return +export default (str: string): number => { const matched = REGEX.exec(str) if (!matched) { @@ -16,6 +17,7 @@ module.exports = (str) => { const value = parseFloat(matched[1]) const unit = matched[2].toLowerCase() + // eslint-disable-next-line default-case switch (unit) { case 'sec': case 'secs': @@ -43,11 +45,8 @@ module.exports = (str) => { case 'weeks': case 'w': return Math.round(value * week) - case 'year': - case 'years': - case 'yr': - case 'yrs': - case 'y': + // years matched + default: return Math.round(value * year) } } diff --git a/src/lib/validate_algorithms.ts b/src/lib/validate_algorithms.ts new file mode 100644 index 0000000000..870efaa6ef --- /dev/null +++ b/src/lib/validate_algorithms.ts @@ -0,0 +1,16 @@ +const validateAlgorithms = (option: string, algorithms?: string[]) => { + if ( + algorithms !== undefined && + (!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== 'string')) + ) { + throw new TypeError(`"${option}" option must be an array of strings`) + } + + if (!algorithms) { + return undefined + } + + return new Set(algorithms) +} + +export default validateAlgorithms diff --git a/src/lib/validate_crit.ts b/src/lib/validate_crit.ts new file mode 100644 index 0000000000..6b795fddca --- /dev/null +++ b/src/lib/validate_crit.ts @@ -0,0 +1,52 @@ +import { JOSENotSupported, JWEInvalid, JWSInvalid } from '../util/errors.js' + +type CritCheckHeader = object & { + b64?: boolean + crit?: string[] +} + +const isString = (input: string) => typeof input !== 'string' || input.length === 0 + +function validateCrit( + Err: typeof JWEInvalid | typeof JWSInvalid, + supported: Map, + protectedHeader: CritCheckHeader, + joseHeader: CritCheckHeader, +) { + if ('crit' in joseHeader && !('crit' in protectedHeader)) { + throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected') + } + + if (!protectedHeader || !('crit' in protectedHeader)) { + return new Set([]) + } + + if ( + !Array.isArray(protectedHeader.crit) || + protectedHeader.crit.length === 0 || + protectedHeader.crit.some(isString) + ) { + throw new Err( + '"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present', + ) + } + + // eslint-disable-next-line no-restricted-syntax + for (const parameter of protectedHeader.crit) { + if (!supported.has(parameter)) { + throw new JOSENotSupported( + `Extension Header Parameter "${parameter}" is not supported by this implementation`, + ) + } + + if (!(parameter in joseHeader)) { + throw new Err(`Extension Header Parameter "${parameter}" is missing`) + } else if (supported.get(parameter) && !(parameter in protectedHeader)) { + throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`) + } + } + + return new Set(protectedHeader.crit) +} + +export default validateCrit diff --git a/src/runtime/browser/aesgcmkw.ts b/src/runtime/browser/aesgcmkw.ts new file mode 100644 index 0000000000..99cef873e7 --- /dev/null +++ b/src/runtime/browser/aesgcmkw.ts @@ -0,0 +1,40 @@ +import type { AesGcmKwUnwrapFunction, AesGcmKwWrapFunction } from '../interfaces.d' +import encrypt from './encrypt.js' +import decrypt from './decrypt.js' +import ivFactory from '../../lib/iv.js' +import random from './random.js' +import { encode as base64url } from './base64url.js' + +const generateIv = ivFactory(random) + +export const wrap: AesGcmKwWrapFunction = async ( + alg: string, + key: CryptoKey | Uint8Array, + cek: Uint8Array, + iv?: Uint8Array, +) => { + const jweAlgorithm = alg.substr(0, 7) + // eslint-disable-next-line no-param-reassign + iv ||= await generateIv(jweAlgorithm) + + const { ciphertext: encryptedKey, tag } = await encrypt( + jweAlgorithm, + cek, + key, + iv, + new Uint8Array(), + ) + + return { encryptedKey, iv: base64url(iv), tag: base64url(tag) } +} + +export const unwrap: AesGcmKwUnwrapFunction = async ( + alg: string, + key: CryptoKey | Uint8Array, + encryptedKey: Uint8Array, + iv: Uint8Array, + tag: Uint8Array, +) => { + const jweAlgorithm = alg.substr(0, 7) + return decrypt(jweAlgorithm, key, encryptedKey, iv, tag, new Uint8Array()) +} diff --git a/src/runtime/browser/aeskw.ts b/src/runtime/browser/aeskw.ts new file mode 100644 index 0000000000..27c160713e --- /dev/null +++ b/src/runtime/browser/aeskw.ts @@ -0,0 +1,58 @@ +import type { AesKwUnwrapFunction, AesKwWrapFunction } from '../interfaces.d' +import bogusWebCrypto from './bogus.js' +import crypto, { ensureSecureContext } from './webcrypto.js' + +function checkKeySize(key: CryptoKey, alg: string) { + if ((key.algorithm as AesKeyAlgorithm).length !== parseInt(alg.substr(1, 3), 10)) { + throw new TypeError(`invalid key size for alg: ${alg}`) + } +} + +export const wrap: AesKwWrapFunction = async ( + alg: string, + key: CryptoKey | Uint8Array, + cek: Uint8Array, +) => { + ensureSecureContext() + let cryptoKey: CryptoKey + + if (key instanceof Uint8Array) { + cryptoKey = await crypto.subtle.importKey('raw', key, 'AES-KW', true, ['wrapKey']) + } else { + cryptoKey = key + } + + checkKeySize(cryptoKey, alg) + + // we're importing the cek to end up with CryptoKey instance that can be wrapped, the algorithm used is irrelevant + const cryptoKeyCek = await crypto.subtle.importKey('raw', cek, ...bogusWebCrypto) + + return new Uint8Array(await crypto.subtle.wrapKey('raw', cryptoKeyCek, cryptoKey, 'AES-KW')) +} + +export const unwrap: AesKwUnwrapFunction = async ( + alg: string, + key: CryptoKey | Uint8Array, + encryptedKey: Uint8Array, +) => { + ensureSecureContext() + let cryptoKey: CryptoKey + + if (key instanceof Uint8Array) { + cryptoKey = await crypto.subtle.importKey('raw', key, 'AES-KW', true, ['unwrapKey']) + } else { + cryptoKey = key + } + + checkKeySize(cryptoKey, alg) + + const cryptoKeyCek = await crypto.subtle.unwrapKey( + 'raw', + encryptedKey, + cryptoKey, + 'AES-KW', + ...bogusWebCrypto, + ) + + return new Uint8Array(await crypto.subtle.exportKey('raw', cryptoKeyCek)) +} diff --git a/src/runtime/browser/base64url.ts b/src/runtime/browser/base64url.ts new file mode 100644 index 0000000000..85d412aa60 --- /dev/null +++ b/src/runtime/browser/base64url.ts @@ -0,0 +1,25 @@ +import type { Base64UrlDecode, Base64UrlEncode } from '../interfaces.d' +import { encoder, decoder } from '../../lib/buffer_utils.js' + +export const encode: Base64UrlEncode = (input) => { + let unencoded = input + if (typeof unencoded === 'string') { + unencoded = encoder.encode(unencoded) + } + const base64string = window.btoa(String.fromCharCode.apply(0, [...unencoded])) + return base64string.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_') +} + +export const decode: Base64UrlDecode = (input) => { + let encoded = input + if (encoded instanceof Uint8Array) { + encoded = decoder.decode(encoded) + } + encoded = encoded.replace(/-/g, '+').replace(/_/g, '/').replace(/\s/g, '') + return new Uint8Array( + window + .atob(encoded) + .split('') + .map((c) => c.charCodeAt(0)), + ) +} diff --git a/src/runtime/browser/bogus.ts b/src/runtime/browser/bogus.ts new file mode 100644 index 0000000000..3f7bcfdf66 --- /dev/null +++ b/src/runtime/browser/bogus.ts @@ -0,0 +1,7 @@ +const bogusWebCrypto: [HmacImportParams, boolean, KeyUsage[]] = [ + { hash: 'SHA-256', name: 'HMAC' }, + true, + ['sign'], +] + +export default bogusWebCrypto diff --git a/src/runtime/browser/check_cek_length.ts b/src/runtime/browser/check_cek_length.ts new file mode 100644 index 0000000000..e938769adc --- /dev/null +++ b/src/runtime/browser/check_cek_length.ts @@ -0,0 +1,43 @@ +import { JWEInvalid, JOSENotSupported } from '../../util/errors.js' + +const checkCekLength = (enc: string, cek: Uint8Array | CryptoKey) => { + let expected: number + switch (enc) { + case 'A128CBC-HS256': + case 'A192CBC-HS384': + case 'A256CBC-HS512': + expected = parseInt(enc.substr(-3), 10) + if (!(cek instanceof Uint8Array)) { + throw new TypeError(`${enc} content encryption requires Uint8Array as key input`) + } + break + case 'A128GCM': + case 'A192GCM': + case 'A256GCM': + expected = parseInt(enc.substr(1, 3), 10) + break + default: + throw new JOSENotSupported( + `Content Encryption Algorithm ${enc} is unsupported either by JOSE or your javascript runtime`, + ) + } + + if (cek instanceof Uint8Array) { + if (cek.length << 3 !== expected) { + throw new JWEInvalid('Invalid Content Encryption Key length') + } + return + } + + // CryptoKey + if ('algorithm' in cek) { + if ((cek.algorithm as AesKeyAlgorithm).length !== expected) { + throw new JWEInvalid('Invalid Content Encryption Key length') + } + return + } + + throw new TypeError('Invalid Content Encryption Key type') +} + +export default checkCekLength diff --git a/src/runtime/browser/check_key_length.ts b/src/runtime/browser/check_key_length.ts new file mode 100644 index 0000000000..550537a85f --- /dev/null +++ b/src/runtime/browser/check_key_length.ts @@ -0,0 +1,17 @@ +export default (alg: string, key: CryptoKey) => { + if (alg.startsWith('HS')) { + const bitlen = parseInt(alg.substr(-3), 10) + if (!('length' in key.algorithm) || (key.algorithm as HmacKeyAlgorithm).length < bitlen) { + throw new TypeError(`${alg} requires symmetric keys to be ${bitlen} bits or larger`) + } + } + + if (alg.startsWith('RS') || alg.startsWith('PS')) { + if ( + !('modulusLength' in key.algorithm) || + (key.algorithm as RsaKeyAlgorithm).modulusLength < 2048 + ) { + throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`) + } + } +} diff --git a/src/runtime/browser/decrypt.ts b/src/runtime/browser/decrypt.ts new file mode 100644 index 0000000000..687331383d --- /dev/null +++ b/src/runtime/browser/decrypt.ts @@ -0,0 +1,112 @@ +import { concat, uint64be } from '../../lib/buffer_utils.js' + +import type { DecryptFunction } from '../interfaces.d' +import checkIvLength from '../../lib/check_iv_length.js' +import checkCekLength from './check_cek_length.js' +import timingSafeEqual from './timing_safe_equal.js' +import { JWEDecryptionFailed } from '../../util/errors.js' +import crypto, { ensureSecureContext } from './webcrypto.js' + +async function cbcDecrypt( + enc: string, + cek: Uint8Array, + ciphertext: Uint8Array, + iv: Uint8Array, + tag: Uint8Array, + aad: Uint8Array, +) { + const keySize = parseInt(enc.substr(1, 3), 10) + const encKey = await crypto.subtle.importKey('raw', cek.slice(keySize >> 3), 'AES-CBC', false, [ + 'decrypt', + ]) + const macKey = await crypto.subtle.importKey( + 'raw', + cek.slice(0, keySize >> 3), + { + hash: `SHA-${keySize << 1}`, + name: 'HMAC', + }, + false, + ['sign'], + ) + let plaintext!: Uint8Array + + try { + plaintext = new Uint8Array( + // TODO: remove .buffer when https://github.com/nodejs/node/issues/36083 is fixed + await crypto.subtle.decrypt({ iv, name: 'AES-CBC' }, encKey, ciphertext.buffer), + ) + } catch { + // + } + + const macData = concat(aad, iv, ciphertext, uint64be(aad.length << 3)) + const expectedTag = new Uint8Array( + (await crypto.subtle.sign('HMAC', macKey, macData)).slice(0, keySize >> 3), + ) + + let macCheckPassed!: boolean + try { + macCheckPassed = timingSafeEqual(tag, expectedTag) + } catch { + // + } + + if (!plaintext || !macCheckPassed) { + throw new JWEDecryptionFailed() + } + + return plaintext +} + +async function gcmDecrypt( + cek: Uint8Array | CryptoKey, + ciphertext: Uint8Array, + iv: Uint8Array, + tag: Uint8Array, + aad: Uint8Array, +) { + const encKey = + cek instanceof Uint8Array + ? await crypto.subtle.importKey('raw', cek, 'AES-GCM', false, ['decrypt']) + : cek + + try { + return new Uint8Array( + await crypto.subtle.decrypt( + { + additionalData: aad, + iv, + name: 'AES-GCM', + tagLength: 128, + }, + encKey, + // TODO: remove .buffer when https://github.com/nodejs/node/issues/36083 is fixed + concat(ciphertext, tag).buffer, + ), + ) + } catch (err) { + throw new JWEDecryptionFailed() + } +} + +const decrypt: DecryptFunction = async ( + enc: string, + cek: CryptoKey | Uint8Array, + ciphertext: Uint8Array, + iv: Uint8Array, + tag: Uint8Array, + aad: Uint8Array, +) => { + ensureSecureContext() + checkCekLength(enc, cek) + checkIvLength(enc, iv) + + if (enc.substr(4, 3) === 'CBC') { + return cbcDecrypt(enc, cek as Uint8Array, ciphertext, iv, tag, aad) + } + + return gcmDecrypt(cek, ciphertext, iv, tag, aad) +} + +export default decrypt diff --git a/src/runtime/browser/digest.ts b/src/runtime/browser/digest.ts new file mode 100644 index 0000000000..7c0caa9d92 --- /dev/null +++ b/src/runtime/browser/digest.ts @@ -0,0 +1,10 @@ +import crypto, { ensureSecureContext } from './webcrypto.js' + +export default async ( + digest: 'sha256' | 'sha384' | 'sha512', + data: Uint8Array, +): Promise => { + ensureSecureContext() + const subtleDigest = `SHA-${digest.substr(-3)}` + return new Uint8Array(await crypto.subtle.digest(subtleDigest, data)) +} diff --git a/src/runtime/browser/ecdhes.ts b/src/runtime/browser/ecdhes.ts new file mode 100644 index 0000000000..4dd941fda4 --- /dev/null +++ b/src/runtime/browser/ecdhes.ts @@ -0,0 +1,82 @@ +import type { + EcdhAllowedFunction, + EcdhESDeriveKeyFunction, + EphemeralKeyToPublicJwkFunction, + GenerateEpkFunction, + PublicJwkToEphemeralKeyFunction, +} from '../interfaces.d' +import { + encoder, + concat, + uint32be, + lengthAndInput, + concatKdf as KDF, +} from '../../lib/buffer_utils.js' +import type { EpkJwk } from '../../types.i.d' +import crypto, { ensureSecureContext } from './webcrypto.js' +import digest from './digest.js' + +const concatKdf = KDF.bind(undefined, digest.bind(undefined, 'sha256')) + +export const deriveKey: EcdhESDeriveKeyFunction = async ( + publicKey: CryptoKey, + privateKey: CryptoKey, + algorithm: string, + keyLength: number, + apu: Uint8Array = new Uint8Array(), + apv: Uint8Array = new Uint8Array(), +) => { + ensureSecureContext() + const value = concat( + lengthAndInput(encoder.encode(algorithm)), + lengthAndInput(apu), + lengthAndInput(apv), + uint32be(keyLength), + ) + + if (!privateKey.usages.includes('deriveBits')) { + throw new TypeError('ECDH-ES private key "usages" must include "deriveBits"') + } + + const sharedSecret = new Uint8Array( + await crypto.subtle.deriveBits( + { + name: 'ECDH', + public: publicKey, + }, + privateKey, + Math.ceil(parseInt((privateKey.algorithm as EcKeyAlgorithm).namedCurve.substr(-3), 10) / 8) << + 3, + ), + ) + + return concatKdf(sharedSecret, keyLength, value) +} + +export const ephemeralKeyToPublicJWK: EphemeralKeyToPublicJwkFunction = async function ephemeralKeyToPublicJWK( + key: CryptoKey, +) { + ensureSecureContext() + const { crv, kty, x, y } = (await crypto.subtle.exportKey('jwk', key)) as EpkJwk + return { crv, kty, x, y } +} + +export const generateEpk: GenerateEpkFunction = async (key: CryptoKey) => { + ensureSecureContext() + return ( + await crypto.subtle.generateKey( + { name: 'ECDH', namedCurve: (key.algorithm as EcKeyAlgorithm).namedCurve }, + true, + ['deriveBits'], + ) + ).privateKey +} + +export const publicJwkToEphemeralKey: PublicJwkToEphemeralKeyFunction = async (jwk: EpkJwk) => { + ensureSecureContext() + return crypto.subtle.importKey('jwk', jwk, { name: 'ECDH', namedCurve: jwk.crv }, true, []) +} + +const curves = ['P-256', 'P-384', 'P-521'] +export const ecdhAllowed: EcdhAllowedFunction = (key: CryptoKey) => + curves.includes((key.algorithm as EcKeyAlgorithm).namedCurve) diff --git a/src/runtime/browser/encrypt.ts b/src/runtime/browser/encrypt.ts new file mode 100644 index 0000000000..8d66a6b6a2 --- /dev/null +++ b/src/runtime/browser/encrypt.ts @@ -0,0 +1,96 @@ +import { concat, uint64be } from '../../lib/buffer_utils.js' +import type { EncryptFunction } from '../interfaces.d' +import checkIvLength from '../../lib/check_iv_length.js' +import checkCekLength from './check_cek_length.js' +import crypto, { ensureSecureContext } from './webcrypto.js' + +async function cbcEncrypt( + enc: string, + plaintext: Uint8Array, + cek: Uint8Array, + iv: Uint8Array, + aad: Uint8Array, +) { + const keySize = parseInt(enc.substr(1, 3), 10) + const encKey = await crypto.subtle.importKey('raw', cek.slice(keySize >> 3), 'AES-CBC', false, [ + 'encrypt', + ]) + const macKey = await crypto.subtle.importKey( + 'raw', + cek.slice(0, keySize >> 3), + { + hash: `SHA-${keySize << 1}`, + name: 'HMAC', + }, + false, + ['sign'], + ) + + const ciphertext = new Uint8Array( + await crypto.subtle.encrypt( + { + iv, + name: 'AES-CBC', + }, + encKey, + plaintext, + ), + ) + + const macData = concat(aad, iv, ciphertext, uint64be(aad.length << 3)) + const tag = new Uint8Array( + (await crypto.subtle.sign('HMAC', macKey, macData)).slice(0, keySize >> 3), + ) + + return { ciphertext, tag } +} + +async function gcmEncrypt( + plaintext: Uint8Array, + cek: Uint8Array | CryptoKey, + iv: Uint8Array, + aad: Uint8Array, +) { + const encKey = + cek instanceof Uint8Array + ? await crypto.subtle.importKey('raw', cek, 'AES-GCM', false, ['encrypt']) + : cek + + const encrypted = new Uint8Array( + await crypto.subtle.encrypt( + { + additionalData: aad, + iv, + name: 'AES-GCM', + tagLength: 128, + }, + encKey, + plaintext, + ), + ) + + const tag = encrypted.slice(-16) + const ciphertext = encrypted.slice(0, -16) + + return { ciphertext, tag } +} + +const encrypt: EncryptFunction = async ( + enc: string, + plaintext: Uint8Array, + cek: CryptoKey | Uint8Array, + iv: Uint8Array, + aad: Uint8Array, +) => { + ensureSecureContext() + checkCekLength(enc, cek) + checkIvLength(enc, iv) + + if (enc.substr(4, 3) === 'CBC') { + return cbcEncrypt(enc, plaintext, cek as Uint8Array, iv, aad) + } + + return gcmEncrypt(plaintext, cek, iv, aad) +} + +export default encrypt diff --git a/src/runtime/browser/fetch.ts b/src/runtime/browser/fetch.ts new file mode 100644 index 0000000000..d265193e9f --- /dev/null +++ b/src/runtime/browser/fetch.ts @@ -0,0 +1,28 @@ +import { JOSEError } from '../../util/errors.js' + +export default async (url: URL, timeout: number) => { + let controller!: AbortController + if (typeof AbortController === 'function') { + controller = new AbortController() + setTimeout(() => controller.abort(), timeout) + } + + const response = await fetch(url.href, { + signal: controller ? controller.signal : undefined, + redirect: 'manual', + referrerPolicy: 'no-referrer', + credentials: 'omit', + mode: 'cors', + method: 'GET', + }) + + if (response.status !== 200) { + throw new JOSEError('Expected 200 OK from the JSON Web Key Set HTTP response') + } + + try { + return await response.json() + } catch (err) { + throw new JOSEError('Failed to parse the JSON Web Key Set HTTP response as JSON') + } +} diff --git a/src/runtime/browser/generate.ts b/src/runtime/browser/generate.ts new file mode 100644 index 0000000000..003267f6a0 --- /dev/null +++ b/src/runtime/browser/generate.ts @@ -0,0 +1,112 @@ +import crypto, { ensureSecureContext } from './webcrypto.js' +import { JOSENotSupported } from '../../util/errors.js' +import random from './random.js' + +const modulusLength = 2048 +const publicExponent = new Uint8Array([0x01, 0x00, 0x01]) + +export async function generateSecret(alg: string) { + let length: number + let algorithm: AesKeyGenParams | HmacKeyGenParams + let keyUsages: KeyUsage[] + switch (alg) { + case 'HS256': + case 'HS384': + case 'HS512': + length = parseInt(alg.substr(-3), 10) + algorithm = { name: 'HMAC', hash: `SHA-${alg.substr(-3)}`, length } + keyUsages = ['sign', 'verify'] + break + case 'A128CBC-HS256': + case 'A192CBC-HS384': + case 'A256CBC-HS512': + length = parseInt(alg.substr(-3), 10) + return random(new Uint8Array(length >> 3)) + case 'A128KW': + case 'A192KW': + case 'A256KW': + length = parseInt(alg.substring(1, 4), 10) + algorithm = { name: 'AES-KW', length } + keyUsages = ['wrapKey', 'unwrapKey'] + break + case 'A128GCMKW': + case 'A192GCMKW': + case 'A256GCMKW': + case 'A128GCM': + case 'A192GCM': + case 'A256GCM': + length = parseInt(alg.substring(1, 4), 10) + algorithm = { name: 'AES-GCM', length } + keyUsages = ['encrypt', 'decrypt'] + break + default: + throw new JOSENotSupported('unsupported or invalid JWK "alg" (Algorithm) Parameter value') + } + + return crypto.subtle.generateKey(algorithm, false, keyUsages) as Promise +} + +interface Options { + crv?: string +} + +export async function generateKeyPair(alg: string, options?: Options) { + let algorithm: RsaHashedKeyGenParams | EcKeyGenParams + let keyUsages: KeyUsage[] + + switch (alg) { + case 'PS256': + case 'PS384': + case 'PS512': + algorithm = { name: 'RSA-PSS', hash: `SHA-${alg.substr(-3)}`, publicExponent, modulusLength } + keyUsages = ['sign', 'verify'] + break + case 'RS256': + case 'RS384': + case 'RS512': + algorithm = { + name: 'RSASSA-PKCS1-v1_5', + hash: `SHA-${alg.substr(-3)}`, + publicExponent, + modulusLength, + } + keyUsages = ['sign', 'verify'] + break + case 'RSA-OAEP': + case 'RSA-OAEP-256': + case 'RSA-OAEP-384': + case 'RSA-OAEP-512': + algorithm = { + name: 'RSA-OAEP', + hash: `SHA-${parseInt(alg.substr(-3), 10) || 1}`, + publicExponent, + modulusLength, + } + keyUsages = ['decrypt', 'unwrapKey', 'encrypt', 'wrapKey'] + break + case 'ES256': + algorithm = { name: 'ECDSA', namedCurve: 'P-256' } + keyUsages = ['sign', 'verify'] + break + case 'ES384': + algorithm = { name: 'ECDSA', namedCurve: 'P-384' } + keyUsages = ['sign', 'verify'] + break + case 'ES512': + algorithm = { name: 'ECDSA', namedCurve: 'P-521' } + keyUsages = ['sign', 'verify'] + break + case 'ECDH-ES': + case 'ECDH-ES+A128KW': + case 'ECDH-ES+A192KW': + case 'ECDH-ES+A256KW': + algorithm = { name: 'ECDH', namedCurve: options?.crv || 'P-256' } + keyUsages = ['deriveKey', 'deriveBits'] + break + default: + throw new JOSENotSupported('unsupported or invalid JWK "alg" (Algorithm) Parameter value') + } + + ensureSecureContext() + return crypto.subtle.generateKey(algorithm, false, keyUsages) as Promise +} diff --git a/src/runtime/browser/jwk_to_key.ts b/src/runtime/browser/jwk_to_key.ts new file mode 100644 index 0000000000..4888e8c32b --- /dev/null +++ b/src/runtime/browser/jwk_to_key.ts @@ -0,0 +1,121 @@ +import crypto, { ensureSecureContext } from './webcrypto.js' +import { JOSENotSupported } from '../../util/errors.js' +import type { JWK } from '../../types.d' +import { decode as base64url } from './base64url.js' + +function parse( + jwk: JWK, +): { algorithm: RsaHashedImportParams | EcKeyAlgorithm | Algorithm; keyUsages: KeyUsage[] } { + let algorithm: RsaHashedImportParams | EcKeyAlgorithm | Algorithm + let keyUsages: KeyUsage[] + + switch (jwk.kty) { + case 'oct': { + switch (jwk.alg) { + case 'HS256': + case 'HS384': + case 'HS512': + algorithm = { name: 'HMAC', hash: `SHA-${jwk.alg.substr(-3)}` } + keyUsages = ['sign', 'verify'] + break + case 'A128CBC-HS256': + case 'A192CBC-HS384': + case 'A256CBC-HS512': + throw new JOSENotSupported(`${jwk.alg} keys cannot be imported as CryptoKey instances`) + case 'A128GCM': + case 'A192GCM': + case 'A256GCM': + case 'A128GCMKW': + case 'A192GCMKW': + case 'A256GCMKW': + algorithm = { name: 'AES-GCM' } + keyUsages = ['encrypt', 'decrypt'] + break + case 'A128KW': + case 'A192KW': + case 'A256KW': + algorithm = { name: 'AES-KW' } + keyUsages = ['wrapKey', 'unwrapKey'] + break + case 'PBES2-HS256+A128KW': + case 'PBES2-HS384+A192KW': + case 'PBES2-HS512+A256KW': + algorithm = { name: 'PBKDF2' } + keyUsages = ['deriveBits'] + break + default: + throw new JOSENotSupported('unsupported or invalid JWK "alg" (Algorithm) Parameter value') + } + break + } + case 'RSA': { + switch (jwk.alg) { + case 'PS256': + case 'PS384': + case 'PS512': + algorithm = { name: 'RSA-PSS', hash: `SHA-${jwk.alg.substr(-3)}` } + keyUsages = jwk.d ? ['sign'] : ['verify'] + break + case 'RS256': + case 'RS384': + case 'RS512': + algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: `SHA-${jwk.alg.substr(-3)}` } + keyUsages = jwk.d ? ['sign'] : ['verify'] + break + case 'RSA-OAEP': + case 'RSA-OAEP-256': + case 'RSA-OAEP-384': + case 'RSA-OAEP-512': + algorithm = { name: 'RSA-OAEP', hash: `SHA-${parseInt(jwk.alg.substr(-3), 10) || 1}` } + keyUsages = jwk.d ? ['decrypt', 'unwrapKey'] : ['encrypt', 'wrapKey'] + break + default: + throw new JOSENotSupported('unsupported or invalid JWK "alg" (Algorithm) Parameter value') + } + break + } + case 'EC': { + switch (jwk.alg) { + case 'ES256': + case 'ES384': + case 'ES512': + algorithm = { name: 'ECDSA', namedCurve: jwk.crv! } + keyUsages = jwk.d ? ['sign'] : ['verify'] + break + case 'ECDH-ES': + case 'ECDH-ES+A128KW': + case 'ECDH-ES+A192KW': + case 'ECDH-ES+A256KW': + algorithm = { name: 'ECDH', namedCurve: jwk.crv! } + keyUsages = jwk.d ? ['deriveBits'] : [] + break + default: + throw new JOSENotSupported('unsupported or invalid JWK "alg" (Algorithm) Parameter value') + } + break + } + default: + throw new JOSENotSupported('unsupported or invalid JWK "kty" (Key Type) Parameter value') + } + + return { algorithm, keyUsages } +} + +export default async (jwk: JWK): Promise => { + const { algorithm, keyUsages } = parse(jwk) + let format = 'jwk' + let keyData: JWK | Uint8Array = { ...jwk } + delete keyData.alg + if (algorithm.name === 'PBKDF2') { + format = 'raw' + keyData = base64url(jwk.k!) + } + ensureSecureContext() + return crypto.subtle.importKey( + format, + keyData, + algorithm, + jwk.ext ?? false, + (jwk.key_ops as KeyUsage[]) ?? keyUsages, + ) +} diff --git a/src/runtime/browser/pbes2kw.ts b/src/runtime/browser/pbes2kw.ts new file mode 100644 index 0000000000..14b3620fed --- /dev/null +++ b/src/runtime/browser/pbes2kw.ts @@ -0,0 +1,93 @@ +import type { Pbes2KWDecryptFunction, Pbes2KWEncryptFunction } from '../interfaces.d' +import random from './random.js' +import { p2s as concatSalt } from '../../lib/buffer_utils.js' +import { encode as base64url } from './base64url.js' +import { wrap, unwrap } from './aeskw.js' +import checkP2s from '../../lib/check_p2s.js' +import crypto, { ensureSecureContext } from './webcrypto.js' + +export const encrypt: Pbes2KWEncryptFunction = async ( + alg: string, + key: CryptoKey | Uint8Array, + cek: Uint8Array, + p2c: number = Math.floor(Math.random() * 2049) + 2048, + p2s: Uint8Array = random(new Uint8Array(16)), +) => { + ensureSecureContext() + checkP2s(p2s) + + const salt = concatSalt(alg, p2s) + const keylen = parseInt(alg.substr(13, 3), 10) + const subtleAlg = { + hash: `SHA-${alg.substr(8, 3)}`, + iterations: p2c, + name: 'PBKDF2', + salt, + } + const wrapAlg = { + length: keylen, + name: 'AES-KW', + } + + let cryptoKey: CryptoKey + if (key instanceof Uint8Array) { + cryptoKey = await crypto.subtle.importKey('raw', key, 'PBKDF2', false, ['deriveBits']) + } else { + cryptoKey = key + } + + let derived: CryptoKey | Uint8Array + if (cryptoKey.usages.includes('deriveBits')) { + derived = new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keylen)) + } else if (cryptoKey.usages.includes('deriveKey')) { + derived = await crypto.subtle.deriveKey(subtleAlg, cryptoKey, wrapAlg, false, ['wrapKey']) + } else { + throw new TypeError('PBKDF2 key "usages" must include "deriveBits" or "deriveKey"') + } + + const encryptedKey = await wrap(alg.substr(-6), derived, cek) + + return { encryptedKey, p2c, p2s: base64url(p2s) } +} + +export const decrypt: Pbes2KWDecryptFunction = async ( + alg: string, + key: CryptoKey | Uint8Array, + encryptedKey: Uint8Array, + p2c: number, + p2s: Uint8Array, +) => { + ensureSecureContext() + checkP2s(p2s) + + const salt = concatSalt(alg, p2s) + const keylen = parseInt(alg.substr(13, 3), 10) + const subtleAlg = { + hash: `SHA-${alg.substr(8, 3)}`, + iterations: p2c, + name: 'PBKDF2', + salt, + } + const wrapAlg = { + length: keylen, + name: 'AES-KW', + } + + let cryptoKey: CryptoKey + if (key instanceof Uint8Array) { + cryptoKey = await crypto.subtle.importKey('raw', key, 'PBKDF2', false, ['deriveBits']) + } else { + cryptoKey = key + } + + let derived: CryptoKey | Uint8Array + if (cryptoKey.usages.includes('deriveBits')) { + derived = new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keylen)) + } else if (cryptoKey.usages.includes('deriveKey')) { + derived = await crypto.subtle.deriveKey(subtleAlg, cryptoKey, wrapAlg, false, ['unwrapKey']) + } else { + throw new TypeError('PBKDF2 key "usages" must include "deriveBits" or "deriveKey"') + } + + return unwrap(alg.substr(-6), derived, encryptedKey) +} diff --git a/src/runtime/browser/random.ts b/src/runtime/browser/random.ts new file mode 100644 index 0000000000..6eac560909 --- /dev/null +++ b/src/runtime/browser/random.ts @@ -0,0 +1,6 @@ +import type { GetRandomValuesFunction } from '../interfaces.d' +import crypto from './webcrypto.js' + +const random: GetRandomValuesFunction = crypto.getRandomValues.bind(crypto) + +export default random diff --git a/src/runtime/browser/rsaes.ts b/src/runtime/browser/rsaes.ts new file mode 100644 index 0000000000..e6f446c980 --- /dev/null +++ b/src/runtime/browser/rsaes.ts @@ -0,0 +1,59 @@ +import type { RsaEsDecryptFunction, RsaEsEncryptFunction } from '../interfaces.d' +import subtleAlgorithm from './subtle_rsaes.js' +import bogusWebCrypto from './bogus.js' +import crypto, { ensureSecureContext } from './webcrypto.js' +import checkKeyLength from './check_key_length.js' + +export const encrypt: RsaEsEncryptFunction = async ( + alg: string, + key: CryptoKey, + cek: Uint8Array, +) => { + ensureSecureContext() + checkKeyLength(alg, key) + + if (key.usages.includes('encrypt')) { + return new Uint8Array(await crypto.subtle.encrypt(subtleAlgorithm(alg), key, cek)) + } + + if (key.usages.includes('wrapKey')) { + // we're importing the cek to end up with CryptoKey instance that can be wrapped, the algorithm used is irrelevant + const cryptoKeyCek = await crypto.subtle.importKey('raw', cek, ...bogusWebCrypto) + return new Uint8Array( + await crypto.subtle.wrapKey('raw', cryptoKeyCek, key, subtleAlgorithm(alg)), + ) + } + + throw new TypeError( + 'RSA-OAEP key "usages" must include "encrypt" or "wrapKey" for this operation', + ) +} + +export const decrypt: RsaEsDecryptFunction = async ( + alg: string, + key: CryptoKey, + encryptedKey: Uint8Array, +) => { + ensureSecureContext() + checkKeyLength(alg, key) + + if (key.usages.includes('decrypt')) { + return new Uint8Array(await crypto.subtle.decrypt(subtleAlgorithm(alg), key, encryptedKey)) + } + + if (key.usages.includes('unwrapKey')) { + const cryptoKeyCek = await crypto.subtle.unwrapKey( + 'raw', + encryptedKey, + key, + subtleAlgorithm(alg), + ...bogusWebCrypto, + ) + + return new Uint8Array(await crypto.subtle.exportKey('raw', cryptoKeyCek)) + } + + throw new TypeError( + 'RSA-OAEP key "usages" must include "decrypt" or "unwrapKey" for this operation', + ) +} diff --git a/src/runtime/browser/sign.ts b/src/runtime/browser/sign.ts new file mode 100644 index 0000000000..ca1dc08f05 --- /dev/null +++ b/src/runtime/browser/sign.ts @@ -0,0 +1,30 @@ +import type { SignFunction } from '../interfaces.d' +import subtleAlgorithm from './subtle_dsa.js' +import crypto, { ensureSecureContext } from './webcrypto.js' +import checkKeyLength from './check_key_length.js' + +const sign: SignFunction = async (alg, key: CryptoKey | Uint8Array, data) => { + ensureSecureContext() + let cryptoKey: CryptoKey + if (key instanceof Uint8Array) { + if (!alg.startsWith('HS')) { + throw new TypeError('symmetric keys are only applicable for HMAC-based algorithms') + } + cryptoKey = await crypto.subtle.importKey( + 'raw', + key, + { hash: `SHA-${alg.substr(-3)}`, name: 'HMAC' }, + false, + ['sign'], + ) + } else { + cryptoKey = key + } + + checkKeyLength(alg, cryptoKey) + + const signature = await crypto.subtle.sign(subtleAlgorithm(alg), cryptoKey, data) + return new Uint8Array(signature) +} + +export default sign diff --git a/src/runtime/browser/subtle_dsa.ts b/src/runtime/browser/subtle_dsa.ts new file mode 100644 index 0000000000..c578f56d54 --- /dev/null +++ b/src/runtime/browser/subtle_dsa.ts @@ -0,0 +1,46 @@ +import { JOSENotSupported } from '../../util/errors.js' + +export default function subtleDsa(alg: string) { + switch (alg) { + case 'HS256': + return { hash: 'SHA-256', name: 'HMAC' } + case 'HS384': + return { hash: 'SHA-384', name: 'HMAC' } + case 'HS512': + return { hash: 'SHA-512', name: 'HMAC' } + case 'PS256': + return { + hash: 'SHA-256', + name: 'RSA-PSS', + saltLength: 256 >> 3, + } + case 'PS384': + return { + hash: 'SHA-384', + name: 'RSA-PSS', + saltLength: 384 >> 3, + } + case 'PS512': + return { + hash: 'SHA-512', + name: 'RSA-PSS', + saltLength: 512 >> 3, + } + case 'RS256': + return { hash: 'SHA-256', name: 'RSASSA-PKCS1-v1_5' } + case 'RS384': + return { hash: 'SHA-384', name: 'RSASSA-PKCS1-v1_5' } + case 'RS512': + return { hash: 'SHA-512', name: 'RSASSA-PKCS1-v1_5' } + case 'ES256': + return { hash: 'SHA-256', name: 'ECDSA', namedCurve: 'P-256' } + case 'ES384': + return { hash: 'SHA-384', name: 'ECDSA', namedCurve: 'P-384' } + case 'ES512': + return { hash: 'SHA-512', name: 'ECDSA', namedCurve: 'P-521' } + default: + throw new JOSENotSupported( + `alg ${alg} is unsupported either by JOSE or your javascript runtime`, + ) + } +} diff --git a/src/runtime/browser/subtle_rsaes.ts b/src/runtime/browser/subtle_rsaes.ts new file mode 100644 index 0000000000..cb832eb729 --- /dev/null +++ b/src/runtime/browser/subtle_rsaes.ts @@ -0,0 +1,15 @@ +import { JOSENotSupported } from '../../util/errors.js' + +export default function subtleRsaEs(alg: string) { + switch (alg) { + case 'RSA-OAEP': + case 'RSA-OAEP-256': + case 'RSA-OAEP-384': + case 'RSA-OAEP-512': + return 'RSA-OAEP' + default: + throw new JOSENotSupported( + `alg ${alg} is unsupported either by JOSE or your javascript runtime`, + ) + } +} diff --git a/src/runtime/browser/timing_safe_equal.ts b/src/runtime/browser/timing_safe_equal.ts new file mode 100644 index 0000000000..7b06568c63 --- /dev/null +++ b/src/runtime/browser/timing_safe_equal.ts @@ -0,0 +1,23 @@ +import type { TimingSafeEqual } from '../interfaces.d' + +const timingSafeEqual: TimingSafeEqual = (a, b) => { + if (!(a instanceof Uint8Array)) { + throw new TypeError('First argument must be a buffer') + } + if (!(b instanceof Uint8Array)) { + throw new TypeError('Second argument must be a buffer') + } + if (a.length !== b.length) { + throw new TypeError('Input buffers must have the same length') + } + + const len = a.length + let out = 0 + let i = -1 + while (++i < len) { + out |= a[i] ^ b[i] + } + return out === 0 +} + +export default timingSafeEqual diff --git a/src/runtime/browser/verify.ts b/src/runtime/browser/verify.ts new file mode 100644 index 0000000000..167be51d09 --- /dev/null +++ b/src/runtime/browser/verify.ts @@ -0,0 +1,29 @@ +import type { VerifyFunction } from '../interfaces.d' +import subtleAlgorithm from './subtle_dsa.js' +import crypto, { ensureSecureContext } from './webcrypto.js' +import checkKeyLength from './check_key_length.js' + +const verify: VerifyFunction = async (alg, key: CryptoKey | Uint8Array, signature, data) => { + ensureSecureContext() + let cryptoKey: CryptoKey + if (key instanceof Uint8Array) { + if (!alg.startsWith('HS')) { + throw new TypeError('symmetric keys are only applicable for HMAC-based algorithms') + } + cryptoKey = await crypto.subtle.importKey( + 'raw', + key, + { hash: `SHA-${alg.substr(-3)}`, name: 'HMAC' }, + false, + ['verify'], + ) + } else { + cryptoKey = key + } + + checkKeyLength(alg, cryptoKey) + + return crypto.subtle.verify(subtleAlgorithm(alg), cryptoKey, signature, data) +} + +export default verify diff --git a/src/runtime/browser/webcrypto.ts b/src/runtime/browser/webcrypto.ts new file mode 100644 index 0000000000..a4fb9b69db --- /dev/null +++ b/src/runtime/browser/webcrypto.ts @@ -0,0 +1,12 @@ +import { JOSEError } from '../../util/errors.js' + +const { crypto } = window + +export default crypto +export function ensureSecureContext() { + if (!window.isSecureContext && !crypto.subtle) { + throw new JOSEError( + 'Web Cryptography API is available only in Secure Contexts. See: https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts', + ) + } +} diff --git a/src/runtime/browser/zlib.ts b/src/runtime/browser/zlib.ts new file mode 100644 index 0000000000..ae2a4e4a5f --- /dev/null +++ b/src/runtime/browser/zlib.ts @@ -0,0 +1,13 @@ +import { JOSENotSupported } from '../../util/errors.js' +import type { InflateFunction, DeflateFunction } from '../../types.d' + +export const inflate: InflateFunction = async () => { + throw new JOSENotSupported( + 'JWE "zip" (Compression Algorithm) Header Parameter is not supported by your javascript runtime. You need to use the `inflateRaw` decrypt option to provide Inflate Raw implementation, e.g. using the "pako" module.', + ) +} +export const deflate: DeflateFunction = async () => { + throw new JOSENotSupported( + 'JWE "zip" (Compression Algorithm) Header Parameter is not supported by your javascript runtime.', + ) +} diff --git a/src/runtime/interfaces.d.ts b/src/runtime/interfaces.d.ts new file mode 100644 index 0000000000..a4b93ab252 --- /dev/null +++ b/src/runtime/interfaces.d.ts @@ -0,0 +1,111 @@ +import type { KeyLike } from '../types.d' +import type { EpkJwk, AsyncOrSync } from '../types.i.d' + +/** + * Utility function to encode a string or Uint8Array as a base64url string. + * + * @param input Value that will be base64url-encoded. + */ +export interface Base64UrlEncode { + (input: Uint8Array | string): string +} +/** + * Utility function to decode a base64url encoded string. + * + * @param input Value that will be base64url-decoded. + */ +export interface Base64UrlDecode { + (input: Uint8Array | string): Uint8Array +} +export interface TimingSafeEqual { + (a: Uint8Array, b: Uint8Array): boolean +} +export interface SignFunction { + (alg: string, key: any, data: Uint8Array): Promise +} +export interface VerifyFunction { + (alg: string, key: any, signature: Uint8Array, data: Uint8Array): Promise +} +export interface GetRandomValuesFunction { + (array: Uint8Array): Uint8Array +} +export interface ExportCekFunction { + (key: any): AsyncOrSync +} +export interface AesKwWrapFunction { + (alg: string, key: any, cek: Uint8Array): Promise +} +export interface AesKwUnwrapFunction { + (alg: string, key: any, encryptedKey: Uint8Array): Promise +} +export interface RsaEsEncryptFunction { + (alg: string, key: any, cek: Uint8Array): Promise +} +export interface RsaEsDecryptFunction { + (alg: string, key: any, encryptedKey: Uint8Array): Promise +} +export interface AesGcmKwWrapFunction { + (alg: string, key: any, cek: Uint8Array, iv?: Uint8Array): Promise<{ + encryptedKey: Uint8Array + iv: string + tag: string + }> +} +export interface AesGcmKwUnwrapFunction { + (alg: string, key: any, encryptedKey: Uint8Array, iv: Uint8Array, tag: Uint8Array): Promise< + Uint8Array + > +} +export interface Pbes2KWEncryptFunction { + (alg: string, key: any, cek: Uint8Array, p2c?: number, p2s?: Uint8Array): Promise<{ + encryptedKey: Uint8Array + p2c: number + p2s: string + }> +} +export interface Pbes2KWDecryptFunction { + (alg: string, key: any, encryptedKey: Uint8Array, p2c: number, p2s: Uint8Array): Promise< + Uint8Array + > +} +export interface EcdhESDeriveKeyFunction { + ( + publicKey: any, + privateKey: any, + enc: string, + keyLength: number, + apu?: Uint8Array, + apv?: Uint8Array, + ): Promise +} +export interface EcdhAllowedFunction { + (key: any): boolean +} +export interface GenerateEpkFunction { + (key: any): Promise +} +export interface GetNamedCurveFunction { + (key: any): string +} +export interface EphemeralKeyToPublicJwkFunction { + (key: any): AsyncOrSync +} +export interface PublicJwkToEphemeralKeyFunction { + (jwk: EpkJwk): AsyncOrSync +} +export interface EncryptFunction { + (enc: string, plaintext: Uint8Array, cek: any, iv: Uint8Array, aad: Uint8Array): Promise<{ + ciphertext: Uint8Array + tag: Uint8Array + }> +} +export interface DecryptFunction { + ( + enc: string, + cek: any, + ciphertext: Uint8Array, + iv: Uint8Array, + tag: Uint8Array, + additionalData: Uint8Array, + ): Promise +} diff --git a/src/runtime/node/aesgcmkw.ts b/src/runtime/node/aesgcmkw.ts new file mode 100644 index 0000000000..ffed5024a6 --- /dev/null +++ b/src/runtime/node/aesgcmkw.ts @@ -0,0 +1,50 @@ +import type { KeyObject } from 'crypto' + +import type { AesGcmKwWrapFunction, AesGcmKwUnwrapFunction } from '../interfaces.d' +import encrypt from './encrypt.js' +import decrypt from './decrypt.js' +import ivFactory from '../../lib/iv.js' +import random from './random.js' +import { encode as base64url } from './base64url.js' + +const generateIv = ivFactory(random) + +export const wrap: AesGcmKwWrapFunction = async ( + alg: string, + key: KeyObject | Uint8Array, + cek: Uint8Array, + iv?: Uint8Array, +) => { + const jweAlgorithm = alg.substr(0, 7) + // eslint-disable-next-line no-param-reassign + iv ||= await generateIv(jweAlgorithm) + + const { ciphertext: encryptedKey, tag } = await encrypt( + jweAlgorithm, + cek, + key instanceof Uint8Array ? key : key.export(), + iv, + new Uint8Array(), + ) + + return { encryptedKey, iv: base64url(iv), tag: base64url(tag) } +} + +export const unwrap: AesGcmKwUnwrapFunction = async ( + alg: string, + key: KeyObject | Uint8Array, + encryptedKey: Uint8Array, + iv: Uint8Array, + tag: Uint8Array, +) => { + const jweAlgorithm = alg.substr(0, 7) + + return decrypt( + jweAlgorithm, + key instanceof Uint8Array ? key : key.export(), + encryptedKey, + iv, + tag, + new Uint8Array(), + ) +} diff --git a/src/runtime/node/aeskw.ts b/src/runtime/node/aeskw.ts new file mode 100644 index 0000000000..c3afba93b9 --- /dev/null +++ b/src/runtime/node/aeskw.ts @@ -0,0 +1,48 @@ +import type { KeyObject } from 'crypto' +import { createDecipheriv, createCipheriv, getCiphers } from 'crypto' +import { JOSENotSupported } from '../../util/errors.js' +import type { AesKwUnwrapFunction, AesKwWrapFunction } from '../interfaces.d' +import { concat } from '../../lib/buffer_utils.js' +import getSecretKey from './secret_key.js' + +function checkKeySize(key: KeyObject, alg: string) { + if (key.symmetricKeySize! << 3 !== parseInt(alg.substr(1, 3), 10)) { + throw new TypeError(`invalid key size for alg: ${alg}`) + } +} + +export const wrap: AesKwWrapFunction = async ( + alg: string, + key: KeyObject | Uint8Array, + cek: Uint8Array, +) => { + const size = parseInt(alg.substr(1, 3), 10) + const algorithm = `aes${size}-wrap` + if (!getCiphers().includes(algorithm)) { + throw new JOSENotSupported( + `alg ${alg} is unsupported either by JOSE or your javascript runtime`, + ) + } + const keyObject = getSecretKey(key) + checkKeySize(keyObject, alg) + const cipher = createCipheriv(algorithm, keyObject, Buffer.alloc(8, 0xa6)) + return concat(cipher.update(cek), cipher.final()) +} + +export const unwrap: AesKwUnwrapFunction = async ( + alg: string, + key: KeyObject | Uint8Array, + encryptedKey: Uint8Array, +) => { + const size = parseInt(alg.substr(1, 3), 10) + const algorithm = `aes${size}-wrap` + if (!getCiphers().includes(algorithm)) { + throw new JOSENotSupported( + `alg ${alg} is unsupported either by JOSE or your javascript runtime`, + ) + } + const keyObject = getSecretKey(key) + checkKeySize(keyObject, alg) + const cipher = createDecipheriv(algorithm, keyObject, Buffer.alloc(8, 0xa6)) + return concat(cipher.update(encryptedKey), cipher.final()) +} diff --git a/src/runtime/node/asn1_sequence_encoder.ts b/src/runtime/node/asn1_sequence_encoder.ts new file mode 100644 index 0000000000..43b4ccc0a9 --- /dev/null +++ b/src/runtime/node/asn1_sequence_encoder.ts @@ -0,0 +1,104 @@ +import { JOSENotSupported } from '../../util/errors.js' + +const tagInteger = 0x02 +const tagBitStr = 0x03 +const tagOctStr = 0x04 +const tagSequence = 0x30 + +const bZero = Buffer.from([0x00]) +const bTagInteger = Buffer.from([tagInteger]) +const bTagBitStr = Buffer.from([tagBitStr]) +const bTagSequence = Buffer.from([tagSequence]) +const bTagOctStr = Buffer.from([tagOctStr]) + +const encodeLength = (len: number) => { + if (len < 128) return Buffer.from([len]) + const buffer = Buffer.alloc(5) + buffer.writeUInt32BE(len, 1) + let offset = 1 + while (buffer[offset] === 0) offset++ + buffer[offset - 1] = 0x80 | (5 - offset) + return buffer.slice(offset - 1) +} + +const oids = new Map([ + ['P-256', Buffer.from('06 08 2A 86 48 CE 3D 03 01 07'.replace(/ /g, ''), 'hex')], + ['secp256k1', Buffer.from('06 05 2B 81 04 00 0A'.replace(/ /g, ''), 'hex')], + ['P-384', Buffer.from('06 05 2B 81 04 00 22'.replace(/ /g, ''), 'hex')], + ['P-521', Buffer.from('06 05 2B 81 04 00 23'.replace(/ /g, ''), 'hex')], + ['ecPublicKey', Buffer.from('06 07 2A 86 48 CE 3D 02 01'.replace(/ /g, ''), 'hex')], + ['X25519', Buffer.from('06 03 2B 65 6E'.replace(/ /g, ''), 'hex')], + ['X448', Buffer.from('06 03 2B 65 6F'.replace(/ /g, ''), 'hex')], + ['Ed25519', Buffer.from('06 03 2B 65 70'.replace(/ /g, ''), 'hex')], + ['Ed448', Buffer.from('06 03 2B 65 71'.replace(/ /g, ''), 'hex')], +]) + +/** + * The end justifies the means. + */ +export default class DumbAsn1Encoder { + length: number + + elements: Buffer[] + + constructor() { + this.length = 0 + this.elements = [] + } + + oidFor(oid: string) { + const bOid = oids.get(oid) + if (!bOid) { + throw new JOSENotSupported('unsupported or invalid OID') + } + this.elements.push(bOid) + this.length += bOid.length + } + + zero() { + this.elements.push(bTagInteger, Buffer.from([0x01]), bZero) + this.length += 3 + } + + one() { + this.elements.push(bTagInteger, Buffer.from([0x01]), Buffer.from([0x01])) + this.length += 3 + } + + unsignedInteger(integer: Buffer) { + if (integer[0] & 0x80) { + const len = encodeLength(integer.length + 1) + this.elements.push(bTagInteger, len, bZero, integer) + this.length += 2 + len.length + integer.length + } else { + let i = 0 + while (integer[i] === 0 && (integer[i + 1] & 0x80) === 0) i++ + + const len = encodeLength(integer.length - i) + this.elements.push(bTagInteger, encodeLength(integer.length - i), integer.slice(i)) + this.length += 1 + len.length + integer.length - i + } + } + + octStr(octStr: Buffer) { + const len = encodeLength(octStr.length) + this.elements.push(bTagOctStr, encodeLength(octStr.length), octStr) + this.length += 1 + len.length + octStr.length + } + + bitStr(bitS: Buffer) { + const len = encodeLength(bitS.length + 1) + this.elements.push(bTagBitStr, encodeLength(bitS.length + 1), bZero, bitS) + this.length += 1 + len.length + bitS.length + 1 + } + + add(seq: Buffer) { + this.elements.push(seq) + this.length += seq.length + } + + end(tag = bTagSequence) { + const len = encodeLength(this.length) + return Buffer.concat([tag, len, ...this.elements], 1 + len.length + this.length) + } +} diff --git a/src/runtime/node/base64url.ts b/src/runtime/node/base64url.ts new file mode 100644 index 0000000000..319cdc2651 --- /dev/null +++ b/src/runtime/node/base64url.ts @@ -0,0 +1,13 @@ +import type { Base64UrlDecode, Base64UrlEncode } from '../interfaces.d' +import { decoder } from '../../lib/buffer_utils.js' + +export const encode: Base64UrlEncode = (input) => + Buffer.from(input).toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_') + +export const decode: Base64UrlDecode = (input) => { + let encoded = input + if (encoded instanceof Uint8Array) { + encoded = decoder.decode(encoded) + } + return new Uint8Array(Buffer.from(encoded, 'base64')) +} diff --git a/src/runtime/node/cbc_tag.ts b/src/runtime/node/cbc_tag.ts new file mode 100644 index 0000000000..0f160af4a8 --- /dev/null +++ b/src/runtime/node/cbc_tag.ts @@ -0,0 +1,16 @@ +import { createHmac } from 'crypto' +import { concat, uint64be } from '../../lib/buffer_utils.js' + +export default function cbcTag( + aad: Uint8Array, + iv: Uint8Array, + ciphertext: Uint8Array, + macSize: number, + macKey: Uint8Array, + keySize: number, +) { + const macData = concat(aad, iv, ciphertext, uint64be(aad.length << 3)) + const hmac = createHmac(`sha${macSize}`, macKey) + hmac.update(macData) + return hmac.digest().slice(0, keySize >> 3) +} diff --git a/src/runtime/node/check_cek_length.ts b/src/runtime/node/check_cek_length.ts new file mode 100644 index 0000000000..a5c5dd7abe --- /dev/null +++ b/src/runtime/node/check_cek_length.ts @@ -0,0 +1,40 @@ +import { KeyObject } from 'crypto' +import { JWEInvalid, JOSENotSupported } from '../../util/errors.js' + +const checkCekLength = (enc: string, cek: Uint8Array | KeyObject) => { + let expected: number + switch (enc) { + case 'A128CBC-HS256': + case 'A192CBC-HS384': + case 'A256CBC-HS512': + expected = parseInt(enc.substr(-3), 10) + break + case 'A128GCM': + case 'A192GCM': + case 'A256GCM': + expected = parseInt(enc.substr(1, 3), 10) + break + default: + throw new JOSENotSupported( + `Content Encryption Algorithm ${enc} is unsupported either by JOSE or your javascript runtime`, + ) + } + + if (cek instanceof Uint8Array) { + if (cek.length << 3 !== expected) { + throw new JWEInvalid('Invalid Content Encryption Key length') + } + return + } + + if (cek instanceof KeyObject && cek.type === 'secret') { + if (cek.symmetricKeySize! << 3 !== expected) { + throw new JWEInvalid('Invalid Content Encryption Key length') + } + return + } + + throw new TypeError('Invalid Content Encryption Key type') +} + +export default checkCekLength diff --git a/src/runtime/node/check_modulus_length.ts b/src/runtime/node/check_modulus_length.ts new file mode 100644 index 0000000000..e576b99e76 --- /dev/null +++ b/src/runtime/node/check_modulus_length.ts @@ -0,0 +1,70 @@ +import type { KeyObject } from 'crypto' + +const weakMap: WeakMap = new WeakMap() + +const getLength = (buf: Buffer, index: number): number => { + let len = buf.readUInt8(1) + + // Short form + if ((len & 0x80) === 0) { + if (index === 0) { + return len + } + return getLength(buf.subarray(2 + len), index - 1) + } + + // Long form + const num = len & 0x7f + + len = 0 + for (let i = 0; i < num; i++) { + len <<= 8 + const j = buf.readUInt8(2 + i) + len |= j + } + + if (index === 0) { + return len + } + + return getLength(buf.subarray(2 + len), index - 1) +} + +const getLengthOfSeqIndex = (sequence: Buffer, index: number): number => { + const len = sequence.readUInt8(1) + + // short form + if ((len & 0x80) === 0) { + return getLength(sequence.subarray(2), index) + } + + // Long form + const num = len & 0x7f + return getLength(sequence.subarray(2 + num), index) +} + +const getModulusLength = (key: KeyObject): number => { + if (weakMap.has(key)) { + return weakMap.get(key)! + } + + const modulusLength = + (getLengthOfSeqIndex( + key.export({ format: 'der', type: 'pkcs1' }), + key.type === 'private' ? 1 : 0, + ) - + 1) << + 3 + weakMap.set(key, modulusLength) + return modulusLength +} + +export const setModulusLength = (keyObject: KeyObject, modulusLength: number) => { + weakMap.set(keyObject, modulusLength) +} + +export default (key: KeyObject, alg: string) => { + if (getModulusLength(key) < 2048) { + throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`) + } +} diff --git a/src/runtime/node/decrypt.ts b/src/runtime/node/decrypt.ts new file mode 100644 index 0000000000..65075dc17f --- /dev/null +++ b/src/runtime/node/decrypt.ts @@ -0,0 +1,102 @@ +import { getCiphers, KeyObject, createDecipheriv } from 'crypto' +import type { CipherGCMTypes } from 'crypto' + +import type { DecryptFunction } from '../interfaces.d' +import checkIvLength from '../../lib/check_iv_length.js' +import checkCekLength from './check_cek_length.js' +import { concat } from '../../lib/buffer_utils.js' +import { JOSENotSupported, JWEDecryptionFailed } from '../../util/errors.js' +import timingSafeEqual from './timing_safe_equal.js' +import cbcTag from './cbc_tag.js' + +async function cbcDecrypt( + enc: string, + cek: Uint8Array | KeyObject, + ciphertext: Uint8Array, + iv: Uint8Array, + tag: Uint8Array, + aad: Uint8Array, +) { + const keySize = parseInt(enc.substr(1, 3), 10) + + if (cek instanceof KeyObject) { + // eslint-disable-next-line no-param-reassign + cek = cek.export() + } + + const encKey = cek.slice(keySize >> 3) + const macKey = cek.slice(0, keySize >> 3) + const macSize = parseInt(enc.substr(-3), 10) + + const algorithm = `aes-${keySize}-cbc` + if (!getCiphers().includes(algorithm)) { + throw new JOSENotSupported(`alg ${enc} is unsupported either by your javascript runtime`) + } + + let plaintext!: Uint8Array + try { + const cipher = createDecipheriv(algorithm, encKey, iv) + plaintext = concat(cipher.update(ciphertext), cipher.final()) + } catch { + // + } + + const expectedTag = cbcTag(aad, iv, ciphertext, macSize, macKey, keySize) + + let macCheckPassed!: boolean + try { + macCheckPassed = timingSafeEqual(tag, expectedTag) + } catch { + // + } + + if (!plaintext || !macCheckPassed) { + throw new JWEDecryptionFailed() + } + + return plaintext +} +async function gcmDecrypt( + enc: string, + cek: Uint8Array | KeyObject, + ciphertext: Uint8Array, + iv: Uint8Array, + tag: Uint8Array, + aad: Uint8Array, +) { + const keySize = parseInt(enc.substr(1, 3), 10) + + const algorithm = `aes-${keySize}-gcm` as CipherGCMTypes + if (!getCiphers().includes(algorithm)) { + throw new JOSENotSupported(`alg ${enc} is unsupported either by your javascript runtime`) + } + try { + const cipher = createDecipheriv(algorithm, cek, iv, { authTagLength: 16 }) + cipher.setAuthTag(tag) + cipher.setAAD(aad) + + return concat(cipher.update(ciphertext), cipher.final()) + } catch (err) { + throw new JWEDecryptionFailed() + } +} + +const decrypt: DecryptFunction = async ( + enc: string, + cek: Uint8Array | KeyObject, + ciphertext: Uint8Array, + iv: Uint8Array, + tag: Uint8Array, + aad: Uint8Array, +) => { + checkCekLength(enc, cek) + checkIvLength(enc, iv) + + if (enc.substr(4, 3) === 'CBC') { + return cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) + } + + return gcmDecrypt(enc, cek, ciphertext, iv, tag, aad) +} + +export default decrypt diff --git a/src/runtime/node/digest.ts b/src/runtime/node/digest.ts new file mode 100644 index 0000000000..6b83e85644 --- /dev/null +++ b/src/runtime/node/digest.ts @@ -0,0 +1,5 @@ +import { createHash } from 'crypto' + +export default (digest: 'sha256' | 'sha384' | 'sha512', data: Uint8Array): Uint8Array => { + return createHash(digest).update(data).digest() +} diff --git a/src/runtime/node/dsa_digest.ts b/src/runtime/node/dsa_digest.ts new file mode 100644 index 0000000000..10fc6754d3 --- /dev/null +++ b/src/runtime/node/dsa_digest.ts @@ -0,0 +1,29 @@ +import { JOSENotSupported } from '../../util/errors.js' + +export default function dsaDigest(alg: string) { + switch (alg) { + case 'PS256': + case 'RS256': + case 'ES256': + case 'ES256K': + return 'sha256' + + case 'PS384': + case 'RS384': + case 'ES384': + return 'sha384' + + case 'PS512': + case 'RS512': + case 'ES512': + return 'sha512' + + case 'EdDSA': + return undefined + + default: + throw new JOSENotSupported( + `alg ${alg} is unsupported either by JOSE or your javascript runtime`, + ) + } +} diff --git a/src/runtime/node/ecdhes.ts b/src/runtime/node/ecdhes.ts new file mode 100644 index 0000000000..c25338cd33 --- /dev/null +++ b/src/runtime/node/ecdhes.ts @@ -0,0 +1,138 @@ +import type { KeyObject } from 'crypto' +import { diffieHellman, generateKeyPair as generateKeyPairCb, createPublicKey } from 'crypto' +import { promisify } from 'util' + +import type { + EcdhAllowedFunction, + EcdhESDeriveKeyFunction, + EphemeralKeyToPublicJwkFunction, + GenerateEpkFunction, + PublicJwkToEphemeralKeyFunction, +} from '../interfaces.d' +import * as base64url from './base64url.js' +import getNamedCurve from './get_named_curve.js' +import { + encoder, + concat, + uint32be, + lengthAndInput, + concatKdf as KDF, +} from '../../lib/buffer_utils.js' +import type { EpkJwk } from '../../types.i.d' +import digest from './digest.js' +import { JOSENotSupported } from '../../util/errors.js' + +const generateKeyPair = promisify(generateKeyPairCb) + +const concatKdf = KDF.bind(undefined, digest.bind(undefined, 'sha256')) + +export const deriveKey: EcdhESDeriveKeyFunction = async ( + publicKey: KeyObject, + privateKey: KeyObject, + algorithm: string, + keyLength: number, + apu: Uint8Array = new Uint8Array(), + apv: Uint8Array = new Uint8Array(), +) => { + const value = concat( + lengthAndInput(encoder.encode(algorithm)), + lengthAndInput(apu), + lengthAndInput(apv), + uint32be(keyLength), + ) + + const sharedSecret = diffieHellman({ privateKey, publicKey }) + return concatKdf(sharedSecret, keyLength, value) +} + +export const ephemeralKeyToPublicJWK: EphemeralKeyToPublicJwkFunction = function ephemeralKeyToPublicJWK( + key: KeyObject, +) { + switch (key.asymmetricKeyType) { + case 'x25519': + case 'x448': { + const s = key.asymmetricKeyType === 'x25519' ? 32 : 56 + return { + crv: key.asymmetricKeyType.toUpperCase(), + kty: 'OKP', + x: base64url.encode(createPublicKey(key).export({ format: 'der', type: 'spki' }).slice(-s)), + } + } + case 'ec': { + const crv = getNamedCurve(key) + // eslint-disable-next-line no-nested-ternary + const s = crv === 'P-256' ? 64 : crv === 'P-384' ? 96 : 132 + const b = key.export({ format: 'der', type: 'pkcs8' }) + const x = base64url.encode(b.slice(-s, -s >> 1)) + const y = base64url.encode(b.slice(-s >> 1)) + return { crv, kty: 'EC', x, y } + } + default: + throw new JOSENotSupported('unsupported or invalid EPK') + } +} + +export const generateEpk: GenerateEpkFunction = async (key: KeyObject) => { + switch (key.asymmetricKeyType) { + case 'x25519': + return (await generateKeyPair('x25519')).privateKey + case 'x448': { + return (await generateKeyPair('x448')).privateKey + } + case 'ec': { + const namedCurve = getNamedCurve(key) + return (await generateKeyPair('ec', { namedCurve })).privateKey + } + default: + throw new JOSENotSupported('unsupported or invalid EPK') + } +} + +export const publicJwkToEphemeralKey: PublicJwkToEphemeralKeyFunction = async (jwk: EpkJwk) => { + let pem: Buffer + switch (jwk.crv) { + case 'P-256': + pem = Buffer.concat([ + Buffer.from('3059301306072a8648ce3d020106082a8648ce3d03010703420004', 'hex'), + base64url.decode(jwk.x!), + base64url.decode(jwk.y!), + ]) + break + case 'P-384': + pem = Buffer.concat([ + Buffer.from('3076301006072a8648ce3d020106052b8104002203620004', 'hex'), + base64url.decode(jwk.x!), + base64url.decode(jwk.y!), + ]) + break + case 'P-521': + pem = Buffer.concat([ + Buffer.from('30819b301006072a8648ce3d020106052b810400230381860004', 'hex'), + base64url.decode(jwk.x!), + base64url.decode(jwk.y!), + ]) + break + case 'X25519': + pem = Buffer.concat([ + Buffer.from('302a300506032b656e032100', 'hex'), + base64url.decode(jwk.x!), + ]) + break + case 'X448': + pem = Buffer.concat([ + Buffer.from('3042300506032b656f033900', 'hex'), + base64url.decode(jwk.x!), + ]) + break + default: + throw new JOSENotSupported( + 'unsupported or invalid JWK "crv" (Curve or Subtype of Key Pair) Parameter value', + ) + } + + return createPublicKey({ format: 'der', key: pem, type: 'spki' }) +} + +const curves = ['P-256', 'P-384', 'P-521', 'X25519', 'X448'] +export const ecdhAllowed: EcdhAllowedFunction = (key: KeyObject) => + curves.includes(getNamedCurve(key)) diff --git a/src/runtime/node/encrypt.ts b/src/runtime/node/encrypt.ts new file mode 100644 index 0000000000..ef3b340302 --- /dev/null +++ b/src/runtime/node/encrypt.ts @@ -0,0 +1,72 @@ +import { KeyObject, createCipheriv } from 'crypto' +import type { CipherGCMTypes } from 'crypto' + +import type { EncryptFunction } from '../interfaces.d' +import checkIvLength from '../../lib/check_iv_length.js' +import checkCekLength from './check_cek_length.js' +import { concat } from '../../lib/buffer_utils.js' +import cbcTag from './cbc_tag.js' + +async function cbcEncrypt( + enc: string, + plaintext: Uint8Array, + cek: KeyObject | Uint8Array, + iv: Uint8Array, + aad: Uint8Array, +) { + const keySize = parseInt(enc.substr(1, 3), 10) + + if (cek instanceof KeyObject) { + // eslint-disable-next-line no-param-reassign + cek = cek.export() + } + + const encKey = cek.slice(keySize >> 3) + const macKey = cek.slice(0, keySize >> 3) + + const algorithm = `aes-${keySize}-cbc` + const cipher = createCipheriv(algorithm, encKey, iv) + const ciphertext = concat(cipher.update(plaintext), cipher.final()) + + const macSize = parseInt(enc.substr(-3), 10) + const tag = cbcTag(aad, iv, ciphertext, macSize, macKey, keySize) + + return { ciphertext, tag } +} +async function gcmEncrypt( + enc: string, + plaintext: Uint8Array, + cek: KeyObject | Uint8Array, + iv: Uint8Array, + aad: Uint8Array, +) { + const keySize = parseInt(enc.substr(1, 3), 10) + + const algorithm = `aes-${keySize}-gcm` as CipherGCMTypes + const cipher = createCipheriv(algorithm, cek, iv, { authTagLength: 16 }) + cipher.setAAD(aad) + + const ciphertext = concat(cipher.update(plaintext), cipher.final()) + const tag = cipher.getAuthTag() + + return { ciphertext, tag } +} + +const encrypt: EncryptFunction = async ( + enc: string, + plaintext: Uint8Array, + cek: KeyObject | Uint8Array, + iv: Uint8Array, + aad: Uint8Array, +) => { + checkCekLength(enc, cek) + checkIvLength(enc, iv) + + if (enc.substr(4, 3) === 'CBC') { + return cbcEncrypt(enc, plaintext, cek, iv, aad) + } + + return gcmEncrypt(enc, plaintext, cek, iv, aad) +} + +export default encrypt diff --git a/src/runtime/node/fetch.ts b/src/runtime/node/fetch.ts new file mode 100644 index 0000000000..b5fee70e84 --- /dev/null +++ b/src/runtime/node/fetch.ts @@ -0,0 +1,43 @@ +import { get as http } from 'http' +import type { ClientRequest } from 'http' +import { get as https, RequestOptions } from 'https' + +import { JOSEError } from '../../util/errors.js' +import { concat, decoder } from '../../lib/buffer_utils.js' + +const protocols: { [protocol: string]: (...args: Parameters) => ClientRequest } = { + 'https:': https, + 'http:': http, +} + +export default async (url: URL, timeout: number, options?: RequestOptions) => { + if (!(url.protocol in protocols)) { + throw new TypeError('Unsupported URL protocol.') + } + return new Promise((resolve, reject) => { + protocols[url.protocol]( + url, + { + ...options, + timeout, + }, + async (response) => { + if (response.statusCode !== 200) { + reject(new JOSEError('Expected 200 OK from the JSON Web Key Set HTTP response')) + } else { + const parts = [] + // eslint-disable-next-line no-restricted-syntax + for await (const part of response) { + parts.push(part) + } + + try { + resolve(JSON.parse(decoder.decode(concat(...parts)))) + } catch (err) { + reject(new JOSEError('Failed to parse the JSON Web Key Set HTTP response as JSON')) + } + } + }, + ).on('error', reject) + }) as Promise +} diff --git a/src/runtime/node/generate.ts b/src/runtime/node/generate.ts new file mode 100644 index 0000000000..912b6076d0 --- /dev/null +++ b/src/runtime/node/generate.ts @@ -0,0 +1,99 @@ +import { createSecretKey, generateKeyPair as generateKeyPairCb } from 'crypto' +import { promisify } from 'util' + +import random from './random.js' +import { JOSENotSupported } from '../../util/errors.js' + +const generate = promisify(generateKeyPairCb) + +export async function generateSecret(alg: string) { + let length: number + switch (alg) { + case 'HS256': + case 'HS384': + case 'HS512': + case 'A128CBC-HS256': + case 'A192CBC-HS384': + case 'A256CBC-HS512': + length = parseInt(alg.substr(-3), 10) + break + case 'A128KW': + case 'A192KW': + case 'A256KW': + case 'A128GCMKW': + case 'A192GCMKW': + case 'A256GCMKW': + case 'A128GCM': + case 'A192GCM': + case 'A256GCM': + length = parseInt(alg.substring(1, 4), 10) + break + default: + throw new JOSENotSupported('unsupported or invalid JWK "alg" (Algorithm) Parameter value') + } + + return createSecretKey(random(new Uint8Array(length >> 3))) +} + +interface Options { + crv?: string +} + +export async function generateKeyPair(alg: string, options?: Options) { + switch (alg) { + case 'RS256': + case 'RS384': + case 'RS512': + case 'PS256': + case 'PS384': + case 'PS512': + case 'RSA-OAEP': + case 'RSA-OAEP-256': + case 'RSA-OAEP-384': + case 'RSA-OAEP-512': + case 'RSA1_5': + return generate('rsa', { modulusLength: 2048, publicExponent: 0x10001 }) + case 'ES256': + return generate('ec', { namedCurve: 'P-256' }) + case 'ES256K': + return generate('ec', { namedCurve: 'secp256k1' }) + case 'ES384': + return generate('ec', { namedCurve: 'P-384' }) + case 'ES512': + return generate('ec', { namedCurve: 'P-521' }) + case 'EdDSA': { + switch (options?.crv) { + case undefined: + case 'Ed25519': + return generate('ed25519') + case 'Ed448': + return generate('ed448') + default: + throw new JOSENotSupported( + 'invalid or unsupported crv option provided, supported values are Ed25519 and Ed448', + ) + } + } + case 'ECDH-ES': + case 'ECDH-ES+A128KW': + case 'ECDH-ES+A192KW': + case 'ECDH-ES+A256KW': + switch (options?.crv) { + case undefined: + case 'P-256': + case 'P-384': + case 'P-521': + return generate('ec', { namedCurve: options?.crv || 'P-256' }) + case 'X25519': + return generate('x25519') + case 'X448': + return generate('x448') + default: + throw new JOSENotSupported( + 'invalid or unsupported crv option provided, supported values are P-256, P-384, P-521, X25519, and X448', + ) + } + default: + throw new JOSENotSupported('unsupported or invalid JWK "alg" (Algorithm) Parameter value') + } +} diff --git a/src/runtime/node/get_named_curve.ts b/src/runtime/node/get_named_curve.ts new file mode 100644 index 0000000000..8062abe9ec --- /dev/null +++ b/src/runtime/node/get_named_curve.ts @@ -0,0 +1,55 @@ +import { KeyObject, createPublicKey } from 'crypto' +import { JOSENotSupported } from '../../util/errors.js' + +const p256 = Buffer.from([42, 134, 72, 206, 61, 3, 1, 7]) +const p384 = Buffer.from([43, 129, 4, 0, 34]) +const p521 = Buffer.from([43, 129, 4, 0, 35]) +const secp256k1 = Buffer.from([43, 129, 4, 0, 10]) + +const weakMap: WeakMap = new WeakMap() + +const getNamedCurve = (key: KeyObject): string => { + if (key.type === 'secret') { + throw new TypeError('only "private" or "public" key objects can be used for this operation') + } + switch (key.asymmetricKeyType) { + case 'x25519': + case 'x448': + return key.asymmetricKeyType.toUpperCase() + case 'ec': { + if (weakMap.has(key)) { + return weakMap.get(key) as string + } + if (key.type === 'private') { + return getNamedCurve(createPublicKey(key)) + } + + const buf = key.export({ format: 'der', type: 'spki' }) + const i = buf[1] < 128 ? 14 : 15 + const len = buf[i] + const curveOid = buf.slice(i + 1, i + 1 + len) + let curve: string + if (curveOid.equals(p256)) { + curve = 'P-256' + } else if (curveOid.equals(p384)) { + curve = 'P-384' + } else if (curveOid.equals(p521)) { + curve = 'P-521' + } else if (curveOid.equals(secp256k1)) { + curve = 'secp256k1' + } else { + throw new JOSENotSupported('unsupported curve for this operation') + } + weakMap.set(key, curve) + return curve + } + default: + throw new TypeError('invalid key asymmetric key type for this operation') + } +} + +export function setCurve(keyObject: KeyObject, curve: string) { + weakMap.set(keyObject, curve) +} + +export default getNamedCurve diff --git a/src/runtime/node/hmac_digest.ts b/src/runtime/node/hmac_digest.ts new file mode 100644 index 0000000000..4295b991b3 --- /dev/null +++ b/src/runtime/node/hmac_digest.ts @@ -0,0 +1,19 @@ +import { JOSENotSupported } from '../../util/errors.js' + +export default function hmacDigest(alg: string) { + switch (alg) { + case 'HS256': + return 'sha256' + + case 'HS384': + return 'sha384' + + case 'HS512': + return 'sha512' + + default: + throw new JOSENotSupported( + `alg ${alg} is unsupported either by JOSE or your javascript runtime`, + ) + } +} diff --git a/src/runtime/node/jwk_to_key.ts b/src/runtime/node/jwk_to_key.ts new file mode 100644 index 0000000000..b784edd573 --- /dev/null +++ b/src/runtime/node/jwk_to_key.ts @@ -0,0 +1,121 @@ +import type { KeyObject, PublicKeyInput, PrivateKeyInput } from 'crypto' +import { createPrivateKey, createPublicKey, createSecretKey } from 'crypto' + +import { decode as base64url } from './base64url.js' +import { JOSENotSupported } from '../../util/errors.js' +import { setCurve } from './get_named_curve.js' +import { setModulusLength } from './check_modulus_length.js' +import Asn1SequenceEncoder from './asn1_sequence_encoder.js' +import type { JWK } from '../../types.d' + +export default async (jwk: JWK): Promise => { + switch (jwk.kty) { + case 'oct': { + return createSecretKey(base64url(jwk.k!)) + } + case 'RSA': { + const enc = new Asn1SequenceEncoder() + const isPrivate = jwk.d !== undefined + + const modulus = Buffer.from(jwk.n!, 'base64') + const exponent = Buffer.from(jwk.e!, 'base64') + + if (isPrivate) { + enc.unsignedInteger(Buffer.from([0x00])) + enc.unsignedInteger(modulus) + enc.unsignedInteger(exponent) + enc.unsignedInteger(Buffer.from(jwk.d!, 'base64')) + enc.unsignedInteger(Buffer.from(jwk.p!, 'base64')) + enc.unsignedInteger(Buffer.from(jwk.q!, 'base64')) + enc.unsignedInteger(Buffer.from(jwk.dp!, 'base64')) + enc.unsignedInteger(Buffer.from(jwk.dq!, 'base64')) + enc.unsignedInteger(Buffer.from(jwk.qi!, 'base64')) + } else { + enc.unsignedInteger(modulus) + enc.unsignedInteger(exponent) + } + + const der = enc.end() + + const createInput: PublicKeyInput & PrivateKeyInput = { + key: der, + format: 'der', + type: 'pkcs1', + } + + const keyObject = isPrivate ? createPrivateKey(createInput) : createPublicKey(createInput) + setModulusLength(keyObject, modulus.length << 3) + + return keyObject + } + case 'EC': { + const enc = new Asn1SequenceEncoder() + const isPrivate = jwk.d !== undefined + + if (isPrivate) { + enc.zero() + const enc$1 = new Asn1SequenceEncoder() + enc$1.oidFor('ecPublicKey') + enc$1.oidFor(jwk.crv!) + enc.add(enc$1.end()) + const enc$2 = new Asn1SequenceEncoder() + enc$2.one() + enc$2.octStr(Buffer.from(jwk.d!, 'base64')) + const f = enc$2.end() + enc.add(Buffer.from([0x04])) + enc.add(Buffer.from([f.length])) + enc.add(f) + const der = enc.end() + const keyObject = createPrivateKey({ key: der, format: 'der', type: 'pkcs8' }) + setCurve(keyObject, jwk.crv!) + return keyObject + } + + const enc$1 = new Asn1SequenceEncoder() + enc$1.oidFor('ecPublicKey') + enc$1.oidFor(jwk.crv!) + enc.add(enc$1.end()) + const pub = Buffer.concat([ + Buffer.alloc(1, 4), + Buffer.from(jwk.x!, 'base64'), + Buffer.from(jwk.y!, 'base64'), + ]) + enc.bitStr(pub) + const der = enc.end() + + const keyObject = createPublicKey({ key: der, format: 'der', type: 'spki' }) + setCurve(keyObject, jwk.crv!) + return keyObject + } + case 'OKP': { + const enc = new Asn1SequenceEncoder() + const isPrivate = jwk.d !== undefined + + if (isPrivate) { + enc.zero() + const enc$1 = new Asn1SequenceEncoder() + enc$1.oidFor(jwk.crv!) + enc.add(enc$1.end()) + + const enc$2 = new Asn1SequenceEncoder() + enc$2.octStr(Buffer.from(jwk.d!, 'base64')) + const f = enc$2.end(Buffer.from([0x04])) + + enc.add(f) + + const der = enc.end() + return createPrivateKey({ key: der, format: 'der', type: 'pkcs8' }) + } + + const enc$1 = new Asn1SequenceEncoder() + enc$1.oidFor(jwk.crv!) + enc.add(enc$1.end()) + enc.bitStr(Buffer.from(jwk.x!, 'base64')) + const der = enc.end() + + return createPublicKey({ key: der, format: 'der', type: 'spki' }) + } + default: + throw new JOSENotSupported('unsupported or invalid JWK "kty" (Key Type) Parameter value') + } +} diff --git a/src/runtime/node/node_key.ts b/src/runtime/node/node_key.ts new file mode 100644 index 0000000000..d2a9b63513 --- /dev/null +++ b/src/runtime/node/node_key.ts @@ -0,0 +1,67 @@ +import type { KeyObject, SignKeyObjectInput } from 'crypto' +import { constants } from 'crypto' + +import getNamedCurve from './get_named_curve.js' +import { JOSENotSupported } from '../../util/errors.js' +import checkModulusLength from './check_modulus_length.js' + +const ecCurveAlgMap = new Map([ + ['ES256', 'P-256'], + ['ES256K', 'secp256k1'], + ['ES384', 'P-384'], + ['ES512', 'P-521'], +]) + +export default function keyForCrypto(alg: string, key: KeyObject): KeyObject | SignKeyObjectInput { + switch (alg) { + case 'EdDSA': + if (key.type === 'secret' || !['ed25519', 'ed448'].includes(key.asymmetricKeyType!)) { + throw new TypeError('invalid key type or asymmetric key type for this operation') + } + + return key + + case 'RS256': + case 'RS384': + case 'RS512': + if (key.type === 'secret' || key.asymmetricKeyType !== 'rsa') { + throw new TypeError('invalid key type or asymmetric key type for this operation') + } + checkModulusLength(key, alg) + + return key + + case 'PS256': + case 'PS384': + case 'PS512': + if (key.type === 'secret' || key.asymmetricKeyType !== 'rsa') { + throw new TypeError('invalid key type or asymmetric key type for this operation') + } + checkModulusLength(key, alg) + + return { + key, + padding: constants.RSA_PKCS1_PSS_PADDING, + saltLength: constants.RSA_PSS_SALTLEN_DIGEST, + } + + case 'ES256': + case 'ES256K': + case 'ES384': + case 'ES512': + if (key.type === 'secret' || key.asymmetricKeyType !== 'ec') { + throw new TypeError('invalid key type or asymmetric key type for this operation') + } + + if (ecCurveAlgMap.get(alg) !== getNamedCurve(key)) { + throw new TypeError('invalid key curve for the algorithm') + } + + return { dsaEncoding: 'ieee-p1363', key } + + default: + throw new JOSENotSupported( + `alg ${alg} is unsupported either by JOSE or your javascript runtime`, + ) + } +} diff --git a/src/runtime/node/pbes2kw.ts b/src/runtime/node/pbes2kw.ts new file mode 100644 index 0000000000..b98b102bcd --- /dev/null +++ b/src/runtime/node/pbes2kw.ts @@ -0,0 +1,44 @@ +import { promisify } from 'util' +import type { KeyObject } from 'crypto' +import { pbkdf2 as pbkdf2cb } from 'crypto' +import type { Pbes2KWDecryptFunction, Pbes2KWEncryptFunction } from '../interfaces.d' +import random from './random.js' +import { p2s as concatSalt } from '../../lib/buffer_utils.js' +import { encode as base64url } from './base64url.js' +import { wrap, unwrap } from './aeskw.js' +import checkP2s from '../../lib/check_p2s.js' + +const pbkdf2 = promisify(pbkdf2cb) + +export const encrypt: Pbes2KWEncryptFunction = async ( + alg: string, + key: KeyObject | Uint8Array, + cek: Uint8Array, + p2c: number = Math.floor(Math.random() * 2049) + 2048, + p2s: Uint8Array = random(new Uint8Array(16)), +) => { + checkP2s(p2s) + const salt = concatSalt(alg, p2s) + const keylen = parseInt(alg.substr(13, 3), 10) >> 3 + const password = key instanceof Uint8Array ? key : key.export() + const derivedKey = await pbkdf2(password, salt, p2c, keylen, `sha${alg.substr(8, 3)}`) + const encryptedKey = await wrap(alg.substr(-6), derivedKey, cek) + + return { encryptedKey, p2c, p2s: base64url(p2s) } +} + +export const decrypt: Pbes2KWDecryptFunction = async ( + alg: string, + key: KeyObject | Uint8Array, + encryptedKey: Uint8Array, + p2c: number, + p2s: Uint8Array, +) => { + checkP2s(p2s) + const salt = concatSalt(alg, p2s) + const keylen = parseInt(alg.substr(13, 3), 10) >> 3 + const password = key instanceof Uint8Array ? key : key.export() + const derivedKey = await pbkdf2(password, salt, p2c, keylen, `sha${alg.substr(8, 3)}`) + + return unwrap(alg.substr(-6), derivedKey, encryptedKey) +} diff --git a/src/runtime/node/random.ts b/src/runtime/node/random.ts new file mode 100644 index 0000000000..e4f9c8852a --- /dev/null +++ b/src/runtime/node/random.ts @@ -0,0 +1,6 @@ +import { randomFillSync } from 'crypto' +import type { GetRandomValuesFunction } from '../interfaces.d' + +const random: GetRandomValuesFunction = randomFillSync + +export default random diff --git a/src/runtime/node/rsaes.ts b/src/runtime/node/rsaes.ts new file mode 100644 index 0000000000..6e55253cd4 --- /dev/null +++ b/src/runtime/node/rsaes.ts @@ -0,0 +1,62 @@ +import type { KeyObject } from 'crypto' +import { publicEncrypt, constants, privateDecrypt } from 'crypto' +import type { RsaEsDecryptFunction, RsaEsEncryptFunction } from '../interfaces.d' +import checkModulusLength from './check_modulus_length.js' + +const checkKey = (key: KeyObject, alg: string) => { + if (key.type === 'secret' || key.asymmetricKeyType !== 'rsa') { + throw new TypeError('invalid key type or asymmetric key type for this operation') + } + checkModulusLength(key, alg) +} + +const resolvePadding = (alg: string) => { + switch (alg) { + case 'RSA-OAEP': + case 'RSA-OAEP-256': + case 'RSA-OAEP-384': + case 'RSA-OAEP-512': + return constants.RSA_PKCS1_OAEP_PADDING + case 'RSA1_5': + return constants.RSA_PKCS1_PADDING + default: + return undefined + } +} + +const resolveOaepHash = (alg: string) => { + switch (alg) { + case 'RSA-OAEP': + return 'sha1' + case 'RSA-OAEP-256': + return 'sha256' + case 'RSA-OAEP-384': + return 'sha384' + case 'RSA-OAEP-512': + return 'sha512' + default: + return undefined + } +} + +export const encrypt: RsaEsEncryptFunction = async ( + alg: string, + key: KeyObject, + cek: Uint8Array, +) => { + const padding = resolvePadding(alg) + const oaepHash = resolveOaepHash(alg) + checkKey(key, alg) + return publicEncrypt({ key, oaepHash, padding }, cek) +} + +export const decrypt: RsaEsDecryptFunction = async ( + alg: string, + key: KeyObject, + encryptedKey: Uint8Array, +) => { + const padding = resolvePadding(alg) + const oaepHash = resolveOaepHash(alg) + checkKey(key, alg) + return privateDecrypt({ key, oaepHash, padding }, encryptedKey) +} diff --git a/src/runtime/node/secret_key.ts b/src/runtime/node/secret_key.ts new file mode 100644 index 0000000000..a5ef8297ff --- /dev/null +++ b/src/runtime/node/secret_key.ts @@ -0,0 +1,13 @@ +import { createSecretKey } from 'crypto' +import type { KeyObject } from 'crypto' + +export default function getSecretKey(key: KeyObject | Uint8Array): KeyObject { + let keyObject: KeyObject + if (key instanceof Uint8Array) { + keyObject = createSecretKey(key) + } else { + keyObject = key + } + + return keyObject +} diff --git a/src/runtime/node/sign.ts b/src/runtime/node/sign.ts new file mode 100644 index 0000000000..d2f5c8cb18 --- /dev/null +++ b/src/runtime/node/sign.ts @@ -0,0 +1,32 @@ +import { sign as oneShotSign, createHmac, KeyObject } from 'crypto' +import type { SignFunction } from '../interfaces.d' +import nodeDigest from './dsa_digest.js' +import hmacDigest from './hmac_digest.js' +import nodeKey from './node_key.js' +import getSecretKey from './secret_key.js' + +const sign: SignFunction = async (alg, key: KeyObject | Uint8Array, data) => { + let keyObject: KeyObject + if (key instanceof Uint8Array) { + if (!alg.startsWith('HS')) { + throw new TypeError('symmetric keys are only applicable for HMAC-based JWA algorithms') + } + keyObject = getSecretKey(key) + } else { + keyObject = key + } + + if (alg.startsWith('HS')) { + const bitlen = parseInt(alg.substr(-3), 10) + if (!keyObject.symmetricKeySize || keyObject.symmetricKeySize << 3 < bitlen) { + throw new TypeError(`${alg} requires symmetric keys to be ${bitlen} bits or larger`) + } + const hmac = createHmac(hmacDigest(alg), keyObject) + hmac.update(data) + return hmac.digest() + } + + return oneShotSign(nodeDigest(alg), data, nodeKey(alg, keyObject)) +} + +export default sign diff --git a/src/runtime/node/timing_safe_equal.ts b/src/runtime/node/timing_safe_equal.ts new file mode 100644 index 0000000000..3d0981f22f --- /dev/null +++ b/src/runtime/node/timing_safe_equal.ts @@ -0,0 +1,7 @@ +import { timingSafeEqual as impl } from 'crypto' + +import type { TimingSafeEqual } from '../interfaces.d' + +const timingSafeEqual: TimingSafeEqual = impl + +export default timingSafeEqual diff --git a/src/runtime/node/verify.ts b/src/runtime/node/verify.ts new file mode 100644 index 0000000000..199d716de9 --- /dev/null +++ b/src/runtime/node/verify.ts @@ -0,0 +1,29 @@ +import { verify as oneShotVerify, timingSafeEqual, KeyObject } from 'crypto' + +import type { VerifyFunction } from '../interfaces.d' +import nodeDigest from './dsa_digest.js' +import nodeKey from './node_key.js' +import sign from './sign.js' + +const verify: VerifyFunction = async (alg, key: KeyObject | Uint8Array, signature, data) => { + if (alg.startsWith('HS')) { + const expected = await sign(alg, key, data) + const actual = signature + try { + return timingSafeEqual(actual, expected) + } catch { + // handle incorrect signature lengths + return false + } + } + + const algorithm = nodeDigest(alg) + + if (!(key instanceof KeyObject)) { + throw new TypeError('invalid key object type provided') + } + + return oneShotVerify(algorithm, data, nodeKey(alg, key), signature) +} + +export default verify diff --git a/src/runtime/node/webcrypto.ts b/src/runtime/node/webcrypto.ts new file mode 100644 index 0000000000..088537fc75 --- /dev/null +++ b/src/runtime/node/webcrypto.ts @@ -0,0 +1,13 @@ +import * as crypto from 'crypto' + +if (!('webcrypto' in crypto)) { + throw new Error('Node.js crypto.webcrypto is not available in your runtime') +} + +process.emitWarning( + 'The implementation of Web Cryptography API in Node.js is experimental.', + 'ExperimentalWarning', +) + +export default crypto.webcrypto +export function ensureSecureContext() {} diff --git a/src/runtime/node/zlib.ts b/src/runtime/node/zlib.ts new file mode 100644 index 0000000000..ea2b748f48 --- /dev/null +++ b/src/runtime/node/zlib.ts @@ -0,0 +1,15 @@ +import { promisify } from 'util' +import { inflateRaw as inflateRawCb, deflateRaw as deflateRawCb } from 'zlib' + +import type { InflateFunction, DeflateFunction } from '../../types.d' + +const inflateRaw = promisify(inflateRawCb) +const deflateRaw = promisify(deflateRawCb) + +export const inflate: InflateFunction = async (input: Uint8Array) => { + return inflateRaw(input) +} + +export const deflate: DeflateFunction = async (input: Uint8Array) => { + return deflateRaw(input) +} diff --git a/src/types.d.ts b/src/types.d.ts new file mode 100644 index 0000000000..34993bb532 --- /dev/null +++ b/src/types.d.ts @@ -0,0 +1,550 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import type { KeyObject } from 'crypto' + +/** + * JSON Web Key ([JWK](https://tools.ietf.org/html/rfc7517)). + * "RSA", "EC", "OKP", and "oct" key types are supported. + */ +export interface JWK { + /** + * JWK "alg" (Algorithm) Parameter. + */ + alg?: string + crv?: string + d?: string + dp?: string + dq?: string + e?: string + /** + * JWK "ext" (Extractable) Parameter. + */ + ext?: boolean + k?: string + /** + * JWK "key_ops" (Key Operations) Parameter. + */ + key_ops?: string[] + /** + * JWK "kid" (Key ID) Parameter. + */ + kid?: string + /** + * JWK "kty" (Key Type) Parameter. + */ + kty?: string + n?: string + oth?: Array<{ + d?: string + r?: string + t?: string + }> + p?: string + q?: string + qi?: string + /** + * JWK "use" (Public Key Use) Parameter. + */ + use?: string + x?: string + y?: string + /** + * JWK "x5c" (X.509 Certificate Chain) Parameter. + */ + x5c?: string[] + /** + * JWK "x5t" (X.509 Certificate SHA-1 Thumbprint) Parameter. + */ + x5t?: string + /** + * "x5t#S256" (X.509 Certificate SHA-256 Thumbprint) Parameter. + */ + 'x5t#S256'?: string + /** + * JWK "x5u" (X.509 URL) Parameter. + */ + x5u?: string +} + +/** + * Generic Interface for consuming operations dynamic key resolution. + * No token components have been verified at the time of this function call. + * + * @param protectedHeader JWE or JWS Protected Header. + * @param token The consumed JWE or JWS token. + */ +interface GetKeyFunction { + (protectedHeader: T, token: T2): Promise +} + +/** + * KeyLike are platform-specific references to keying material. + * + * - [KeyObject](https://nodejs.org/api/crypto.html#crypto_class_keyobject) instances come from + * node's [crypto module](https://nodejs.org/api/crypto.html) (see crypto.generateKeyPair, + * crypto.createPublicKey, crypto.createPrivateKey, crypto.createSecretKey). + * - [CryptoKey](https://www.w3.org/TR/WebCryptoAPI) instances come from + * [Web Cryptography API](https://www.w3.org/TR/WebCryptoAPI) (see SubtleCrypto.importKey, + * SubtleCrypto.generateKey, SubtleCrypto.deriveKey, SubtleCrypto.unwrapKey). + * - [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) + * is used exclusively for symmetric secret representations, a CryptoKey or KeyObject is + * preferred, but in Web Crypto API this isn't an option for some algorithms. + */ +export type KeyLike = KeyObject | CryptoKey | Uint8Array + +/** + * Flattened JWS definition for verify function inputs, allows payload as + * Uint8Array for detached signature validation. + */ +export interface FlattenedJWSInput { + /** + * The "header" member MUST be present and contain the value JWS + * Unprotected Header when the JWS Unprotected Header value is non- + * empty; otherwise, it MUST be absent. This value is represented as + * an unencoded JSON object, rather than as a string. These Header + * Parameter values are not integrity protected. + */ + header?: JWSHeaderParameters + + /** + * The "payload" member MUST be present and contain the value + * BASE64URL(JWS Payload). When RFC7797 "b64": false is used + * the value passed may also be a Uint8Array. + */ + payload: string | Uint8Array + + /** + * The "protected" member MUST be present and contain the value + * BASE64URL(UTF8(JWS Protected Header)) when the JWS Protected + * Header value is non-empty; otherwise, it MUST be absent. These + * Header Parameter values are integrity protected. + */ + protected?: string + + /** + * The "signature" member MUST be present and contain the value + * BASE64URL(JWS Signature). + */ + signature: string +} + +/** + * Flattened JWS definition. Payload is an optional return property, it + * is not returned when JWS Unencoded Payload Option + * [RFC7797](https://tools.ietf.org/html/rfc7797) is used. + */ +export interface FlattenedJWS extends Partial { + payload?: string + signature: string +} + +export interface JoseHeaderParameters { + /** + * "kid" (Key ID) Header Parameter. + */ + kid?: string + + /** + * "x5t" (X.509 Certificate SHA-1 Thumbprint) Header Parameter. + */ + x5t?: string + + /** + * "x5c" (X.509 Certificate Chain) Header Parameter. + */ + x5c?: string[] + + /** + * "x5u" (X.509 URL) Header Parameter. + */ + x5u?: string + + /** + * "jwk" (JSON Web Key) Header Parameter. + */ + jwk?: Pick + + /** + * "typ" (Type) Header Parameter. + */ + typ?: string + + /** + * "cty" (Content Type) Header Parameter. + */ + cty?: string +} + +/** + * Recognized JWS Header Parameters, any other Header Members + * may also be present. + */ +export interface JWSHeaderParameters extends JoseHeaderParameters { + /** + * JWS "alg" (Algorithm) Header Parameter. + */ + alg?: string + + /** + * This JWS Extension Header Parameter modifies the JWS Payload + * representation and the JWS Signing Input computation as per + * [RFC7797](https://tools.ietf.org/html/rfc7797). + */ + b64?: boolean + + /** + * JWS "crit" (Critical) Header Parameter. + */ + crit?: string[] + + /** + * Any other JWS Header member. + */ + [propName: string]: any +} + +/** + * Recognized JWE Key Management-related Header Parameters. + */ +export interface JWEKeyManagementHeaderParameters { + apu?: Uint8Array + apv?: Uint8Array + epk?: KeyLike + iv?: Uint8Array + p2c?: number + p2s?: Uint8Array +} + +/** + * Flattened JWE definition. + */ +export interface FlattenedJWE { + /** + * The "aad" member MUST be present and contain the value + * BASE64URL(JWE AAD)) when the JWE AAD value is non-empty; + * otherwise, it MUST be absent. A JWE AAD value can be included to + * supply a base64url-encoded value to be integrity protected but not + * encrypted. + */ + aad?: string + + /** + * The "ciphertext" member MUST be present and contain the value + * BASE64URL(JWE Ciphertext). + */ + ciphertext: string + + /** + * The "encrypted_key" member MUST be present and contain the value + * BASE64URL(JWE Encrypted Key) when the JWE Encrypted Key value is + * non-empty; otherwise, it MUST be absent. + */ + encrypted_key?: string + + /** + * The "header" member MUST be present and contain the value JWE Per- + * Recipient Unprotected Header when the JWE Per-Recipient + * Unprotected Header value is non-empty; otherwise, it MUST be + * absent. This value is represented as an unencoded JSON object, + * rather than as a string. These Header Parameter values are not + * integrity protected. + */ + header?: JWEHeaderParameters + + /** + * The "iv" member MUST be present and contain the value + * BASE64URL(JWE Initialization Vector) when the JWE Initialization + * Vector value is non-empty; otherwise, it MUST be absent. + */ + iv: string + + /** + * The "protected" member MUST be present and contain the value + * BASE64URL(UTF8(JWE Protected Header)) when the JWE Protected + * Header value is non-empty; otherwise, it MUST be absent. These + * Header Parameter values are integrity protected. + */ + protected?: string + + /** + * The "tag" member MUST be present and contain the value + * BASE64URL(JWE Authentication Tag) when the JWE Authentication Tag + * value is non-empty; otherwise, it MUST be absent. + */ + tag: string + + /** + * The "unprotected" member MUST be present and contain the value JWE + * Shared Unprotected Header when the JWE Shared Unprotected Header + * value is non-empty; otherwise, it MUST be absent. This value is + * represented as an unencoded JSON object, rather than as a string. + * These Header Parameter values are not integrity protected. + */ + unprotected?: JWEHeaderParameters +} + +/** + * Recognized JWE Header Parameters, any other Header members + * may also be present. + */ +export interface JWEHeaderParameters extends JoseHeaderParameters { + /** + * JWE "alg" (Algorithm) Header Parameter. + */ + alg?: string + + /** + * JWE "enc" (Encryption Algorithm) Header Parameter. + */ + enc?: string + + /** + * JWE "crit" (Critical) Header Parameter. + */ + crit?: string[] + + /** + * JWE "zip" (Compression Algorithm) Header Parameter. + */ + zip?: string + + /** + * Any other JWE Header member. + */ + [propName: string]: any +} + +/** + * JWE Decryption options. + */ +export interface DecryptOptions { + /** + * A list of accepted JWE "alg" (Algorithm) Header Parameter values. + */ + keyManagementAlgorithms?: string[] + + /** + * A list of accepted JWE "enc" (Encryption Algorithm) Header Parameter values. + */ + contentEncryptionAlgorithms?: string[] + + /** + * In a browser runtime you have to provide an implementation for Inflate Raw + * when you expect JWEs with compressed plaintext. + */ + inflateRaw?: InflateFunction +} + +/** + * JWE Encryption options. + */ +export interface EncryptOptions { + /** + * In a browser runtime you have to provide an implementation for Deflate Raw + * when you will be producing JWEs with compressed plaintext. + */ + deflateRaw?: DeflateFunction +} + +/** + * JWT Claims Set verification options. + */ +export interface JWTClaimVerificationOptions { + /** + * Expected JWT "aud" (Audience) Claim value(s). + */ + audience?: string | string[] + + /** + * Expected clock tolerance + * - in seconds when number (e.g. 5) + * - parsed as seconds when a string (e.g. "5 seconds"). + */ + clockTolerance?: string | number + + /** + * Expected JWT "iss" (Issuer) Claim value(s). + */ + issuer?: string | string[] + + /** + * Maximum time elapsed (in seconds) from the JWT "iat" (Issued At) Claim value. + */ + maxTokenAge?: string + + /** + * Expected JWT "sub" (Subject) Claim value. + */ + subject?: string + + /** + * Expected JWT "typ" (Type) Header Parameter value. + */ + typ?: string + + /** + * Date to use when comparing NumericDate claims, defaults to `new Date()`. + */ + currentDate?: Date +} + +/** + * JWS Verification options. + */ +export interface VerifyOptions { + /** + * A list of accepted JWS "alg" (Algorithm) Header Parameter values. + */ + algorithms?: string[] +} + +/** + * Recognized JWT Claims Set members, any other members + * may also be present. + */ +export interface JWTPayload { + /** + * JWT Issuer - [RFC7519#section-4.1.1](https://tools.ietf.org/html/rfc7519#section-4.1.1). + */ + iss?: string + + /** + * JWT Subject - [RFC7519#section-4.1.2](https://tools.ietf.org/html/rfc7519#section-4.1.2). + */ + sub?: string + + /** + * JWT Audience [RFC7519#section-4.1.3](https://tools.ietf.org/html/rfc7519#section-4.1.3). + */ + aud?: string | string[] + + /** + * JWT ID - [RFC7519#section-4.1.7](https://tools.ietf.org/html/rfc7519#section-4.1.7). + */ + jti?: string + + /** + * JWT Not Before - [RFC7519#section-4.1.5](https://tools.ietf.org/html/rfc7519#section-4.1.5). + */ + nbf?: number + + /** + * JWT Expiration Time - [RFC7519#section-4.1.4](https://tools.ietf.org/html/rfc7519#section-4.1.4). + */ + exp?: number + + /** + * JWT Issued At - [RFC7519#section-4.1.6](https://tools.ietf.org/html/rfc7519#section-4.1.6). + */ + iat?: number + + /** + * Any other JWT Claim Set member. + */ + [propName: string]: any +} + +/** + * Deflate Raw implementation, e.g. promisified [zlib.deflateRaw](https://nodejs.org/api/zlib.html#zlib_zlib_deflateraw_buffer_options_callback). + */ +export interface DeflateFunction { + (input: Uint8Array): Promise +} + +/** + * Inflate Raw implementation, e.g. promisified [zlib.inflateRaw](https://nodejs.org/api/zlib.html#zlib_zlib_inflateraw_buffer_options_callback). + */ +export interface InflateFunction { + (input: Uint8Array): Promise +} + +export interface FlattenedDecryptResult { + /** + * JWE AAD. + */ + additionalAuthenticatedData?: Uint8Array + + /** + * Plaintext. + */ + plaintext: Uint8Array + + /** + * JWE Protected Header. + */ + protectedHeader?: JWEHeaderParameters + + /** + * JWE Shared Unprotected Header. + */ + sharedUnprotectedHeader?: JWEHeaderParameters + + /** + * JWE Per-Recipient Unprotected Header. + */ + unprotectedHeader?: JWEHeaderParameters +} + +export interface CompactDecryptResult { + /** + * Plaintext. + */ + plaintext: Uint8Array + + /** + * JWE Protected Header. + */ + protectedHeader: JWEHeaderParameters +} + +export interface FlattenedVerifyResult { + /** + * JWS Payload. + */ + payload: Uint8Array + + /** + * JWS Protected Header. + */ + protectedHeader?: JWSHeaderParameters + + /** + * JWS Unprotected Header. + */ + unprotectedHeader?: JWSHeaderParameters +} + +export interface CompactVerifyResult { + /** + * JWS Payload. + */ + payload: Uint8Array + + /** + * JWS Protected Header. + */ + protectedHeader: JWSHeaderParameters +} + +export interface JWTVerifyResult { + /** + * JWT Claims Set. + */ + payload: JWTPayload + + /** + * JWS Protected Header. + */ + protectedHeader: JWSHeaderParameters +} + +export interface JWTDecryptResult { + /** + * JWT Claims Set. + */ + payload: JWTPayload + + /** + * JWE Protected Header. + */ + protectedHeader: JWEHeaderParameters +} diff --git a/src/types.i.d.ts b/src/types.i.d.ts new file mode 100644 index 0000000000..14b968a3bc --- /dev/null +++ b/src/types.i.d.ts @@ -0,0 +1,31 @@ +/* eslint-disable @typescript-eslint/naming-convention */ + +interface NodeCrypto extends Crypto { + readonly CryptoKey: typeof CryptoKey +} + +declare module 'crypto' { + const webcrypto: NodeCrypto +} + +export type Awaited = T extends PromiseLike ? PT : never +export type AsyncOrSync = PromiseLike | T + +export interface JWEKeyManagementHeaderResults { + apu?: string + apv?: string + epk?: EpkJwk + iv?: string + p2c?: number + p2s?: string + tag?: string +} + +export interface EpkJwk { + crv: string + d?: string + kty: string + x: string + y?: string + [propName: string]: any +} diff --git a/src/util/base64url.ts b/src/util/base64url.ts new file mode 100644 index 0000000000..c587ba7db3 --- /dev/null +++ b/src/util/base64url.ts @@ -0,0 +1 @@ +export * from '../runtime/base64url.js' diff --git a/src/util/errors.ts b/src/util/errors.ts new file mode 100644 index 0000000000..d381e0b1e2 --- /dev/null +++ b/src/util/errors.ts @@ -0,0 +1,136 @@ +/* eslint-disable max-classes-per-file */ + +/** + * A generic Error subclass that all other specific + * JOSE Error subclasses inherit from. + */ +export class JOSEError extends Error { + /** + * A unique error code for the particular error subclass. + */ + code = 'ERR_JOSE_GENERIC' + + constructor(message?: string) { + super(message) + this.name = this.constructor.name + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor) + } + } +} + +/** + * An error subclass thrown when a JWT Claim Set member validation fails. + */ +export class JWTClaimValidationFailed extends JOSEError { + code = 'ERR_JWT_CLAIM_VALIDATION_FAILED' + + /** + * The Claim for which the validation failed. + */ + claim: string + + /** + * Reason code for the validation failure. + */ + reason: string + + constructor(message: string, claim = 'unspecified', reason = 'unspecified') { + super(message) + this.claim = claim + this.reason = reason + } +} + +/** + * An error subclass thrown when a JOSE Algorithm is not allowed per developer preference. + */ +export class JOSEAlgNotAllowed extends JOSEError { + code = 'ERR_JOSE_ALG_NOT_ALLOWED' +} + +/** + * An error subclass thrown when a particular feature or algorithm is not supported by this + * implementation or JOSE in general. + */ +export class JOSENotSupported extends JOSEError { + code = 'ERR_JOSE_NOT_SUPPORTED' +} + +/** + * An error subclass thrown when a JWE ciphertext decryption fails. + */ +export class JWEDecryptionFailed extends JOSEError { + code = 'ERR_JWE_DECRYPTION_FAILED' + + message = 'decryption operation failed' +} + +/** + * An error subclass thrown when a JWE is invalid. + */ +export class JWEInvalid extends JOSEError { + code = 'ERR_JWE_INVALID' +} + +/** + * An error subclass thrown when a JWS is invalid. + */ +export class JWSInvalid extends JOSEError { + code = 'ERR_JWS_INVALID' +} + +/** + * An error subclass thrown when a JWT is invalid. + */ +export class JWTInvalid extends JOSEError { + code = 'ERR_JWT_INVALID' +} + +/** + * An error subclass thrown when a JWK is invalid. + */ +export class JWKInvalid extends JOSEError { + code = 'ERR_JWK_INVALID' +} + +/** + * An error subclass thrown when a JWKS is invalid. + */ +export class JWKSInvalid extends JOSEError { + code = 'ERR_JWKS_INVALID' +} + +/** + * An error subclass thrown when no keys match from a JWKS. + */ +export class JWKSNoMatchingKey extends JOSEError { + code = 'ERR_JWKS_NO_MATCHING_KEY' + + message = 'no applicable key found in the JSON Web Key Set' +} + +/** + * An error subclass thrown when multiple keys match from a JWKS. + */ +export class JWKSMultipleMatchingKeys extends JOSEError { + code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS' + + message = 'multiple matching keys found in the JSON Web Key Set' +} + +/** + * An error subclass thrown when JWS signature verification fails. + */ +export class JWSSignatureVerificationFailed extends JOSEError { + code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED' + + message = 'signature verification failed' +} + +/** + * An error subclass thrown when a JWT is expired. + */ +export class JWTExpired extends JWTClaimValidationFailed { + code = 'ERR_JWT_EXPIRED' +} diff --git a/src/util/generate_key_pair.ts b/src/util/generate_key_pair.ts new file mode 100644 index 0000000000..d3a87b740c --- /dev/null +++ b/src/util/generate_key_pair.ts @@ -0,0 +1,46 @@ +import type { KeyObject } from 'crypto' +import { generateKeyPair as generate } from '../runtime/generate.js' + +export interface GenerateKeyPairOptions { + /** + * The EC "crv" (Curve) or OKP "crv" (Subtype of Key Pair) value to generate. + * The curve must be both supported on the runtime as well as applicable for + * the given JWA algorithm identifier. + */ + crv?: string +} + +/** + * Generates a private and a public key for a given JWA algorithm identifier. + * This can only generate asymmetric key pairs. For symmetric secrets use the + * `generateSecret` function. + * + * @example + * ``` + * // ESM import + * import generateKeyPair from 'jose/util/generate_key_pair' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: generateKeyPair } = require('jose/util/generate_key_pair') + * ``` + * + * @example + * ``` + * // usage + * const { publicKey, privateKey } = await generateKeyPair('PS256') + * console.log(publicKey) + * console.log(privateKey) + * ``` + * + * @param alg JWA Algorithm Identifier to be used with the generated key pair. + * @param options Additional options passed down to the key pair generation. + */ +export default async function generateKeyPair( + alg: string, + options?: GenerateKeyPairOptions, +): Promise<{ privateKey: CryptoKey | KeyObject; publicKey: CryptoKey | KeyObject }> { + return generate(alg, options) +} diff --git a/src/util/generate_secret.ts b/src/util/generate_secret.ts new file mode 100644 index 0000000000..0516e7938c --- /dev/null +++ b/src/util/generate_secret.ts @@ -0,0 +1,30 @@ +import { generateSecret as generate } from '../runtime/generate.js' +import type { KeyLike } from '../types.d' + +/** + * Generates a symmetric secret key for a given JWA algorithm identifier. + * + * @example + * ``` + * // ESM import + * import generateSecret from 'jose/util/generate_secret' + * ``` + * + * @example + * ``` + * // CJS import + * const { default: generateSecret } = require('jose/util/generate_secret') + * ``` + * + * @example + * ``` + * // usage + * const secret = await generateSecret('HS256') + * console.log(secret) + * ``` + * + * @param alg JWA Algorithm Identifier to be used with the generated secret. + */ +export default async function generateSecret(alg: string): Promise { + return generate(alg) +} diff --git a/src/util/random.ts b/src/util/random.ts new file mode 100644 index 0000000000..3c0d72fdde --- /dev/null +++ b/src/util/random.ts @@ -0,0 +1,3 @@ +import random from '../runtime/random.js' + +export default random diff --git a/test-browser/.eslintrc.json b/test-browser/.eslintrc.json new file mode 100644 index 0000000000..38a6685580 --- /dev/null +++ b/test-browser/.eslintrc.json @@ -0,0 +1,12 @@ +{ + "globals": { + "fetch": true, + "window": true, + "QUnit": true + }, + "extends": "airbnb-base", + "rules": { + "import/no-extraneous-dependencies": "off", + "import/no-unresolved": "off" + } +} diff --git a/test-browser/.prettierrc.json b/test-browser/.prettierrc.json new file mode 100644 index 0000000000..d2bd3c8912 --- /dev/null +++ b/test-browser/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "trailingComma": "all", + "singleQuote": true, + "printWidth": 100, + "semi": true +} diff --git a/test-browser/generate_keys.js b/test-browser/generate_keys.js new file mode 100644 index 0000000000..6ae62005ef --- /dev/null +++ b/test-browser/generate_keys.js @@ -0,0 +1,83 @@ +import * as Bowser from 'bowser'; + +import generateKeyPair from '../dist/browser/util/generate_key_pair'; + +const browser = Bowser.parse(window.navigator.userAgent); + +const p521 = browser.engine.name !== 'WebKit'; + +QUnit.test('Generate PS256', async (assert) => { + assert.ok(await generateKeyPair('PS256')); +}); + +QUnit.test('Generate PS384', async (assert) => { + assert.ok(await generateKeyPair('PS384')); +}); + +QUnit.test('Generate PS512', async (assert) => { + assert.ok(await generateKeyPair('PS512')); +}); + +QUnit.test('Generate RS256', async (assert) => { + assert.ok(await generateKeyPair('RS256')); +}); + +QUnit.test('Generate RS384', async (assert) => { + assert.ok(await generateKeyPair('RS384')); +}); + +QUnit.test('Generate RS512', async (assert) => { + assert.ok(await generateKeyPair('RS512')); +}); + +QUnit.test('Generate ES256', async (assert) => { + assert.ok(await generateKeyPair('ES256')); +}); + +QUnit.test('Generate ES384', async (assert) => { + assert.ok(await generateKeyPair('ES384')); +}); + +if (p521) { + QUnit.test('Generate ES512', async (assert) => { + assert.ok(await generateKeyPair('ES512')); + }); +} else { + QUnit.test('Generate ES512', async (assert) => { + await assert.rejects(generateKeyPair('ES512')); + }); +} + +QUnit.test('RSA-OAEP', async (assert) => { + assert.ok(await generateKeyPair('RSA-OAEP')); +}); + +QUnit.test('RSA-OAEP-256', async (assert) => { + assert.ok(await generateKeyPair('RSA-OAEP-256')); +}); + +QUnit.test('RSA-OAEP-384', async (assert) => { + assert.ok(await generateKeyPair('RSA-OAEP-384')); +}); + +QUnit.test('RSA-OAEP-512', async (assert) => { + assert.ok(await generateKeyPair('RSA-OAEP-512')); +}); + +QUnit.test('ECDH-ES crv: P-256', async (assert) => { + assert.ok(await generateKeyPair('ECDH-ES', { crv: 'P-256' })); +}); + +QUnit.test('ECDH-ES crv: P-384', async (assert) => { + assert.ok(await generateKeyPair('ECDH-ES', { crv: 'P-384' })); +}); + +if (p521) { + QUnit.test('ECDH-ES crv: P-521', async (assert) => { + assert.ok(await generateKeyPair('ECDH-ES', { crv: 'P-521' })); + }); +} else { + QUnit.test('ECDH-ES crv: P-521', async (assert) => { + await assert.rejects(generateKeyPair('ECDH-ES', { crv: 'P-521' })); + }); +} diff --git a/test-browser/generate_secrets.js b/test-browser/generate_secrets.js new file mode 100644 index 0000000000..0cdc0bc439 --- /dev/null +++ b/test-browser/generate_secrets.js @@ -0,0 +1,85 @@ +import * as Bowser from 'bowser'; + +import generateSecret from '../dist/browser/util/generate_secret'; + +const browser = Bowser.parse(window.navigator.userAgent); + +const aes192 = browser.engine.name !== 'Blink'; + +QUnit.test('HS256', async (assert) => { + assert.ok(await generateSecret('HS256')); +}); + +QUnit.test('HS384', async (assert) => { + assert.ok(await generateSecret('HS384')); +}); + +QUnit.test('HS512', async (assert) => { + assert.ok(await generateSecret('HS512')); +}); + +QUnit.test('A128CBC-HS256', async (assert) => { + assert.ok(await generateSecret('A128CBC-HS256')); +}); + +QUnit.test('A192CBC-HS384', async (assert) => { + assert.ok(await generateSecret('A192CBC-HS384')); +}); + +QUnit.test('A256CBC-HS512', async (assert) => { + assert.ok(await generateSecret('A256CBC-HS512')); +}); + +QUnit.test('A128KW', async (assert) => { + assert.ok(await generateSecret('A128KW')); +}); + +if (aes192) { + QUnit.test('A192KW', async (assert) => { + assert.ok(await generateSecret('A192KW')); + }); +} else { + QUnit.test('A192KW', async (assert) => { + await assert.rejects(generateSecret('A192KW')); + }); +} + +QUnit.test('A256KW', async (assert) => { + assert.ok(await generateSecret('A256KW')); +}); + +QUnit.test('A128GCMKW', async (assert) => { + assert.ok(await generateSecret('A128GCMKW')); +}); + +if (aes192) { + QUnit.test('A192GCMKW', async (assert) => { + assert.ok(await generateSecret('A192GCMKW')); + }); +} else { + QUnit.test('A192GCMKW', async (assert) => { + await assert.rejects(generateSecret('A192GCMKW')); + }); +} + +QUnit.test('A256GCMKW', async (assert) => { + assert.ok(await generateSecret('A256GCMKW')); +}); + +QUnit.test('A128GCM', async (assert) => { + assert.ok(await generateSecret('A128GCM')); +}); + +if (aes192) { + QUnit.test('A192GCM', async (assert) => { + assert.ok(await generateSecret('A192GCM')); + }); +} else { + QUnit.test('A192GCM', async (assert) => { + await assert.rejects(generateSecret('A192GCM')); + }); +} + +QUnit.test('A256GCM', async (assert) => { + assert.ok(await generateSecret('A256GCM')); +}); diff --git a/test-browser/jwe_asymmetric.js b/test-browser/jwe_asymmetric.js new file mode 100644 index 0000000000..e44749bb68 --- /dev/null +++ b/test-browser/jwe_asymmetric.js @@ -0,0 +1,59 @@ +import * as Bowser from 'bowser'; + +import generateKeyPair from '../dist/browser/util/generate_key_pair'; +import random from '../dist/browser/util/random'; +import FlattenedEncrypt from '../dist/browser/jwe/flattened/encrypt'; +import decryptFlattened from '../dist/browser/jwe/flattened/decrypt'; + +const browser = Bowser.parse(window.navigator.userAgent); + +const p521 = browser.engine.name !== 'WebKit'; + +async function test(generate, alg, assert) { + const { publicKey, privateKey } = await generate(); + + const jwe = await new FlattenedEncrypt(random(new Uint8Array(32))) + .setProtectedHeader({ alg, enc: 'A256GCM' }) + .setAdditionalAuthenticatedData(random(new Uint8Array(32))) + .encrypt(publicKey); + + await decryptFlattened(jwe, privateKey); + assert.ok(1); +} + +// eslint-disable-next-line no-restricted-syntax +for (const crv of ['P-256', 'P-384', 'P-521']) { + if (crv === 'P-521' && !p521) { + QUnit.test(`ECDH-ES crv: ${crv}`, async (assert) => { + await assert.rejects( + test.bind( + undefined, + generateKeyPair.bind(undefined, 'ECDH-ES', { crv }), + 'ECDH-ES', + )(assert), + ); + }); + } else { + QUnit.test( + `ECDH-ES crv: ${crv}`, + test.bind(undefined, generateKeyPair.bind(undefined, 'ECDH-ES', { crv }), 'ECDH-ES'), + ); + } +} + +QUnit.test( + 'RSA-OAEP-256', + test.bind(undefined, generateKeyPair.bind(undefined, 'RSA-OAEP-256'), 'RSA-OAEP-256'), +); +QUnit.test( + 'RSA-OAEP-384', + test.bind(undefined, generateKeyPair.bind(undefined, 'RSA-OAEP-384'), 'RSA-OAEP-384'), +); +QUnit.test( + 'RSA-OAEP-512', + test.bind(undefined, generateKeyPair.bind(undefined, 'RSA-OAEP-512'), 'RSA-OAEP-512'), +); +QUnit.test( + 'RSA-OAEP', + test.bind(undefined, generateKeyPair.bind(undefined, 'RSA-OAEP'), 'RSA-OAEP'), +); diff --git a/test-browser/jwe_symmetric.js b/test-browser/jwe_symmetric.js new file mode 100644 index 0000000000..e60406fe9c --- /dev/null +++ b/test-browser/jwe_symmetric.js @@ -0,0 +1,185 @@ +import * as Bowser from 'bowser'; + +import generateSecret from '../dist/browser/util/generate_secret'; +import random from '../dist/browser/util/random'; +import FlattenedEncrypt from '../dist/browser/jwe/flattened/encrypt'; +import decryptFlattened from '../dist/browser/jwe/flattened/decrypt'; + +const browser = Bowser.parse(window.navigator.userAgent); + +const aes192 = browser.engine.name !== 'Blink'; + +async function test(generate, { alg, enc }, assert) { + const secretKey = await generate(); + + const jwe = await new FlattenedEncrypt(random(new Uint8Array(32))) + .setProtectedHeader({ alg, enc }) + .setAdditionalAuthenticatedData(random(new Uint8Array(32))) + .encrypt(secretKey); + + await decryptFlattened(jwe, secretKey); + assert.ok(1); +} + +QUnit.test( + 'A128CBC-HS256', + test.bind(undefined, generateSecret.bind(undefined, 'A128CBC-HS256'), { + alg: 'dir', + enc: 'A128CBC-HS256', + }), +); +QUnit.test( + 'A128GCM', + test.bind(undefined, generateSecret.bind(undefined, 'A128GCM'), { + alg: 'dir', + enc: 'A128GCM', + }), +); +if (aes192) { + QUnit.test( + 'A192CBC-HS384', + test.bind(undefined, generateSecret.bind(undefined, 'A192CBC-HS384'), { + alg: 'dir', + enc: 'A192CBC-HS384', + }), + ); +} else { + QUnit.test('A192CBC-HS384', async (assert) => { + await assert.rejects( + test.bind(undefined, generateSecret.bind(undefined, 'A192CBC-HS384'), { + alg: 'dir', + enc: 'A192CBC-HS384', + })(assert), + ); + }); +} +if (aes192) { + QUnit.test( + 'A192GCM', + test.bind(undefined, generateSecret.bind(undefined, 'A192GCM'), { + alg: 'dir', + enc: 'A192GCM', + }), + ); +} else { + QUnit.test('A192GCM', async (assert) => { + await assert.rejects( + test.bind(undefined, generateSecret.bind(undefined, 'A192GCM'), { + alg: 'dir', + enc: 'A192GCM', + })(assert), + ); + }); +} +QUnit.test( + 'A256CBC-HS512', + test.bind(undefined, generateSecret.bind(undefined, 'A256CBC-HS512'), { + alg: 'dir', + enc: 'A256CBC-HS512', + }), +); +QUnit.test( + 'A256GCM', + test.bind(undefined, generateSecret.bind(undefined, 'A256GCM'), { + alg: 'dir', + enc: 'A256GCM', + }), +); + +QUnit.test( + 'A128GCMKW', + test.bind(undefined, generateSecret.bind(undefined, 'A128GCMKW'), { + alg: 'A128GCMKW', + enc: 'A256GCM', + }), +); +QUnit.test( + 'A128KW', + test.bind(undefined, generateSecret.bind(undefined, 'A128KW'), { + alg: 'A128KW', + enc: 'A256GCM', + }), +); +if (aes192) { + QUnit.test( + 'A192GCMKW', + test.bind(undefined, generateSecret.bind(undefined, 'A192GCMKW'), { + alg: 'A192GCMKW', + enc: 'A256GCM', + }), + ); +} else { + QUnit.test('A192GCMKW', async (assert) => { + await assert.rejects( + test.bind(undefined, generateSecret.bind(undefined, 'A192GCMKW'), { + alg: 'A192GCMKW', + enc: 'A256GCM', + })(assert), + ); + }); +} +if (aes192) { + QUnit.test( + 'A192KW', + test.bind(undefined, generateSecret.bind(undefined, 'A192KW'), { + alg: 'A192KW', + enc: 'A256GCM', + }), + ); +} else { + QUnit.test('A192KW', async (assert) => { + await assert.rejects( + test.bind(undefined, generateSecret.bind(undefined, 'A192KW'), { + alg: 'A192KW', + enc: 'A256GCM', + })(assert), + ); + }); +} +QUnit.test( + 'A256GCMKW', + test.bind(undefined, generateSecret.bind(undefined, 'A256GCMKW'), { + alg: 'A256GCMKW', + enc: 'A256GCM', + }), +); +QUnit.test( + 'A256KW', + test.bind(undefined, generateSecret.bind(undefined, 'A256KW'), { + alg: 'A256KW', + enc: 'A256GCM', + }), +); + +QUnit.test( + 'PBES2-HS256+A128KW', + test.bind(undefined, () => random(new Uint8Array(10)), { + alg: 'PBES2-HS256+A128KW', + enc: 'A256GCM', + }), +); +if (aes192) { + QUnit.test( + 'PBES2-HS384+A192KW', + test.bind(undefined, () => random(new Uint8Array(10)), { + alg: 'PBES2-HS384+A192KW', + enc: 'A256GCM', + }), + ); +} else { + QUnit.test('PBES2-HS384+A192KW', async (assert) => { + await assert.rejects( + test.bind(undefined, () => random(new Uint8Array(10)), { + alg: 'PBES2-HS384+A192KW', + enc: 'A256GCM', + })(assert), + ); + }); +} +QUnit.test( + 'PBES2-HS512+A256KW', + test.bind(undefined, () => random(new Uint8Array(10)), { + alg: 'PBES2-HS512+A256KW', + enc: 'A256GCM', + }), +); diff --git a/test-browser/jwks.js b/test-browser/jwks.js new file mode 100644 index 0000000000..8e67540132 --- /dev/null +++ b/test-browser/jwks.js @@ -0,0 +1,18 @@ +import createRemoteJWKSet from '../dist/browser/jwks/remote'; + +const jwksUri = 'https://www.googleapis.com/oauth2/v3/certs'; + +QUnit.test('fetches the JWKSet', async (assert) => { + const response = await fetch(jwksUri).then((r) => r.json()); + const { alg, kid } = response.keys[0]; + const jwks = createRemoteJWKSet(new URL(jwksUri)); + await assert.rejects( + jwks({ alg: 'RS256' }), + 'multiple matching keys found in the JSON Web Key Set', + ); + await assert.rejects( + jwks({ kid: 'foo', alg: 'RS256' }), + 'no applicable key found in the JSON Web Key Set', + ); + assert.ok(await jwks({ alg, kid })); +}); diff --git a/test-browser/jws.js b/test-browser/jws.js new file mode 100644 index 0000000000..99963f8e62 --- /dev/null +++ b/test-browser/jws.js @@ -0,0 +1,50 @@ +import * as Bowser from 'bowser'; + +import generateKeyPair from '../dist/browser/util/generate_key_pair'; +import generateSecret from '../dist/browser/util/generate_secret'; +import random from '../dist/browser/util/random'; +import FlattenedSign from '../dist/browser/jws/flattened/sign'; +import verifyFlattened from '../dist/browser/jws/flattened/verify'; + +const browser = Bowser.parse(window.navigator.userAgent); + +const p521 = browser.engine.name !== 'WebKit'; + +async function test(generate, alg, assert) { + const generated = await generate(); + let privateKey; + let publicKey; + if (generated.type === 'secret') { + publicKey = privateKey = generated; + } else { + ({ publicKey, privateKey } = generated); + } + + const jws = await new FlattenedSign(random(new Uint8Array(32))) + .setProtectedHeader({ alg }) + .sign(privateKey); + + await verifyFlattened(jws, publicKey); + assert.ok(1); +} + +QUnit.test('HS256', test.bind(undefined, generateSecret.bind(undefined, 'HS256'), 'HS256')); +QUnit.test('HS384', test.bind(undefined, generateSecret.bind(undefined, 'HS384'), 'HS384')); +QUnit.test('HS512', test.bind(undefined, generateSecret.bind(undefined, 'HS512'), 'HS512')); +QUnit.test('ES256', test.bind(undefined, generateKeyPair.bind(undefined, 'ES256'), 'ES256')); +QUnit.test('ES384', test.bind(undefined, generateKeyPair.bind(undefined, 'ES384'), 'ES384')); +if (p521) { + QUnit.test('ES512', test.bind(undefined, generateKeyPair.bind(undefined, 'ES512'), 'ES512')); +} else { + QUnit.test('ES512', async (assert) => { + await assert.rejects( + test.bind(undefined, generateKeyPair.bind(undefined, 'ES512'), 'ES512')(assert), + ); + }); +} +QUnit.test('PS256', test.bind(undefined, generateKeyPair.bind(undefined, 'PS256'), 'PS256')); +QUnit.test('PS384', test.bind(undefined, generateKeyPair.bind(undefined, 'PS384'), 'PS384')); +QUnit.test('PS512', test.bind(undefined, generateKeyPair.bind(undefined, 'PS512'), 'PS512')); +QUnit.test('RS256', test.bind(undefined, generateKeyPair.bind(undefined, 'RS256'), 'RS256')); +QUnit.test('RS384', test.bind(undefined, generateKeyPair.bind(undefined, 'RS384'), 'RS384')); +QUnit.test('RS512', test.bind(undefined, generateKeyPair.bind(undefined, 'RS512'), 'RS512')); diff --git a/test/.eslintrc.json b/test/.eslintrc.json new file mode 100644 index 0000000000..181b7f293a --- /dev/null +++ b/test/.eslintrc.json @@ -0,0 +1,7 @@ +{ + "extends": "airbnb-base", + "rules": { + "import/no-extraneous-dependencies": "off", + "import/no-unresolved": "off" + } +} diff --git a/test/.prettierrc.json b/test/.prettierrc.json new file mode 100644 index 0000000000..d2bd3c8912 --- /dev/null +++ b/test/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "trailingComma": "all", + "singleQuote": true, + "printWidth": 100, + "semi": true +} diff --git a/test/cookbook/4_1.rsa_v15_signature.test.js b/test/cookbook/4_1.rsa_v15_signature.test.js deleted file mode 100644 index f7ab64048b..0000000000 --- a/test/cookbook/4_1.rsa_v15_signature.test.js +++ /dev/null @@ -1,88 +0,0 @@ -const test = require('ava') - -const recipe = require('./recipes').get('4.1') - -const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - -const { input: { payload, key: jwk }, signing: { protected: header } } = recipe - -const key = asKey(jwk) - -const keystoreEmpty = new KeyStore() -const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) -const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - -test(`${recipe.title} - compact sign`, t => { - t.is(JWS.sign(payload, key, header), recipe.output.compact) -}) - -test(`${recipe.title} - flattened sign`, t => { - t.deepEqual(JWS.sign.flattened(payload, key, header), recipe.output.json_flat) -}) - -test(`${recipe.title} - general sign`, t => { - t.deepEqual(JWS.sign.general(payload, key, header), recipe.output.json) -}) - -test(`${recipe.title} - compact verify (using key)`, t => { - t.deepEqual(JWS.verify(recipe.output.compact, key), payload) -}) - -test(`${recipe.title} - flattened verify (using key)`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, key), payload) -}) - -test(`${recipe.title} - general verify (using key)`, t => { - t.deepEqual(JWS.verify(recipe.output.json, key), payload) -}) - -;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - compact verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.compact, keystore), payload) - }) - - test(`${recipe.title} - flattened verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, keystore), payload) - }) - - test(`${recipe.title} - general verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json, keystore), payload) - }) -}) - -test(`${recipe.title} - compact verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.compact, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - compact verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.compact, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) diff --git a/test/cookbook/4_2.rsa-pss_signature.test.js b/test/cookbook/4_2.rsa-pss_signature.test.js deleted file mode 100644 index c43351bea7..0000000000 --- a/test/cookbook/4_2.rsa-pss_signature.test.js +++ /dev/null @@ -1,95 +0,0 @@ -const test = require('ava') - -const recipe = require('./recipes').get('4.2') -const { sig: verifiers } = require('./verifiers') - -const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - -const { input: { payload, key: jwk }, signing: { protected: header } } = recipe - -const key = asKey(jwk) - -const keystoreEmpty = new KeyStore() -const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) -const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - -test(`${recipe.title} - compact sign (random)`, t => { - const res = JWS.sign(payload, key, header) - verifiers.compact(t, res, recipe.output.compact) - t.deepEqual(JWS.verify(res, key), payload) -}) - -test(`${recipe.title} - flattened sign (random)`, t => { - const res = JWS.sign.flattened(payload, key, header) - verifiers.flattened(t, res, recipe.output.json_flat) - t.deepEqual(JWS.verify(res, key), payload) -}) - -test(`${recipe.title} - general sign (random)`, t => { - const res = JWS.sign.general(payload, key, header) - verifiers.general(t, res, recipe.output.json) - t.deepEqual(JWS.verify(res, key), payload) -}) - -test(`${recipe.title} - compact verify`, t => { - t.deepEqual(JWS.verify(recipe.output.compact, key), payload) -}) - -test(`${recipe.title} - flattened verify`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, key), payload) -}) - -test(`${recipe.title} - general verify`, t => { - t.deepEqual(JWS.verify(recipe.output.json, key), payload) -}) - -;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - compact verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.compact, keystore), payload) - }) - - test(`${recipe.title} - flattened verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, keystore), payload) - }) - - test(`${recipe.title} - general verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json, keystore), payload) - }) -}) - -test(`${recipe.title} - compact verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.compact, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - compact verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.compact, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) diff --git a/test/cookbook/4_3.ecdsa_signature.test.js b/test/cookbook/4_3.ecdsa_signature.test.js deleted file mode 100644 index 5c1d38022b..0000000000 --- a/test/cookbook/4_3.ecdsa_signature.test.js +++ /dev/null @@ -1,95 +0,0 @@ -const test = require('ava') - -const recipe = require('./recipes').get('4.3') -const { sig: verifiers } = require('./verifiers') - -const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - -const { input: { payload, key: jwk }, signing: { protected: header } } = recipe - -const key = asKey(jwk) - -const keystoreEmpty = new KeyStore() -const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.crv, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.crv, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) -const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - -test(`${recipe.title} - compact sign (random)`, t => { - const res = JWS.sign(payload, key, header) - verifiers.compact(t, res, recipe.output.compact) - t.deepEqual(JWS.verify(res, key), payload) -}) - -test(`${recipe.title} - flattened sign (random)`, t => { - const res = JWS.sign.flattened(payload, key, header) - verifiers.flattened(t, res, recipe.output.json_flat) - t.deepEqual(JWS.verify(res, key), payload) -}) - -test(`${recipe.title} - general sign (random)`, t => { - const res = JWS.sign.general(payload, key, header) - verifiers.general(t, res, recipe.output.json) - t.deepEqual(JWS.verify(res, key), payload) -}) - -test(`${recipe.title} - compact verify`, t => { - t.deepEqual(JWS.verify(recipe.output.compact, key), payload) -}) - -test(`${recipe.title} - flattened verify`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, key), payload) -}) - -test(`${recipe.title} - general verify`, t => { - t.deepEqual(JWS.verify(recipe.output.json, key), payload) -}) - -;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - compact verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.compact, keystore), payload) - }) - - test(`${recipe.title} - flattened verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, keystore), payload) - }) - - test(`${recipe.title} - general verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json, keystore), payload) - }) -}) - -test(`${recipe.title} - compact verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.compact, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - compact verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.compact, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) diff --git a/test/cookbook/4_4.hmac-sha2_integrity_protection.test.js b/test/cookbook/4_4.hmac-sha2_integrity_protection.test.js deleted file mode 100644 index 05f5f1ab15..0000000000 --- a/test/cookbook/4_4.hmac-sha2_integrity_protection.test.js +++ /dev/null @@ -1,88 +0,0 @@ -const test = require('ava') - -const recipe = require('./recipes').get('4.4') - -const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - -const { input: { payload, key: jwk }, signing: { protected: header } } = recipe - -const key = asKey(jwk) - -const keystoreEmpty = new KeyStore() -const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) -const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - -test(`${recipe.title} - compact sign`, t => { - t.is(JWS.sign(payload, key, header), recipe.output.compact) -}) - -test(`${recipe.title} - flattened sign`, t => { - t.deepEqual(JWS.sign.flattened(payload, key, header), recipe.output.json_flat) -}) - -test(`${recipe.title} - general sign`, t => { - t.deepEqual(JWS.sign.general(payload, key, header), recipe.output.json) -}) - -test(`${recipe.title} - compact verify`, t => { - t.deepEqual(JWS.verify(recipe.output.compact, key), payload) -}) - -test(`${recipe.title} - flattened verify`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, key), payload) -}) - -test(`${recipe.title} - general verify`, t => { - t.deepEqual(JWS.verify(recipe.output.json, key), payload) -}) - -;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - compact verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.compact, keystore), payload) - }) - - test(`${recipe.title} - flattened verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, keystore), payload) - }) - - test(`${recipe.title} - general verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json, keystore), payload) - }) -}) - -test(`${recipe.title} - compact verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.compact, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - compact verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.compact, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) diff --git a/test/cookbook/4_6.protecting_specific_header_fields.test.js b/test/cookbook/4_6.protecting_specific_header_fields.test.js deleted file mode 100644 index 2b0b14ceb6..0000000000 --- a/test/cookbook/4_6.protecting_specific_header_fields.test.js +++ /dev/null @@ -1,64 +0,0 @@ -const test = require('ava') - -const recipe = require('./recipes').get('4.6') - -const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - -const { input: { payload, key: jwk }, signing: { protected: protec, unprotected } } = recipe - -const key = asKey(jwk) - -const keystoreEmpty = new KeyStore() -const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) -const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - -test(`${recipe.title} - flattened sign`, t => { - t.deepEqual(JWS.sign.flattened(payload, key, protec, unprotected), recipe.output.json_flat) -}) - -test(`${recipe.title} - general sign`, t => { - t.deepEqual(JWS.sign.general(payload, key, protec, unprotected), recipe.output.json) -}) - -test(`${recipe.title} - flattened verify`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, key), payload) -}) - -test(`${recipe.title} - general verify`, t => { - t.deepEqual(JWS.verify(recipe.output.json, key), payload) -}) - -;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - flattened verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, keystore), payload) - }) - - test(`${recipe.title} - general verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json, keystore), payload) - }) -}) - -test(`${recipe.title} - flattened verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) diff --git a/test/cookbook/4_7.protecting_content_only.test.js b/test/cookbook/4_7.protecting_content_only.test.js deleted file mode 100644 index fff07f23c3..0000000000 --- a/test/cookbook/4_7.protecting_content_only.test.js +++ /dev/null @@ -1,64 +0,0 @@ -const test = require('ava') - -const recipe = require('./recipes').get('4.7') - -const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - -const { input: { payload, key: jwk }, signing: { unprotected } } = recipe - -const key = asKey(jwk) - -const keystoreEmpty = new KeyStore() -const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) -const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - -test(`${recipe.title} - flattened sign`, t => { - t.deepEqual(JWS.sign.flattened(payload, key, undefined, unprotected), recipe.output.json_flat) -}) - -test(`${recipe.title} - general sign`, t => { - t.deepEqual(JWS.sign.general(payload, key, undefined, unprotected), recipe.output.json) -}) - -test(`${recipe.title} - flattened verify`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, key), payload) -}) - -test(`${recipe.title} - general verify`, t => { - t.deepEqual(JWS.verify(recipe.output.json, key), payload) -}) - -;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - flattened verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, keystore), payload) - }) - - test(`${recipe.title} - general verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json, keystore), payload) - }) -}) - -test(`${recipe.title} - flattened verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) diff --git a/test/cookbook/4_8.multiple_signatures.test.js b/test/cookbook/4_8.multiple_signatures.test.js deleted file mode 100644 index adfc47dc66..0000000000 --- a/test/cookbook/4_8.multiple_signatures.test.js +++ /dev/null @@ -1,59 +0,0 @@ -const test = require('ava') - -const recipe = require('./recipes').get('4.8') - -const { JWS, JWK: { asKey }, JWKS: { KeyStore }, errors } = require('../..') - -const { input: { payload, key: jwks }, signing: recipients } = recipe - -const keys = jwks.map((jwk) => asKey(jwk)) - -const keystoreEmpty = new KeyStore() -const keystore = new KeyStore(...keys) -const keystoreMatchNone = new KeyStore() -keys.forEach(({ kty }) => { - keystoreMatchNone.generateSync(kty) -}) - -test(`${recipe.title} - general sign`, t => { - const jws = new JWS.Sign(payload) - - keys.forEach((key, i) => { - const { protected: protec, unprotected } = recipients[i] - jws.recipient(key, protec, unprotected) - }) - - // t.deepEqual(jws.sign('general'), recipe.output.json) // EC cannot be reproduced - - const result = jws.sign('general') - t.is(result.payload, recipe.output.json.payload) - t.deepEqual(result.signatures[0], recipe.output.json.signatures[0]) - // t.deepEqual(result.signatures[1], recipe.output.json.signatures[1]) // EC cannot be reproduced - t.deepEqual(result.signatures[2], recipe.output.json.signatures[2]) - - keys.forEach((key) => { - t.deepEqual(JWS.verify(recipe.output.json, key), payload) - }) -}) - -keys.forEach((key, i) => { - test(`${recipe.title} - general verify - key ${i + 1}`, t => { - t.deepEqual(JWS.verify(recipe.output.json, key), payload) - }) -}) - -test(`${recipe.title} - general verify - keystore`, t => { - t.deepEqual(JWS.verify(recipe.output.json, keystore), payload) -}) - -test(`${recipe.title} - general verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) diff --git a/test/cookbook/5_1.key_encryption_using_rsa_v15_and_aes-hmac-sha2.test.js b/test/cookbook/5_1.key_encryption_using_rsa_v15_and_aes-hmac-sha2.test.js deleted file mode 100644 index 7fe89bfcfc..0000000000 --- a/test/cookbook/5_1.key_encryption_using_rsa_v15_and_aes-hmac-sha2.test.js +++ /dev/null @@ -1,98 +0,0 @@ -const test = require('ava') - -const recipe = require('./recipes').get('5.1') -const { enc: verifiers } = require('./verifiers') - -const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - -const { - input: { plaintext, key: jwk }, - encrypting_content: { protected: prot } -} = recipe - -const key = asKey(jwk) - -const keystoreEmpty = new KeyStore() -const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) -const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - -test(`${recipe.title} - compact encrypt`, t => { - const res = JWE.encrypt(plaintext, key, prot) - verifiers.compact(t, res, recipe.output.compact) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - flattened encrypt`, t => { - const res = JWE.encrypt.flattened(plaintext, key, prot) - verifiers.flattened(t, res, recipe.output.json_flat) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - general encrypt`, t => { - const res = JWE.encrypt.general(plaintext, key, prot) - verifiers.general(t, res, recipe.output.json) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - compact decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - flattened decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - general decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, key), Buffer.from(plaintext)) -}) - -;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - compact decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, keystore), Buffer.from(plaintext)) - }) -}) - -test(`${recipe.title} - compact decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - compact decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) diff --git a/test/cookbook/5_10.including_additional_authentication_data.test.js b/test/cookbook/5_10.including_additional_authentication_data.test.js deleted file mode 100644 index 0376ff6f93..0000000000 --- a/test/cookbook/5_10.including_additional_authentication_data.test.js +++ /dev/null @@ -1,74 +0,0 @@ -const test = require('ava') - -if (!('electron' in process.versions)) { - const recipe = require('./recipes').get('5.10') - const { enc: verifiers } = require('./verifiers') - - const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - - const { - input: { plaintext, key: jwk, aad }, - encrypting_content: { protected: prot } - } = recipe - - const key = asKey(jwk) - - const keystoreEmpty = new KeyStore() - const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) - const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) - const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - - test(`${recipe.title} - flattened encrypt`, t => { - const res = JWE.encrypt.flattened(plaintext, key, prot, aad) - verifiers.flattened(t, res, recipe.output.json_flat) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general encrypt`, t => { - const res = JWE.encrypt.general(plaintext, key, prot, aad) - verifiers.general(t, res, recipe.output.json) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, key), Buffer.from(plaintext)) - }) - - ;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - flattened decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, keystore), Buffer.from(plaintext)) - }) - }) - - test(`${recipe.title} - flattened decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - general decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - flattened decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - general decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) -} diff --git a/test/cookbook/5_11.protecting_specific_header_fields.test.js b/test/cookbook/5_11.protecting_specific_header_fields.test.js deleted file mode 100644 index bbd0ad07a8..0000000000 --- a/test/cookbook/5_11.protecting_specific_header_fields.test.js +++ /dev/null @@ -1,74 +0,0 @@ -const test = require('ava') - -if (!('electron' in process.versions)) { - const recipe = require('./recipes').get('5.11') - const { enc: verifiers } = require('./verifiers') - - const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - - const { - input: { plaintext, key: jwk }, - encrypting_content: { protected: prot, unprotected } - } = recipe - - const key = asKey(jwk) - - const keystoreEmpty = new KeyStore() - const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) - const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) - const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - - test(`${recipe.title} - flattened encrypt`, t => { - const res = JWE.encrypt.flattened(plaintext, key, prot, undefined, unprotected) - verifiers.flattened(t, res, recipe.output.json_flat) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general encrypt`, t => { - const res = JWE.encrypt.general(plaintext, key, prot, undefined, unprotected) - verifiers.general(t, res, recipe.output.json) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, key), Buffer.from(plaintext)) - }) - - ;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - flattened decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, keystore), Buffer.from(plaintext)) - }) - }) - - test(`${recipe.title} - flattened decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - general decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - flattened decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - general decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) -} diff --git a/test/cookbook/5_12.protecting_content_only.test.js b/test/cookbook/5_12.protecting_content_only.test.js deleted file mode 100644 index 4df301e18a..0000000000 --- a/test/cookbook/5_12.protecting_content_only.test.js +++ /dev/null @@ -1,74 +0,0 @@ -const test = require('ava') - -if (!('electron' in process.versions)) { - const recipe = require('./recipes').get('5.12') - const { enc: verifiers } = require('./verifiers') - - const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - - const { - input: { plaintext, key: jwk }, - encrypting_content: { unprotected } - } = recipe - - const key = asKey(jwk) - - const keystoreEmpty = new KeyStore() - const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) - const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) - const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - - test(`${recipe.title} - flattened encrypt`, t => { - const res = JWE.encrypt.flattened(plaintext, key, undefined, undefined, unprotected) - verifiers.flattened(t, res, recipe.output.json_flat) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general encrypt`, t => { - const res = JWE.encrypt.general(plaintext, key, undefined, undefined, unprotected) - verifiers.general(t, res, recipe.output.json) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, key), Buffer.from(plaintext)) - }) - - ;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - flattened decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, keystore), Buffer.from(plaintext)) - }) - }) - - test(`${recipe.title} - flattened decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - general decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - flattened decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - general decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) -} diff --git a/test/cookbook/5_13.encrypting_to_multiple_recipients.test.js b/test/cookbook/5_13.encrypting_to_multiple_recipients.test.js deleted file mode 100644 index fc5f996842..0000000000 --- a/test/cookbook/5_13.encrypting_to_multiple_recipients.test.js +++ /dev/null @@ -1,58 +0,0 @@ -const test = require('ava') - -if (!('electron' in process.versions)) { - const recipe = require('./recipes').get('5.13') - const { enc: verifiers } = require('./verifiers') - - const { JWE, JWK: { asKey }, JWKS: { KeyStore }, errors } = require('../..') - - const { - input: { plaintext, key: jwks }, - encrypting_content: { protected: prot, unprotected }, - encrypting_key: recipients - } = recipe - - const keys = jwks.map((jwk) => asKey(jwk)) - - const keystoreEmpty = new KeyStore() - const keystore = new KeyStore(...keys) - const keystoreMatchNone = new KeyStore() - keys.forEach(({ kty }) => { - keystoreMatchNone.generateSync(kty) - }) - - test(`${recipe.title} - general encrypt`, t => { - const jwe = new JWE.Encrypt(plaintext, prot, undefined, unprotected) - keys.forEach((key, i) => { - jwe.recipient(key, recipients[i].header) - }) - const res = jwe.encrypt('general') - verifiers.general(t, res, recipe.output.json) - - keys.forEach((key, i) => { - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - }) - - keys.forEach((key, i) => { - test(`${recipe.title} - general decrypt - key ${i + 1}`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, key), Buffer.from(plaintext)) - }) - }) - - test(`${recipe.title} - general decrypt - keystore`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - general decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) -} diff --git a/test/cookbook/5_2.key_encryption_using_rsa-oaep_with_aes-gcm.test.js b/test/cookbook/5_2.key_encryption_using_rsa-oaep_with_aes-gcm.test.js deleted file mode 100644 index 4a5f409680..0000000000 --- a/test/cookbook/5_2.key_encryption_using_rsa-oaep_with_aes-gcm.test.js +++ /dev/null @@ -1,98 +0,0 @@ -const test = require('ava') - -const recipe = require('./recipes').get('5.2') -const { enc: verifiers } = require('./verifiers') - -const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - -const { - input: { plaintext, key: jwk }, - encrypting_content: { protected: prot } -} = recipe - -const key = asKey(jwk) - -const keystoreEmpty = new KeyStore() -const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) -const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - -test(`${recipe.title} - compact encrypt`, t => { - const res = JWE.encrypt(plaintext, key, prot) - verifiers.compact(t, res, recipe.output.compact) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - flattened encrypt`, t => { - const res = JWE.encrypt.flattened(plaintext, key, prot) - verifiers.flattened(t, res, recipe.output.json_flat) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - general encrypt`, t => { - const res = JWE.encrypt.general(plaintext, key, prot) - verifiers.general(t, res, recipe.output.json) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - compact decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - flattened decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - general decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, key), Buffer.from(plaintext)) -}) - -;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - compact decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, keystore), Buffer.from(plaintext)) - }) -}) - -test(`${recipe.title} - compact decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - compact decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) diff --git a/test/cookbook/5_3.key_wrap_using_pbes2-aes-keywrap_with-aes-cbc-hmac-sha2.test.js b/test/cookbook/5_3.key_wrap_using_pbes2-aes-keywrap_with-aes-cbc-hmac-sha2.test.js deleted file mode 100644 index 76b72a3d97..0000000000 --- a/test/cookbook/5_3.key_wrap_using_pbes2-aes-keywrap_with-aes-cbc-hmac-sha2.test.js +++ /dev/null @@ -1,100 +0,0 @@ -const test = require('ava') - -if (!('electron' in process.versions)) { - const recipe = require('./recipes').get('5.3') - const { enc: verifiers } = require('./verifiers') - - const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - - const { - input: { plaintext, pwd }, - encrypting_content: { protected: prot } - } = recipe - - const key = asKey(Buffer.from(pwd)) - - const keystoreEmpty = new KeyStore() - const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) - const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) - const keystoreMatchNone = new KeyStore(generateSync('EC'), generateSync('RSA')) - - test(`${recipe.title} - compact encrypt`, t => { - const res = JWE.encrypt(plaintext, key, prot) - verifiers.compact(t, res, recipe.output.compact) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened encrypt`, t => { - const res = JWE.encrypt.flattened(plaintext, key, prot) - verifiers.flattened(t, res, recipe.output.json_flat) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general encrypt`, t => { - const res = JWE.encrypt.general(plaintext, key, prot) - verifiers.general(t, res, recipe.output.json) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - compact decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, key), Buffer.from(plaintext)) - }) - - ;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - compact decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, keystore), Buffer.from(plaintext)) - }) - }) - - test(`${recipe.title} - compact decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - flattened decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - general decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - compact decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - flattened decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - general decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) -} diff --git a/test/cookbook/5_4.key_agreement_with_key_wrapping_using_ecdh-es_and_aes-keywrap_with_aes-gcm.test.js b/test/cookbook/5_4.key_agreement_with_key_wrapping_using_ecdh-es_and_aes-keywrap_with_aes-gcm.test.js deleted file mode 100644 index 870d782e5f..0000000000 --- a/test/cookbook/5_4.key_agreement_with_key_wrapping_using_ecdh-es_and_aes-keywrap_with_aes-gcm.test.js +++ /dev/null @@ -1,100 +0,0 @@ -const test = require('ava') - -if (!('electron' in process.versions)) { - const recipe = require('./recipes').get('5.4') - const { enc: verifiers } = require('./verifiers') - - const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - - const { - input: { plaintext, key: jwk }, - encrypting_content: { protected: prot } - } = recipe - - const key = asKey(jwk) - - const keystoreEmpty = new KeyStore() - const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.crv, { alg: key.alg, use: key.use }), key) - const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.crv, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) - const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - - test(`${recipe.title} - compact encrypt`, t => { - const res = JWE.encrypt(plaintext, key, prot) - verifiers.compact(t, res, recipe.output.compact) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened encrypt`, t => { - const res = JWE.encrypt.flattened(plaintext, key, prot) - verifiers.flattened(t, res, recipe.output.json_flat) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general encrypt`, t => { - const res = JWE.encrypt.general(plaintext, key, prot) - verifiers.general(t, res, recipe.output.json) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - compact decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, key), Buffer.from(plaintext)) - }) - - ;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - compact decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, keystore), Buffer.from(plaintext)) - }) - }) - - test(`${recipe.title} - compact decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - flattened decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - general decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - compact decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - flattened decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - general decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) -} diff --git a/test/cookbook/5_5.key_agreement_using_ecdh-es_with_aes-cbc-hmac-sha2.test.js b/test/cookbook/5_5.key_agreement_using_ecdh-es_with_aes-cbc-hmac-sha2.test.js deleted file mode 100644 index 2cacbb8b33..0000000000 --- a/test/cookbook/5_5.key_agreement_using_ecdh-es_with_aes-cbc-hmac-sha2.test.js +++ /dev/null @@ -1,98 +0,0 @@ -const test = require('ava') - -const recipe = require('./recipes').get('5.5') -const { enc: verifiers } = require('./verifiers') - -const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - -const { - input: { plaintext, key: jwk }, - encrypting_content: { protected: prot } -} = recipe - -const key = asKey(jwk) - -const keystoreEmpty = new KeyStore() -const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.crv, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.crv, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) -const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - -test(`${recipe.title} - compact encrypt`, t => { - const res = JWE.encrypt(plaintext, key, prot) - verifiers.compact(t, res, recipe.output.compact) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - flattened encrypt`, t => { - const res = JWE.encrypt.flattened(plaintext, key, prot) - verifiers.flattened(t, res, recipe.output.json_flat) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - general encrypt`, t => { - const res = JWE.encrypt.general(plaintext, key, prot) - verifiers.general(t, res, recipe.output.json) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - compact decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - flattened decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - general decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, key), Buffer.from(plaintext)) -}) - -;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - compact decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, keystore), Buffer.from(plaintext)) - }) -}) - -test(`${recipe.title} - compact decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - compact decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) diff --git a/test/cookbook/5_6.direct_encryption_using_aes-gcm.test.js b/test/cookbook/5_6.direct_encryption_using_aes-gcm.test.js deleted file mode 100644 index 16ebda3f2d..0000000000 --- a/test/cookbook/5_6.direct_encryption_using_aes-gcm.test.js +++ /dev/null @@ -1,98 +0,0 @@ -const test = require('ava') - -const recipe = require('./recipes').get('5.6') -const { enc: verifiers } = require('./verifiers') - -const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - -const { - input: { plaintext, key: jwk }, - encrypting_content: { protected: prot } -} = recipe - -const key = asKey(jwk) - -const keystoreEmpty = new KeyStore() -const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) -const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - -test(`${recipe.title} - compact encrypt`, t => { - const res = JWE.encrypt(plaintext, key, prot) - verifiers.compact(t, res, recipe.output.compact) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - flattened encrypt`, t => { - const res = JWE.encrypt.flattened(plaintext, key, prot) - verifiers.flattened(t, res, recipe.output.json_flat) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - general encrypt`, t => { - const res = JWE.encrypt.general(plaintext, key, prot) - verifiers.general(t, res, recipe.output.json) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - compact decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - flattened decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - general decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, key), Buffer.from(plaintext)) -}) - -;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - compact decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, keystore), Buffer.from(plaintext)) - }) -}) - -test(`${recipe.title} - compact decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - compact decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) diff --git a/test/cookbook/5_7.key_wrap_using_aes-gcm_keywrap_with_aes-cbc-hmac-sha2.test.js b/test/cookbook/5_7.key_wrap_using_aes-gcm_keywrap_with_aes-cbc-hmac-sha2.test.js deleted file mode 100644 index d7760d336b..0000000000 --- a/test/cookbook/5_7.key_wrap_using_aes-gcm_keywrap_with_aes-cbc-hmac-sha2.test.js +++ /dev/null @@ -1,98 +0,0 @@ -const test = require('ava') - -const recipe = require('./recipes').get('5.7') -const { enc: verifiers } = require('./verifiers') - -const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - -const { - input: { plaintext, key: jwk }, - encrypting_content: { protected: prot } -} = recipe - -const key = asKey(jwk) - -const keystoreEmpty = new KeyStore() -const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) -const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - -test(`${recipe.title} - compact encrypt`, t => { - const res = JWE.encrypt(plaintext, key, prot) - verifiers.compact(t, res, recipe.output.compact) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - flattened encrypt`, t => { - const res = JWE.encrypt.flattened(plaintext, key, prot) - verifiers.flattened(t, res, recipe.output.json_flat) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - general encrypt`, t => { - const res = JWE.encrypt.general(plaintext, key, prot) - verifiers.general(t, res, recipe.output.json) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - compact decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - flattened decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, key), Buffer.from(plaintext)) -}) - -test(`${recipe.title} - general decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, key), Buffer.from(plaintext)) -}) - -;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - compact decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, keystore), Buffer.from(plaintext)) - }) -}) - -test(`${recipe.title} - compact decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - compact decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) diff --git a/test/cookbook/5_8.key_wrap_using_aes-keywrap_with_aes-gcm.test.js b/test/cookbook/5_8.key_wrap_using_aes-keywrap_with_aes-gcm.test.js deleted file mode 100644 index ba0c04c195..0000000000 --- a/test/cookbook/5_8.key_wrap_using_aes-keywrap_with_aes-gcm.test.js +++ /dev/null @@ -1,100 +0,0 @@ -const test = require('ava') - -if (!('electron' in process.versions)) { - const recipe = require('./recipes').get('5.8') - const { enc: verifiers } = require('./verifiers') - - const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - - const { - input: { plaintext, key: jwk }, - encrypting_content: { protected: prot } - } = recipe - - const key = asKey(jwk) - - const keystoreEmpty = new KeyStore() - const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) - const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) - const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - - test(`${recipe.title} - compact encrypt`, t => { - const res = JWE.encrypt(plaintext, key, prot) - verifiers.compact(t, res, recipe.output.compact) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened encrypt`, t => { - const res = JWE.encrypt.flattened(plaintext, key, prot) - verifiers.flattened(t, res, recipe.output.json_flat) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general encrypt`, t => { - const res = JWE.encrypt.general(plaintext, key, prot) - verifiers.general(t, res, recipe.output.json) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - compact decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, key), Buffer.from(plaintext)) - }) - - ;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - compact decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, keystore), Buffer.from(plaintext)) - }) - }) - - test(`${recipe.title} - compact decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - flattened decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - general decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - compact decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - flattened decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - general decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) -} diff --git a/test/cookbook/5_9.compressed_content.test.js b/test/cookbook/5_9.compressed_content.test.js deleted file mode 100644 index b8f4a7aaaf..0000000000 --- a/test/cookbook/5_9.compressed_content.test.js +++ /dev/null @@ -1,100 +0,0 @@ -const test = require('ava') - -if (!('electron' in process.versions)) { - const recipe = require('./recipes').get('5.9') - const { enc: verifiers } = require('./verifiers') - - const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - - const { - input: { plaintext, key: jwk }, - encrypting_content: { protected: prot } - } = recipe - - const key = asKey(jwk) - - const keystoreEmpty = new KeyStore() - const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) - const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) - const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - - test(`${recipe.title} - compact encrypt`, t => { - const res = JWE.encrypt(plaintext, key, prot) - verifiers.compact(t, res, recipe.output.compact) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened encrypt`, t => { - const res = JWE.encrypt.flattened(plaintext, key, prot) - verifiers.flattened(t, res, recipe.output.json_flat) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general encrypt`, t => { - const res = JWE.encrypt.general(plaintext, key, prot) - verifiers.general(t, res, recipe.output.json) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - compact decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, key), Buffer.from(plaintext)) - }) - - ;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - compact decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, keystore), Buffer.from(plaintext)) - }) - }) - - test(`${recipe.title} - compact decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - flattened decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - general decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - compact decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - flattened decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - general decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) -} diff --git a/test/cookbook/jwk.test.js b/test/cookbook/jwk.test.js deleted file mode 100644 index c1538cf199..0000000000 --- a/test/cookbook/jwk.test.js +++ /dev/null @@ -1,125 +0,0 @@ -const test = require('ava') - -const { keyObjectSupported } = require('../../lib/help/runtime_support') - -const recipes = require('./recipes') - -const { JWK: { asKey }, JWKS: { KeyStore } } = require('../..') -const errors = require('../../lib/errors') - -test('public EC', t => { - const jwk = recipes.get('3.1') - const key = asKey(jwk) - t.true(key.toPEM().includes('BEGIN PUBLIC KEY')) - t.deepEqual(key.toJWK(), jwk) - t.deepEqual(key.toJWK(false), jwk) - t.throws(() => { - key.toJWK(true) - }, { instanceOf: TypeError, message: 'public key cannot be exported as private' }) - t.throws(() => { - key.toPEM(false, { cipher: 'aes-256-cbc' }) - }, { instanceOf: TypeError, message: 'cipher and passphrase can only be applied when exporting private keys' }) - t.throws(() => { - key.toPEM(false, { passphrase: 'top secret' }) - }, { instanceOf: TypeError, message: 'cipher and passphrase can only be applied when exporting private keys' }) - t.throws(() => { - key.toPEM(true) - }, { instanceOf: TypeError, message: 'public key cannot be exported as private' }) -}) - -test('private EC', t => { - const jwk = recipes.get('3.2') - const key = asKey(jwk) - t.true(key.toPEM(true, { type: 'sec1' }).includes('BEGIN EC PRIVATE KEY')) - if (keyObjectSupported) { - t.true(key.toPEM(true, { cipher: 'aes-256-cbc', passphrase: 'top secret' }).includes('BEGIN ENCRYPTED PRIVATE KEY')) - t.true(key.toPEM(true, { type: 'sec1', cipher: 'aes-256-cbc', passphrase: 'top secret' }).includes('ENCRYPTED')) - } else { - t.throws(() => { - key.toPEM(true, { cipher: 'aes-256-cbc', passphrase: 'top secret' }).includes('BEGIN ENCRYPTED PRIVATE KEY') - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'encrypted private keys are not supported in your Node.js runtime version' }) - } - t.true(key.toPEM(true).includes('BEGIN PRIVATE KEY')) - t.true(key.toPEM().includes('BEGIN PUBLIC KEY')) - t.deepEqual(key.toJWK(true), jwk) - const { d, ...pub } = jwk - t.deepEqual(key.toJWK(), pub) - t.deepEqual(key.toJWK(false), pub) - t.throws(() => { - key.toPEM(false, { cipher: 'aes-256-cbc' }) - }, { instanceOf: TypeError, message: 'cipher and passphrase can only be applied when exporting private keys' }) - t.throws(() => { - key.toPEM(false, { passphrase: 'top secret' }) - }, { instanceOf: TypeError, message: 'cipher and passphrase can only be applied when exporting private keys' }) -}) - -test('public RSA', t => { - const jwk = recipes.get('3.3') - const key = asKey(jwk) - t.true(key.toPEM().includes('BEGIN PUBLIC KEY')) - t.deepEqual(key.toJWK(), jwk) - t.deepEqual(key.toJWK(false), jwk) - t.throws(() => { - key.toJWK(true) - }, { instanceOf: TypeError, message: 'public key cannot be exported as private' }) - t.throws(() => { - key.toPEM(true) - }, { instanceOf: TypeError, message: 'public key cannot be exported as private' }) -}) - -test('private RSA', t => { - const jwk = recipes.get('3.4') - const key = asKey(jwk) - t.true(key.toPEM(true, { type: 'pkcs1' }).includes('BEGIN RSA PRIVATE KEY')) - if (keyObjectSupported) { - t.true(key.toPEM(true, { cipher: 'aes-256-cbc', passphrase: 'top secret', type: 'pkcs1' }).includes('ENCRYPTED')) - t.true(key.toPEM(true, { type: 'pkcs1', cipher: 'aes-256-cbc', passphrase: 'top secret' }).includes('BEGIN RSA PRIVATE KEY')) - t.true(key.toPEM(true, { cipher: 'aes-256-cbc', passphrase: 'top secret' }).includes('BEGIN ENCRYPTED PRIVATE KEY')) - } else { - t.throws(() => { - key.toPEM(true, { cipher: 'aes-256-cbc', passphrase: 'top secret' }).includes('BEGIN ENCRYPTED PRIVATE KEY') - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'encrypted private keys are not supported in your Node.js runtime version' }) - } - t.true(key.toPEM(true).includes('BEGIN PRIVATE KEY')) - t.true(key.toPEM().includes('BEGIN PUBLIC KEY')) - t.deepEqual(key.toJWK(true), jwk) - const { d, dp, dq, p, q, qi, ...pub } = jwk - t.deepEqual(key.toJWK(), pub) - t.deepEqual(key.toJWK(false), pub) -}) - -test('oct (1/2)', t => { - const jwk = recipes.get('3.5') - const key = asKey(jwk) - t.throws(() => { - key.toPEM() - }, { instanceOf: TypeError, message: 'symmetric keys cannot be exported as PEM' }) - t.deepEqual(key.toJWK(true), jwk) - const { k, ...pub } = jwk - t.deepEqual(key.toJWK(), pub) - t.deepEqual(key.toJWK(false), pub) -}) - -test('oct (2/2)', t => { - const jwk = recipes.get('3.6') - const key = asKey(jwk) - t.deepEqual(key.toJWK(true), jwk) - const { k, ...pub } = jwk - t.deepEqual(key.toJWK(), pub) - t.deepEqual(key.toJWK(false), pub) -}) - -test('keystore .toJWKS()', t => { - const ec = recipes.get('3.2') - const { d: throwaway, ...pubEc } = ec - const rsa = recipes.get('3.4') - const { d, dp, dq, p, q, qi, ...pubRsa } = rsa - const oct = recipes.get('3.5') - const { k, ...pubOct } = oct - const ks = new KeyStore(asKey(ec), asKey(rsa), asKey(oct)) - t.deepEqual(ks.toJWKS(true), { keys: [ec, rsa, oct] }) - t.deepEqual(ks.toJWKS(), { keys: [pubEc, pubRsa, pubOct] }) - t.deepEqual(ks.toJWKS(false), { keys: [pubEc, pubRsa, pubOct] }) - ks.add(asKey(pubRsa)) - t.deepEqual(ks.toJWKS(true), { keys: [ec, rsa, oct, pubRsa] }) -}) diff --git a/test/cookbook/ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256.test.js b/test/cookbook/ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256.test.js deleted file mode 100644 index 9c2e7df18e..0000000000 --- a/test/cookbook/ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256.test.js +++ /dev/null @@ -1,102 +0,0 @@ -const test = require('ava') - -const { oaepHashSupported } = require('../../lib/help/runtime_support') - -if (oaepHashSupported) { - const recipe = require('./recipes').get('ml-oeap-256') - const { enc: verifiers } = require('./verifiers') - - const { JWE, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - - const { - input: { plaintext, key: jwk }, - encrypting_content: { protected: prot } - } = recipe - - const key = asKey(jwk) - - const keystoreEmpty = new KeyStore() - const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) - const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) - const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - - test(`${recipe.title} - compact encrypt`, t => { - const res = JWE.encrypt(plaintext, key, prot) - verifiers.compact(t, res, recipe.output.compact) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened encrypt`, t => { - const res = JWE.encrypt.flattened(plaintext, key, prot) - verifiers.flattened(t, res, recipe.output.json_flat) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general encrypt`, t => { - const res = JWE.encrypt.general(plaintext, key, prot) - verifiers.general(t, res, recipe.output.json) - t.deepEqual(JWE.decrypt(res, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - compact decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, key), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, key), Buffer.from(plaintext)) - }) - - ;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - compact decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.compact, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - flattened decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json_flat, keystore), Buffer.from(plaintext)) - }) - - test(`${recipe.title} - general decrypt (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWE.decrypt(recipe.output.json, keystore), Buffer.from(plaintext)) - }) - }) - - test(`${recipe.title} - compact decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreMatchNone) - }, { instanceOf: errors.JWEDecryptionFailed, code: 'ERR_JWE_DECRYPTION_FAILED', message: 'decryption operation failed' }) - }) - - test(`${recipe.title} - flattened decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWEDecryptionFailed, code: 'ERR_JWE_DECRYPTION_FAILED', message: 'decryption operation failed' }) - }) - - test(`${recipe.title} - general decrypt (failing)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWEDecryptionFailed, code: 'ERR_JWE_DECRYPTION_FAILED', message: 'decryption operation failed' }) - }) - - test(`${recipe.title} - compact decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.compact, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - flattened decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - general decrypt (using empty keystore)`, t => { - t.throws(() => { - JWE.decrypt(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) -} diff --git a/test/cookbook/recipes/3_1.ec_public_key.js b/test/cookbook/recipes/3_1.ec_public_key.js deleted file mode 100644 index 01ab8b58f7..0000000000 --- a/test/cookbook/recipes/3_1.ec_public_key.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - kty: 'EC', - kid: 'bilbo.baggins@hobbiton.example', - use: 'sig', - crv: 'P-521', - x: 'AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt', - y: 'AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVySsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1' -} diff --git a/test/cookbook/recipes/3_2.ec_private_key.js b/test/cookbook/recipes/3_2.ec_private_key.js deleted file mode 100644 index 131dc4fe73..0000000000 --- a/test/cookbook/recipes/3_2.ec_private_key.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - kty: 'EC', - kid: 'bilbo.baggins@hobbiton.example', - use: 'sig', - crv: 'P-521', - x: 'AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt', - y: 'AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVySsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1', - d: 'AAhRON2r9cqXX1hg-RoI6R1tX5p2rUAYdmpHZoC1XNM56KtscrX6zbKipQrCW9CGZH3T4ubpnoTKLDYJ_fF3_rJt' -} diff --git a/test/cookbook/recipes/3_3.rsa_public_key.js b/test/cookbook/recipes/3_3.rsa_public_key.js deleted file mode 100644 index 2bd472b874..0000000000 --- a/test/cookbook/recipes/3_3.rsa_public_key.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - kty: 'RSA', - kid: 'bilbo.baggins@hobbiton.example', - use: 'sig', - n: 'n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw', - e: 'AQAB' -} diff --git a/test/cookbook/recipes/3_4.rsa_private_key.js b/test/cookbook/recipes/3_4.rsa_private_key.js deleted file mode 100644 index 44f398d7a9..0000000000 --- a/test/cookbook/recipes/3_4.rsa_private_key.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - kty: 'RSA', - kid: 'bilbo.baggins@hobbiton.example', - use: 'sig', - n: 'n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw', - e: 'AQAB', - d: 'bWUC9B-EFRIo8kpGfh0ZuyGPvMNKvYWNtB_ikiH9k20eT-O1q_I78eiZkpXxXQ0UTEs2LsNRS-8uJbvQ-A1irkwMSMkK1J3XTGgdrhCku9gRldY7sNA_AKZGh-Q661_42rINLRCe8W-nZ34ui_qOfkLnK9QWDDqpaIsA-bMwWWSDFu2MUBYwkHTMEzLYGqOe04noqeq1hExBTHBOBdkMXiuFhUq1BU6l-DqEiWxqg82sXt2h-LMnT3046AOYJoRioz75tSUQfGCshWTBnP5uDjd18kKhyv07lhfSJdrPdM5Plyl21hsFf4L_mHCuoFau7gdsPfHPxxjVOcOpBrQzwQ', - p: '3Slxg_DwTXJcb6095RoXygQCAZ5RnAvZlno1yhHtnUex_fp7AZ_9nRaO7HX_-SFfGQeutao2TDjDAWU4Vupk8rw9JR0AzZ0N2fvuIAmr_WCsmGpeNqQnev1T7IyEsnh8UMt-n5CafhkikzhEsrmndH6LxOrvRJlsPp6Zv8bUq0k', - q: 'uKE2dh-cTf6ERF4k4e_jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR_cu0Dm1MZwWmtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7z4yMkuUwFWoBvyY898EXvRD-hdqRxHlSqAZ192zB3pVFJ0s7pFc', - dp: 'B8PVvXkvJrj2L-GYQ7v3y9r6Kw5g9SahXBwsWUzp19TVlgI-YV85q1NIb1rxQtD-IsXXR3-TanevuRPRt5OBOdiMGQp8pbt26gljYfKU_E9xn-RULHz0-ed9E9gXLKD4VGngpz-PfQ_q29pk5xWHoJp009Qf1HvChixRX59ehik', - dq: 'CLDmDGduhylc9o7r84rEUVn7pzQ6PF83Y-iBZx5NT-TpnOZKF1pErAMVeKzFEl41DlHHqqBLSM0W1sOFbwTxYWZDm6sI6og5iTbwQGIC3gnJKbi_7k_vJgGHwHxgPaX2PnvP-zyEkDERuf-ry4c_Z11Cq9AqC2yeL6kdKT1cYF8', - qi: '3PiqvXQN0zwMeE-sBvZgi289XP9XCQF3VWqPzMKnIgQp7_Tugo6-NZBKCQsMf3HaEGBjTVJs_jcK8-TRXvaKe-7ZMaQj8VfBdYkssbu0NKDDhjJ-GtiseaDVWt7dcH0cfwxgFUHpQh7FoCrjFJ6h6ZEpMF6xmujs4qMpPz8aaI4' -} diff --git a/test/cookbook/recipes/3_5.symmetric_key_mac_computation.js b/test/cookbook/recipes/3_5.symmetric_key_mac_computation.js deleted file mode 100644 index 94d06a64a1..0000000000 --- a/test/cookbook/recipes/3_5.symmetric_key_mac_computation.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - kty: 'oct', - kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037', - use: 'sig', - alg: 'HS256', - k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg' -} diff --git a/test/cookbook/recipes/3_6.symmetric_key_encryption.js b/test/cookbook/recipes/3_6.symmetric_key_encryption.js deleted file mode 100644 index 6302d4caab..0000000000 --- a/test/cookbook/recipes/3_6.symmetric_key_encryption.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - kty: 'oct', - kid: '1e571774-2e08-40da-8308-e8d68773842d', - use: 'enc', - alg: 'A256GCM', - k: 'AAPapAv4LbFbiVawEjagUBluYqN5rhna-8nuldDvOx8' -} diff --git a/test/cookbook/recipes/4_1.rsa_v15_signature.js b/test/cookbook/recipes/4_1.rsa_v15_signature.js deleted file mode 100644 index ac211b0d37..0000000000 --- a/test/cookbook/recipes/4_1.rsa_v15_signature.js +++ /dev/null @@ -1,43 +0,0 @@ -module.exports = { - title: 'RSA v1.5 Signature', - input: { - payload: Buffer.from('It’s a dangerous business, Frodo, going out your door. You step onto the road, and if you don\'t keep your feet, there’s no knowing where you might be swept off to.'), - key: { - kty: 'RSA', - kid: 'bilbo.baggins@hobbiton.example', - use: 'sig', - n: 'n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw', - e: 'AQAB', - d: 'bWUC9B-EFRIo8kpGfh0ZuyGPvMNKvYWNtB_ikiH9k20eT-O1q_I78eiZkpXxXQ0UTEs2LsNRS-8uJbvQ-A1irkwMSMkK1J3XTGgdrhCku9gRldY7sNA_AKZGh-Q661_42rINLRCe8W-nZ34ui_qOfkLnK9QWDDqpaIsA-bMwWWSDFu2MUBYwkHTMEzLYGqOe04noqeq1hExBTHBOBdkMXiuFhUq1BU6l-DqEiWxqg82sXt2h-LMnT3046AOYJoRioz75tSUQfGCshWTBnP5uDjd18kKhyv07lhfSJdrPdM5Plyl21hsFf4L_mHCuoFau7gdsPfHPxxjVOcOpBrQzwQ', - p: '3Slxg_DwTXJcb6095RoXygQCAZ5RnAvZlno1yhHtnUex_fp7AZ_9nRaO7HX_-SFfGQeutao2TDjDAWU4Vupk8rw9JR0AzZ0N2fvuIAmr_WCsmGpeNqQnev1T7IyEsnh8UMt-n5CafhkikzhEsrmndH6LxOrvRJlsPp6Zv8bUq0k', - q: 'uKE2dh-cTf6ERF4k4e_jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR_cu0Dm1MZwWmtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7z4yMkuUwFWoBvyY898EXvRD-hdqRxHlSqAZ192zB3pVFJ0s7pFc', - dp: 'B8PVvXkvJrj2L-GYQ7v3y9r6Kw5g9SahXBwsWUzp19TVlgI-YV85q1NIb1rxQtD-IsXXR3-TanevuRPRt5OBOdiMGQp8pbt26gljYfKU_E9xn-RULHz0-ed9E9gXLKD4VGngpz-PfQ_q29pk5xWHoJp009Qf1HvChixRX59ehik', - dq: 'CLDmDGduhylc9o7r84rEUVn7pzQ6PF83Y-iBZx5NT-TpnOZKF1pErAMVeKzFEl41DlHHqqBLSM0W1sOFbwTxYWZDm6sI6og5iTbwQGIC3gnJKbi_7k_vJgGHwHxgPaX2PnvP-zyEkDERuf-ry4c_Z11Cq9AqC2yeL6kdKT1cYF8', - qi: '3PiqvXQN0zwMeE-sBvZgi289XP9XCQF3VWqPzMKnIgQp7_Tugo6-NZBKCQsMf3HaEGBjTVJs_jcK8-TRXvaKe-7ZMaQj8VfBdYkssbu0NKDDhjJ-GtiseaDVWt7dcH0cfwxgFUHpQh7FoCrjFJ6h6ZEpMF6xmujs4qMpPz8aaI4' - }, - alg: 'RS256' - }, - signing: { - protected: { - alg: 'RS256', - kid: 'bilbo.baggins@hobbiton.example' - } - }, - output: { - compact: 'eyJhbGciOiJSUzI1NiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4.MRjdkly7_-oTPTS3AXP41iQIGKa80A0ZmTuV5MEaHoxnW2e5CZ5NlKtainoFmKZopdHM1O2U4mwzJdQx996ivp83xuglII7PNDi84wnB-BDkoBwA78185hX-Es4JIwmDLJK3lfWRa-XtL0RnltuYv746iYTh_qHRD68BNt1uSNCrUCTJDt5aAE6x8wW1Kt9eRo4QPocSadnHXFxnt8Is9UzpERV0ePPQdLuW3IS_de3xyIrDaLGdjluPxUAhb6L2aXic1U12podGU0KLUQSE_oI-ZnmKJ3F4uOZDnd6QZWJushZ41Axf_fcIe8u9ipH84ogoree7vjbU5y18kDquDg', - json: { - payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', - signatures: [ - { - protected: 'eyJhbGciOiJSUzI1NiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9', - signature: 'MRjdkly7_-oTPTS3AXP41iQIGKa80A0ZmTuV5MEaHoxnW2e5CZ5NlKtainoFmKZopdHM1O2U4mwzJdQx996ivp83xuglII7PNDi84wnB-BDkoBwA78185hX-Es4JIwmDLJK3lfWRa-XtL0RnltuYv746iYTh_qHRD68BNt1uSNCrUCTJDt5aAE6x8wW1Kt9eRo4QPocSadnHXFxnt8Is9UzpERV0ePPQdLuW3IS_de3xyIrDaLGdjluPxUAhb6L2aXic1U12podGU0KLUQSE_oI-ZnmKJ3F4uOZDnd6QZWJushZ41Axf_fcIe8u9ipH84ogoree7vjbU5y18kDquDg' - } - ] - }, - json_flat: { - payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', - protected: 'eyJhbGciOiJSUzI1NiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9', - signature: 'MRjdkly7_-oTPTS3AXP41iQIGKa80A0ZmTuV5MEaHoxnW2e5CZ5NlKtainoFmKZopdHM1O2U4mwzJdQx996ivp83xuglII7PNDi84wnB-BDkoBwA78185hX-Es4JIwmDLJK3lfWRa-XtL0RnltuYv746iYTh_qHRD68BNt1uSNCrUCTJDt5aAE6x8wW1Kt9eRo4QPocSadnHXFxnt8Is9UzpERV0ePPQdLuW3IS_de3xyIrDaLGdjluPxUAhb6L2aXic1U12podGU0KLUQSE_oI-ZnmKJ3F4uOZDnd6QZWJushZ41Axf_fcIe8u9ipH84ogoree7vjbU5y18kDquDg' - } - } -} diff --git a/test/cookbook/recipes/4_2.rsa-pss_signature.js b/test/cookbook/recipes/4_2.rsa-pss_signature.js deleted file mode 100644 index 33226057d7..0000000000 --- a/test/cookbook/recipes/4_2.rsa-pss_signature.js +++ /dev/null @@ -1,43 +0,0 @@ -module.exports = { - title: 'RSA-PSS Signature', - input: { - payload: Buffer.from('It’s a dangerous business, Frodo, going out your door. You step onto the road, and if you don\'t keep your feet, there’s no knowing where you might be swept off to.'), - key: { - kty: 'RSA', - kid: 'bilbo.baggins@hobbiton.example', - use: 'sig', - n: 'n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw', - e: 'AQAB', - d: 'bWUC9B-EFRIo8kpGfh0ZuyGPvMNKvYWNtB_ikiH9k20eT-O1q_I78eiZkpXxXQ0UTEs2LsNRS-8uJbvQ-A1irkwMSMkK1J3XTGgdrhCku9gRldY7sNA_AKZGh-Q661_42rINLRCe8W-nZ34ui_qOfkLnK9QWDDqpaIsA-bMwWWSDFu2MUBYwkHTMEzLYGqOe04noqeq1hExBTHBOBdkMXiuFhUq1BU6l-DqEiWxqg82sXt2h-LMnT3046AOYJoRioz75tSUQfGCshWTBnP5uDjd18kKhyv07lhfSJdrPdM5Plyl21hsFf4L_mHCuoFau7gdsPfHPxxjVOcOpBrQzwQ', - p: '3Slxg_DwTXJcb6095RoXygQCAZ5RnAvZlno1yhHtnUex_fp7AZ_9nRaO7HX_-SFfGQeutao2TDjDAWU4Vupk8rw9JR0AzZ0N2fvuIAmr_WCsmGpeNqQnev1T7IyEsnh8UMt-n5CafhkikzhEsrmndH6LxOrvRJlsPp6Zv8bUq0k', - q: 'uKE2dh-cTf6ERF4k4e_jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR_cu0Dm1MZwWmtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7z4yMkuUwFWoBvyY898EXvRD-hdqRxHlSqAZ192zB3pVFJ0s7pFc', - dp: 'B8PVvXkvJrj2L-GYQ7v3y9r6Kw5g9SahXBwsWUzp19TVlgI-YV85q1NIb1rxQtD-IsXXR3-TanevuRPRt5OBOdiMGQp8pbt26gljYfKU_E9xn-RULHz0-ed9E9gXLKD4VGngpz-PfQ_q29pk5xWHoJp009Qf1HvChixRX59ehik', - dq: 'CLDmDGduhylc9o7r84rEUVn7pzQ6PF83Y-iBZx5NT-TpnOZKF1pErAMVeKzFEl41DlHHqqBLSM0W1sOFbwTxYWZDm6sI6og5iTbwQGIC3gnJKbi_7k_vJgGHwHxgPaX2PnvP-zyEkDERuf-ry4c_Z11Cq9AqC2yeL6kdKT1cYF8', - qi: '3PiqvXQN0zwMeE-sBvZgi289XP9XCQF3VWqPzMKnIgQp7_Tugo6-NZBKCQsMf3HaEGBjTVJs_jcK8-TRXvaKe-7ZMaQj8VfBdYkssbu0NKDDhjJ-GtiseaDVWt7dcH0cfwxgFUHpQh7FoCrjFJ6h6ZEpMF6xmujs4qMpPz8aaI4' - }, - alg: 'PS384' - }, - signing: { - protected: { - alg: 'PS384', - kid: 'bilbo.baggins@hobbiton.example' - } - }, - output: { - compact: 'eyJhbGciOiJQUzM4NCIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4.cu22eBqkYDKgIlTpzDXGvaFfz6WGoz7fUDcfT0kkOy42miAh2qyBzk1xEsnk2IpN6-tPid6VrklHkqsGqDqHCdP6O8TTB5dDDItllVo6_1OLPpcbUrhiUSMxbbXUvdvWXzg-UD8biiReQFlfz28zGWVsdiNAUf8ZnyPEgVFn442ZdNqiVJRmBqrYRXe8P_ijQ7p8Vdz0TTrxUeT3lm8d9shnr2lfJT8ImUjvAA2Xez2Mlp8cBE5awDzT0qI0n6uiP1aCN_2_jLAeQTlqRHtfa64QQSUmFAAjVKPbByi7xho0uTOcbH510a6GYmJUAfmWjwZ6oD4ifKo8DYM-X72Eaw', - json: { - payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', - signatures: [ - { - protected: 'eyJhbGciOiJQUzM4NCIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9', - signature: 'cu22eBqkYDKgIlTpzDXGvaFfz6WGoz7fUDcfT0kkOy42miAh2qyBzk1xEsnk2IpN6-tPid6VrklHkqsGqDqHCdP6O8TTB5dDDItllVo6_1OLPpcbUrhiUSMxbbXUvdvWXzg-UD8biiReQFlfz28zGWVsdiNAUf8ZnyPEgVFn442ZdNqiVJRmBqrYRXe8P_ijQ7p8Vdz0TTrxUeT3lm8d9shnr2lfJT8ImUjvAA2Xez2Mlp8cBE5awDzT0qI0n6uiP1aCN_2_jLAeQTlqRHtfa64QQSUmFAAjVKPbByi7xho0uTOcbH510a6GYmJUAfmWjwZ6oD4ifKo8DYM-X72Eaw' - } - ] - }, - json_flat: { - payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', - protected: 'eyJhbGciOiJQUzM4NCIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9', - signature: 'cu22eBqkYDKgIlTpzDXGvaFfz6WGoz7fUDcfT0kkOy42miAh2qyBzk1xEsnk2IpN6-tPid6VrklHkqsGqDqHCdP6O8TTB5dDDItllVo6_1OLPpcbUrhiUSMxbbXUvdvWXzg-UD8biiReQFlfz28zGWVsdiNAUf8ZnyPEgVFn442ZdNqiVJRmBqrYRXe8P_ijQ7p8Vdz0TTrxUeT3lm8d9shnr2lfJT8ImUjvAA2Xez2Mlp8cBE5awDzT0qI0n6uiP1aCN_2_jLAeQTlqRHtfa64QQSUmFAAjVKPbByi7xho0uTOcbH510a6GYmJUAfmWjwZ6oD4ifKo8DYM-X72Eaw' - } - } -} diff --git a/test/cookbook/recipes/4_3.ecdsa_signature.js b/test/cookbook/recipes/4_3.ecdsa_signature.js deleted file mode 100644 index fd562e1a72..0000000000 --- a/test/cookbook/recipes/4_3.ecdsa_signature.js +++ /dev/null @@ -1,39 +0,0 @@ -module.exports = { - title: 'ECDSA Signature', - input: { - payload: Buffer.from('It’s a dangerous business, Frodo, going out your door. You step onto the road, and if you don\'t keep your feet, there’s no knowing where you might be swept off to.'), - key: { - kty: 'EC', - kid: 'bilbo.baggins@hobbiton.example', - use: 'sig', - crv: 'P-521', - x: 'AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt', - y: 'AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVySsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1', - d: 'AAhRON2r9cqXX1hg-RoI6R1tX5p2rUAYdmpHZoC1XNM56KtscrX6zbKipQrCW9CGZH3T4ubpnoTKLDYJ_fF3_rJt' - }, - alg: 'ES512' - }, - signing: { - protected: { - alg: 'ES512', - kid: 'bilbo.baggins@hobbiton.example' - } - }, - output: { - compact: 'eyJhbGciOiJFUzUxMiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4.AE_R_YZCChjn4791jSQCrdPZCNYqHXCTZH0-JZGYNlaAjP2kqaluUIIUnC9qvbu9Plon7KRTzoNEuT4Va2cmL1eJAQy3mtPBu_u_sDDyYjnAMDxXPn7XrT0lw-kvAD890jl8e2puQens_IEKBpHABlsbEPX6sFY8OcGDqoRuBomu9xQ2', - json: { - payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', - signatures: [ - { - protected: 'eyJhbGciOiJFUzUxMiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9', - signature: 'AE_R_YZCChjn4791jSQCrdPZCNYqHXCTZH0-JZGYNlaAjP2kqaluUIIUnC9qvbu9Plon7KRTzoNEuT4Va2cmL1eJAQy3mtPBu_u_sDDyYjnAMDxXPn7XrT0lw-kvAD890jl8e2puQens_IEKBpHABlsbEPX6sFY8OcGDqoRuBomu9xQ2' - } - ] - }, - json_flat: { - payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', - protected: 'eyJhbGciOiJFUzUxMiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9', - signature: 'AE_R_YZCChjn4791jSQCrdPZCNYqHXCTZH0-JZGYNlaAjP2kqaluUIIUnC9qvbu9Plon7KRTzoNEuT4Va2cmL1eJAQy3mtPBu_u_sDDyYjnAMDxXPn7XrT0lw-kvAD890jl8e2puQens_IEKBpHABlsbEPX6sFY8OcGDqoRuBomu9xQ2' - } - } -} diff --git a/test/cookbook/recipes/4_4.hmac-sha2_integrity_protection.js b/test/cookbook/recipes/4_4.hmac-sha2_integrity_protection.js deleted file mode 100644 index 460742d8ea..0000000000 --- a/test/cookbook/recipes/4_4.hmac-sha2_integrity_protection.js +++ /dev/null @@ -1,37 +0,0 @@ -module.exports = { - title: 'HMAC-SHA2 Integrity Protection', - input: { - payload: Buffer.from('It’s a dangerous business, Frodo, going out your door. You step onto the road, and if you don\'t keep your feet, there’s no knowing where you might be swept off to.'), - key: { - kty: 'oct', - kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037', - use: 'sig', - alg: 'HS256', - k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg' - }, - alg: 'HS256' - }, - signing: { - protected: { - alg: 'HS256', - kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037' - } - }, - output: { - compact: 'eyJhbGciOiJIUzI1NiIsImtpZCI6IjAxOGMwYWU1LTRkOWItNDcxYi1iZmQ2LWVlZjMxNGJjNzAzNyJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4.s0h6KThzkfBBBkLspW1h84VsJZFTsPPqMDA7g1Md7p0', - json: { - payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', - signatures: [ - { - protected: 'eyJhbGciOiJIUzI1NiIsImtpZCI6IjAxOGMwYWU1LTRkOWItNDcxYi1iZmQ2LWVlZjMxNGJjNzAzNyJ9', - signature: 's0h6KThzkfBBBkLspW1h84VsJZFTsPPqMDA7g1Md7p0' - } - ] - }, - json_flat: { - payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', - protected: 'eyJhbGciOiJIUzI1NiIsImtpZCI6IjAxOGMwYWU1LTRkOWItNDcxYi1iZmQ2LWVlZjMxNGJjNzAzNyJ9', - signature: 's0h6KThzkfBBBkLspW1h84VsJZFTsPPqMDA7g1Md7p0' - } - } -} diff --git a/test/cookbook/recipes/4_6.protecting_specific_header_fields.js b/test/cookbook/recipes/4_6.protecting_specific_header_fields.js deleted file mode 100644 index 6b5b999e80..0000000000 --- a/test/cookbook/recipes/4_6.protecting_specific_header_fields.js +++ /dev/null @@ -1,44 +0,0 @@ -module.exports = { - title: 'Protecting Specific Header Fields', - input: { - payload: Buffer.from('It’s a dangerous business, Frodo, going out your door. You step onto the road, and if you don\'t keep your feet, there’s no knowing where you might be swept off to.'), - key: { - kty: 'oct', - kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037', - use: 'sig', - alg: 'HS256', - k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg' - }, - alg: 'HS256' - }, - signing: { - protected: { - alg: 'HS256' - }, - unprotected: { - kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037' - } - }, - output: { - json: { - payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', - signatures: [ - { - protected: 'eyJhbGciOiJIUzI1NiJ9', - header: { - kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037' - }, - signature: 'bWUSVaxorn7bEF1djytBd0kHv70Ly5pvbomzMWSOr20' - } - ] - }, - json_flat: { - payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', - protected: 'eyJhbGciOiJIUzI1NiJ9', - header: { - kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037' - }, - signature: 'bWUSVaxorn7bEF1djytBd0kHv70Ly5pvbomzMWSOr20' - } - } -} diff --git a/test/cookbook/recipes/4_7.protecting_content_only.js b/test/cookbook/recipes/4_7.protecting_content_only.js deleted file mode 100644 index 648a24b35b..0000000000 --- a/test/cookbook/recipes/4_7.protecting_content_only.js +++ /dev/null @@ -1,45 +0,0 @@ -module.exports = { - title: 'Protecting Content Only', - reproducible: true, - input: { - payload: Buffer.from('It’s a dangerous business, Frodo, going out your door. You step onto the road, and if you don\'t keep your feet, there’s no knowing where you might be swept off to.'), - key: { - kty: 'oct', - kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037', - use: 'sig', - alg: 'HS256', - k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg' - }, - alg: 'HS256' - }, - signing: { - unprotected: { - alg: 'HS256', - kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037' - }, - 'sig-input': '.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', - sig: 'xuLifqLGiblpv9zBpuZczWhNj1gARaLV3UxvxhJxZuk' - }, - output: { - json: { - payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', - signatures: [ - { - header: { - alg: 'HS256', - kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037' - }, - signature: 'xuLifqLGiblpv9zBpuZczWhNj1gARaLV3UxvxhJxZuk' - } - ] - }, - json_flat: { - payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', - header: { - alg: 'HS256', - kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037' - }, - signature: 'xuLifqLGiblpv9zBpuZczWhNj1gARaLV3UxvxhJxZuk' - } - } -} diff --git a/test/cookbook/recipes/4_8.multiple_signatures.js b/test/cookbook/recipes/4_8.multiple_signatures.js deleted file mode 100644 index 47865ad835..0000000000 --- a/test/cookbook/recipes/4_8.multiple_signatures.js +++ /dev/null @@ -1,89 +0,0 @@ -module.exports = { - title: 'Multiple Signatures', - input: { - payload: Buffer.from('It’s a dangerous business, Frodo, going out your door. You step onto the road, and if you don\'t keep your feet, there’s no knowing where you might be swept off to.'), - key: [ - { - kty: 'RSA', - kid: 'bilbo.baggins@hobbiton.example', - use: 'sig', - n: 'n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw', - e: 'AQAB', - d: 'bWUC9B-EFRIo8kpGfh0ZuyGPvMNKvYWNtB_ikiH9k20eT-O1q_I78eiZkpXxXQ0UTEs2LsNRS-8uJbvQ-A1irkwMSMkK1J3XTGgdrhCku9gRldY7sNA_AKZGh-Q661_42rINLRCe8W-nZ34ui_qOfkLnK9QWDDqpaIsA-bMwWWSDFu2MUBYwkHTMEzLYGqOe04noqeq1hExBTHBOBdkMXiuFhUq1BU6l-DqEiWxqg82sXt2h-LMnT3046AOYJoRioz75tSUQfGCshWTBnP5uDjd18kKhyv07lhfSJdrPdM5Plyl21hsFf4L_mHCuoFau7gdsPfHPxxjVOcOpBrQzwQ', - p: '3Slxg_DwTXJcb6095RoXygQCAZ5RnAvZlno1yhHtnUex_fp7AZ_9nRaO7HX_-SFfGQeutao2TDjDAWU4Vupk8rw9JR0AzZ0N2fvuIAmr_WCsmGpeNqQnev1T7IyEsnh8UMt-n5CafhkikzhEsrmndH6LxOrvRJlsPp6Zv8bUq0k', - q: 'uKE2dh-cTf6ERF4k4e_jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR_cu0Dm1MZwWmtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7z4yMkuUwFWoBvyY898EXvRD-hdqRxHlSqAZ192zB3pVFJ0s7pFc', - dp: 'B8PVvXkvJrj2L-GYQ7v3y9r6Kw5g9SahXBwsWUzp19TVlgI-YV85q1NIb1rxQtD-IsXXR3-TanevuRPRt5OBOdiMGQp8pbt26gljYfKU_E9xn-RULHz0-ed9E9gXLKD4VGngpz-PfQ_q29pk5xWHoJp009Qf1HvChixRX59ehik', - dq: 'CLDmDGduhylc9o7r84rEUVn7pzQ6PF83Y-iBZx5NT-TpnOZKF1pErAMVeKzFEl41DlHHqqBLSM0W1sOFbwTxYWZDm6sI6og5iTbwQGIC3gnJKbi_7k_vJgGHwHxgPaX2PnvP-zyEkDERuf-ry4c_Z11Cq9AqC2yeL6kdKT1cYF8', - qi: '3PiqvXQN0zwMeE-sBvZgi289XP9XCQF3VWqPzMKnIgQp7_Tugo6-NZBKCQsMf3HaEGBjTVJs_jcK8-TRXvaKe-7ZMaQj8VfBdYkssbu0NKDDhjJ-GtiseaDVWt7dcH0cfwxgFUHpQh7FoCrjFJ6h6ZEpMF6xmujs4qMpPz8aaI4' - }, - { - kty: 'EC', - kid: 'bilbo.baggins@hobbiton.example', - use: 'sig', - crv: 'P-521', - x: 'AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt', - y: 'AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVySsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1', - d: 'AAhRON2r9cqXX1hg-RoI6R1tX5p2rUAYdmpHZoC1XNM56KtscrX6zbKipQrCW9CGZH3T4ubpnoTKLDYJ_fF3_rJt' - }, - { - kty: 'oct', - kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037', - use: 'sig', - alg: 'HS256', - k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg' - } - ], - alg: [ - 'RS256', - 'ES512', - 'HS256' - ] - }, - signing: [ - { - protected: { - alg: 'RS256' - }, - unprotected: { - kid: 'bilbo.baggins@hobbiton.example' - } - }, - { - unprotected: { - alg: 'ES512', - kid: 'bilbo.baggins@hobbiton.example' - } - }, - { - protected: { - alg: 'HS256', - kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037' - } - } - ], - output: { - json: { - payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', - signatures: [ - { - protected: 'eyJhbGciOiJSUzI1NiJ9', - header: { - kid: 'bilbo.baggins@hobbiton.example' - }, - signature: 'MIsjqtVlOpa71KE-Mss8_Nq2YH4FGhiocsqrgi5NvyG53uoimic1tcMdSg-qptrzZc7CG6Svw2Y13TDIqHzTUrL_lR2ZFcryNFiHkSw129EghGpwkpxaTn_THJTCglNbADko1MZBCdwzJxwqZc-1RlpO2HibUYyXSwO97BSe0_evZKdjvvKSgsIqjytKSeAMbhMBdMma622_BG5t4sdbuCHtFjp9iJmkio47AIwqkZV1aIZsv33uPUqBBCXbYoQJwt7mxPftHmNlGoOSMxR_3thmXTCm4US-xiNOyhbm8afKK64jU6_TPtQHiJeQJxz9G3Tx-083B745_AfYOnlC9w' - }, - { - header: { - alg: 'ES512', - kid: 'bilbo.baggins@hobbiton.example' - }, - signature: 'ARcVLnaJJaUWG8fG-8t5BREVAuTY8n8YHjwDO1muhcdCoFZFFjfISu0Cdkn9Ybdlmi54ho0x924DUz8sK7ZXkhc7AFM8ObLfTvNCrqcI3Jkl2U5IX3utNhODH6v7xgy1Qahsn0fyb4zSAkje8bAWz4vIfj5pCMYxxm4fgV3q7ZYhm5eD' - }, - { - protected: 'eyJhbGciOiJIUzI1NiIsImtpZCI6IjAxOGMwYWU1LTRkOWItNDcxYi1iZmQ2LWVlZjMxNGJjNzAzNyJ9', - signature: 's0h6KThzkfBBBkLspW1h84VsJZFTsPPqMDA7g1Md7p0' - } - ] - } - } -} diff --git a/test/cookbook/recipes/5_1.key_encryption_using_rsa_v15_and_aes-hmac-sha2.js b/test/cookbook/recipes/5_1.key_encryption_using_rsa_v15_and_aes-hmac-sha2.js deleted file mode 100644 index 6c7416bc18..0000000000 --- a/test/cookbook/recipes/5_1.key_encryption_using_rsa_v15_and_aes-hmac-sha2.js +++ /dev/null @@ -1,49 +0,0 @@ -module.exports = { - title: 'Key Encryption using RSA v1.5 and AES-HMAC-SHA2', - input: { - plaintext: Buffer.from('You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.'), - key: { - kty: 'RSA', - kid: 'frodo.baggins@hobbiton.example', - use: 'enc', - n: 'maxhbsmBtdQ3CNrKvprUE6n9lYcregDMLYNeTAWcLj8NnPU9XIYegTHVHQjxKDSHP2l-F5jS7sppG1wgdAqZyhnWvXhYNvcM7RfgKxqNx_xAHx6f3yy7s-M9PSNCwPC2lh6UAkR4I00EhV9lrypM9Pi4lBUop9t5fS9W5UNwaAllhrd-osQGPjIeI1deHTwx-ZTHu3C60Pu_LJIl6hKn9wbwaUmA4cR5Bd2pgbaY7ASgsjCUbtYJaNIHSoHXprUdJZKUMAzV0WOKPfA6OPI4oypBadjvMZ4ZAj3BnXaSYsEZhaueTXvZB4eZOAjIyh2e_VOIKVMsnDrJYAVotGlvMQ', - e: 'AQAB', - d: 'Kn9tgoHfiTVi8uPu5b9TnwyHwG5dK6RE0uFdlpCGnJN7ZEi963R7wybQ1PLAHmpIbNTztfrheoAniRV1NCIqXaW_qS461xiDTp4ntEPnqcKsyO5jMAji7-CL8vhpYYowNFvIesgMoVaPRYMYT9TW63hNM0aWs7USZ_hLg6Oe1mY0vHTI3FucjSM86Nff4oIENt43r2fspgEPGRrdE6fpLc9Oaq-qeP1GFULimrRdndm-P8q8kvN3KHlNAtEgrQAgTTgz80S-3VD0FgWfgnb1PNmiuPUxO8OpI9KDIfu_acc6fg14nsNaJqXe6RESvhGPH2afjHqSy_Fd2vpzj85bQQ', - p: '2DwQmZ43FoTnQ8IkUj3BmKRf5Eh2mizZA5xEJ2MinUE3sdTYKSLtaEoekX9vbBZuWxHdVhM6UnKCJ_2iNk8Z0ayLYHL0_G21aXf9-unynEpUsH7HHTklLpYAzOOx1ZgVljoxAdWNn3hiEFrjZLZGS7lOH-a3QQlDDQoJOJ2VFmU', - q: 'te8LY4-W7IyaqH1ExujjMqkTAlTeRbv0VLQnfLY2xINnrWdwiQ93_VF099aP1ESeLja2nw-6iKIe-qT7mtCPozKfVtUYfz5HrJ_XY2kfexJINb9lhZHMv5p1skZpeIS-GPHCC6gRlKo1q-idn_qxyusfWv7WAxlSVfQfk8d6Et0', - dp: 'UfYKcL_or492vVc0PzwLSplbg4L3-Z5wL48mwiswbpzOyIgd2xHTHQmjJpFAIZ8q-zf9RmgJXkDrFs9rkdxPtAsL1WYdeCT5c125Fkdg317JVRDo1inX7x2Kdh8ERCreW8_4zXItuTl_KiXZNU5lvMQjWbIw2eTx1lpsflo0rYU', - dq: 'iEgcO-QfpepdH8FWd7mUFyrXdnOkXJBCogChY6YKuIHGc_p8Le9MbpFKESzEaLlN1Ehf3B6oGBl5Iz_ayUlZj2IoQZ82znoUrpa9fVYNot87ACfzIG7q9Mv7RiPAderZi03tkVXAdaBau_9vs5rS-7HMtxkVrxSUvJY14TkXlHE', - qi: 'kC-lzZOqoFaZCr5l0tOVtREKoVqaAYhQiqIRGL-MzS4sCmRkxm5vZlXYx6RtE1n_AagjqajlkjieGlxTTThHD8Iga6foGBMaAr5uR1hGQpSc7Gl7CF1DZkBJMTQN6EshYzZfxW08mIO8M6Rzuh0beL6fG9mkDcIyPrBXx2bQ_mM' - }, - alg: 'RSA1_5', - enc: 'A128CBC-HS256' - }, - encrypting_content: { - protected: { - alg: 'RSA1_5', - kid: 'frodo.baggins@hobbiton.example', - enc: 'A128CBC-HS256' - } - }, - output: { - compact: 'eyJhbGciOiJSU0ExXzUiLCJraWQiOiJmcm9kby5iYWdnaW5zQGhvYmJpdG9uLmV4YW1wbGUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.laLxI0j-nLH-_BgLOXMozKxmy9gffy2gTdvqzfTihJBuuzxg0V7yk1WClnQePFvG2K-pvSlWc9BRIazDrn50RcRai__3TDON395H3c62tIouJJ4XaRvYHFjZTZ2GXfz8YAImcc91Tfk0WXC2F5Xbb71ClQ1DDH151tlpH77f2ff7xiSxh9oSewYrcGTSLUeeCt36r1Kt3OSj7EyBQXoZlN7IxbyhMAfgIe7Mv1rOTOI5I8NQqeXXW8VlzNmoxaGMny3YnGir5Wf6Qt2nBq4qDaPdnaAuuGUGEecelIO1wx1BpyIfgvfjOhMBs9M8XL223Fg47xlGsMXdfuY-4jaqVw.bbd5sTkYwhAIqfHsx8DayA.0fys_TY_na7f8dwSfXLiYdHaA2DxUjD67ieF7fcVbIR62JhJvGZ4_FNVSiGc_raa0HnLQ6s1P2sv3Xzl1p1l_o5wR_RsSzrS8Z-wnI3Jvo0mkpEEnlDmZvDu_k8OWzJv7eZVEqiWKdyVzFhPpiyQU28GLOpRc2VbVbK4dQKPdNTjPPEmRqcaGeTWZVyeSUvf5k59yJZxRuSvWFf6KrNtmRdZ8R4mDOjHSrM_s8uwIFcqt4r5GX8TKaI0zT5CbL5Qlw3sRc7u_hg0yKVOiRytEAEs3vZkcfLkP6nbXdC_PkMdNS-ohP78T2O6_7uInMGhFeX4ctHG7VelHGiT93JfWDEQi5_V9UN1rhXNrYu-0fVMkZAKX3VWi7lzA6BP430m.kvKuFBXHe5mQr4lqgobAUg', - json: { - recipients: [ - { - encrypted_key: 'laLxI0j-nLH-_BgLOXMozKxmy9gffy2gTdvqzfTihJBuuzxg0V7yk1WClnQePFvG2K-pvSlWc9BRIazDrn50RcRai__3TDON395H3c62tIouJJ4XaRvYHFjZTZ2GXfz8YAImcc91Tfk0WXC2F5Xbb71ClQ1DDH151tlpH77f2ff7xiSxh9oSewYrcGTSLUeeCt36r1Kt3OSj7EyBQXoZlN7IxbyhMAfgIe7Mv1rOTOI5I8NQqeXXW8VlzNmoxaGMny3YnGir5Wf6Qt2nBq4qDaPdnaAuuGUGEecelIO1wx1BpyIfgvfjOhMBs9M8XL223Fg47xlGsMXdfuY-4jaqVw' - } - ], - protected: 'eyJhbGciOiJSU0ExXzUiLCJraWQiOiJmcm9kby5iYWdnaW5zQGhvYmJpdG9uLmV4YW1wbGUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0', - iv: 'bbd5sTkYwhAIqfHsx8DayA', - ciphertext: '0fys_TY_na7f8dwSfXLiYdHaA2DxUjD67ieF7fcVbIR62JhJvGZ4_FNVSiGc_raa0HnLQ6s1P2sv3Xzl1p1l_o5wR_RsSzrS8Z-wnI3Jvo0mkpEEnlDmZvDu_k8OWzJv7eZVEqiWKdyVzFhPpiyQU28GLOpRc2VbVbK4dQKPdNTjPPEmRqcaGeTWZVyeSUvf5k59yJZxRuSvWFf6KrNtmRdZ8R4mDOjHSrM_s8uwIFcqt4r5GX8TKaI0zT5CbL5Qlw3sRc7u_hg0yKVOiRytEAEs3vZkcfLkP6nbXdC_PkMdNS-ohP78T2O6_7uInMGhFeX4ctHG7VelHGiT93JfWDEQi5_V9UN1rhXNrYu-0fVMkZAKX3VWi7lzA6BP430m', - tag: 'kvKuFBXHe5mQr4lqgobAUg' - }, - json_flat: { - protected: 'eyJhbGciOiJSU0ExXzUiLCJraWQiOiJmcm9kby5iYWdnaW5zQGhvYmJpdG9uLmV4YW1wbGUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0', - encrypted_key: 'laLxI0j-nLH-_BgLOXMozKxmy9gffy2gTdvqzfTihJBuuzxg0V7yk1WClnQePFvG2K-pvSlWc9BRIazDrn50RcRai__3TDON395H3c62tIouJJ4XaRvYHFjZTZ2GXfz8YAImcc91Tfk0WXC2F5Xbb71ClQ1DDH151tlpH77f2ff7xiSxh9oSewYrcGTSLUeeCt36r1Kt3OSj7EyBQXoZlN7IxbyhMAfgIe7Mv1rOTOI5I8NQqeXXW8VlzNmoxaGMny3YnGir5Wf6Qt2nBq4qDaPdnaAuuGUGEecelIO1wx1BpyIfgvfjOhMBs9M8XL223Fg47xlGsMXdfuY-4jaqVw', - iv: 'bbd5sTkYwhAIqfHsx8DayA', - ciphertext: '0fys_TY_na7f8dwSfXLiYdHaA2DxUjD67ieF7fcVbIR62JhJvGZ4_FNVSiGc_raa0HnLQ6s1P2sv3Xzl1p1l_o5wR_RsSzrS8Z-wnI3Jvo0mkpEEnlDmZvDu_k8OWzJv7eZVEqiWKdyVzFhPpiyQU28GLOpRc2VbVbK4dQKPdNTjPPEmRqcaGeTWZVyeSUvf5k59yJZxRuSvWFf6KrNtmRdZ8R4mDOjHSrM_s8uwIFcqt4r5GX8TKaI0zT5CbL5Qlw3sRc7u_hg0yKVOiRytEAEs3vZkcfLkP6nbXdC_PkMdNS-ohP78T2O6_7uInMGhFeX4ctHG7VelHGiT93JfWDEQi5_V9UN1rhXNrYu-0fVMkZAKX3VWi7lzA6BP430m', - tag: 'kvKuFBXHe5mQr4lqgobAUg' - } - } -} diff --git a/test/cookbook/recipes/5_10.including_additional_authentication_data.js b/test/cookbook/recipes/5_10.including_additional_authentication_data.js deleted file mode 100644 index 4c4a5cc516..0000000000 --- a/test/cookbook/recipes/5_10.including_additional_authentication_data.js +++ /dev/null @@ -1,46 +0,0 @@ -module.exports = { - title: 'Including Additional Authenticated Data', - reproducible: true, - input: { - plaintext: Buffer.from('You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.'), - key: { - kty: 'oct', - kid: '81b20965-8332-43d9-a468-82160ad91ac8', - use: 'enc', - alg: 'A128KW', - k: 'GZy6sIZ6wl9NJOKB-jnmVQ' - }, - alg: 'A128KW', - enc: 'A128GCM', - aad: '["vcard",[["version",{},"text","4.0"],["fn",{},"text","Meriadoc Brandybuck"],["n",{},"text",["Brandybuck","Meriadoc","Mr.",""]],["bday",{},"text","TA 2982"],["gender",{},"text","M"]]]' - }, - encrypting_content: { - protected: { - alg: 'A128KW', - kid: '81b20965-8332-43d9-a468-82160ad91ac8', - enc: 'A128GCM' - } - }, - output: { - json: { - recipients: [ - { - encrypted_key: '4YiiQ_ZzH76TaIkJmYfRFgOV9MIpnx4X' - } - ], - protected: 'eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIn0', - iv: 'veCx9ece2orS7c_N', - aad: 'WyJ2Y2FyZCIsW1sidmVyc2lvbiIse30sInRleHQiLCI0LjAiXSxbImZuIix7fSwidGV4dCIsIk1lcmlhZG9jIEJyYW5keWJ1Y2siXSxbIm4iLHt9LCJ0ZXh0IixbIkJyYW5keWJ1Y2siLCJNZXJpYWRvYyIsIk1yLiIsIiJdXSxbImJkYXkiLHt9LCJ0ZXh0IiwiVEEgMjk4MiJdLFsiZ2VuZGVyIix7fSwidGV4dCIsIk0iXV1d', - ciphertext: 'Z_3cbr0k3bVM6N3oSNmHz7Lyf3iPppGf3Pj17wNZqteJ0Ui8p74SchQP8xygM1oFRWCNzeIa6s6BcEtp8qEFiqTUEyiNkOWDNoF14T_4NFqF-p2Mx8zkbKxI7oPK8KNarFbyxIDvICNqBLba-v3uzXBdB89fzOI-Lv4PjOFAQGHrgv1rjXAmKbgkft9cB4WeyZw8MldbBhc-V_KWZslrsLNygon_JJWd_ek6LQn5NRehvApqf9ZrxB4aq3FXBxOxCys35PhCdaggy2kfUfl2OkwKnWUbgXVD1C6HxLIlqHhCwXDG59weHrRDQeHyMRoBljoV3X_bUTJDnKBFOod7nLz-cj48JMx3SnCZTpbQAkFV', - tag: 'vOaH_Rajnpy_3hOtqvZHRA' - }, - json_flat: { - protected: 'eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIn0', - encrypted_key: '4YiiQ_ZzH76TaIkJmYfRFgOV9MIpnx4X', - aad: 'WyJ2Y2FyZCIsW1sidmVyc2lvbiIse30sInRleHQiLCI0LjAiXSxbImZuIix7fSwidGV4dCIsIk1lcmlhZG9jIEJyYW5keWJ1Y2siXSxbIm4iLHt9LCJ0ZXh0IixbIkJyYW5keWJ1Y2siLCJNZXJpYWRvYyIsIk1yLiIsIiJdXSxbImJkYXkiLHt9LCJ0ZXh0IiwiVEEgMjk4MiJdLFsiZ2VuZGVyIix7fSwidGV4dCIsIk0iXV1d', - iv: 'veCx9ece2orS7c_N', - ciphertext: 'Z_3cbr0k3bVM6N3oSNmHz7Lyf3iPppGf3Pj17wNZqteJ0Ui8p74SchQP8xygM1oFRWCNzeIa6s6BcEtp8qEFiqTUEyiNkOWDNoF14T_4NFqF-p2Mx8zkbKxI7oPK8KNarFbyxIDvICNqBLba-v3uzXBdB89fzOI-Lv4PjOFAQGHrgv1rjXAmKbgkft9cB4WeyZw8MldbBhc-V_KWZslrsLNygon_JJWd_ek6LQn5NRehvApqf9ZrxB4aq3FXBxOxCys35PhCdaggy2kfUfl2OkwKnWUbgXVD1C6HxLIlqHhCwXDG59weHrRDQeHyMRoBljoV3X_bUTJDnKBFOod7nLz-cj48JMx3SnCZTpbQAkFV', - tag: 'vOaH_Rajnpy_3hOtqvZHRA' - } - } -} diff --git a/test/cookbook/recipes/5_11.protecting_specific_header_fields.js b/test/cookbook/recipes/5_11.protecting_specific_header_fields.js deleted file mode 100644 index ce4e375c19..0000000000 --- a/test/cookbook/recipes/5_11.protecting_specific_header_fields.js +++ /dev/null @@ -1,53 +0,0 @@ -module.exports = { - title: 'Protecting Specific Header Fields', - reproducible: true, - input: { - plaintext: Buffer.from('You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.'), - key: { - kty: 'oct', - kid: '81b20965-8332-43d9-a468-82160ad91ac8', - use: 'enc', - alg: 'A128KW', - k: 'GZy6sIZ6wl9NJOKB-jnmVQ' - }, - alg: 'A128KW', - enc: 'A128GCM' - }, - encrypting_content: { - protected: { - enc: 'A128GCM' - }, - unprotected: { - alg: 'A128KW', - kid: '81b20965-8332-43d9-a468-82160ad91ac8' - } - }, - output: { - json: { - recipients: [ - { - encrypted_key: 'jJIcM9J-hbx3wnqhf5FlkEYos0sHsF0H' - } - ], - unprotected: { - alg: 'A128KW', - kid: '81b20965-8332-43d9-a468-82160ad91ac8' - }, - protected: 'eyJlbmMiOiJBMTI4R0NNIn0', - iv: 'WgEJsDS9bkoXQ3nR', - ciphertext: 'lIbCyRmRJxnB2yLQOTqjCDKV3H30ossOw3uD9DPsqLL2DM3swKkjOwQyZtWsFLYMj5YeLht_StAn21tHmQJuuNt64T8D4t6C7kC9OCCJ1IHAolUv4MyOt80MoPb8fZYbNKqplzYJgIL58g8N2v46OgyG637d6uuKPwhAnTGm_zWhqc_srOvgiLkzyFXPq1hBAURbc3-8BqeRb48iR1-_5g5UjWVD3lgiLCN_P7AW8mIiFvUNXBPJK3nOWL4teUPS8yHLbWeL83olU4UAgL48x-8dDkH23JykibVSQju-f7e-1xreHWXzWLHs1NqBbre0dEwK3HX_xM0LjUz77Krppgegoutpf5qaKg3l-_xMINmf', - tag: 'fNYLqpUe84KD45lvDiaBAQ' - }, - json_flat: { - protected: 'eyJlbmMiOiJBMTI4R0NNIn0', - unprotected: { - alg: 'A128KW', - kid: '81b20965-8332-43d9-a468-82160ad91ac8' - }, - encrypted_key: 'jJIcM9J-hbx3wnqhf5FlkEYos0sHsF0H', - iv: 'WgEJsDS9bkoXQ3nR', - ciphertext: 'lIbCyRmRJxnB2yLQOTqjCDKV3H30ossOw3uD9DPsqLL2DM3swKkjOwQyZtWsFLYMj5YeLht_StAn21tHmQJuuNt64T8D4t6C7kC9OCCJ1IHAolUv4MyOt80MoPb8fZYbNKqplzYJgIL58g8N2v46OgyG637d6uuKPwhAnTGm_zWhqc_srOvgiLkzyFXPq1hBAURbc3-8BqeRb48iR1-_5g5UjWVD3lgiLCN_P7AW8mIiFvUNXBPJK3nOWL4teUPS8yHLbWeL83olU4UAgL48x-8dDkH23JykibVSQju-f7e-1xreHWXzWLHs1NqBbre0dEwK3HX_xM0LjUz77Krppgegoutpf5qaKg3l-_xMINmf', - tag: 'fNYLqpUe84KD45lvDiaBAQ' - } - } -} diff --git a/test/cookbook/recipes/5_12.protecting_content_only.js b/test/cookbook/recipes/5_12.protecting_content_only.js deleted file mode 100644 index 805943faf8..0000000000 --- a/test/cookbook/recipes/5_12.protecting_content_only.js +++ /dev/null @@ -1,60 +0,0 @@ -module.exports = { - title: 'Protecting Content Only', - reproducible: true, - input: { - plaintext: Buffer.from('You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.'), - key: { - kty: 'oct', - kid: '81b20965-8332-43d9-a468-82160ad91ac8', - use: 'enc', - alg: 'A128KW', - k: 'GZy6sIZ6wl9NJOKB-jnmVQ' - }, - alg: 'A128KW', - enc: 'A128GCM' - }, - generated: { - cek: 'KBooAFl30QPV3vkcZlXnzQ', - iv: 'YihBoVOGsR1l7jCD' - }, - encrypting_key: { - encrypted_key: '244YHfO_W7RMpQW81UjQrZcq5LSyqiPv' - }, - encrypting_content: { - unprotected: { - alg: 'A128KW', - kid: '81b20965-8332-43d9-a468-82160ad91ac8', - enc: 'A128GCM' - }, - ciphertext: 'qtPIMMaOBRgASL10dNQhOa7Gqrk7Eal1vwht7R4TT1uq-arsVCPaIeFwQfzrSS6oEUWbBtxEasE0vC6r7sphyVziMCVJEuRJyoAHFSP3eqQPb4Ic1SDSqyXjw_L3svybhHYUGyQuTmUQEDjgjJfBOifwHIsDsRPeBz1NomqeifVPq5GTCWFo5k_MNIQURR2Wj0AHC2k7JZfu2iWjUHLF8ExFZLZ4nlmsvJu_mvifMYiikfNfsZAudISOa6O73yPZtL04k_1FI7WDfrb2w7OqKLWDXzlpcxohPVOLQwpA3mFNRKdY-bQz4Z4KX9lfz1cne31N4-8BKmojpw-OdQjKdLOGkC445Fb_K1tlDQXw2sBF', - tag: 'e2m0Vm7JvjK2VpCKXS-kyg' - }, - output: { - json: { - recipients: [ - { - encrypted_key: '244YHfO_W7RMpQW81UjQrZcq5LSyqiPv' - } - ], - unprotected: { - alg: 'A128KW', - kid: '81b20965-8332-43d9-a468-82160ad91ac8', - enc: 'A128GCM' - }, - iv: 'YihBoVOGsR1l7jCD', - ciphertext: 'qtPIMMaOBRgASL10dNQhOa7Gqrk7Eal1vwht7R4TT1uq-arsVCPaIeFwQfzrSS6oEUWbBtxEasE0vC6r7sphyVziMCVJEuRJyoAHFSP3eqQPb4Ic1SDSqyXjw_L3svybhHYUGyQuTmUQEDjgjJfBOifwHIsDsRPeBz1NomqeifVPq5GTCWFo5k_MNIQURR2Wj0AHC2k7JZfu2iWjUHLF8ExFZLZ4nlmsvJu_mvifMYiikfNfsZAudISOa6O73yPZtL04k_1FI7WDfrb2w7OqKLWDXzlpcxohPVOLQwpA3mFNRKdY-bQz4Z4KX9lfz1cne31N4-8BKmojpw-OdQjKdLOGkC445Fb_K1tlDQXw2sBF', - tag: 'e2m0Vm7JvjK2VpCKXS-kyg' - }, - json_flat: { - unprotected: { - alg: 'A128KW', - kid: '81b20965-8332-43d9-a468-82160ad91ac8', - enc: 'A128GCM' - }, - encrypted_key: '244YHfO_W7RMpQW81UjQrZcq5LSyqiPv', - iv: 'YihBoVOGsR1l7jCD', - ciphertext: 'qtPIMMaOBRgASL10dNQhOa7Gqrk7Eal1vwht7R4TT1uq-arsVCPaIeFwQfzrSS6oEUWbBtxEasE0vC6r7sphyVziMCVJEuRJyoAHFSP3eqQPb4Ic1SDSqyXjw_L3svybhHYUGyQuTmUQEDjgjJfBOifwHIsDsRPeBz1NomqeifVPq5GTCWFo5k_MNIQURR2Wj0AHC2k7JZfu2iWjUHLF8ExFZLZ4nlmsvJu_mvifMYiikfNfsZAudISOa6O73yPZtL04k_1FI7WDfrb2w7OqKLWDXzlpcxohPVOLQwpA3mFNRKdY-bQz4Z4KX9lfz1cne31N4-8BKmojpw-OdQjKdLOGkC445Fb_K1tlDQXw2sBF', - tag: 'e2m0Vm7JvjK2VpCKXS-kyg' - } - } -} diff --git a/test/cookbook/recipes/5_13.encrypting_to_multiple_recipients.js b/test/cookbook/recipes/5_13.encrypting_to_multiple_recipients.js deleted file mode 100644 index e7f0a41cdd..0000000000 --- a/test/cookbook/recipes/5_13.encrypting_to_multiple_recipients.js +++ /dev/null @@ -1,113 +0,0 @@ -module.exports = { - title: 'Encrypting to Multiple Recipients', - input: { - plaintext: Buffer.from('You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.'), - key: [ - { - kty: 'RSA', - kid: 'frodo.baggins@hobbiton.example', - use: 'enc', - n: 'maxhbsmBtdQ3CNrKvprUE6n9lYcregDMLYNeTAWcLj8NnPU9XIYegTHVHQjxKDSHP2l-F5jS7sppG1wgdAqZyhnWvXhYNvcM7RfgKxqNx_xAHx6f3yy7s-M9PSNCwPC2lh6UAkR4I00EhV9lrypM9Pi4lBUop9t5fS9W5UNwaAllhrd-osQGPjIeI1deHTwx-ZTHu3C60Pu_LJIl6hKn9wbwaUmA4cR5Bd2pgbaY7ASgsjCUbtYJaNIHSoHXprUdJZKUMAzV0WOKPfA6OPI4oypBadjvMZ4ZAj3BnXaSYsEZhaueTXvZB4eZOAjIyh2e_VOIKVMsnDrJYAVotGlvMQ', - e: 'AQAB', - d: 'Kn9tgoHfiTVi8uPu5b9TnwyHwG5dK6RE0uFdlpCGnJN7ZEi963R7wybQ1PLAHmpIbNTztfrheoAniRV1NCIqXaW_qS461xiDTp4ntEPnqcKsyO5jMAji7-CL8vhpYYowNFvIesgMoVaPRYMYT9TW63hNM0aWs7USZ_hLg6Oe1mY0vHTI3FucjSM86Nff4oIENt43r2fspgEPGRrdE6fpLc9Oaq-qeP1GFULimrRdndm-P8q8kvN3KHlNAtEgrQAgTTgz80S-3VD0FgWfgnb1PNmiuPUxO8OpI9KDIfu_acc6fg14nsNaJqXe6RESvhGPH2afjHqSy_Fd2vpzj85bQQ', - p: '2DwQmZ43FoTnQ8IkUj3BmKRf5Eh2mizZA5xEJ2MinUE3sdTYKSLtaEoekX9vbBZuWxHdVhM6UnKCJ_2iNk8Z0ayLYHL0_G21aXf9-unynEpUsH7HHTklLpYAzOOx1ZgVljoxAdWNn3hiEFrjZLZGS7lOH-a3QQlDDQoJOJ2VFmU', - q: 'te8LY4-W7IyaqH1ExujjMqkTAlTeRbv0VLQnfLY2xINnrWdwiQ93_VF099aP1ESeLja2nw-6iKIe-qT7mtCPozKfVtUYfz5HrJ_XY2kfexJINb9lhZHMv5p1skZpeIS-GPHCC6gRlKo1q-idn_qxyusfWv7WAxlSVfQfk8d6Et0', - dp: 'UfYKcL_or492vVc0PzwLSplbg4L3-Z5wL48mwiswbpzOyIgd2xHTHQmjJpFAIZ8q-zf9RmgJXkDrFs9rkdxPtAsL1WYdeCT5c125Fkdg317JVRDo1inX7x2Kdh8ERCreW8_4zXItuTl_KiXZNU5lvMQjWbIw2eTx1lpsflo0rYU', - dq: 'iEgcO-QfpepdH8FWd7mUFyrXdnOkXJBCogChY6YKuIHGc_p8Le9MbpFKESzEaLlN1Ehf3B6oGBl5Iz_ayUlZj2IoQZ82znoUrpa9fVYNot87ACfzIG7q9Mv7RiPAderZi03tkVXAdaBau_9vs5rS-7HMtxkVrxSUvJY14TkXlHE', - qi: 'kC-lzZOqoFaZCr5l0tOVtREKoVqaAYhQiqIRGL-MzS4sCmRkxm5vZlXYx6RtE1n_AagjqajlkjieGlxTTThHD8Iga6foGBMaAr5uR1hGQpSc7Gl7CF1DZkBJMTQN6EshYzZfxW08mIO8M6Rzuh0beL6fG9mkDcIyPrBXx2bQ_mM' - }, - { - kty: 'EC', - kid: 'peregrin.took@tuckborough.example', - use: 'enc', - crv: 'P-384', - x: 'YU4rRUzdmVqmRtWOs2OpDE_T5fsNIodcG8G5FWPrTPMyxpzsSOGaQLpe2FpxBmu2', - y: 'A8-yxCHxkfBz3hKZfI1jUYMjUhsEveZ9THuwFjH2sCNdtksRJU7D5-SkgaFL1ETP', - d: 'iTx2pk7wW-GqJkHcEkFQb2EFyYcO7RugmaW3mRrQVAOUiPommT0IdnYK2xDlZh-j' - }, - { - kty: 'oct', - kid: '18ec08e1-bfa9-4d95-b205-2b4dd1d4321d', - use: 'enc', - alg: 'A256GCMKW', - k: 'qC57l_uxcm7Nm3K-ct4GFjx8tM1U8CZ0NLBvdQstiS8' - } - ], - alg: [ - 'RSA1_5', - 'ECDH-ES+A256KW', - 'A256GCMKW' - ], - enc: 'A128CBC-H256' - }, - encrypting_key: [ - { - header: { - alg: 'RSA1_5', - kid: 'frodo.baggins@hobbiton.example' - } - }, - { - header: { - alg: 'ECDH-ES+A256KW', - kid: 'peregrin.took@tuckborough.example' - } - }, - { - header: { - alg: 'A256GCMKW', - kid: '18ec08e1-bfa9-4d95-b205-2b4dd1d4321d' - } - } - ], - encrypting_content: { - protected: { - enc: 'A128CBC-HS256' - }, - unprotected: { - cty: 'text/plain' - } - }, - output: { - json: { - recipients: [ - { - encrypted_key: 'dYOD28kab0Vvf4ODgxVAJXgHcSZICSOp8M51zjwj4w6Y5G4XJQsNNIBiqyvUUAOcpL7S7-cFe7Pio7gV_Q06WmCSa-vhW6me4bWrBf7cHwEQJdXihidAYWVajJIaKMXMvFRMV6iDlRr076DFthg2_AV0_tSiV6xSEIFqt1xnYPpmP91tc5WJDOGb-wqjw0-b-S1laS11QVbuP78dQ7Fa0zAVzzjHX-xvyM2wxj_otxr9clN1LnZMbeYSrRicJK5xodvWgkpIdkMHo4LvdhRRvzoKzlic89jFWPlnBq_V4n5trGuExtp_-dbHcGlihqc_wGgho9fLMK8JOArYLcMDNQ', - header: { - alg: 'RSA1_5', - kid: 'frodo.baggins@hobbiton.example' - } - }, - { - encrypted_key: 'ExInT0io9BqBMYF6-maw5tZlgoZXThD1zWKsHixJuw_elY4gSSId_w', - header: { - alg: 'ECDH-ES+A256KW', - kid: 'peregrin.took@tuckborough.example', - epk: { - kty: 'EC', - crv: 'P-384', - x: 'Uzdvk3pi5wKCRc1izp5_r0OjeqT-I68i8g2b8mva8diRhsE2xAn2DtMRb25Ma2CX', - y: 'VDrRyFJh-Kwd1EjAgmj5Eo-CTHAZ53MC7PjjpLioy3ylEjI1pOMbw91fzZ84pbfm' - } - } - }, - { - encrypted_key: 'a7CclAejo_7JSuPB8zeagxXRam8dwCfmkt9-WyTpS1E', - header: { - alg: 'A256GCMKW', - kid: '18ec08e1-bfa9-4d95-b205-2b4dd1d4321d', - tag: '59Nqh1LlYtVIhfD3pgRGvw', - iv: 'AvpeoPZ9Ncn9mkBn' - } - } - ], - unprotected: { - cty: 'text/plain' - }, - protected: 'eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0', - iv: 'VgEIHY20EnzUtZFl2RpB1g', - ciphertext: 'ajm2Q-OpPXCr7-MHXicknb1lsxLdXxK_yLds0KuhJzfWK04SjdxQeSw2L9mu3a_k1C55kCQ_3xlkcVKC5yr__Is48VOoK0k63_QRM9tBURMFqLByJ8vOYQX0oJW4VUHJLmGhF-tVQWB7Kz8mr8zeE7txF0MSaP6ga7-siYxStR7_G07Thd1jh-zGT0wxM5g-VRORtq0K6AXpLlwEqRp7pkt2zRM0ZAXqSpe1O6FJ7FHLDyEFnD-zDIZukLpCbzhzMDLLw2-8I14FQrgi-iEuzHgIJFIJn2wh9Tj0cg_kOZy9BqMRZbmYXMY9YQjorZ_P_JYG3ARAIF3OjDNqpdYe-K_5Q5crGJSDNyij_ygEiItR5jssQVH2ofDQdLChtazE', - tag: 'BESYyFN7T09KY7i8zKs5_g' - } - } -} diff --git a/test/cookbook/recipes/5_2.key_encryption_using_rsa-oaep_with_aes-gcm.js b/test/cookbook/recipes/5_2.key_encryption_using_rsa-oaep_with_aes-gcm.js deleted file mode 100644 index 57c31f639b..0000000000 --- a/test/cookbook/recipes/5_2.key_encryption_using_rsa-oaep_with_aes-gcm.js +++ /dev/null @@ -1,50 +0,0 @@ -module.exports = { - title: 'Key Encryption using RSA-OAEP with AES-GCM', - input: { - plaintext: Buffer.from('You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.'), - key: { - kty: 'RSA', - kid: 'samwise.gamgee@hobbiton.example', - use: 'enc', - n: 'wbdxI55VaanZXPY29Lg5hdmv2XhvqAhoxUkanfzf2-5zVUxa6prHRrI4pP1AhoqJRlZfYtWWd5mmHRG2pAHIlh0ySJ9wi0BioZBl1XP2e-C-FyXJGcTy0HdKQWlrfhTm42EW7Vv04r4gfao6uxjLGwfpGrZLarohiWCPnkNrg71S2CuNZSQBIPGjXfkmIy2tl_VWgGnL22GplyXj5YlBLdxXp3XeStsqo571utNfoUTU8E4qdzJ3U1DItoVkPGsMwlmmnJiwA7sXRItBCivR4M5qnZtdw-7v4WuR4779ubDuJ5nalMv2S66-RPcnFAzWSKxtBDnFJJDGIUe7Tzizjg1nms0Xq_yPub_UOlWn0ec85FCft1hACpWG8schrOBeNqHBODFskYpUc2LC5JA2TaPF2dA67dg1TTsC_FupfQ2kNGcE1LgprxKHcVWYQb86B-HozjHZcqtauBzFNV5tbTuB-TpkcvJfNcFLlH3b8mb-H_ox35FjqBSAjLKyoeqfKTpVjvXhd09knwgJf6VKq6UC418_TOljMVfFTWXUxlnfhOOnzW6HSSzD1c9WrCuVzsUMv54szidQ9wf1cYWf3g5qFDxDQKis99gcDaiCAwM3yEBIzuNeeCa5dartHDb1xEB_HcHSeYbghbMjGfasvKn0aZRsnTyC0xhWBlsolZE', - e: 'AQAB', - alg: 'RSA-OAEP', - d: 'n7fzJc3_WG59VEOBTkayzuSMM780OJQuZjN_KbH8lOZG25ZoA7T4Bxcc0xQn5oZE5uSCIwg91oCt0JvxPcpmqzaJZg1nirjcWZ-oBtVk7gCAWq-B3qhfF3izlbkosrzjHajIcY33HBhsy4_WerrXg4MDNE4HYojy68TcxT2LYQRxUOCf5TtJXvM8olexlSGtVnQnDRutxEUCwiewfmmrfveEogLx9EA-KMgAjTiISXxqIXQhWUQX1G7v_mV_Hr2YuImYcNcHkRvp9E7ook0876DhkO8v4UOZLwA1OlUX98mkoqwc58A_Y2lBYbVx1_s5lpPsEqbbH-nqIjh1fL0gdNfihLxnclWtW7pCztLnImZAyeCWAG7ZIfv-Rn9fLIv9jZ6r7r-MSH9sqbuziHN2grGjD_jfRluMHa0l84fFKl6bcqN1JWxPVhzNZo01yDF-1LiQnqUYSepPf6X3a2SOdkqBRiquE6EvLuSYIDpJq3jDIsgoL8Mo1LoomgiJxUwL_GWEOGu28gplyzm-9Q0U0nyhEf1uhSR8aJAQWAiFImWH5W_IQT9I7-yrindr_2fWQ_i1UgMsGzA7aOGzZfPljRy6z-tY_KuBG00-28S_aWvjyUc-Alp8AUyKjBZ-7CWH32fGWK48j1t-zomrwjL_mnhsPbGs0c9WsWgRzI-K8gE', - p: '7_2v3OQZzlPFcHyYfLABQ3XP85Es4hCdwCkbDeltaUXgVy9l9etKghvM4hRkOvbb01kYVuLFmxIkCDtpi-zLCYAdXKrAK3PtSbtzld_XZ9nlsYa_QZWpXB_IrtFjVfdKUdMz94pHUhFGFj7nr6NNxfpiHSHWFE1zD_AC3mY46J961Y2LRnreVwAGNw53p07Db8yD_92pDa97vqcZOdgtybH9q6uma-RFNhO1AoiJhYZj69hjmMRXx-x56HO9cnXNbmzNSCFCKnQmn4GQLmRj9sfbZRqL94bbtE4_e0Zrpo8RNo8vxRLqQNwIy85fc6BRgBJomt8QdQvIgPgWCv5HoQ', - q: 'zqOHk1P6WN_rHuM7ZF1cXH0x6RuOHq67WuHiSknqQeefGBA9PWs6ZyKQCO-O6mKXtcgE8_Q_hA2kMRcKOcvHil1hqMCNSXlflM7WPRPZu2qCDcqssd_uMbP-DqYthH_EzwL9KnYoH7JQFxxmcv5An8oXUtTwk4knKjkIYGRuUwfQTus0w1NfjFAyxOOiAQ37ussIcE6C6ZSsM3n41UlbJ7TCqewzVJaPJN5cxjySPZPD3Vp01a9YgAD6a3IIaKJdIxJS1ImnfPevSJQBE79-EXe2kSwVgOzvt-gsmM29QQ8veHy4uAqca5dZzMs7hkkHtw1z0jHV90epQJJlXXnH8Q', - dp: '19oDkBh1AXelMIxQFm2zZTqUhAzCIr4xNIGEPNoDt1jK83_FJA-xnx5kA7-1erdHdms_Ef67HsONNv5A60JaR7w8LHnDiBGnjdaUmmuO8XAxQJ_ia5mxjxNjS6E2yD44USo2JmHvzeeNczq25elqbTPLhUpGo1IZuG72FZQ5gTjXoTXC2-xtCDEUZfaUNh4IeAipfLugbpe0JAFlFfrTDAMUFpC3iXjxqzbEanflwPvj6V9iDSgjj8SozSM0dLtxvu0LIeIQAeEgT_yXcrKGmpKdSO08kLBx8VUjkbv_3Pn20Gyu2YEuwpFlM_H1NikuxJNKFGmnAq9LcnwwT0jvoQ', - dq: 'S6p59KrlmzGzaQYQM3o0XfHCGvfqHLYjCO557HYQf72O9kLMCfd_1VBEqeD-1jjwELKDjck8kOBl5UvohK1oDfSP1DleAy-cnmL29DqWmhgwM1ip0CCNmkmsmDSlqkUXDi6sAaZuntyukyflI-qSQ3C_BafPyFaKrt1fgdyEwYa08pESKwwWisy7KnmoUvaJ3SaHmohFS78TJ25cfc10wZ9hQNOrIChZlkiOdFCtxDqdmCqNacnhgE3bZQjGp3n83ODSz9zwJcSUvODlXBPc2AycH6Ci5yjbxt4Ppox_5pjm6xnQkiPgj01GpsUssMmBN7iHVsrE7N2iznBNCeOUIQ', - qi: 'FZhClBMywVVjnuUud-05qd5CYU0dK79akAgy9oX6RX6I3IIIPckCciRrokxglZn-omAY5CnCe4KdrnjFOT5YUZE7G_Pg44XgCXaarLQf4hl80oPEf6-jJ5Iy6wPRx7G2e8qLxnh9cOdf-kRqgOS3F48Ucvw3ma5V6KGMwQqWFeV31XtZ8l5cVI-I3NzBS7qltpUVgz2Ju021eyc7IlqgzR98qKONl27DuEES0aK0WE97jnsyO27Yp88Wa2RiBrEocM89QZI1seJiGDizHRUP4UZxw9zsXww46wy0P6f9grnYp7t8LkyDDk8eoI4KX6SNMNVcyVS9IWjlq8EzqZEKIA' - }, - alg: 'RSA-OAEP', - enc: 'A256GCM' - }, - encrypting_content: { - protected: { - alg: 'RSA-OAEP', - kid: 'samwise.gamgee@hobbiton.example', - enc: 'A256GCM' - } - }, - output: { - compact: 'eyJhbGciOiJSU0EtT0FFUCIsImtpZCI6InNhbXdpc2UuZ2FtZ2VlQGhvYmJpdG9uLmV4YW1wbGUiLCJlbmMiOiJBMjU2R0NNIn0.rT99rwrBTbTI7IJM8fU3Eli7226HEB7IchCxNuh7lCiud48LxeolRdtFF4nzQibeYOl5S_PJsAXZwSXtDePz9hk-BbtsTBqC2UsPOdwjC9NhNupNNu9uHIVftDyucvI6hvALeZ6OGnhNV4v1zx2k7O1D89mAzfw-_kT3tkuorpDU-CpBENfIHX1Q58-Aad3FzMuo3Fn9buEP2yXakLXYa15BUXQsupM4A1GD4_H4Bd7V3u9h8Gkg8BpxKdUV9ScfJQTcYm6eJEBz3aSwIaK4T3-dwWpuBOhROQXBosJzS1asnuHtVMt2pKIIfux5BC6huIvmY7kzV7W7aIUrpYm_3H4zYvyMeq5pGqFmW2k8zpO878TRlZx7pZfPYDSXZyS0CfKKkMozT_qiCwZTSz4duYnt8hS4Z9sGthXn9uDqd6wycMagnQfOTs_lycTWmY-aqWVDKhjYNRf03NiwRtb5BE-tOdFwCASQj3uuAgPGrO2AWBe38UjQb0lvXn1SpyvYZ3WFc7WOJYaTa7A8DRn6MC6T-xDmMuxC0G7S2rscw5lQQU06MvZTlFOt0UvfuKBa03cxA_nIBIhLMjY2kOTxQMmpDPTr6Cbo8aKaOnx6ASE5Jx9paBpnNmOOKH35j_QlrQhDWUN6A2Gg8iFayJ69xDEdHAVCGRzN3woEI2ozDRs.-nBoKLH0YkLZPSI9.o4k2cnGN8rSSw3IDo1YuySkqeS_t2m1GXklSgqBdpACm6UJuJowOHC5ytjqYgRL-I-soPlwqMUf4UgRWWeaOGNw6vGW-xyM01lTYxrXfVzIIaRdhYtEMRBvBWbEwP7ua1DRfvaOjgZv6Ifa3brcAM64d8p5lhhNcizPersuhw5f-pGYzseva-TUaL8iWnctc-sSwy7SQmRkfhDjwbz0fz6kFovEgj64X1I5s7E6GLp5fnbYGLa1QUiML7Cc2GxgvI7zqWo0YIEc7aCflLG1-8BboVWFdZKLK9vNoycrYHumwzKluLWEbSVmaPpOslY2n525DxDfWaVFUfKQxMF56vn4B9QMpWAbnypNimbM8zVOw.UCGiqJxhBI3IFVdPalHHvA', - json: { - recipients: [ - { - encrypted_key: 'rT99rwrBTbTI7IJM8fU3Eli7226HEB7IchCxNuh7lCiud48LxeolRdtFF4nzQibeYOl5S_PJsAXZwSXtDePz9hk-BbtsTBqC2UsPOdwjC9NhNupNNu9uHIVftDyucvI6hvALeZ6OGnhNV4v1zx2k7O1D89mAzfw-_kT3tkuorpDU-CpBENfIHX1Q58-Aad3FzMuo3Fn9buEP2yXakLXYa15BUXQsupM4A1GD4_H4Bd7V3u9h8Gkg8BpxKdUV9ScfJQTcYm6eJEBz3aSwIaK4T3-dwWpuBOhROQXBosJzS1asnuHtVMt2pKIIfux5BC6huIvmY7kzV7W7aIUrpYm_3H4zYvyMeq5pGqFmW2k8zpO878TRlZx7pZfPYDSXZyS0CfKKkMozT_qiCwZTSz4duYnt8hS4Z9sGthXn9uDqd6wycMagnQfOTs_lycTWmY-aqWVDKhjYNRf03NiwRtb5BE-tOdFwCASQj3uuAgPGrO2AWBe38UjQb0lvXn1SpyvYZ3WFc7WOJYaTa7A8DRn6MC6T-xDmMuxC0G7S2rscw5lQQU06MvZTlFOt0UvfuKBa03cxA_nIBIhLMjY2kOTxQMmpDPTr6Cbo8aKaOnx6ASE5Jx9paBpnNmOOKH35j_QlrQhDWUN6A2Gg8iFayJ69xDEdHAVCGRzN3woEI2ozDRs' - } - ], - protected: 'eyJhbGciOiJSU0EtT0FFUCIsImtpZCI6InNhbXdpc2UuZ2FtZ2VlQGhvYmJpdG9uLmV4YW1wbGUiLCJlbmMiOiJBMjU2R0NNIn0', - iv: '-nBoKLH0YkLZPSI9', - ciphertext: 'o4k2cnGN8rSSw3IDo1YuySkqeS_t2m1GXklSgqBdpACm6UJuJowOHC5ytjqYgRL-I-soPlwqMUf4UgRWWeaOGNw6vGW-xyM01lTYxrXfVzIIaRdhYtEMRBvBWbEwP7ua1DRfvaOjgZv6Ifa3brcAM64d8p5lhhNcizPersuhw5f-pGYzseva-TUaL8iWnctc-sSwy7SQmRkfhDjwbz0fz6kFovEgj64X1I5s7E6GLp5fnbYGLa1QUiML7Cc2GxgvI7zqWo0YIEc7aCflLG1-8BboVWFdZKLK9vNoycrYHumwzKluLWEbSVmaPpOslY2n525DxDfWaVFUfKQxMF56vn4B9QMpWAbnypNimbM8zVOw', - tag: 'UCGiqJxhBI3IFVdPalHHvA' - }, - json_flat: { - protected: 'eyJhbGciOiJSU0EtT0FFUCIsImtpZCI6InNhbXdpc2UuZ2FtZ2VlQGhvYmJpdG9uLmV4YW1wbGUiLCJlbmMiOiJBMjU2R0NNIn0', - encrypted_key: 'rT99rwrBTbTI7IJM8fU3Eli7226HEB7IchCxNuh7lCiud48LxeolRdtFF4nzQibeYOl5S_PJsAXZwSXtDePz9hk-BbtsTBqC2UsPOdwjC9NhNupNNu9uHIVftDyucvI6hvALeZ6OGnhNV4v1zx2k7O1D89mAzfw-_kT3tkuorpDU-CpBENfIHX1Q58-Aad3FzMuo3Fn9buEP2yXakLXYa15BUXQsupM4A1GD4_H4Bd7V3u9h8Gkg8BpxKdUV9ScfJQTcYm6eJEBz3aSwIaK4T3-dwWpuBOhROQXBosJzS1asnuHtVMt2pKIIfux5BC6huIvmY7kzV7W7aIUrpYm_3H4zYvyMeq5pGqFmW2k8zpO878TRlZx7pZfPYDSXZyS0CfKKkMozT_qiCwZTSz4duYnt8hS4Z9sGthXn9uDqd6wycMagnQfOTs_lycTWmY-aqWVDKhjYNRf03NiwRtb5BE-tOdFwCASQj3uuAgPGrO2AWBe38UjQb0lvXn1SpyvYZ3WFc7WOJYaTa7A8DRn6MC6T-xDmMuxC0G7S2rscw5lQQU06MvZTlFOt0UvfuKBa03cxA_nIBIhLMjY2kOTxQMmpDPTr6Cbo8aKaOnx6ASE5Jx9paBpnNmOOKH35j_QlrQhDWUN6A2Gg8iFayJ69xDEdHAVCGRzN3woEI2ozDRs', - iv: '-nBoKLH0YkLZPSI9', - ciphertext: 'o4k2cnGN8rSSw3IDo1YuySkqeS_t2m1GXklSgqBdpACm6UJuJowOHC5ytjqYgRL-I-soPlwqMUf4UgRWWeaOGNw6vGW-xyM01lTYxrXfVzIIaRdhYtEMRBvBWbEwP7ua1DRfvaOjgZv6Ifa3brcAM64d8p5lhhNcizPersuhw5f-pGYzseva-TUaL8iWnctc-sSwy7SQmRkfhDjwbz0fz6kFovEgj64X1I5s7E6GLp5fnbYGLa1QUiML7Cc2GxgvI7zqWo0YIEc7aCflLG1-8BboVWFdZKLK9vNoycrYHumwzKluLWEbSVmaPpOslY2n525DxDfWaVFUfKQxMF56vn4B9QMpWAbnypNimbM8zVOw', - tag: 'UCGiqJxhBI3IFVdPalHHvA' - } - } -} diff --git a/test/cookbook/recipes/5_3.key_wrap_using_pbes2-aes-keywrap_with-aes-cbc-hmac-sha2.js b/test/cookbook/recipes/5_3.key_wrap_using_pbes2-aes-keywrap_with-aes-cbc-hmac-sha2.js deleted file mode 100644 index a9199904df..0000000000 --- a/test/cookbook/recipes/5_3.key_wrap_using_pbes2-aes-keywrap_with-aes-cbc-hmac-sha2.js +++ /dev/null @@ -1,37 +0,0 @@ -module.exports = { - title: 'Key Wrap using PBES2-AES-KeyWrap with AES-CBC-HMAC-SHA2', - input: { - plaintext: Buffer.from('{"keys":[{"kty":"oct","kid":"77c7e2b8-6e13-45cf-8672-617b5b45243a","use":"enc","alg":"A128GCM","k":"XctOhJAkA-pD9Lh7ZgW_2A"},{"kty":"oct","kid":"81b20965-8332-43d9-a468-82160ad91ac8","use":"enc","alg":"A128KW","k":"GZy6sIZ6wl9NJOKB-jnmVQ"},{"kty":"oct","kid":"18ec08e1-bfa9-4d95-b205-2b4dd1d4321d","use":"enc","alg":"A256GCMKW","k":"qC57l_uxcm7Nm3K-ct4GFjx8tM1U8CZ0NLBvdQstiS8"}]}'), - pwd: 'entrap_o–peter_long–credit_tun', - alg: 'PBES2-HS512+A256KW', - enc: 'A128CBC-HS256' - }, - encrypting_content: { - protected: { - alg: 'PBES2-HS512+A256KW', - cty: 'jwk-set+json', - enc: 'A128CBC-HS256' - } - }, - output: { - compact: 'eyJhbGciOiJQQkVTMi1IUzUxMitBMjU2S1ciLCJwMnMiOiI4UTFTemluYXNSM3hjaFl6NlpaY0hBIiwicDJjIjo4MTkyLCJjdHkiOiJqd2stc2V0K2pzb24iLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.d3qNhUWfqheyPp4H8sjOWsDYajoej4c5Je6rlUtFPWdgtURtmeDV1g.VBiCzVHNoLiR3F4V82uoTQ.23i-Tb1AV4n0WKVSSgcQrdg6GRqsUKxjruHXYsTHAJLZ2nsnGIX86vMXqIi6IRsfywCRFzLxEcZBRnTvG3nhzPk0GDD7FMyXhUHpDjEYCNA_XOmzg8yZR9oyjo6lTF6si4q9FZ2EhzgFQCLO_6h5EVg3vR75_hkBsnuoqoM3dwejXBtIodN84PeqMb6asmas_dpSsz7H10fC5ni9xIz424givB1YLldF6exVmL93R3fOoOJbmk2GBQZL_SEGllv2cQsBgeprARsaQ7Bq99tT80coH8ItBjgV08AtzXFFsx9qKvC982KLKdPQMTlVJKkqtV4Ru5LEVpBZXBnZrtViSOgyg6AiuwaS-rCrcD_ePOGSuxvgtrokAKYPqmXUeRdjFJwafkYEkiuDCV9vWGAi1DH2xTafhJwcmywIyzi4BqRpmdn_N-zl5tuJYyuvKhjKv6ihbsV_k1hJGPGAxJ6wUpmwC4PTQ2izEm0TuSE8oMKdTw8V3kobXZ77ulMwDs4p.0HlwodAhOCILG5SQ2LQ9dg', - json: { - recipients: [ - { - encrypted_key: 'd3qNhUWfqheyPp4H8sjOWsDYajoej4c5Je6rlUtFPWdgtURtmeDV1g' - } - ], - protected: 'eyJhbGciOiJQQkVTMi1IUzUxMitBMjU2S1ciLCJwMnMiOiI4UTFTemluYXNSM3hjaFl6NlpaY0hBIiwicDJjIjo4MTkyLCJjdHkiOiJqd2stc2V0K2pzb24iLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0', - iv: 'VBiCzVHNoLiR3F4V82uoTQ', - ciphertext: '23i-Tb1AV4n0WKVSSgcQrdg6GRqsUKxjruHXYsTHAJLZ2nsnGIX86vMXqIi6IRsfywCRFzLxEcZBRnTvG3nhzPk0GDD7FMyXhUHpDjEYCNA_XOmzg8yZR9oyjo6lTF6si4q9FZ2EhzgFQCLO_6h5EVg3vR75_hkBsnuoqoM3dwejXBtIodN84PeqMb6asmas_dpSsz7H10fC5ni9xIz424givB1YLldF6exVmL93R3fOoOJbmk2GBQZL_SEGllv2cQsBgeprARsaQ7Bq99tT80coH8ItBjgV08AtzXFFsx9qKvC982KLKdPQMTlVJKkqtV4Ru5LEVpBZXBnZrtViSOgyg6AiuwaS-rCrcD_ePOGSuxvgtrokAKYPqmXUeRdjFJwafkYEkiuDCV9vWGAi1DH2xTafhJwcmywIyzi4BqRpmdn_N-zl5tuJYyuvKhjKv6ihbsV_k1hJGPGAxJ6wUpmwC4PTQ2izEm0TuSE8oMKdTw8V3kobXZ77ulMwDs4p', - tag: '0HlwodAhOCILG5SQ2LQ9dg' - }, - json_flat: { - protected: 'eyJhbGciOiJQQkVTMi1IUzUxMitBMjU2S1ciLCJwMnMiOiI4UTFTemluYXNSM3hjaFl6NlpaY0hBIiwicDJjIjo4MTkyLCJjdHkiOiJqd2stc2V0K2pzb24iLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0', - encrypted_key: 'd3qNhUWfqheyPp4H8sjOWsDYajoej4c5Je6rlUtFPWdgtURtmeDV1g', - iv: 'VBiCzVHNoLiR3F4V82uoTQ', - ciphertext: '23i-Tb1AV4n0WKVSSgcQrdg6GRqsUKxjruHXYsTHAJLZ2nsnGIX86vMXqIi6IRsfywCRFzLxEcZBRnTvG3nhzPk0GDD7FMyXhUHpDjEYCNA_XOmzg8yZR9oyjo6lTF6si4q9FZ2EhzgFQCLO_6h5EVg3vR75_hkBsnuoqoM3dwejXBtIodN84PeqMb6asmas_dpSsz7H10fC5ni9xIz424givB1YLldF6exVmL93R3fOoOJbmk2GBQZL_SEGllv2cQsBgeprARsaQ7Bq99tT80coH8ItBjgV08AtzXFFsx9qKvC982KLKdPQMTlVJKkqtV4Ru5LEVpBZXBnZrtViSOgyg6AiuwaS-rCrcD_ePOGSuxvgtrokAKYPqmXUeRdjFJwafkYEkiuDCV9vWGAi1DH2xTafhJwcmywIyzi4BqRpmdn_N-zl5tuJYyuvKhjKv6ihbsV_k1hJGPGAxJ6wUpmwC4PTQ2izEm0TuSE8oMKdTw8V3kobXZ77ulMwDs4p', - tag: '0HlwodAhOCILG5SQ2LQ9dg' - } - } -} diff --git a/test/cookbook/recipes/5_4.key_agreement_with_key_wrapping_using_ecdh-es_and_aes-keywrap_with_aes-gcm.js b/test/cookbook/recipes/5_4.key_agreement_with_key_wrapping_using_ecdh-es_and_aes-keywrap_with_aes-gcm.js deleted file mode 100644 index d79d31a12d..0000000000 --- a/test/cookbook/recipes/5_4.key_agreement_with_key_wrapping_using_ecdh-es_and_aes-keywrap_with_aes-gcm.js +++ /dev/null @@ -1,45 +0,0 @@ -module.exports = { - title: 'Key Agreement with Key Wrapping using ECDH-ES and AES-KeyWrap with AES-GCM', - input: { - plaintext: Buffer.from('You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.'), - key: { - kty: 'EC', - kid: 'peregrin.took@tuckborough.example', - use: 'enc', - crv: 'P-384', - x: 'YU4rRUzdmVqmRtWOs2OpDE_T5fsNIodcG8G5FWPrTPMyxpzsSOGaQLpe2FpxBmu2', - y: 'A8-yxCHxkfBz3hKZfI1jUYMjUhsEveZ9THuwFjH2sCNdtksRJU7D5-SkgaFL1ETP', - d: 'iTx2pk7wW-GqJkHcEkFQb2EFyYcO7RugmaW3mRrQVAOUiPommT0IdnYK2xDlZh-j' - }, - alg: 'ECDH-ES+A128KW', - enc: 'A128GCM' - }, - encrypting_content: { - protected: { - alg: 'ECDH-ES+A128KW', - kid: 'peregrin.took@tuckborough.example', - enc: 'A128GCM' - } - }, - output: { - compact: 'eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImtpZCI6InBlcmVncmluLnRvb2tAdHVja2Jvcm91Z2guZXhhbXBsZSIsImVwayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMzg0IiwieCI6InVCbzRrSFB3Nmtiang1bDB4b3dyZF9vWXpCbWF6LUdLRlp1NHhBRkZrYllpV2d1dEVLNml1RURzUTZ3TmROZzMiLCJ5Ijoic3AzcDVTR2haVkMyZmFYdW1JLWU5SlUyTW84S3BvWXJGRHI1eVBOVnRXNFBnRXdaT3lRVEEtSmRhWTh0YjdFMCJ9LCJlbmMiOiJBMTI4R0NNIn0.0DJjBXri_kBcC46IkU5_Jk9BqaQeHdv2.mH-G2zVqgztUtnW_.tkZuOO9h95OgHJmkkrfLBisku8rGf6nzVxhRM3sVOhXgz5NJ76oID7lpnAi_cPWJRCjSpAaUZ5dOR3Spy7QuEkmKx8-3RCMhSYMzsXaEwDdXta9Mn5B7cCBoJKB0IgEnj_qfo1hIi-uEkUpOZ8aLTZGHfpl05jMwbKkTe2yK3mjF6SBAsgicQDVCkcY9BLluzx1RmC3ORXaM0JaHPB93YcdSDGgpgBWMVrNU1ErkjcMqMoT_wtCex3w03XdLkjXIuEr2hWgeP-nkUZTPU9EoGSPj6fAS-bSz87RCPrxZdj_iVyC6QWcqAu07WNhjzJEPc4jVntRJ6K53NgPQ5p99l3Z408OUqj4ioYezbS6vTPlQ.WuGzxmcreYjpHGJoa17EBg', - json: { - recipients: [ - { - encrypted_key: '0DJjBXri_kBcC46IkU5_Jk9BqaQeHdv2' - } - ], - protected: 'eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImtpZCI6InBlcmVncmluLnRvb2tAdHVja2Jvcm91Z2guZXhhbXBsZSIsImVwayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMzg0IiwieCI6InVCbzRrSFB3Nmtiang1bDB4b3dyZF9vWXpCbWF6LUdLRlp1NHhBRkZrYllpV2d1dEVLNml1RURzUTZ3TmROZzMiLCJ5Ijoic3AzcDVTR2haVkMyZmFYdW1JLWU5SlUyTW84S3BvWXJGRHI1eVBOVnRXNFBnRXdaT3lRVEEtSmRhWTh0YjdFMCJ9LCJlbmMiOiJBMTI4R0NNIn0', - iv: 'mH-G2zVqgztUtnW_', - ciphertext: 'tkZuOO9h95OgHJmkkrfLBisku8rGf6nzVxhRM3sVOhXgz5NJ76oID7lpnAi_cPWJRCjSpAaUZ5dOR3Spy7QuEkmKx8-3RCMhSYMzsXaEwDdXta9Mn5B7cCBoJKB0IgEnj_qfo1hIi-uEkUpOZ8aLTZGHfpl05jMwbKkTe2yK3mjF6SBAsgicQDVCkcY9BLluzx1RmC3ORXaM0JaHPB93YcdSDGgpgBWMVrNU1ErkjcMqMoT_wtCex3w03XdLkjXIuEr2hWgeP-nkUZTPU9EoGSPj6fAS-bSz87RCPrxZdj_iVyC6QWcqAu07WNhjzJEPc4jVntRJ6K53NgPQ5p99l3Z408OUqj4ioYezbS6vTPlQ', - tag: 'WuGzxmcreYjpHGJoa17EBg' - }, - json_flat: { - protected: 'eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImtpZCI6InBlcmVncmluLnRvb2tAdHVja2Jvcm91Z2guZXhhbXBsZSIsImVwayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMzg0IiwieCI6InVCbzRrSFB3Nmtiang1bDB4b3dyZF9vWXpCbWF6LUdLRlp1NHhBRkZrYllpV2d1dEVLNml1RURzUTZ3TmROZzMiLCJ5Ijoic3AzcDVTR2haVkMyZmFYdW1JLWU5SlUyTW84S3BvWXJGRHI1eVBOVnRXNFBnRXdaT3lRVEEtSmRhWTh0YjdFMCJ9LCJlbmMiOiJBMTI4R0NNIn0', - encrypted_key: '0DJjBXri_kBcC46IkU5_Jk9BqaQeHdv2', - iv: 'mH-G2zVqgztUtnW_', - ciphertext: 'tkZuOO9h95OgHJmkkrfLBisku8rGf6nzVxhRM3sVOhXgz5NJ76oID7lpnAi_cPWJRCjSpAaUZ5dOR3Spy7QuEkmKx8-3RCMhSYMzsXaEwDdXta9Mn5B7cCBoJKB0IgEnj_qfo1hIi-uEkUpOZ8aLTZGHfpl05jMwbKkTe2yK3mjF6SBAsgicQDVCkcY9BLluzx1RmC3ORXaM0JaHPB93YcdSDGgpgBWMVrNU1ErkjcMqMoT_wtCex3w03XdLkjXIuEr2hWgeP-nkUZTPU9EoGSPj6fAS-bSz87RCPrxZdj_iVyC6QWcqAu07WNhjzJEPc4jVntRJ6K53NgPQ5p99l3Z408OUqj4ioYezbS6vTPlQ', - tag: 'WuGzxmcreYjpHGJoa17EBg' - } - } -} diff --git a/test/cookbook/recipes/5_5.key_agreement_using_ecdh-es_with_aes-cbc-hmac-sha2.js b/test/cookbook/recipes/5_5.key_agreement_using_ecdh-es_with_aes-cbc-hmac-sha2.js deleted file mode 100644 index e9e4234d34..0000000000 --- a/test/cookbook/recipes/5_5.key_agreement_using_ecdh-es_with_aes-cbc-hmac-sha2.js +++ /dev/null @@ -1,39 +0,0 @@ -module.exports = { - title: 'Key Agreement using ECDH-ES with AES-CBC-HMAC-SHA2', - input: { - plaintext: Buffer.from('You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.'), - key: { - kty: 'EC', - kid: 'meriadoc.brandybuck@buckland.example', - use: 'enc', - crv: 'P-256', - x: 'Ze2loSV3wrroKUN_4zhwGhCqo3Xhu1td4QjeQ5wIVR0', - y: 'HlLtdXARY_f55A3fnzQbPcm6hgr34Mp8p-nuzQCE0Zw', - d: 'r_kHyZ-a06rmxM3yESK84r1otSg-aQcVStkRhA-iCM8' - }, - alg: 'ECDH-ES', - enc: 'A128CBC-HS256' - }, - encrypting_content: { - protected: { - alg: 'ECDH-ES', - kid: 'meriadoc.brandybuck@buckland.example', - enc: 'A128CBC-HS256' - } - }, - output: { - compact: 'eyJhbGciOiJFQ0RILUVTIiwia2lkIjoibWVyaWFkb2MuYnJhbmR5YnVja0BidWNrbGFuZC5leGFtcGxlIiwiZXBrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoibVBVS1RfYkFXR0hJaGcwVHBqanFWc1AxclhXUXVfdndWT0hIdE5rZFlvQSIsInkiOiI4QlFBc0ltR2VBUzQ2ZnlXdzVNaFlmR1RUMElqQnBGdzJTUzM0RHY0SXJzIn0sImVuYyI6IkExMjhDQkMtSFMyNTYifQ..yc9N8v5sYyv3iGQT926IUg.BoDlwPnTypYq-ivjmQvAYJLb5Q6l-F3LIgQomlz87yW4OPKbWE1zSTEFjDfhU9IPIOSA9Bml4m7iDFwA-1ZXvHteLDtw4R1XRGMEsDIqAYtskTTmzmzNa-_q4F_evAPUmwlO-ZG45Mnq4uhM1fm_D9rBtWolqZSF3xGNNkpOMQKF1Cl8i8wjzRli7-IXgyirlKQsbhhqRzkv8IcY6aHl24j03C-AR2le1r7URUhArM79BY8soZU0lzwI-sD5PZ3l4NDCCei9XkoIAfsXJWmySPoeRb2Ni5UZL4mYpvKDiwmyzGd65KqVw7MsFfI_K767G9C9Azp73gKZD0DyUn1mn0WW5LmyX_yJ-3AROq8p1WZBfG-ZyJ6195_JGG2m9Csg.WCCkNa-x4BeB9hIDIfFuhg', - json: { - protected: 'eyJhbGciOiJFQ0RILUVTIiwia2lkIjoibWVyaWFkb2MuYnJhbmR5YnVja0BidWNrbGFuZC5leGFtcGxlIiwiZXBrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoibVBVS1RfYkFXR0hJaGcwVHBqanFWc1AxclhXUXVfdndWT0hIdE5rZFlvQSIsInkiOiI4QlFBc0ltR2VBUzQ2ZnlXdzVNaFlmR1RUMElqQnBGdzJTUzM0RHY0SXJzIn0sImVuYyI6IkExMjhDQkMtSFMyNTYifQ', - iv: 'yc9N8v5sYyv3iGQT926IUg', - ciphertext: 'BoDlwPnTypYq-ivjmQvAYJLb5Q6l-F3LIgQomlz87yW4OPKbWE1zSTEFjDfhU9IPIOSA9Bml4m7iDFwA-1ZXvHteLDtw4R1XRGMEsDIqAYtskTTmzmzNa-_q4F_evAPUmwlO-ZG45Mnq4uhM1fm_D9rBtWolqZSF3xGNNkpOMQKF1Cl8i8wjzRli7-IXgyirlKQsbhhqRzkv8IcY6aHl24j03C-AR2le1r7URUhArM79BY8soZU0lzwI-sD5PZ3l4NDCCei9XkoIAfsXJWmySPoeRb2Ni5UZL4mYpvKDiwmyzGd65KqVw7MsFfI_K767G9C9Azp73gKZD0DyUn1mn0WW5LmyX_yJ-3AROq8p1WZBfG-ZyJ6195_JGG2m9Csg', - tag: 'WCCkNa-x4BeB9hIDIfFuhg' - }, - json_flat: { - protected: 'eyJhbGciOiJFQ0RILUVTIiwia2lkIjoibWVyaWFkb2MuYnJhbmR5YnVja0BidWNrbGFuZC5leGFtcGxlIiwiZXBrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoibVBVS1RfYkFXR0hJaGcwVHBqanFWc1AxclhXUXVfdndWT0hIdE5rZFlvQSIsInkiOiI4QlFBc0ltR2VBUzQ2ZnlXdzVNaFlmR1RUMElqQnBGdzJTUzM0RHY0SXJzIn0sImVuYyI6IkExMjhDQkMtSFMyNTYifQ', - iv: 'yc9N8v5sYyv3iGQT926IUg', - ciphertext: 'BoDlwPnTypYq-ivjmQvAYJLb5Q6l-F3LIgQomlz87yW4OPKbWE1zSTEFjDfhU9IPIOSA9Bml4m7iDFwA-1ZXvHteLDtw4R1XRGMEsDIqAYtskTTmzmzNa-_q4F_evAPUmwlO-ZG45Mnq4uhM1fm_D9rBtWolqZSF3xGNNkpOMQKF1Cl8i8wjzRli7-IXgyirlKQsbhhqRzkv8IcY6aHl24j03C-AR2le1r7URUhArM79BY8soZU0lzwI-sD5PZ3l4NDCCei9XkoIAfsXJWmySPoeRb2Ni5UZL4mYpvKDiwmyzGd65KqVw7MsFfI_K767G9C9Azp73gKZD0DyUn1mn0WW5LmyX_yJ-3AROq8p1WZBfG-ZyJ6195_JGG2m9Csg', - tag: 'WCCkNa-x4BeB9hIDIfFuhg' - } - } -} diff --git a/test/cookbook/recipes/5_6.direct_encryption_using_aes-gcm.js b/test/cookbook/recipes/5_6.direct_encryption_using_aes-gcm.js deleted file mode 100644 index 7485a7ebfc..0000000000 --- a/test/cookbook/recipes/5_6.direct_encryption_using_aes-gcm.js +++ /dev/null @@ -1,37 +0,0 @@ -module.exports = { - title: 'Direct Encryption using AES-GCM', - input: { - plaintext: Buffer.from('You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.'), - key: { - kty: 'oct', - kid: '77c7e2b8-6e13-45cf-8672-617b5b45243a', - use: 'enc', - alg: 'A128GCM', - k: 'XctOhJAkA-pD9Lh7ZgW_2A' - }, - alg: 'dir', - enc: 'A128GCM' - }, - encrypting_content: { - protected: { - alg: 'dir', - kid: '77c7e2b8-6e13-45cf-8672-617b5b45243a', - enc: 'A128GCM' - } - }, - output: { - compact: 'eyJhbGciOiJkaXIiLCJraWQiOiI3N2M3ZTJiOC02ZTEzLTQ1Y2YtODY3Mi02MTdiNWI0NTI0M2EiLCJlbmMiOiJBMTI4R0NNIn0..refa467QzzKx6QAB.JW_i_f52hww_ELQPGaYyeAB6HYGcR559l9TYnSovc23XJoBcW29rHP8yZOZG7YhLpT1bjFuvZPjQS-m0IFtVcXkZXdH_lr_FrdYt9HRUYkshtrMmIUAyGmUnd9zMDB2n0cRDIHAzFVeJUDxkUwVAE7_YGRPdcqMyiBoCO-FBdE-Nceb4h3-FtBP-c_BIwCPTjb9o0SbdcdREEMJMyZBH8ySWMVi1gPD9yxi-aQpGbSv_F9N4IZAxscj5g-NJsUPbjk29-s7LJAGb15wEBtXphVCgyy53CoIKLHHeJHXex45Uz9aKZSRSInZI-wjsY0yu3cT4_aQ3i1o-tiE-F8Ios61EKgyIQ4CWao8PFMj8TTnp.vbb32Xvllea2OtmHAdccRQ', - json: { - protected: 'eyJhbGciOiJkaXIiLCJraWQiOiI3N2M3ZTJiOC02ZTEzLTQ1Y2YtODY3Mi02MTdiNWI0NTI0M2EiLCJlbmMiOiJBMTI4R0NNIn0', - iv: 'refa467QzzKx6QAB', - ciphertext: 'JW_i_f52hww_ELQPGaYyeAB6HYGcR559l9TYnSovc23XJoBcW29rHP8yZOZG7YhLpT1bjFuvZPjQS-m0IFtVcXkZXdH_lr_FrdYt9HRUYkshtrMmIUAyGmUnd9zMDB2n0cRDIHAzFVeJUDxkUwVAE7_YGRPdcqMyiBoCO-FBdE-Nceb4h3-FtBP-c_BIwCPTjb9o0SbdcdREEMJMyZBH8ySWMVi1gPD9yxi-aQpGbSv_F9N4IZAxscj5g-NJsUPbjk29-s7LJAGb15wEBtXphVCgyy53CoIKLHHeJHXex45Uz9aKZSRSInZI-wjsY0yu3cT4_aQ3i1o-tiE-F8Ios61EKgyIQ4CWao8PFMj8TTnp', - tag: 'vbb32Xvllea2OtmHAdccRQ' - }, - json_flat: { - protected: 'eyJhbGciOiJkaXIiLCJraWQiOiI3N2M3ZTJiOC02ZTEzLTQ1Y2YtODY3Mi02MTdiNWI0NTI0M2EiLCJlbmMiOiJBMTI4R0NNIn0', - iv: 'refa467QzzKx6QAB', - ciphertext: 'JW_i_f52hww_ELQPGaYyeAB6HYGcR559l9TYnSovc23XJoBcW29rHP8yZOZG7YhLpT1bjFuvZPjQS-m0IFtVcXkZXdH_lr_FrdYt9HRUYkshtrMmIUAyGmUnd9zMDB2n0cRDIHAzFVeJUDxkUwVAE7_YGRPdcqMyiBoCO-FBdE-Nceb4h3-FtBP-c_BIwCPTjb9o0SbdcdREEMJMyZBH8ySWMVi1gPD9yxi-aQpGbSv_F9N4IZAxscj5g-NJsUPbjk29-s7LJAGb15wEBtXphVCgyy53CoIKLHHeJHXex45Uz9aKZSRSInZI-wjsY0yu3cT4_aQ3i1o-tiE-F8Ios61EKgyIQ4CWao8PFMj8TTnp', - tag: 'vbb32Xvllea2OtmHAdccRQ' - } - } -} diff --git a/test/cookbook/recipes/5_7.key_wrap_using_aes-gcm_keywrap_with_aes-cbc-hmac-sha2.js b/test/cookbook/recipes/5_7.key_wrap_using_aes-gcm_keywrap_with_aes-cbc-hmac-sha2.js deleted file mode 100644 index 4f17c62896..0000000000 --- a/test/cookbook/recipes/5_7.key_wrap_using_aes-gcm_keywrap_with_aes-cbc-hmac-sha2.js +++ /dev/null @@ -1,45 +0,0 @@ -module.exports = { - title: 'Key Wrap using AES-GCM KeyWrap with AES-CBC-HMAC-SHA2', - input: { - plaintext: Buffer.from('You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.'), - key: { - kty: 'oct', - kid: '18ec08e1-bfa9-4d95-b205-2b4dd1d4321d', - use: 'enc', - alg: 'A256GCMKW', - k: 'qC57l_uxcm7Nm3K-ct4GFjx8tM1U8CZ0NLBvdQstiS8' - }, - alg: 'A256GCMKW', - enc: 'A128CBC-HS256' - }, - encrypting_content: { - protected: { - alg: 'A256GCMKW', - kid: '18ec08e1-bfa9-4d95-b205-2b4dd1d4321d', - tag: 'kfPduVQ3T3H6vnewt--ksw', - iv: 'KkYT0GX_2jHlfqN_', - enc: 'A128CBC-HS256' - } - }, - output: { - compact: 'eyJhbGciOiJBMjU2R0NNS1ciLCJraWQiOiIxOGVjMDhlMS1iZmE5LTRkOTUtYjIwNS0yYjRkZDFkNDMyMWQiLCJ0YWciOiJrZlBkdVZRM1QzSDZ2bmV3dC0ta3N3IiwiaXYiOiJLa1lUMEdYXzJqSGxmcU5fIiwiZW5jIjoiQTEyOENCQy1IUzI1NiJ9.lJf3HbOApxMEBkCMOoTnnABxs_CvTWUmZQ2ElLvYNok.gz6NjyEFNm_vm8Gj6FwoFQ.Jf5p9-ZhJlJy_IQ_byKFmI0Ro7w7G1QiaZpI8OaiVgD8EqoDZHyFKFBupS8iaEeVIgMqWmsuJKuoVgzR3YfzoMd3GxEm3VxNhzWyWtZKX0gxKdy6HgLvqoGNbZCzLjqcpDiF8q2_62EVAbr2uSc2oaxFmFuIQHLcqAHxy51449xkjZ7ewzZaGV3eFqhpco8o4DijXaG5_7kp3h2cajRfDgymuxUbWgLqaeNQaJtvJmSMFuEOSAzw9Hdeb6yhdTynCRmu-kqtO5Dec4lT2OMZKpnxc_F1_4yDJFcqb5CiDSmA-psB2k0JtjxAj4UPI61oONK7zzFIu4gBfjJCndsZfdvG7h8wGjV98QhrKEnR7xKZ3KCr0_qR1B-gxpNk3xWU.DKW7jrb4WaRSNfbXVPlT5g', - json: { - recipients: [ - { - encrypted_key: 'lJf3HbOApxMEBkCMOoTnnABxs_CvTWUmZQ2ElLvYNok' - } - ], - protected: 'eyJhbGciOiJBMjU2R0NNS1ciLCJraWQiOiIxOGVjMDhlMS1iZmE5LTRkOTUtYjIwNS0yYjRkZDFkNDMyMWQiLCJ0YWciOiJrZlBkdVZRM1QzSDZ2bmV3dC0ta3N3IiwiaXYiOiJLa1lUMEdYXzJqSGxmcU5fIiwiZW5jIjoiQTEyOENCQy1IUzI1NiJ9', - iv: 'gz6NjyEFNm_vm8Gj6FwoFQ', - ciphertext: 'Jf5p9-ZhJlJy_IQ_byKFmI0Ro7w7G1QiaZpI8OaiVgD8EqoDZHyFKFBupS8iaEeVIgMqWmsuJKuoVgzR3YfzoMd3GxEm3VxNhzWyWtZKX0gxKdy6HgLvqoGNbZCzLjqcpDiF8q2_62EVAbr2uSc2oaxFmFuIQHLcqAHxy51449xkjZ7ewzZaGV3eFqhpco8o4DijXaG5_7kp3h2cajRfDgymuxUbWgLqaeNQaJtvJmSMFuEOSAzw9Hdeb6yhdTynCRmu-kqtO5Dec4lT2OMZKpnxc_F1_4yDJFcqb5CiDSmA-psB2k0JtjxAj4UPI61oONK7zzFIu4gBfjJCndsZfdvG7h8wGjV98QhrKEnR7xKZ3KCr0_qR1B-gxpNk3xWU', - tag: 'DKW7jrb4WaRSNfbXVPlT5g' - }, - json_flat: { - protected: 'eyJhbGciOiJBMjU2R0NNS1ciLCJraWQiOiIxOGVjMDhlMS1iZmE5LTRkOTUtYjIwNS0yYjRkZDFkNDMyMWQiLCJ0YWciOiJrZlBkdVZRM1QzSDZ2bmV3dC0ta3N3IiwiaXYiOiJLa1lUMEdYXzJqSGxmcU5fIiwiZW5jIjoiQTEyOENCQy1IUzI1NiJ9', - encrypted_key: 'lJf3HbOApxMEBkCMOoTnnABxs_CvTWUmZQ2ElLvYNok', - iv: 'gz6NjyEFNm_vm8Gj6FwoFQ', - ciphertext: 'Jf5p9-ZhJlJy_IQ_byKFmI0Ro7w7G1QiaZpI8OaiVgD8EqoDZHyFKFBupS8iaEeVIgMqWmsuJKuoVgzR3YfzoMd3GxEm3VxNhzWyWtZKX0gxKdy6HgLvqoGNbZCzLjqcpDiF8q2_62EVAbr2uSc2oaxFmFuIQHLcqAHxy51449xkjZ7ewzZaGV3eFqhpco8o4DijXaG5_7kp3h2cajRfDgymuxUbWgLqaeNQaJtvJmSMFuEOSAzw9Hdeb6yhdTynCRmu-kqtO5Dec4lT2OMZKpnxc_F1_4yDJFcqb5CiDSmA-psB2k0JtjxAj4UPI61oONK7zzFIu4gBfjJCndsZfdvG7h8wGjV98QhrKEnR7xKZ3KCr0_qR1B-gxpNk3xWU', - tag: 'DKW7jrb4WaRSNfbXVPlT5g' - } - } -} diff --git a/test/cookbook/recipes/5_8.key_wrap_using_aes-keywrap_with_aes-gcm.js b/test/cookbook/recipes/5_8.key_wrap_using_aes-keywrap_with_aes-gcm.js deleted file mode 100644 index 7d607f4874..0000000000 --- a/test/cookbook/recipes/5_8.key_wrap_using_aes-keywrap_with_aes-gcm.js +++ /dev/null @@ -1,43 +0,0 @@ -module.exports = { - title: 'Key Wrap using AES-KeyWrap with AES-GCM', - input: { - plaintext: Buffer.from('You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.'), - key: { - kty: 'oct', - kid: '81b20965-8332-43d9-a468-82160ad91ac8', - use: 'enc', - alg: 'A128KW', - k: 'GZy6sIZ6wl9NJOKB-jnmVQ' - }, - alg: 'A128KW', - enc: 'A128GCM' - }, - encrypting_content: { - protected: { - alg: 'A128KW', - kid: '81b20965-8332-43d9-a468-82160ad91ac8', - enc: 'A128GCM' - } - }, - output: { - compact: 'eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIn0.CBI6oDw8MydIx1IBntf_lQcw2MmJKIQx.Qx0pmsDa8KnJc9Jo.AwliP-KmWgsZ37BvzCefNen6VTbRK3QMA4TkvRkH0tP1bTdhtFJgJxeVmJkLD61A1hnWGetdg11c9ADsnWgL56NyxwSYjU1ZEHcGkd3EkU0vjHi9gTlb90qSYFfeF0LwkcTtjbYKCsiNJQkcIp1yeM03OmuiYSoYJVSpf7ej6zaYcMv3WwdxDFl8REwOhNImk2Xld2JXq6BR53TSFkyT7PwVLuq-1GwtGHlQeg7gDT6xW0JqHDPn_H-puQsmthc9Zg0ojmJfqqFvETUxLAF-KjcBTS5dNy6egwkYtOt8EIHK-oEsKYtZRaa8Z7MOZ7UGxGIMvEmxrGCPeJa14slv2-gaqK0kEThkaSqdYw0FkQZF.ER7MWJZ1FBI_NKvn7Zb1Lw', - json: { - recipients: [ - { - encrypted_key: 'CBI6oDw8MydIx1IBntf_lQcw2MmJKIQx' - } - ], - protected: 'eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIn0', - iv: 'Qx0pmsDa8KnJc9Jo', - ciphertext: 'AwliP-KmWgsZ37BvzCefNen6VTbRK3QMA4TkvRkH0tP1bTdhtFJgJxeVmJkLD61A1hnWGetdg11c9ADsnWgL56NyxwSYjU1ZEHcGkd3EkU0vjHi9gTlb90qSYFfeF0LwkcTtjbYKCsiNJQkcIp1yeM03OmuiYSoYJVSpf7ej6zaYcMv3WwdxDFl8REwOhNImk2Xld2JXq6BR53TSFkyT7PwVLuq-1GwtGHlQeg7gDT6xW0JqHDPn_H-puQsmthc9Zg0ojmJfqqFvETUxLAF-KjcBTS5dNy6egwkYtOt8EIHK-oEsKYtZRaa8Z7MOZ7UGxGIMvEmxrGCPeJa14slv2-gaqK0kEThkaSqdYw0FkQZF', - tag: 'ER7MWJZ1FBI_NKvn7Zb1Lw' - }, - json_flat: { - protected: 'eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIn0', - encrypted_key: 'CBI6oDw8MydIx1IBntf_lQcw2MmJKIQx', - iv: 'Qx0pmsDa8KnJc9Jo', - ciphertext: 'AwliP-KmWgsZ37BvzCefNen6VTbRK3QMA4TkvRkH0tP1bTdhtFJgJxeVmJkLD61A1hnWGetdg11c9ADsnWgL56NyxwSYjU1ZEHcGkd3EkU0vjHi9gTlb90qSYFfeF0LwkcTtjbYKCsiNJQkcIp1yeM03OmuiYSoYJVSpf7ej6zaYcMv3WwdxDFl8REwOhNImk2Xld2JXq6BR53TSFkyT7PwVLuq-1GwtGHlQeg7gDT6xW0JqHDPn_H-puQsmthc9Zg0ojmJfqqFvETUxLAF-KjcBTS5dNy6egwkYtOt8EIHK-oEsKYtZRaa8Z7MOZ7UGxGIMvEmxrGCPeJa14slv2-gaqK0kEThkaSqdYw0FkQZF', - tag: 'ER7MWJZ1FBI_NKvn7Zb1Lw' - } - } -} diff --git a/test/cookbook/recipes/5_9.compressed_content.js b/test/cookbook/recipes/5_9.compressed_content.js deleted file mode 100644 index 2bd04c064b..0000000000 --- a/test/cookbook/recipes/5_9.compressed_content.js +++ /dev/null @@ -1,46 +0,0 @@ -module.exports = { - title: 'Compressed Content', - reproducible: true, - input: { - plaintext: Buffer.from('You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.'), - key: { - kty: 'oct', - kid: '81b20965-8332-43d9-a468-82160ad91ac8', - use: 'enc', - alg: 'A128KW', - k: 'GZy6sIZ6wl9NJOKB-jnmVQ' - }, - alg: 'A128KW', - enc: 'A128GCM', - zip: 'DEF' - }, - encrypting_content: { - protected: { - alg: 'A128KW', - kid: '81b20965-8332-43d9-a468-82160ad91ac8', - enc: 'A128GCM', - zip: 'DEF' - } - }, - output: { - compact: 'eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIiwiemlwIjoiREVGIn0.5vUT2WOtQxKWcekM_IzVQwkGgzlFDwPi.p9pUq6XHY0jfEZIl.HbDtOsdai1oYziSx25KEeTxmwnh8L8jKMFNc1k3zmMI6VB8hry57tDZ61jXyezSPt0fdLVfe6Jf5y5-JaCap_JQBcb5opbmT60uWGml8blyiMQmOn9J--XhhlYg0m-BHaqfDO5iTOWxPxFMUedx7WCy8mxgDHj0aBMG6152PsM-w5E_o2B3jDbrYBKhpYA7qi3AyijnCJ7BP9rr3U8kxExCpG3mK420TjOw.VILuUwuIxaLVmh5X-T7kmA', - json: { - recipients: [ - { - encrypted_key: '5vUT2WOtQxKWcekM_IzVQwkGgzlFDwPi' - } - ], - protected: 'eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIiwiemlwIjoiREVGIn0', - iv: 'p9pUq6XHY0jfEZIl', - ciphertext: 'HbDtOsdai1oYziSx25KEeTxmwnh8L8jKMFNc1k3zmMI6VB8hry57tDZ61jXyezSPt0fdLVfe6Jf5y5-JaCap_JQBcb5opbmT60uWGml8blyiMQmOn9J--XhhlYg0m-BHaqfDO5iTOWxPxFMUedx7WCy8mxgDHj0aBMG6152PsM-w5E_o2B3jDbrYBKhpYA7qi3AyijnCJ7BP9rr3U8kxExCpG3mK420TjOw', - tag: 'VILuUwuIxaLVmh5X-T7kmA' - }, - json_flat: { - protected: 'eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIiwiemlwIjoiREVGIn0', - encrypted_key: '5vUT2WOtQxKWcekM_IzVQwkGgzlFDwPi', - iv: 'p9pUq6XHY0jfEZIl', - ciphertext: 'HbDtOsdai1oYziSx25KEeTxmwnh8L8jKMFNc1k3zmMI6VB8hry57tDZ61jXyezSPt0fdLVfe6Jf5y5-JaCap_JQBcb5opbmT60uWGml8blyiMQmOn9J--XhhlYg0m-BHaqfDO5iTOWxPxFMUedx7WCy8mxgDHj0aBMG6152PsM-w5E_o2B3jDbrYBKhpYA7qi3AyijnCJ7BP9rr3U8kxExCpG3mK420TjOw', - tag: 'VILuUwuIxaLVmh5X-T7kmA' - } - } -} diff --git a/test/cookbook/recipes/index.js b/test/cookbook/recipes/index.js deleted file mode 100644 index eb65571c7f..0000000000 --- a/test/cookbook/recipes/index.js +++ /dev/null @@ -1,32 +0,0 @@ -module.exports = new Map([ - ['3.1', require('./3_1.ec_public_key')], - ['3.2', require('./3_2.ec_private_key')], - ['3.3', require('./3_3.rsa_public_key')], - ['3.4', require('./3_4.rsa_private_key')], - ['3.5', require('./3_5.symmetric_key_mac_computation')], - ['3.6', require('./3_6.symmetric_key_encryption')], - ['4.1', require('./4_1.rsa_v15_signature')], - ['4.2', require('./4_2.rsa-pss_signature')], - ['4.3', require('./4_3.ecdsa_signature')], - ['4.4', require('./4_4.hmac-sha2_integrity_protection')], - ['4.6', require('./4_6.protecting_specific_header_fields')], - ['4.7', require('./4_7.protecting_content_only')], - ['4.8', require('./4_8.multiple_signatures')], - ['5.1', require('./5_1.key_encryption_using_rsa_v15_and_aes-hmac-sha2')], - ['5.2', require('./5_2.key_encryption_using_rsa-oaep_with_aes-gcm')], - ['5.3', require('./5_3.key_wrap_using_pbes2-aes-keywrap_with-aes-cbc-hmac-sha2')], - ['5.4', require('./5_4.key_agreement_with_key_wrapping_using_ecdh-es_and_aes-keywrap_with_aes-gcm')], - ['5.5', require('./5_5.key_agreement_using_ecdh-es_with_aes-cbc-hmac-sha2')], - ['5.6', require('./5_6.direct_encryption_using_aes-gcm')], - ['5.7', require('./5_7.key_wrap_using_aes-gcm_keywrap_with_aes-cbc-hmac-sha2')], - ['5.8', require('./5_8.key_wrap_using_aes-keywrap_with_aes-gcm')], - ['5.9', require('./5_9.compressed_content')], - ['5.10', require('./5_10.including_additional_authentication_data')], - ['5.11', require('./5_11.protecting_specific_header_fields')], - ['5.12', require('./5_12.protecting_content_only')], - ['5.13', require('./5_13.encrypting_to_multiple_recipients')], - ['4.1 rfc7797', require('./rfc7797.4_1.hmac-sha2_b64_false')], - ['4.2 rfc7797', require('./rfc7797.4_2.hmac-sha2_b64_false')], - ['A.4 rfc8037', require('./rfc8037.a4.ed25519')], - ['ml-oeap-256', require('./ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256')] -]) diff --git a/test/cookbook/recipes/ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256.js b/test/cookbook/recipes/ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256.js deleted file mode 100644 index 6e3f36ef4c..0000000000 --- a/test/cookbook/recipes/ml.key_encryption_using_rsa-oaep-256_with_a128cbc-hs256.js +++ /dev/null @@ -1,46 +0,0 @@ -module.exports = { - title: 'Key Encryption using RSA-OAEP-256 with AES_CBC_HMAC_SHA2', - input: { - plaintext: Buffer.from("Well, as of this moment, they're on DOUBLE SECRET PROBATION!"), - key: { - e: 'AQAB', - n: '2cQJH1f6yF9DcGa8Cmbnhn4LHLs5L6kNb2rxkrNFZArJLRaKvaC3tMCKZ8ZgIpO9bVMPx5UMjJoaf7p9O5BSApVqA2J10fUbdSIomCcDwvGo0eyhty0DILLWTMXzGEVM3BXzuJQoeDkuUCXXcCwA4Msyyd2OHVu-pB2OrGv6fcjHwjINty3UoKm08lCvAevBKHsuA-FFwQII9bycvRx5wRqFUjdMAyiOmLYBHBaJSi11g3HVexMcb29v14PSlVzdGUMN8oboa-zcIyaPrIiczLqAkSXQNdEFHrjsJHfFeNMfOblLM7icKN_tyWujYeItt4kqUIimPn5dHjwgcQYE7w', - d: 'dyUz3ItVceX1Tv1WqtZMnKA_0jN5gWMcL7ayf5JISAlCssGfnUre2C10TH0UQjbVMIh-nLMnD5KNJw9Qz5MR28oGG932Gq7hm__ZeA34l-OCe4DdpgwhpvVSHOU9MS1RdSUpmPavAcA_X6ikrAHXZSaoHhxzUgrNTpvBYQMfJUv_492fStIseQ9rwAMOpCWOiWMZOQm3KJVTLLunXdKf_UxmzmKXYKYZWke3AWIzUqnOfqIjfDTMunF4UWU0zKlhcsaQNmYMVrJGajD1bJdy_dbUU3LE8sx-bdkUI6oBk-sFtTTVyVdQcetG9kChJ5EnY5R6tt_4_xFG5kxzTo6qaQ', - p: '7yQmgE60SL7QrXpAJhChLgKnXWi6C8tVx1lA8FTpphpLaCtK-HbgBVHCprC2CfaM1mxFJZahxgFjC9ehuV8OzMNyFs8kekS82EsQGksi8HJPxyR1fU6ATa36ogPG0nNaqm3EDmYyjowhntgBz2OkbFAsTMHTdna-pZBRJa9lm5U', - q: '6R4dzo9LwHLO73EMQPQsmwXjVOvAS5W6rgQ-BCtMhec_QosAXIVE3AGyfweqZm6rurXCVFykDLwJ30GepLQ8nTlzeV6clx0x70saGGKKVmCsHuVYWwgIRyJTrt4SX29NQDZ_FE52NlO3OhPkj1ExSk_pGMqGRFd26K8g0jJsXXM', - dp: 'VByn-hs0qB2Ncmb8ZycUOgWu7ljmjz1up1ZKU_3ZzJWVDkej7-6H7vcJ-u1OqgRxFv4v9_-aWPWl68VlWbkIkJbx6vniv6qrrXwBZu4klOPwEYBOXsucrzXRYOjpJp5yNl2zRslFYQQC00bwpAxNCdfNLRZDlXhAqCUxlYqyt10', - dq: 'MJFbuGtWZvQEdRJicS3uFSY25LxxRc4eJJ8xpIC44rT5Ew4Otzf0zrlzzM92Cv1HvhCcOiNK8nRCwkbTnJEIh-EuU70IdttYSfilqSruk2x0r8Msk1qrDtbyBF60CToRKC2ycDKgolTyuaDnX4yU7lyTvdyD-L0YQwYpmmFy_k0', - qi: 'vy7XCwZ3jyMGik81TIZDAOQKC8FVUc0TG5KVYfti4tgwzUqFwtuB8Oc1ctCKRbE7uZUPwZh4OsCTLqIvqBQda_kaxOxo5EF7iXj6yHmZ2s8P_Z_u3JLuh-oAT_6kmbLx6CAO0DbtKtxp24Ivc1hDfqSwWORgN1AOrSRCmE3nwxg', - kty: 'RSA' - }, - alg: 'RSA-OAEP-256', - enc: 'A128CBC-HS256' - }, - encrypting_content: { - protected: { - alg: 'RSA-OAEP-256', - enc: 'A128CBC-HS256' - } - }, - output: { - compact: 'eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.fL5IL5cMCjjU9G9_ZjsD2XO0HIwTOwbVwulcZVw31_rx2qTcHzbYhIvrvbcVLTfJzn8xbQ3UEL442ZgZ1PcFYKENYePXiEyvYxPN8dmvj_OfLSJDEqR6kvwOb6nghGtxfzdB_VRvFt2eehbCA3gWpiOYHHvSTFdBPGx2KZHQisLz3oZR8EWiZ1woEpHy8a7FoQ2zzuDlZEJQOUrh09b_EJxmcE2jL6wmEtgabyxy3VgWg3GqSPUISlJZV9HThuVJezzktJdpntRDnAPUqjc8IwByGpMleIQcPuBUseRRPr_OsroOJ6eTl5DuFCmBOKb-eNNw5v-GEcVYr1w7X9oXoA.0frdIwx8P8UAzh1s9_PgOA.RAzILH0xfs0yxzML1CzzGExCfE2_wzWKs0FVuXfM8R5H68yTqTbqIqRCp2feAH5GSvluzmztk2_CkGNSjAyoaw.4nMUXOgmgWvM-08tIZ-h5w', - json: { - recipients: [ - { - encrypted_key: 'fL5IL5cMCjjU9G9_ZjsD2XO0HIwTOwbVwulcZVw31_rx2qTcHzbYhIvrvbcVLTfJzn8xbQ3UEL442ZgZ1PcFYKENYePXiEyvYxPN8dmvj_OfLSJDEqR6kvwOb6nghGtxfzdB_VRvFt2eehbCA3gWpiOYHHvSTFdBPGx2KZHQisLz3oZR8EWiZ1woEpHy8a7FoQ2zzuDlZEJQOUrh09b_EJxmcE2jL6wmEtgabyxy3VgWg3GqSPUISlJZV9HThuVJezzktJdpntRDnAPUqjc8IwByGpMleIQcPuBUseRRPr_OsroOJ6eTl5DuFCmBOKb-eNNw5v-GEcVYr1w7X9oXoA' - } - ], - protected: 'eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0', - iv: '0frdIwx8P8UAzh1s9_PgOA', - ciphertext: 'RAzILH0xfs0yxzML1CzzGExCfE2_wzWKs0FVuXfM8R5H68yTqTbqIqRCp2feAH5GSvluzmztk2_CkGNSjAyoaw', - tag: '4nMUXOgmgWvM-08tIZ-h5w' - }, - json_flat: { - protected: 'eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0', - encrypted_key: 'fL5IL5cMCjjU9G9_ZjsD2XO0HIwTOwbVwulcZVw31_rx2qTcHzbYhIvrvbcVLTfJzn8xbQ3UEL442ZgZ1PcFYKENYePXiEyvYxPN8dmvj_OfLSJDEqR6kvwOb6nghGtxfzdB_VRvFt2eehbCA3gWpiOYHHvSTFdBPGx2KZHQisLz3oZR8EWiZ1woEpHy8a7FoQ2zzuDlZEJQOUrh09b_EJxmcE2jL6wmEtgabyxy3VgWg3GqSPUISlJZV9HThuVJezzktJdpntRDnAPUqjc8IwByGpMleIQcPuBUseRRPr_OsroOJ6eTl5DuFCmBOKb-eNNw5v-GEcVYr1w7X9oXoA', - iv: '0frdIwx8P8UAzh1s9_PgOA', - ciphertext: 'RAzILH0xfs0yxzML1CzzGExCfE2_wzWKs0FVuXfM8R5H68yTqTbqIqRCp2feAH5GSvluzmztk2_CkGNSjAyoaw', - tag: '4nMUXOgmgWvM-08tIZ-h5w' - } - } -} diff --git a/test/cookbook/recipes/rfc7797.4_1.hmac-sha2_b64_false.js b/test/cookbook/recipes/rfc7797.4_1.hmac-sha2_b64_false.js deleted file mode 100644 index 7f29c80760..0000000000 --- a/test/cookbook/recipes/rfc7797.4_1.hmac-sha2_b64_false.js +++ /dev/null @@ -1,37 +0,0 @@ -module.exports = { - title: '"b64"=false compatible with compact serialization', - reproducible: true, - input: { - payload: 'This is the payload string!', - key: { - kty: 'oct', - alg: 'HS256', - k: 'AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow' - }, - alg: 'HS256' - }, - signing: { - protected: { - alg: 'HS256', - b64: false, - crit: ['b64'] - } - }, - output: { - compact: 'eyJhbGciOiJIUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19.This is the payload string!.ciks0B6Hs-amhOqxI5_iG6mPKnMDlWCb7J2Wu7mtIcg', - json: { - payload: 'This is the payload string!', - signatures: [ - { - protected: 'eyJhbGciOiJIUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19', - signature: 'ciks0B6Hs-amhOqxI5_iG6mPKnMDlWCb7J2Wu7mtIcg' - } - ] - }, - json_flat: { - payload: 'This is the payload string!', - protected: 'eyJhbGciOiJIUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19', - signature: 'ciks0B6Hs-amhOqxI5_iG6mPKnMDlWCb7J2Wu7mtIcg' - } - } -} diff --git a/test/cookbook/recipes/rfc7797.4_2.hmac-sha2_b64_false.js b/test/cookbook/recipes/rfc7797.4_2.hmac-sha2_b64_false.js deleted file mode 100644 index 37f5a33371..0000000000 --- a/test/cookbook/recipes/rfc7797.4_2.hmac-sha2_b64_false.js +++ /dev/null @@ -1,36 +0,0 @@ -module.exports = { - title: '"b64"=false JSON only', - reproducible: true, - input: { - payload: '$.02', - key: { - kty: 'oct', - alg: 'HS256', - k: 'AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow' - }, - alg: 'HS256' - }, - signing: { - protected: { - alg: 'HS256', - b64: false, - crit: ['b64'] - } - }, - output: { - json: { - payload: '$.02', - signatures: [ - { - protected: 'eyJhbGciOiJIUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19', - signature: 'A5dxf2s96_n5FLueVuW1Z_vh161FwXZC4YLPff6dmDY' - } - ] - }, - json_flat: { - payload: '$.02', - protected: 'eyJhbGciOiJIUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19', - signature: 'A5dxf2s96_n5FLueVuW1Z_vh161FwXZC4YLPff6dmDY' - } - } -} diff --git a/test/cookbook/recipes/rfc8037.a4.ed25519.js b/test/cookbook/recipes/rfc8037.a4.ed25519.js deleted file mode 100644 index e73e1b4910..0000000000 --- a/test/cookbook/recipes/rfc8037.a4.ed25519.js +++ /dev/null @@ -1,35 +0,0 @@ -module.exports = { - title: 'Ed25519 Signature', - input: { - payload: Buffer.from('Example of Ed25519 signing'), - key: { - kty: 'OKP', - crv: 'Ed25519', - d: 'nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A', - x: '11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo' - }, - alg: 'EdDSA' - }, - signing: { - protected: { - alg: 'EdDSA' - } - }, - output: { - compact: 'eyJhbGciOiJFZERTQSJ9.RXhhbXBsZSBvZiBFZDI1NTE5IHNpZ25pbmc.hgyY0il_MGCjP0JzlnLWG1PPOt7-09PGcvMg3AIbQR6dWbhijcNR4ki4iylGjg5BhVsPt9g7sVvpAr_MuM0KAg', - json: { - payload: 'RXhhbXBsZSBvZiBFZDI1NTE5IHNpZ25pbmc', - signatures: [ - { - protected: 'eyJhbGciOiJFZERTQSJ9', - signature: 'hgyY0il_MGCjP0JzlnLWG1PPOt7-09PGcvMg3AIbQR6dWbhijcNR4ki4iylGjg5BhVsPt9g7sVvpAr_MuM0KAg' - } - ] - }, - json_flat: { - payload: 'RXhhbXBsZSBvZiBFZDI1NTE5IHNpZ25pbmc', - protected: 'eyJhbGciOiJFZERTQSJ9', - signature: 'hgyY0il_MGCjP0JzlnLWG1PPOt7-09PGcvMg3AIbQR6dWbhijcNR4ki4iylGjg5BhVsPt9g7sVvpAr_MuM0KAg' - } - } -} diff --git a/test/cookbook/rfc7797.4_1.hmac-sha2_b64_false.test.js b/test/cookbook/rfc7797.4_1.hmac-sha2_b64_false.test.js deleted file mode 100644 index 89e05374db..0000000000 --- a/test/cookbook/rfc7797.4_1.hmac-sha2_b64_false.test.js +++ /dev/null @@ -1,88 +0,0 @@ -const test = require('ava') - -const recipe = require('./recipes').get('4.1 rfc7797') - -const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - -const { input: { payload, key: jwk }, signing: { protected: header } } = recipe - -const key = asKey(jwk) - -const keystoreEmpty = new KeyStore() -const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) -const keystoreMatchNone = new KeyStore(generateSync('EC'), generateSync('RSA')) - -test(`${recipe.title} - compact sign`, t => { - t.is(JWS.sign(payload, key, header), recipe.output.compact) -}) - -test(`${recipe.title} - flattened sign`, t => { - t.deepEqual(JWS.sign.flattened(payload, key, header), recipe.output.json_flat) -}) - -test(`${recipe.title} - general sign`, t => { - t.deepEqual(JWS.sign.general(payload, key, header), recipe.output.json) -}) - -test(`${recipe.title} - compact verify`, t => { - t.deepEqual(JWS.verify(recipe.output.compact, key, { crit: ['b64'] }), Buffer.from(payload)) -}) - -test(`${recipe.title} - flattened verify`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, key, { crit: ['b64'] }), Buffer.from(payload)) -}) - -test(`${recipe.title} - general verify`, t => { - t.deepEqual(JWS.verify(recipe.output.json, key, { crit: ['b64'] }), Buffer.from(payload)) -}) - -;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - compact verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.compact, keystore, { crit: ['b64'] }), Buffer.from(payload)) - }) - - test(`${recipe.title} - flattened verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, keystore, { crit: ['b64'] }), Buffer.from(payload)) - }) - - test(`${recipe.title} - general verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json, keystore, { crit: ['b64'] }), Buffer.from(payload)) - }) -}) - -test(`${recipe.title} - compact verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.compact, keystoreMatchNone, { crit: ['b64'] }) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY' }) -}) - -test(`${recipe.title} - flattened verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreMatchNone, { crit: ['b64'] }) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY' }) -}) - -test(`${recipe.title} - general verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreMatchNone, { crit: ['b64'] }) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY' }) -}) - -test(`${recipe.title} - compact verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.compact, keystoreEmpty, { crit: ['b64'] }) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - flattened verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreEmpty, { crit: ['b64'] }) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreEmpty, { crit: ['b64'] }) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) diff --git a/test/cookbook/rfc7797.4_2.hmac-sha2_b64_false.test.js b/test/cookbook/rfc7797.4_2.hmac-sha2_b64_false.test.js deleted file mode 100644 index 7304c8e0a2..0000000000 --- a/test/cookbook/rfc7797.4_2.hmac-sha2_b64_false.test.js +++ /dev/null @@ -1,64 +0,0 @@ -const test = require('ava') - -const recipe = require('./recipes').get('4.2 rfc7797') - -const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - -const { input: { payload, key: jwk }, signing: { protected: header } } = recipe - -const key = asKey(jwk) - -const keystoreEmpty = new KeyStore() -const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) -const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) -const keystoreMatchNone = new KeyStore(generateSync(key.kty), generateSync(key.kty)) - -test(`${recipe.title} - flattened sign`, t => { - t.deepEqual(JWS.sign.flattened(payload, key, header), recipe.output.json_flat) -}) - -test(`${recipe.title} - general sign`, t => { - t.deepEqual(JWS.sign.general(payload, key, header), recipe.output.json) -}) - -test(`${recipe.title} - flattened verify`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, key, { crit: ['b64'] }), Buffer.from(payload)) -}) - -test(`${recipe.title} - general verify`, t => { - t.deepEqual(JWS.verify(recipe.output.json, key, { crit: ['b64'] }), Buffer.from(payload)) -}) - -;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - flattened verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, keystore, { crit: ['b64'] }), Buffer.from(payload)) - }) - - test(`${recipe.title} - general verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json, keystore, { crit: ['b64'] }), Buffer.from(payload)) - }) -}) - -test(`${recipe.title} - flattened verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreMatchNone, { crit: ['b64'] }) - }, { instanceOf: errors.JWSVerificationFailed, code: 'ERR_JWS_VERIFICATION_FAILED' }) -}) - -test(`${recipe.title} - general verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreMatchNone, { crit: ['b64'] }) - }, { instanceOf: errors.JWSVerificationFailed, code: 'ERR_JWS_VERIFICATION_FAILED' }) -}) - -test(`${recipe.title} - flattened verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreEmpty, { crit: ['b64'] }) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) - -test(`${recipe.title} - general verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreEmpty, { crit: ['b64'] }) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) -}) diff --git a/test/cookbook/rfc8037.a4.ed25519.test.js b/test/cookbook/rfc8037.a4.ed25519.test.js deleted file mode 100644 index 4f676403d0..0000000000 --- a/test/cookbook/rfc8037.a4.ed25519.test.js +++ /dev/null @@ -1,96 +0,0 @@ -const test = require('ava') - -const { edDSASupported } = require('../../lib/help/runtime_support') - -if (edDSASupported) { - const recipe = require('./recipes').get('A.4 rfc8037') - - const { JWS, JWK: { asKey, generateSync }, JWKS: { KeyStore }, errors } = require('../..') - - const { input: { payload, key: jwk }, signing: { protected: header } } = recipe - - const key = asKey(jwk) - - test('OKP JWK Thumbprint Canonicalization', t => { - t.is(key.kid, 'kPrK_qmxVWaYVA9wwBF6Iuo3vVzz7TxHCTwXBygrS4k') - }) - - const keystoreEmpty = new KeyStore() - const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) - const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, asKey(key)) - const keystoreMatchNone = new KeyStore(generateSync('EC'), generateSync('RSA')) - - test(`${recipe.title} - compact sign`, t => { - t.is(JWS.sign(payload, key, header), recipe.output.compact) - }) - - test(`${recipe.title} - flattened sign`, t => { - t.deepEqual(JWS.sign.flattened(payload, key, header), recipe.output.json_flat) - }) - - test(`${recipe.title} - general sign`, t => { - t.deepEqual(JWS.sign.general(payload, key, header), recipe.output.json) - }) - - test(`${recipe.title} - compact verify`, t => { - t.deepEqual(JWS.verify(recipe.output.compact, key), payload) - }) - - test(`${recipe.title} - flattened verify`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, key), payload) - }) - - test(`${recipe.title} - general verify`, t => { - t.deepEqual(JWS.verify(recipe.output.json, key), payload) - }) - - ;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { - test(`${recipe.title} - compact verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.compact, keystore), payload) - }) - - test(`${recipe.title} - flattened verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json_flat, keystore), payload) - }) - - test(`${recipe.title} - general verify (using keystore ${i + 1}/2)`, t => { - t.deepEqual(JWS.verify(recipe.output.json, keystore), payload) - }) - }) - - test(`${recipe.title} - compact verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.compact, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY' }) - }) - - test(`${recipe.title} - flattened verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY' }) - }) - - test(`${recipe.title} - general verify (failing)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreMatchNone) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY' }) - }) - - test(`${recipe.title} - compact verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.compact, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - flattened verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json_flat, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) - - test(`${recipe.title} - general verify (using empty keystore)`, t => { - t.throws(() => { - JWS.verify(recipe.output.json, keystoreEmpty) - }, { instanceOf: errors.JWKSNoMatchingKey, code: 'ERR_JWKS_NO_MATCHING_KEY', message: 'no matching key found in the KeyStore' }) - }) -} diff --git a/test/cookbook/rfc8037.ecdhes.test.js b/test/cookbook/rfc8037.ecdhes.test.js deleted file mode 100644 index c43831b704..0000000000 --- a/test/cookbook/rfc8037.ecdhes.test.js +++ /dev/null @@ -1,42 +0,0 @@ -const test = require('ava') - -const { improvedDH } = require('../../lib/help/runtime_support') - -if (improvedDH) { - const { JWK: { asKey } } = require('../..') - const computeSecret = require('../../lib/jwa/ecdh/compute_secret') - - test('RFC8037 - A.6. ECDH-ES with X25519', t => { - const pub = asKey({ - kty: 'OKP', - crv: 'X25519', - x: '3p7bfXt9wbTTW2HC7OQ1Nz-DQ8hbeGdNrfx-FG-IK08' - }) - - const ephemeral = asKey({ - kty: 'OKP', - crv: 'X25519', - x: 'hSDwCYkwp1R0i33ctD73Wg2_Og0mOBr066SpjqqbTmo', - d: 'dwdtCnMYpX08FsFyUbJmRd9ML4frwJkqsXf7pR25LCo' - }) - - t.deepEqual(computeSecret(ephemeral, pub), Buffer.from('4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742', 'hex')) - }) - - test('RFC8037 - A.6. ECDH-ES with X448', t => { - const pub = asKey({ - kty: 'OKP', - crv: 'X448', - x: 'PreoKbDNIPW8_AtZm2_sz22kYnEHvbDU80W0MCfYuXL8PjT7QjKhPKcG3LV67D2uB73BxnvzNgk' - }) - - const ephemeral = asKey({ - kty: 'OKP', - crv: 'X448', - x: 'mwj3zDG34-Z9ItWuoSEHSic70rg94Jxj-qc9LCLF2bvINmRyQdlT1AxbEtqIEg1TF3-A5TLEH6A', - d: 'mo9JJdFRn1d1z0awS1gA1O6e6LrovFVl1JjCjdnJuvV0qUGXRIlzkQBjgqbxJ6sdmsLYwKWYcms' - }) - - t.deepEqual(computeSecret(ephemeral, pub), Buffer.from('07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d', 'hex')) - }) -} diff --git a/test/cookbook/verifiers.js b/test/cookbook/verifiers.js deleted file mode 100644 index 00b877973a..0000000000 --- a/test/cookbook/verifiers.js +++ /dev/null @@ -1,136 +0,0 @@ -const base64url = require('../../lib/help/base64url') -const withoutRandom = ({ p2s, p2c, epk, iv, tag, ...rest } = {}) => rest -const decodeWithoutRandom = (input) => { - return withoutRandom(base64url.JSON.decode(input)) -} - -module.exports = { - enc: { - compact (t, actual, expected) { - const partsA = actual.split('.') - const partsE = expected.split('.') - - partsE.forEach((part, i) => { - t.is(partsA[i].length, part.length) - if (i === 0) { - t.deepEqual(decodeWithoutRandom(partsA[i]), decodeWithoutRandom(part)) - } - }) - }, - flattened (t, actual, expected) { - t.deepEqual(Object.keys(expected).sort(), Object.keys(actual).sort()) - - t.is(!actual.protected ^ !expected.protected, 0) - - if (expected.protected) { - t.is(actual.protected.length, expected.protected.length) - t.deepEqual(decodeWithoutRandom(actual.protected), decodeWithoutRandom(expected.protected)) - } - - t.is(actual.aad, expected.aad) - t.deepEqual(actual.header, expected.header) - t.deepEqual(actual.unprotected, expected.unprotected) - - t.is(!actual.recipients ^ !expected.recipients, 0) - t.is(!actual.encrypted_key ^ !expected.encrypted_key, 0) - - if (expected.encrypted_key) { - t.is(actual.encrypted_key.length, expected.encrypted_key.length) - } - t.is(actual.iv.length, expected.iv.length) - t.is(actual.ciphertext.length, expected.ciphertext.length) - t.is(actual.tag.length, expected.tag.length) - }, - general (t, actual, expected) { - t.deepEqual(Object.keys(expected).sort(), Object.keys(actual).sort()) - - t.is(!actual.protected ^ !expected.protected, 0) - - if (expected.protected) { - t.is(actual.protected.length, expected.protected.length) - t.deepEqual(decodeWithoutRandom(actual.protected), decodeWithoutRandom(expected.protected)) - } - - t.is(actual.aad, expected.aad) - t.deepEqual(actual.unprotected, expected.unprotected) - - t.is(actual.iv.length, expected.iv.length) - t.is(actual.ciphertext.length, expected.ciphertext.length) - t.is(actual.tag.length, expected.tag.length) - - t.is(!actual.recipients ^ !expected.recipients, 0) - - if (actual.recipients) { - t.true(Array.isArray(actual.recipients)) - expected.recipients.forEach((eRecipient, i) => { - const aRecipient = actual.recipients[i] - t.deepEqual(withoutRandom(aRecipient.header), withoutRandom(eRecipient.header)) - t.is(!aRecipient.encrypted_key ^ !eRecipient.encrypted_key, 0) - - if (eRecipient.encrypted_key) { - t.is(aRecipient.encrypted_key.length, eRecipient.encrypted_key.length) - } - }) - } - } - }, - sig: { - compact (t, actual, expected) { - const partsA = actual.split('.') - const partsE = expected.split('.') - - partsE.forEach((part, i) => { - t.is(partsA[i].length, part.length) - if (i === 0) { - t.deepEqual(base64url.JSON.decode(partsA[i]), base64url.JSON.decode(part)) - } - if (i === 1) { - t.deepEqual(partsA[i], part) - } - }) - }, - flattened (t, actual, expected) { - t.deepEqual(Object.keys(expected).sort(), Object.keys(actual).sort()) - - t.is(!actual.protected ^ !expected.protected, 0) - t.is(actual.payload, expected.payload) - - if (expected.protected) { - t.is(actual.protected.length, expected.protected.length) - t.deepEqual(decodeWithoutRandom(actual.protected), decodeWithoutRandom(expected.protected)) - } - - t.deepEqual(actual.header, expected.header) - t.deepEqual(actual.unprotected, expected.unprotected) - - t.is(!actual.signatures ^ !expected.signatures, 0) - }, - general (t, actual, expected) { - t.deepEqual(Object.keys(expected).sort(), Object.keys(actual).sort()) - - t.is(!actual.protected ^ !expected.protected, 0) - - if (expected.protected) { - t.is(actual.protected.length, expected.protected.length) - t.deepEqual(decodeWithoutRandom(actual.protected), decodeWithoutRandom(expected.protected)) - } - t.deepEqual(actual.unprotected, expected.unprotected) - - t.is(!actual.signatures ^ !expected.signatures, 0) - - if (actual.signatures) { - t.true(Array.isArray(actual.signatures)) - expected.signatures.forEach((eRecipient, i) => { - const aRecipient = actual.signatures[i] - t.deepEqual(aRecipient.header, eRecipient.header) - t.deepEqual(aRecipient.protected, eRecipient.protected) - t.is(!aRecipient.signature ^ !eRecipient.signature, 0) - - if (eRecipient.signature) { - t.is(aRecipient.signature.length, eRecipient.signature.length) - } - }) - } - } - } -} diff --git a/test/electron/electron.test.js b/test/electron/electron.test.js deleted file mode 100644 index 3f3621fec0..0000000000 --- a/test/electron/electron.test.js +++ /dev/null @@ -1,29 +0,0 @@ -const test = require('ava') - -if ('electron' in process.versions) { - const crypto = require('crypto') - - const fixtures = require('../fixtures') - - ;['aes128', 'aes192', 'aes256'].forEach((cipher) => { - test(`${cipher} is not supported`, t => { - t.false(crypto.getCiphers().includes(cipher)) - }) - }) - - test('secp256k1 is not supported', t => { - t.false(crypto.getCurves().includes('secp256k1')) - }) - - const unsupported = process.versions.electron.startsWith('6') ? ['Ed448', 'X25519', 'X448'] : ['Ed448', 'X448'] - - // crypto.generateKeyPair('x25519') crashes the process in 7.0.0, that's why X25519 is not enabled - - unsupported.forEach((okp) => { - test(`${okp} is not supported`, t => { - t.throws(() => { - crypto.createPrivateKey(fixtures.PEM[okp].private) - }, { instanceOf: Error, code: 'ERR_OSSL_EVP_UNSUPPORTED_ALGORITHM' }) - }) - }) -} diff --git a/test/electron/index.js b/test/electron/index.js deleted file mode 100644 index 1d99cbfd0d..0000000000 --- a/test/electron/index.js +++ /dev/null @@ -1,3 +0,0 @@ -const { app } = require('electron') -const exit = () => app.exit(process.exitCode) -require('ava/lib/cli').run().then(exit, exit) diff --git a/test/fixtures/Ed25519.key b/test/fixtures/Ed25519.key deleted file mode 100644 index 7075d804fc..0000000000 --- a/test/fixtures/Ed25519.key +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN PRIVATE KEY----- -MC4CAQAwBQYDK2VwBCIEIGpAjr6yJyzkSQbv3KVV7KF7EQTe71Ty2SYB16rX3Dfu ------END PRIVATE KEY----- diff --git a/test/fixtures/Ed25519.pem b/test/fixtures/Ed25519.pem deleted file mode 100644 index b6cd2f3d14..0000000000 --- a/test/fixtures/Ed25519.pem +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN PUBLIC KEY----- -MCowBQYDK2VwAyEAhaCxp2RnxBQne/i7Xf9AUatVj3YFeBWfFZrT4cqVD3U= ------END PUBLIC KEY----- diff --git a/test/fixtures/Ed448.key b/test/fixtures/Ed448.key deleted file mode 100644 index 61bb533a31..0000000000 --- a/test/fixtures/Ed448.key +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PRIVATE KEY----- -MEcCAQAwBQYDK2VxBDsEOco+BEKj1fxqSvUkMOJl6h6X4P2f4HWwFtUQ8MAMV18O -IUMV8/Cd21xvncdI1ElF9ZmjpC4CznRY1A== ------END PRIVATE KEY----- diff --git a/test/fixtures/Ed448.pem b/test/fixtures/Ed448.pem deleted file mode 100644 index 25301691ac..0000000000 --- a/test/fixtures/Ed448.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MEMwBQYDK2VxAzoArkqxt4T5h/1vH3rHp8QEMRuUIPLX+o88wsOu0VcHeX0QRMGk -cmvBcyURZbPjLjJ9x5XBLsQmwJEA ------END PUBLIC KEY----- diff --git a/test/fixtures/P-256.key b/test/fixtures/P-256.key deleted file mode 100644 index dd9e8c4934..0000000000 --- a/test/fixtures/P-256.key +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgHqCdpkULjtDUhxHr -V5L+i8tiT+MBpoHAY5uroRd40Z+hRANCAAT6D0Kuj87LlPx4k8dXDSjZeQsZNx4D -ft9vBxO7YrGnjN6c59HBm2n0LHMtUzIRHV7jky4qVzAoPO8A5b9wNoad ------END PRIVATE KEY----- diff --git a/test/fixtures/P-256.pem b/test/fixtures/P-256.pem deleted file mode 100644 index d8d5034054..0000000000 --- a/test/fixtures/P-256.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+g9Cro/Oy5T8eJPHVw0o2XkLGTce -A37fbwcTu2Kxp4zenOfRwZtp9CxzLVMyER1e45MuKlcwKDzvAOW/cDaGnQ== ------END PUBLIC KEY----- diff --git a/test/fixtures/P-384.key b/test/fixtures/P-384.key deleted file mode 100644 index 69337e638a..0000000000 --- a/test/fixtures/P-384.key +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAFEoEWiEIbdBab9jNn -6jlPWdUzDEXTPtRkiSTBpL8zf/Z4xSKDuHRXJlu1EDjdT4ShZANiAAQn/DX2gISG -2NI2MFRP1ilgLqtPGaZ1htq+ZqHLgQMqTUrA9mXWtt6VpBXpnZ0oe9YQx/BYazg+ -7/G1RXZl/DpKY6l9ktmYslw9esQL+tdHTo2Hf9V/3j7q4oEVjoiKb/s= ------END PRIVATE KEY----- diff --git a/test/fixtures/P-384.pem b/test/fixtures/P-384.pem deleted file mode 100644 index f90764411e..0000000000 --- a/test/fixtures/P-384.pem +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEJ/w19oCEhtjSNjBUT9YpYC6rTxmmdYba -vmahy4EDKk1KwPZl1rbelaQV6Z2dKHvWEMfwWGs4Pu/xtUV2Zfw6SmOpfZLZmLJc -PXrEC/rXR06Nh3/Vf94+6uKBFY6Iim/7 ------END PUBLIC KEY----- diff --git a/test/fixtures/P-521.key b/test/fixtures/P-521.key deleted file mode 100644 index 59cb86a896..0000000000 --- a/test/fixtures/P-521.key +++ /dev/null @@ -1,8 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIBsBhxPn0p/oZWTdkk -DNpWZbke0QY0BpaBQrs4aZwzZtvRSdBQFSE8F0kIzxl3YTkRR7oBItFO5iP9xGCV -emhphjOhgYkDgYYABAHQuZli0IhFfDL7bvRpHwKzAakFojIOvrzIeuP5+yF8rA8G -jxMi0H+nu0XnPBD6jRwx6telG0mJI5LS6vQGYkZc6ADC6k23BSR59wSWIg/oAIm7 -85jFkK3Gmgyqc1Ki/J8Mnr1qHPyMllIfRRRe5OyxozOcHUot1sKMA1BRuwOruCLx -4w== ------END PRIVATE KEY----- diff --git a/test/fixtures/P-521.pem b/test/fixtures/P-521.pem deleted file mode 100644 index 45d4eeb3aa..0000000000 --- a/test/fixtures/P-521.pem +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQB0LmZYtCIRXwy+270aR8CswGpBaIy -Dr68yHrj+fshfKwPBo8TItB/p7tF5zwQ+o0cMerXpRtJiSOS0ur0BmJGXOgAwupN -twUkefcEliIP6ACJu/OYxZCtxpoMqnNSovyfDJ69ahz8jJZSH0UUXuTssaMznB1K -LdbCjANQUbsDq7gi8eM= ------END PUBLIC KEY----- diff --git a/test/fixtures/X25519.key b/test/fixtures/X25519.key deleted file mode 100644 index b2f60cca40..0000000000 --- a/test/fixtures/X25519.key +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN PRIVATE KEY----- -MC4CAQAwBQYDK2VuBCIEILD/13Y5R/tmcCjZVSooIcpfGvZxf+qt6dMu5FYaOC1a ------END PRIVATE KEY----- diff --git a/test/fixtures/X25519.pem b/test/fixtures/X25519.pem deleted file mode 100644 index 3d1e7b835e..0000000000 --- a/test/fixtures/X25519.pem +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN PUBLIC KEY----- -MCowBQYDK2VuAyEAYHCXnz085FKclfnx+gdiGXAyy7BhJjx0pxyE4wbXF0A= ------END PUBLIC KEY----- diff --git a/test/fixtures/X448.key b/test/fixtures/X448.key deleted file mode 100644 index 39c507d2b8..0000000000 --- a/test/fixtures/X448.key +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PRIVATE KEY----- -MEYCAQAwBQYDK2VvBDoEOPilLIAZTQqUbFb0LhTGaqn47zN2p2yGVk+2hhQQk9C8 -8SvFqEFw73YITSIJ2NUBZnZKNz2nGkrm ------END PRIVATE KEY----- diff --git a/test/fixtures/X448.pem b/test/fixtures/X448.pem deleted file mode 100644 index 841c2bb66b..0000000000 --- a/test/fixtures/X448.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MEIwBQYDK2VvAzkAbceBBM+LkveTK09QojZdnHokCh7lOWxyVZrlbH3Ny3WorprD -Iir5A6heZzlRnz1elOHp7ZpPfWk= ------END PUBLIC KEY----- diff --git a/test/fixtures/index.js b/test/fixtures/index.js deleted file mode 100644 index f2b6dec713..0000000000 --- a/test/fixtures/index.js +++ /dev/null @@ -1,127 +0,0 @@ -const { readFileSync } = require('fs') -const { join } = require('path') -const { improvedDH } = require('../../lib/help/runtime_support') - -module.exports.JWK = { - RSA_PUBLIC: { - kty: 'RSA', - e: 'AQAB', - n: 'wIs03tSBrzj_6nU0uj6AFOmOVljdYORu3AX0kiDamgQmGDRYTGnjWNbePRWMkAFTAp-kpH71WeSV9n3y0MpDuwJqrmiPr7Wy1A_iUhw1X2bZU2MjwNref-i42V8nbPeshm48HzXD-ZRuLVgrn10VuQxRBnbGrOWA7tgfgb9JyDL1ae4dZdJw7Uz87FiVxR71twH1AibIhonEHnmbZqIdqQhpoP1PSPKkQRHPHZWQMXLm9kYbCbsIc36RfbpEe5ybnvBM2xxZKT1DrEQx5ykGwmVe_KzSePSDsdr7hQV5OrM0tftlNLDbxLfy2MtplzdEtLPms8Ma8bO_gvutt2-97w' - }, - - RSA_PRIVATE: { - kty: 'RSA', - e: 'AQAB', - n: 'wIs03tSBrzj_6nU0uj6AFOmOVljdYORu3AX0kiDamgQmGDRYTGnjWNbePRWMkAFTAp-kpH71WeSV9n3y0MpDuwJqrmiPr7Wy1A_iUhw1X2bZU2MjwNref-i42V8nbPeshm48HzXD-ZRuLVgrn10VuQxRBnbGrOWA7tgfgb9JyDL1ae4dZdJw7Uz87FiVxR71twH1AibIhonEHnmbZqIdqQhpoP1PSPKkQRHPHZWQMXLm9kYbCbsIc36RfbpEe5ybnvBM2xxZKT1DrEQx5ykGwmVe_KzSePSDsdr7hQV5OrM0tftlNLDbxLfy2MtplzdEtLPms8Ma8bO_gvutt2-97w', - d: 'fxbjjPmDqB7dfOpkJVK_xA3tb700UpI1QnGD3zhkUijO5EcYyUdTUv5wrq0cnKjjG-Y4DIPoeq9Q9ORpc7suPa_4rqpBvV8XbLYXUs9fw1rltA7KOK-_EXqRGJmgMmLAs_LrKEaa1pBMsQ1zrbsJbZ1dlgCsXs8V7ZEmKsQSdVtYXdrPN3qMP5w62VF-1_QPRkK7qr0gixQv165beHtuJiWD_jB3OjOKVe70-CkTOYzSnomb1cQdUGRcx2v-WQ4G5E0ytn-grTz8hCF7rL3YHToXTFquByar2Fj7GD-LC9Dn6okHlwQ1kAyN0Xt0ezfJxdRN9NmlOi0CUt4E7MREAQ', - p: '3xswmQo278dRS8XZBLW2rpyxW5zjvpHvmnicPEnWYhaNwHQMe1LUViAXtrmc_e00L_EcNjM0q528mUwgdOEZwRAtinrw2JNUE2fF9BvE-Q8BRSOxWYuMahJjXhmMTaqPXQrPiO7o3KQgzoJJKS1JaXlpR1ElgeTbhTvnm9a1AwE', - q: '3O57ufYRcIqlKxxdXBj3J3mnSUTr3ATWOYhVNC2xN2cLDAHwHwt3Rd7UdqI3TjrSwhQokOmzDIBW6APo0T4X_76KweFeiDDkmP9S4y1TDVDO3rx1MO4i5rLWe8NN4N6-L1pNbS4TMuh5tOn6MozFySkNRCicJD38dF6JBa6h8O8', - dp: 'Jb8j6cCgqtC-IGPI49MapVA9cZKJtaRbNXdSd6DGdLH8KaN4uSS6aBfl6zRcK1oGilXwv_rJ3n9BeW43z46GHPPvwI4sUXgbsWzNQQ-xs7GmNVxklRHXH9sclL8dzcYdm1BI7JH_M9VQ959zYVQYJ5AzD63a-q8NtOz9spAQ8AE', - dq: 'bJRkiGtv_MCXFk31cDrw1RzL442U4WgbJOFlBqTiMNlaq4cUTR2ke9lc0AU_axor1Kh1m2rPzXgRviuVs6hxwQYTSeAKRqLI5oytXus6oxOw5_T1H5wZ2QnRsbe1wauXCsy1us_nLaDll81aYpee6RNc6r-OpZ01QrfnXbyK6E8', - qi: 'QrCoyZm-rco2Mziyfxdziaw2S8_rofiKXi7Qz6O5loSslYJtrIXq7w8MX-TVSt6r03lLbK9gthslPRPdp68wmH-By0mfw66JtuSKOAHdHWotFOwYvkkE76O4-eY78pTE9oEzu-lu309NSPSpADd58DIRYMqwuFhbLa35Yrw3TxU' - }, - - Ed25519: { - kty: 'OKP', - crv: 'Ed25519', - d: 'nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A', - x: '11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo' - }, - - Ed448: { - kty: 'OKP', - crv: 'Ed448', - d: 'wdwf3Gu5aZCJufcUrSkkvqJjqPCgyd6R5Cmx3zkNNh90JYYzOoXC7ptuxTTGWQumHeUjohkQyPT_', - x: 'NAh0EO9nwdXZkR_2KrY_2A66oH_654oEcoFbtUprlF8AvrXnQ0rlcg1VxJvlp85lR23CuX8jNnKA' - }, - - X25519: { - kty: 'OKP', - crv: 'X25519', - d: 'sP_XdjlH-2ZwKNlVKighyl8a9nF_6q3p0y7kVho4LVo', - x: 'YHCXnz085FKclfnx-gdiGXAyy7BhJjx0pxyE4wbXF0A' - }, - - X448: { - kty: 'OKP', - crv: 'X448', - d: 'bceBBM-LkveTK09QojZdnHokCh7lOWxyVZrlbH3Ny3WorprDIir5A6heZzlRnz1elOHp7ZpPfWk', - x: 'rmZOFmJPUVLlQDeG2_V4pgMmTidTtD_GGTq1gMKx9hJfAqTlC9K-qaJBhSYQtS1xHBkfUREKa3I' - }, - - 'P-256': { - kty: 'EC', - crv: 'P-256', - x: 'gskvlmd8hChm_hxtH4oyDC2rizV1jwK4exTn3icBxu8', - y: '0El8NqTyybjkEJ2grVUDK1BdPo49OF1pmCJCD92_h-Y', - d: '_i_1Ac5oVmbBxGvEvOEFHMpzMXKZi8voUx8I3Gl6IxY' - }, - - secp256k1: { - kty: 'EC', - crv: 'secp256k1', - x: 'VRaLqtMjg_JRaDzkbfit7zonkOGDZ42qbZyljhqsg3U', - y: '5qgTxoRAf0hJxcphVg1NE9r0Xv-HHZyVIJxEbo6SAsQ', - d: 'xTAmXNRL8ksBlr-F3yXDrUdRDn1gyIvY_PC2e_iUK7c' - }, - - 'P-384': { - kty: 'EC', - crv: 'P-384', - x: 'sOilTs4JMAaXio-fG2rVdLpt7Zoxn3fqWSI58DlwxpS8dgbYI2WLh_OymYy3GZtl', - y: '23aUE5XAxfr3Ok-nDymgYb1X3TI0dRq1V1Oj0ngItP5ot2tIcL-hnD4kyabg97Ya', - d: 'cLNsZ0Nm7MsuVsqTCwK_edo982LoVU4sFGZZaEdX8Xvytn8Cdm2HszNVkS3FOl_7' - }, - - 'P-521': { - kty: 'EC', - crv: 'P-521', - x: 'AJRHTTRwIoGp7WDE90vsBKIyWbVaESCxEXy-s29X68dpguSra_u1Mhter7b_7kTgb6dX2lXX5wrZSJOJ1gcflXQM', - y: 'ANW_hbEvDSm-q-NLVEkKR1m2Qfvy6Kp5YnbQ7E_yfupjeZCII81rb55WBAFd4fG5-tcRJtil67E0GH_l6RXZj5Ie', - d: 'AcrcrbQ-Fu2d2jlxQM0_nSVXM5Kt7mByIxsbgJUe_wgb4DrwVWBC1OJe2ONr0Ovcd_4ydDgWlbIJJhzS3tL9KM0S' - } -} - -module.exports.PEM = { - RSA: { - private: readFileSync(join(__dirname, 'rsa.key')), - public: readFileSync(join(__dirname, 'rsa.pem')) - }, - Ed25519: { - testEnc: false, - private: readFileSync(join(__dirname, 'Ed25519.key')), - public: readFileSync(join(__dirname, 'Ed25519.pem')) - }, - Ed448: { - testEnc: false, - private: readFileSync(join(__dirname, 'Ed448.key')), - public: readFileSync(join(__dirname, 'Ed448.pem')) - }, - X25519: { - testEnc: improvedDH && !('electron' in process.versions), - private: readFileSync(join(__dirname, 'X25519.key')), - public: readFileSync(join(__dirname, 'X25519.pem')) - }, - X448: { - testEnc: improvedDH && !('electron' in process.versions), - private: readFileSync(join(__dirname, 'X448.key')), - public: readFileSync(join(__dirname, 'X448.pem')) - }, - 'P-256': { - private: readFileSync(join(__dirname, 'P-256.key')), - public: readFileSync(join(__dirname, 'P-256.pem')) - }, - secp256k1: { - testEnc: false, - private: readFileSync(join(__dirname, 'secp256k1.key')), - public: readFileSync(join(__dirname, 'secp256k1.pem')) - }, - 'P-384': { - private: readFileSync(join(__dirname, 'P-384.key')), - public: readFileSync(join(__dirname, 'P-384.pem')) - }, - 'P-521': { - private: readFileSync(join(__dirname, 'P-521.key')), - public: readFileSync(join(__dirname, 'P-521.pem')) - } -} diff --git a/test/fixtures/rsa.key b/test/fixtures/rsa.key deleted file mode 100644 index c52eb5323e..0000000000 --- a/test/fixtures/rsa.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDAeyuckBoOSIYW -emUxSLkat93gIQ9TD2pui6bcCGG44TN/S7D9I6058uSQQ7EeblynwJQ2Qe0Q1Ur8 -7RXAXlRcGF61yWAScp/n31H0lVZU3VocQ+4R87b0lvHaTliqo3tTVZZg9Uogmf/F -U1vGFvqC251KpAYjSiCtJs1vpQjFQgvKxtGYU3x3bmSzMO6R/QqSywcam5Tyit+S -fELxGgvbbwJGaA0rujspoYEsC1r24V4FLNsQcJXomfaCK9bUJ9AVIraekGT+uOyW -I/Ob0P4+T4NZb54XWd6jzPDuQCQxbRAGdURgBVhyrFJfjY6yXZ3SX8pqyRq9PTq6 -e8LOOJELAgMBAAECggEAMNYPdqXJNp6IBuP/EMYW0QSdsuQwcy6SHoIoT+OAh9v7 -qOyXd2K57N4Hx+Kk6ceukpF2CV4ovACiChJNVoWYedVlElKJoaSblcU/kgLh6J5Q -4qMJoFxpqx0xN+Zw8LqR687nXKpfqG3qSzKfMl9aKCF4gxuiwwlnyQbzUMRauVFb -7OLe3oIyn4wDavjGZH8pCFMvRw+Dtw/8yTx+TjQGaVJ4AWO7OvJs8IG/GjkU4M1y -cmsMsAgt/HZNwEuHhA8CECmPHk8OcSjy7jRW+USn1e92e531LNfVscdifWk5kXyi -DBYORZ0KTl0H99Kkqe85x6CPTCpjvMfb1UZ0uS0iwQKBgQDhQCOY2J2jceNbdwvg -YyKsC6z5ZWXB9i5Mo1laWh5giWUxR0J41XeJV/LHrvWW3ffIJXIg31lgTuGsMkOF -bHKMpl6THQ9293SvmJjiDLpS6RsS/e7VovCMZ4ZObAlDziihq7nlRWdk24YibcD1 -3Yi8Hzdbu5+cuSxaGzXpweieuQKBgQDawdWZqLk3pc1/+3rRwCooODn06r6OltDo -Bdc68jaIcZ3nG2rZwt4CI7srmiY4892G2YxOvmj12jFUAJGsfhXasWeXON0rXJF2 -NsPUcahbe0YbU14JwEQWC00JCClYECh6yHiUUREc3DGbFeh8jlIlRh7HyJHgcCZs -B0BGTUDr4wKBgQC9em+3TlhkuhPPx/eUnK/426V48WPE4mqWCz7Js08kU89swY3Y -CXGRdgsDEFkEvNmHYoB7yIXtbs2FRY7o+I3vZK/fvq1YnNZqM8o/NQezYOVmd3dl -/Leu1BL1ewncINqrDMLGaziLbeKKqZqM9/rijLvLjau5cUcu0P7sETK1+QKBgQCl -CkBAoY67cRfNSsmqnbQwi9sN8Fy77wTFSELNche6cR2UUpcWm3IrYxG/H5letn2X -U2ILtpQxh+BXY+aDoMyUJevlpz0Vjc0gxsiP6v/9pM+LpiX4bVnw163S9plamzYv -DDgMjey/PVEflDPGZQmMnY5zY9rK3VHfhsjzQS2NyQKBgQDQZdDE0Y4bHapEFvNz -ez/X2wNEluRu6v8k4j455g4EDu8KTCmMH/U0ys/rK3IoYaYuqZawnDjyiyJ9NJHa -cOAS0HofeNqu+SbQwPBQv+xHQK+sCNKzT6WM0WSSv2JoIR2jmlpOLkuwkE077D/q -KxcmCpeLiMhJ83MOPcXYadKhSA== ------END PRIVATE KEY----- diff --git a/test/fixtures/rsa.pem b/test/fixtures/rsa.pem deleted file mode 100644 index c88de9c268..0000000000 --- a/test/fixtures/rsa.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwHsrnJAaDkiGFnplMUi5 -Grfd4CEPUw9qboum3AhhuOEzf0uw/SOtOfLkkEOxHm5cp8CUNkHtENVK/O0VwF5U -XBhetclgEnKf599R9JVWVN1aHEPuEfO29Jbx2k5YqqN7U1WWYPVKIJn/xVNbxhb6 -gtudSqQGI0ogrSbNb6UIxUILysbRmFN8d25kszDukf0KkssHGpuU8orfknxC8RoL -228CRmgNK7o7KaGBLAta9uFeBSzbEHCV6Jn2givW1CfQFSK2npBk/rjsliPzm9D+ -Pk+DWW+eF1neo8zw7kAkMW0QBnVEYAVYcqxSX42Osl2d0l/KaskavT06unvCzjiR -CwIDAQAB ------END PUBLIC KEY----- diff --git a/test/fixtures/secp256k1.key b/test/fixtures/secp256k1.key deleted file mode 100644 index 149e95c8a3..0000000000 --- a/test/fixtures/secp256k1.key +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgxTAmXNRL8ksBlr+F3yXD -rUdRDn1gyIvY/PC2e/iUK7ehRANCAARVFouq0yOD8lFoPORt+K3vOieQ4YNnjapt -nKWOGqyDdeaoE8aEQH9IScXKYVYNTRPa9F7/hx2clSCcRG6OkgLE ------END PRIVATE KEY----- diff --git a/test/fixtures/secp256k1.pem b/test/fixtures/secp256k1.pem deleted file mode 100644 index 7affcba985..0000000000 --- a/test/fixtures/secp256k1.pem +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEVRaLqtMjg/JRaDzkbfit7zonkOGDZ42q -bZyljhqsg3XmqBPGhEB/SEnFymFWDU0T2vRe/4cdnJUgnERujpICxA== ------END PUBLIC KEY----- diff --git a/test/help/base64url.test.js b/test/help/base64url.test.js deleted file mode 100644 index 9a561f0597..0000000000 --- a/test/help/base64url.test.js +++ /dev/null @@ -1,42 +0,0 @@ -const test = require('ava') - -const base64url = require('../../lib/help/base64url') - -const testStr = 'fmkIOj+kafqtjMl+iC32a+9YGz0cKj/JT9Jt31uXR1la7FSXkjoBzg/F+huYm0udbM5z5qGlmPBNZASsixJLcA==' -const testBuf = Buffer.from('fmkIOj+kafqtjMl+iC32a+9YGz0cKj/JT9Jt31uXR1la7FSXkjoBzg/F+huYm0udbM5z5qGlmPBNZASsixJLcA==', 'base64') - -test('.encodeBuffer buffer', t => { - t.is(base64url.encodeBuffer(testBuf), 'fmkIOj-kafqtjMl-iC32a-9YGz0cKj_JT9Jt31uXR1la7FSXkjoBzg_F-huYm0udbM5z5qGlmPBNZASsixJLcA') -}) - -test('.encode string with default encoding', t => { - t.is(base64url.encode('foo'), 'Zm9v') -}) - -test('.encode string with non-default encoding', t => { - t.is(base64url.encode(testStr, 'base64'), 'fmkIOj-kafqtjMl-iC32a-9YGz0cKj_JT9Jt31uXR1la7FSXkjoBzg_F-huYm0udbM5z5qGlmPBNZASsixJLcA') -}) - -test('.decode with default encoding', t => { - t.is(base64url.decode('Zm9v'), 'foo') -}) - -test('.decodeToBuffer', t => { - t.deepEqual(base64url.decodeToBuffer('fmkIOj-kafqtjMl-iC32a-9YGz0cKj_JT9Jt31uXR1la7FSXkjoBzg_F-huYm0udbM5z5qGlmPBNZASsixJLcA'), testBuf) -}) - -test('.JSON.encode', t => { - t.deepEqual(base64url.JSON.encode({ foo: 'bar' }), 'eyJmb28iOiJiYXIifQ') -}) - -test('.JSON.decode', t => { - t.deepEqual(base64url.JSON.decode('eyJmb28iOiJiYXIifQ'), { foo: 'bar' }) -}) - -test('.JSON.decode.try (valid json)', t => { - t.deepEqual(base64url.JSON.decode.try('eyJmb28iOiJiYXIifQ'), { foo: 'bar' }) -}) - -test('.JSON.decode.try (invalid json)', t => { - t.is(base64url.JSON.decode.try('Zm9v'), 'foo') -}) diff --git a/test/help/ecdsa_signatures.test.js b/test/help/ecdsa_signatures.test.js deleted file mode 100644 index 65c2ecedc2..0000000000 --- a/test/help/ecdsa_signatures.test.js +++ /dev/null @@ -1,216 +0,0 @@ -const test = require('ava') - -const { decodeToBuffer } = require('../../lib/help/base64url') -const { derToJose, joseToDer } = require('../../lib/help/ecdsa_signatures') - -const CLASS_UNIVERSAL = 0 -const PRIMITIVE_BIT = 0x20 -const TAG_SEQ = (0x10 | PRIMITIVE_BIT) | (CLASS_UNIVERSAL << 6) -const TAG_INT = 0x02 | (CLASS_UNIVERSAL << 6) - -test('.derToJose no signature', t => { - t.throws(() => derToJose(), { instanceOf: TypeError, message: 'ECDSA signature must be a Buffer' }) -}) - -test('.derToJose non buffer or base64 signature', t => { - t.throws(() => derToJose(123), { instanceOf: TypeError, message: 'ECDSA signature must be a Buffer' }) -}) - -test('.derToJose unknown algorithm', t => { - t.throws(() => derToJose(decodeToBuffer('Zm9vLmJhci5iYXo'), 'foobar'), { instanceOf: Error, message: 'Unknown algorithm "foobar"' }) -}) - -Object.entries({ - ES256: 32, - ES384: 48, - ES512: 66 -}).forEach(([alg, len]) => { - test(`.derToJose no seq (${alg})`, t => { - const input = Buffer.alloc(10) - input[0] = TAG_SEQ + 1 // not seq - - t.throws(() => { - derToJose(input, alg) - }, { instanceOf: Error, message: /expected "seq"/ }) - }) - - test(`.derToJose seq length exceeding input (${alg})`, t => { - const input = Buffer.alloc(10) - input[0] = TAG_SEQ - input[1] = 10 - - t.throws(() => { - derToJose(input, alg) - }, { instanceOf: Error, message: /length/ }) - }) - - test(`.derToJose r is not marked as int (${alg})`, t => { - const input = Buffer.alloc(10) - input[0] = TAG_SEQ - input[1] = 8 - input[2] = TAG_INT + 1 // not int - - t.throws(() => { - derToJose(input, alg) - }, { instanceOf: Error, message: /expected "int".+"r"/ }) - }) - - test(`.derToJose r length exceeds available input (${alg})`, t => { - const input = Buffer.alloc(10) - input[0] = TAG_SEQ - input[1] = 8 - input[2] = TAG_INT - input[3] = 5 - - t.throws(() => { - derToJose(input, alg) - }, { instanceOf: Error, message: /"r".+length/ }) - }) - - test(`.derToJose r length exceeds sensical param length (${alg})`, t => { - const input = Buffer.alloc(len + 2 + 6) - input[0] = TAG_SEQ - input[1] = len + 2 + 4 - input[2] = TAG_INT - input[3] = len + 2 - - t.throws(() => { - derToJose(input, alg) - }, { instanceOf: Error, message: /"r".+length.+acceptable/ }) - }) - - test(`.derToJose s is not marked as int (${alg})`, t => { - const input = Buffer.alloc(10) - input[0] = TAG_SEQ - input[1] = 8 - input[2] = TAG_INT - input[3] = 2 - input[4] = 0 - input[5] = 0 - input[6] = TAG_INT + 1 // not int - - t.throws(() => { - derToJose(input, alg) - }, { instanceOf: Error, message: /expected "int".+"s"/ }) - }) - - test(`.derToJose s length exceeds available input (${alg})`, t => { - const input = Buffer.alloc(10) - input[0] = TAG_SEQ - input[1] = 8 - input[2] = TAG_INT - input[3] = 2 - input[4] = 0 - input[5] = 0 - input[6] = TAG_INT - input[7] = 3 - - t.throws(() => { - derToJose(input, alg) - }, { instanceOf: Error, message: /"s".+length/ }) - }) - - test(`.derToJose s length does not consume available input (${alg})`, t => { - const input = Buffer.alloc(10) - input[0] = TAG_SEQ - input[1] = 8 - input[2] = TAG_INT - input[3] = 2 - input[4] = 0 - input[5] = 0 - input[6] = TAG_INT - input[7] = 1 - - t.throws(() => { - derToJose(input, alg) - }, { instanceOf: Error, message: /"s".+length/ }) - }) - - test(`.derToJose s length exceeds sensical param length (${alg})`, t => { - const input = Buffer.alloc(len + 2 + 8) - input[0] = TAG_SEQ - input[1] = len + 2 + 6 - input[2] = TAG_INT - input[3] = 2 - input[4] = 0 - input[5] = 0 - input[6] = TAG_INT - input[7] = len + 2 - - t.throws(() => { - derToJose(input, alg) - }, { instanceOf: Error, message: /"s".+length.+acceptable/ }) - }) -}) - -test('.joseToDer no signature', t => { - t.throws(() => joseToDer(), { instanceOf: TypeError, message: 'ECDSA signature must be a Buffer' }) -}) - -test('.joseToDer non buffer or base64 signature', t => { - t.throws(() => joseToDer(123), { instanceOf: TypeError, message: 'ECDSA signature must be a Buffer' }) -}) - -test('.joseToDer unknown algorithm', t => { - t.throws(() => joseToDer(decodeToBuffer('Zm9vLmJhci5iYXo'), 'foobar'), { instanceOf: Error, message: /"foobar"/ }) -}) - -test('.joseToDer incorrect signature length (ES256)', t => { - t.throws(() => joseToDer(decodeToBuffer('Zm9vLmJhci5iYXo'), 'ES256'), { instanceOf: Error, message: /"64"/ }) -}) - -test('.joseToDer incorrect signature length (ES384)', t => { - t.throws(() => joseToDer(decodeToBuffer('Zm9vLmJhci5iYXo'), 'ES384'), { instanceOf: Error, message: /"96"/ }) -}) - -test('.joseToDer incorrect signature length (ES512)', t => { - t.throws(() => joseToDer(decodeToBuffer('Zm9vLmJhci5iYXo'), 'ES512'), { instanceOf: Error, message: '"ES512" signatures must be "132" bytes, saw "11"' }) -}) - -test('ES256 should jose -> der -> jose', t => { - const expected = decodeToBuffer('yA4WNemRpUreSh9qgMh_ePGqhgn328ghJ_HG7WOBKQV98eFNm3FIvweoiSzHvl49Z6YTdV4Up7NDD7UcZ-52cw') - const der = joseToDer(expected, 'ES256') - const actual = derToJose(der, 'ES256') - - t.deepEqual(actual, expected) -}) - -test('ES256 should der -> jose -> der', t => { - const expected = decodeToBuffer('MEUCIQD0nDQE4uBS6JuklnyACfPQRB_LMEh5Stq6sAfp38k6ewIgHvhX59iuruBiFpVkg3dQKJ3-Wk29lJmXfxp6ciRdj-Q') - const jose = derToJose(expected, 'ES256') - const actual = joseToDer(jose, 'ES256') - - t.deepEqual(actual, expected) -}) - -test('ES384 should jose -> der -> jose', t => { - const expected = decodeToBuffer('TsS1fXqgq5S2lpjO-Tz5w6ZAKqNFuQ6PufvXRN2NRY2DEsQ3iUXdEcAzcMXNqVehkZ-NwUxdIvDqwKTGLYQYVhjBxkdnwm1T5VKG2v1BYFeDQ91sgBlVhHFzvFty5wCI') - const der = joseToDer(expected, 'ES384') - const actual = derToJose(der, 'ES384') - - t.deepEqual(actual, expected) -}) - -test('ES384 should der -> jose -> der', t => { - const expected = decodeToBuffer('MGUCMADcY5icKo-sLF0YCh5eVzju55Elt3Dfu4geMMDnUlLNaEO8NiCFzCHeqMx7mW5GMwIxAI6sp8ihHjRJ0sn_WV6mZCxN6_5lEg1QZJ5eiUHYv2kBgmiJ_Yv1pnqqFY3gVDBp_g') - const jose = derToJose(expected, 'ES384') - const actual = joseToDer(jose, 'ES384') - - t.deepEqual(actual, expected) -}) - -test('ES512 should jose -> der -> jose', t => { - const expected = decodeToBuffer('AFKapY_5gq60n8NZ_C2iOQFov7sXgcMyDzCrnGsbvE7OlSBKbgj95aZ7GtdSdbw6joK2jjWJio8IgKNB9o11GdMTADfLUsv9oAJvmIApsmsPBAIe1vH8oeHYiDMBEz9OQcwS5eL-r1iO2v7oxzl9zZb1rA5kzBqS93ARCPKbjgcr602r') - const der = joseToDer(expected, 'ES512') - const actual = derToJose(der, 'ES512') - - t.deepEqual(actual, expected) -}) - -test('ES512 should der -> jose -> der', t => { - const expected = decodeToBuffer('MIGHAkFgiYpVsYxx6XiQp2OXscRW_PrbEcoime_FftP-B7x4QVa-M3KZzXlfP66zKqjo7O3nwK2s8GbTftW8H4HwojzimwJCAYQNsozTpCo5nwIkBgelcfIQ0y_U_60TbNH1-rlKpFDCFs6Q1ro7R1tjtXoAUb9aPIOVyXGiSQX_-fcmmWs1rkJU') - const jose = derToJose(expected, 'ES512') - const actual = joseToDer(jose, 'ES512') - - t.deepEqual(actual, expected) -}) diff --git a/test/help/get_key.test.js b/test/help/get_key.test.js deleted file mode 100644 index e0904a526b..0000000000 --- a/test/help/get_key.test.js +++ /dev/null @@ -1,78 +0,0 @@ -const test = require('ava') - -const { createSecretKey, generateKeyPairSync } = require('crypto') - -const { keyObjectSupported } = require('../../lib/help/runtime_support') -const errors = require('../../lib/errors') -const getKey = require('../../lib/help/get_key') -const { JWKS, JWK } = require('../..') - -test('key must not be a KeyStore instance unless keyStoreAllowed is true', t => { - const ks = new JWKS.KeyStore() - t.throws(() => { - getKey(ks) - }, { instanceOf: TypeError, message: 'key argument for this operation must not be a JWKS.KeyStore instance' }) - t.is(getKey(ks, true), ks) -}) - -test('Key instances are passed through', async t => { - const k = await JWK.generate('oct') - t.is(getKey(k, true), k) -}) - -test('JWK is instantiated', async t => { - const jwk = (await JWK.generate('RSA')).toJWK() - const key = getKey(jwk) - t.truthy(key) - t.true(JWK.isKey(key)) -}) - -if (keyObjectSupported) { - test('KeyObject is instantiated', async t => { - const key = getKey(createSecretKey(Buffer.from('foo'))) - t.truthy(key) - t.true(JWK.isKey(key)) - }) -} - -test('Buffer is instantiated', async t => { - const key = getKey(Buffer.from('foo')) - t.truthy(key) - t.true(JWK.isKey(key)) - t.is(key.kty, 'oct') -}) - -test('oct tring is instantiated', async t => { - const key = getKey(Buffer.from('foo')) - t.truthy(key) - t.true(JWK.isKey(key)) - t.is(key.kty, 'oct') -}) - -test('PEM key is instantiated', async t => { - const pem = (await JWK.generate('RSA')).toPEM() - const key = getKey(pem) - t.truthy(key) - t.true(JWK.isKey(key)) - t.is(key.kty, 'RSA') -}) - -test('invalid inputs throw TypeError', t => { - ;[{}, new Object(), false, null, Infinity, 0, 1].forEach((val) => { // eslint-disable-line no-new-object - t.throws(() => { - getKey(val) - }, { instanceOf: TypeError, message: 'key must be an instance of a key instantiated by JWK.asKey, or a valid JWK.asKey input' }) - t.throws(() => { - getKey(val, true) - }, { instanceOf: TypeError, message: 'key must be an instance of a key instantiated by JWK.asKey, a valid JWK.asKey input, or a JWKS.KeyStore instance' }) - }) - - if (keyObjectSupported && !('electron' in process.versions)) { - const { privateKey, publicKey } = generateKeyPairSync('dsa', { modulusLength: 1024 }) - ;[privateKey, publicKey].forEach((val) => { - t.throws(() => { - getKey(val) - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'only RSA, EC and OKP asymmetric keys are supported' }) - }) - } -}) diff --git a/test/help/key_utils.test.js b/test/help/key_utils.test.js deleted file mode 100644 index e933f9e77a..0000000000 --- a/test/help/key_utils.test.js +++ /dev/null @@ -1,165 +0,0 @@ -const test = require('ava') - -const { edDSASupported } = require('../../lib/help/runtime_support') -const { createPublicKey, createPrivateKey } = require('../../lib/help/key_object') -const { errors } = require('../..') -const { keyObjectToJWK, jwkToPem } = require('../../lib/help/key_utils') -const { JWK: fixtures } = require('../fixtures') -const clone = obj => JSON.parse(JSON.stringify(obj)) - -test('jwkToPem only works for EC, RSA and OKP', t => { - t.throws(() => { - jwkToPem({ kty: 'foo' }) - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported key type: foo' }) -}) - -test('jwkToPem only handles known EC curves', t => { - t.throws(() => { - jwkToPem({ kty: 'EC', crv: 'foo' }) - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported EC key curve: foo' }) -}) - -test('jwkToPem only handles known OKP curves', t => { - t.throws(() => { - jwkToPem({ kty: 'OKP', crv: 'foo' }) - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported OKP key curve: foo' }) -}) - -test('RSA Public key', t => { - const expected = fixtures.RSA_PUBLIC - const pem = createPublicKey(jwkToPem(expected)) - const actual = keyObjectToJWK(pem) - - t.deepEqual(actual, expected) -}) - -test('RSA Private key', t => { - const expected = fixtures.RSA_PRIVATE - const pem = createPrivateKey(jwkToPem(expected)) - const actual = keyObjectToJWK(pem) - - t.deepEqual(actual, expected) -}) - -if (edDSASupported) { - test('Ed25519 Public key', t => { - const expected = clone(fixtures.Ed25519) - delete expected.d - const pem = createPublicKey(jwkToPem(expected)) - const actual = keyObjectToJWK(pem) - - t.deepEqual(actual, expected) - }) - - test('Ed25519 Private key', t => { - const expected = fixtures.Ed25519 - const pem = createPrivateKey(jwkToPem(expected)) - const actual = keyObjectToJWK(pem) - - t.deepEqual(actual, expected) - }) -} - -if (!('electron' in process.versions) && edDSASupported) { - test('Ed448 Public key', t => { - const expected = clone(fixtures.Ed448) - delete expected.d - const pem = createPublicKey(jwkToPem(expected)) - const actual = keyObjectToJWK(pem) - - t.deepEqual(actual, expected) - }) - - test('Ed448 Private key', t => { - const expected = fixtures.Ed448 - const pem = createPrivateKey(jwkToPem(expected)) - const actual = keyObjectToJWK(pem) - - t.deepEqual(actual, expected) - }) - - test('X25519 Public key', t => { - const expected = clone(fixtures.X25519) - delete expected.d - const pem = createPublicKey(jwkToPem(expected)) - const actual = keyObjectToJWK(pem) - - t.deepEqual(actual, expected) - }) - - test('X25519 Private key', t => { - const expected = fixtures.X25519 - const pem = createPrivateKey(jwkToPem(expected)) - const actual = keyObjectToJWK(pem) - - t.deepEqual(actual, expected) - }) - - test('X448 Public key', t => { - const expected = clone(fixtures.X448) - delete expected.d - const pem = createPublicKey(jwkToPem(expected)) - const actual = keyObjectToJWK(pem) - - t.deepEqual(actual, expected) - }) - - test('X448 Private key', t => { - const expected = fixtures.X448 - const pem = createPrivateKey(jwkToPem(expected)) - const actual = keyObjectToJWK(pem) - - t.deepEqual(actual, expected) - }) -} - -test('EC P-256 Public key', t => { - const expected = clone(fixtures['P-256']) - delete expected.d - const pem = createPublicKey(jwkToPem(expected)) - const actual = keyObjectToJWK(pem) - - t.deepEqual(actual, expected) -}) - -test('EC P-256 Private key', t => { - const expected = fixtures['P-256'] - const pem = createPrivateKey(jwkToPem(expected)) - const actual = keyObjectToJWK(pem) - - t.deepEqual(actual, expected) -}) - -test('EC P-384 Public key', t => { - const expected = clone(fixtures['P-384']) - delete expected.d - const pem = createPublicKey(jwkToPem(expected)) - const actual = keyObjectToJWK(pem) - - t.deepEqual(actual, expected) -}) - -test('EC P-384 Private key', t => { - const expected = fixtures['P-384'] - const pem = createPrivateKey(jwkToPem(expected)) - const actual = keyObjectToJWK(pem) - - t.deepEqual(actual, expected) -}) - -test('EC P-521 Public key', t => { - const expected = clone(fixtures['P-521']) - delete expected.d - const pem = createPublicKey(jwkToPem(expected)) - const actual = keyObjectToJWK(pem) - - t.deepEqual(actual, expected) -}) - -test('EC P-521 Private key', t => { - const expected = fixtures['P-521'] - const pem = createPrivateKey(jwkToPem(expected)) - const actual = keyObjectToJWK(pem) - - t.deepEqual(actual, expected) -}) diff --git a/test/help/multi_error.test.js b/test/help/multi_error.test.js deleted file mode 100644 index ce6ae26e11..0000000000 --- a/test/help/multi_error.test.js +++ /dev/null @@ -1,24 +0,0 @@ -const test = require('ava') - -const { JOSEMultiError } = require('../../lib/errors') - -test('flattens the errors', t => { - t.plan(5) - const multi = new JOSEMultiError([ - new Error(), - new Error(), - new JOSEMultiError([ - new Error() - ]), - new JOSEMultiError([ - new Error(), - new JOSEMultiError([ - new Error() - ]) - ]) - ]) - - for (const error of multi) { - t.false(error instanceof JOSEMultiError) - } -}) diff --git a/test/help/secs.test.js b/test/help/secs.test.js deleted file mode 100644 index e93b1070aa..0000000000 --- a/test/help/secs.test.js +++ /dev/null @@ -1,58 +0,0 @@ -const test = require('ava') - -const secs = require('../../lib/help/secs') - -const values = { - sec: 1, - secs: 1, - second: 1, - seconds: 1, - s: 1, - minute: 60, - minutes: 60, - min: 60, - mins: 60, - m: 60, - hour: 3600, - hours: 3600, - hr: 3600, - hrs: 3600, - h: 3600, - day: 86400, - days: 86400, - d: 86400, - week: 604800, - weeks: 604800, - w: 604800, - year: 31557600, - years: 31557600, - yr: 31557600, - yrs: 31557600, - y: 31557600 -} - -test('invalid formats', t => { - ;['-1w', '2.2.w', '2.w', '2.', '', '2 w ', ' 2w'].forEach((val) => { - t.throws(() => { - secs(val) - }, { instanceOf: TypeError }) - }) -}) - -Object.entries(values).forEach(([unit, value]) => { - test(`0 ${unit}`, t => { - t.is(0, secs(`0 ${unit}`)) - }) - - test(`1 ${unit}`, t => { - t.is(value, secs(`1 ${unit}`)) - }) - - test(`2${unit}`, t => { - t.is(2 * value, secs(`2${unit}`)) - }) - - test(`2.5${unit}`, t => { - t.is(Math.round(2.5 * value), secs(`2.5${unit}`)) - }) -}) diff --git a/test/help/timing_safe_equal.test.js b/test/help/timing_safe_equal.test.js deleted file mode 100644 index a50affbe0d..0000000000 --- a/test/help/timing_safe_equal.test.js +++ /dev/null @@ -1,12 +0,0 @@ -const test = require('ava') - -const timingSafeEqual = require('../../lib/help/timing_safe_equal') - -test('same length buffers', t => { - t.is(true, timingSafeEqual(Buffer.from('foo'), Buffer.from('foo'))) - t.is(false, timingSafeEqual(Buffer.from('foo'), Buffer.from('bar'))) -}) - -test('different length buffers', t => { - t.is(false, timingSafeEqual(Buffer.from('foo'), Buffer.from('barbaz'))) -}) diff --git a/test/jwa/sanity.test.js b/test/jwa/sanity.test.js deleted file mode 100644 index 49b3be7d65..0000000000 --- a/test/jwa/sanity.test.js +++ /dev/null @@ -1,17 +0,0 @@ -const test = require('ava') - -const { errors } = require('../..') -const JWA = require('../../lib/jwa') -const JWK = require('../../lib/jwk') - -;['sign', 'verify', 'keyManagementEncrypt', 'keyManagementDecrypt', 'encrypt', 'decrypt'].forEach((op) => { - let label - if (op.startsWith('keyManagement')) { - label = `key management (${op.substr(13).toLowerCase()}ion)` - } - test(`JWA.${op} will not accept an "unimplemented" algorithm`, t => { - t.throws(() => { - JWA[op]('foo', JWK.generateSync('oct')) - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: `unsupported ${label || op} alg: foo` }) - }) -}) diff --git a/test/jwe/compact.decrypt.test.mjs b/test/jwe/compact.decrypt.test.mjs new file mode 100644 index 0000000000..cc60778cb7 --- /dev/null +++ b/test/jwe/compact.decrypt.test.mjs @@ -0,0 +1,24 @@ +/* eslint-disable no-param-reassign */ +import test from 'ava'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +import(`${root}/jwe/compact/decrypt`).then( + ({ default: flattenedDecrypt }) => { + test('JWE format validation', async (t) => { + await t.throwsAsync(flattenedDecrypt(null, new Uint8Array()), { + message: 'Compact JWE must be a string', + code: 'ERR_JWE_INVALID', + }); + await t.throwsAsync(flattenedDecrypt('...', new Uint8Array()), { + message: 'Invalid Compact JWE', + code: 'ERR_JWE_INVALID', + }); + }); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jwe/compact.encrypt.test.mjs b/test/jwe/compact.encrypt.test.mjs new file mode 100644 index 0000000000..8579d6806b --- /dev/null +++ b/test/jwe/compact.encrypt.test.mjs @@ -0,0 +1,112 @@ +/* eslint-disable no-param-reassign */ +import test from 'ava'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +import(`${root}/jwe/compact/encrypt`).then( + ({ default: CompactEncrypt }) => { + test.before(async (t) => { + const encode = TextEncoder.prototype.encode.bind(new TextEncoder()); + t.context.plaintext = encode('It’s a dangerous business, Frodo, going out your door.'); + t.context.initializationVector = new Uint8Array(12); + t.context.secret = new Uint8Array(16); + }); + + test('CompactEncrypt', async (t) => { + const jwe = await new CompactEncrypt(t.context.plaintext) + .setInitializationVector(t.context.initializationVector) + .setProtectedHeader({ alg: 'dir', enc: 'A128GCM' }) + .encrypt(t.context.secret); + t.deepEqual( + jwe, + 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..AAAAAAAAAAAAAAAA.Svw4TvnFg_PTTKPXFteMF4Lmisk8ODBNko7607TNs49EbT0BKRz9tEep2dmks9KPvD-CfX7hW1M.Y5cdeOSFYNyxcPWQlrVFzw', + ); + }); + + test('CompactEncrypt.prototype.setProtectedHeader', (t) => { + t.throws( + () => new CompactEncrypt(t.context.plaintext).setProtectedHeader({}).setProtectedHeader({}), + { + instanceOf: TypeError, + message: 'setProtectedHeader can only be called once', + }, + ); + }); + + test('CompactEncrypt.prototype.setKeyManagementParameters', (t) => { + t.throws( + () => + new CompactEncrypt(t.context.plaintext) + .setKeyManagementParameters({}) + .setKeyManagementParameters({}), + { + instanceOf: TypeError, + message: 'setKeyManagementParameters can only be called once', + }, + ); + }); + + test('CompactEncrypt.prototype.setInitializationVector', (t) => { + t.throws( + () => + new CompactEncrypt(t.context.plaintext) + .setInitializationVector(t.context.initializationVector) + .setInitializationVector(t.context.initializationVector), + { + instanceOf: TypeError, + message: 'setInitializationVector can only be called once', + }, + ); + }); + + test('CompactEncrypt.prototype.setContentEncryptionKey', (t) => { + t.throws( + () => + new CompactEncrypt(t.context.plaintext) + .setContentEncryptionKey(t.context.secret) + .setContentEncryptionKey(t.context.secret), + { + instanceOf: TypeError, + message: 'setContentEncryptionKey can only be called once', + }, + ); + }); + + test('CompactEncrypt.prototype.encrypt must have a JOSE header', async (t) => { + await t.throwsAsync(new CompactEncrypt(t.context.plaintext).encrypt(t.context.secret), { + code: 'ERR_JWE_INVALID', + message: + 'either setProtectedHeader, setUnprotectedHeader, or sharedUnprotectedHeader must be called before #encrypt()', + }); + }); + + test('CompactEncrypt.prototype.encrypt JOSE header have an alg', async (t) => { + await t.throwsAsync( + new CompactEncrypt(t.context.plaintext) + .setProtectedHeader({ enc: 'A128GCM' }) + .encrypt(t.context.secret), + { + code: 'ERR_JWE_INVALID', + message: 'JWE "alg" (Algorithm) Header Parameter missing', + }, + ); + }); + + test('CompactEncrypt.prototype.encrypt JOSE header have an enc', async (t) => { + await t.throwsAsync( + new CompactEncrypt(t.context.plaintext) + .setProtectedHeader({ alg: 'dir' }) + .encrypt(t.context.secret), + { + code: 'ERR_JWE_INVALID', + message: 'JWE "enc" (Encryption Algorithm) Header Parameter missing', + }, + ); + }); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jwe/complete.test.js b/test/jwe/complete.test.js deleted file mode 100644 index 9931245e62..0000000000 --- a/test/jwe/complete.test.js +++ /dev/null @@ -1,71 +0,0 @@ -const test = require('ava') - -const isObject = require('../../lib/help/is_object') -const Key = require('../../lib/jwk/key/base') -const { JWKS, JWK: { generateSync }, JWE } = require('../..') -const key = generateSync('oct') -const ks = new JWKS.KeyStore(generateSync('EC'), key) - -const complete = (t, jwe, k, ...keys) => { - if (typeof k === 'string') { - keys.unshift(k) - k = key - } - const decrypted = JWE.decrypt(jwe(), k, { complete: true }) - t.is(Object.values(decrypted).length, keys.length) - if (k instanceof Key) { - t.is(decrypted.key, k) - } else { - t.is(decrypted.key, ks.get(decrypted.protected)) - } - t.true(keys.every(k => k in decrypted)) - if (keys.includes('header')) { - t.true(isObject(decrypted.header)) - } - if (keys.includes('protected')) { - t.true(isObject(decrypted.protected)) - } - if (keys.includes('unprotected')) { - t.true(isObject(decrypted.unprotected)) - } - if (keys.includes('aad')) { - t.is(typeof decrypted.aad, 'string') - } - t.true(Buffer.isBuffer(decrypted.cleartext)) -} - -test('compact', complete, () => JWE.encrypt('foo', key), 'cleartext', 'protected', 'key', 'cek') -test('flattened', complete, () => JWE.encrypt.flattened('foo', key), 'cleartext', 'protected', 'key', 'cek') -test('flattened w/ aad', complete, () => JWE.encrypt.flattened('foo', key, undefined, 'bar'), 'cleartext', 'protected', 'aad', 'key', 'cek') -test('flattened w/ unprotected', complete, () => JWE.encrypt.flattened('foo', key, undefined, undefined, { foo: 'bar' }), 'cleartext', 'protected', 'unprotected', 'key', 'cek') -test('flattened w/ header', complete, () => { - const enc = new JWE.Encrypt('foo') - enc.recipient(key, { foo: 'bar' }) - return enc.encrypt('flattened') -}, 'cleartext', 'protected', 'header', 'key', 'cek') -test('general', complete, () => JWE.encrypt.general('foo', key), 'cleartext', 'protected', 'key', 'cek') -test('general w/ aad', complete, () => JWE.encrypt.general('foo', key, undefined, 'bar'), 'cleartext', 'protected', 'aad', 'key', 'cek') -test('general w/ unprotected', complete, () => JWE.encrypt.general('foo', key, undefined, undefined, { foo: 'bar' }), 'cleartext', 'protected', 'unprotected', 'key', 'cek') -test('general w/ header', complete, () => { - const enc = new JWE.Encrypt('foo') - enc.recipient(key, { foo: 'bar' }) - return enc.encrypt('general') -}, 'cleartext', 'protected', 'header', 'key', 'cek') - -test('with keystore > compact', complete, () => JWE.encrypt('foo', key), ks, 'cleartext', 'protected', 'key', 'cek') -test('with keystore > flattened', complete, () => JWE.encrypt.flattened('foo', key), ks, 'cleartext', 'protected', 'key', 'cek') -test('with keystore > flattened w/ aad', complete, () => JWE.encrypt.flattened('foo', key, undefined, 'bar'), ks, 'cleartext', 'protected', 'aad', 'key', 'cek') -test('with keystore > flattened w/ unprotected', complete, () => JWE.encrypt.flattened('foo', key, undefined, undefined, { foo: 'bar' }), ks, 'cleartext', 'protected', 'unprotected', 'key', 'cek') -test('with keystore > flattened w/ header', complete, () => { - const enc = new JWE.Encrypt('foo') - enc.recipient(key, { foo: 'bar' }) - return enc.encrypt('flattened') -}, ks, 'cleartext', 'protected', 'header', 'key', 'cek') -test('with keystore > general', complete, () => JWE.encrypt.general('foo', key), ks, 'cleartext', 'protected', 'key', 'cek') -test('with keystore > general w/ aad', complete, () => JWE.encrypt.general('foo', key, undefined, 'bar'), ks, 'cleartext', 'protected', 'aad', 'key', 'cek') -test('with keystore > general w/ unprotected', complete, () => JWE.encrypt.general('foo', key, undefined, undefined, { foo: 'bar' }), ks, 'cleartext', 'protected', 'unprotected', 'key', 'cek') -test('with keystore > general w/ header', complete, () => { - const enc = new JWE.Encrypt('foo') - enc.recipient(key, { foo: 'bar' }) - return enc.encrypt('general') -}, ks, 'cleartext', 'protected', 'header', 'key', 'cek') diff --git a/test/jwe/cookbook.test.mjs b/test/jwe/cookbook.test.mjs new file mode 100644 index 0000000000..64b9cf179e --- /dev/null +++ b/test/jwe/cookbook.test.mjs @@ -0,0 +1,943 @@ +import test from 'ava'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; + +Promise.all([ + import(`${root}/jwe/flattened/encrypt`), + import(`${root}/jwe/flattened/decrypt`), + import(`${root}/jwe/compact/encrypt`), + import(`${root}/jwe/compact/decrypt`), + import(`${root}/jwk/parse`), + import(`${root}/util/base64url`), +]).then( + ([ + { default: FlattenedEncrypt }, + { default: flattenedDecrypt }, + { default: CompactEncrypt }, + { default: compactDecrypt }, + { default: parseJwk }, + base64url, + ]) => { + const flattened = { + Encrypt: FlattenedEncrypt, + decrypt: flattenedDecrypt, + }; + const compact = { + Encrypt: CompactEncrypt, + decrypt: compactDecrypt, + }; + const encode = TextEncoder.prototype.encode.bind(new TextEncoder()); + + const toJWK = (input) => { + if (typeof input === 'string') { + return { + kty: 'oct', + k: base64url.encode(encode(input)), + }; + } + return input; + }; + const pubjwk = ({ d, p, q, dp, dq, qi, ...jwk }) => jwk; + + async function testCookbook(t, vector) { + const dir = vector.input.alg === 'dir'; + + const reproducible = !!vector.reproducible; + + if (reproducible) { + // sign and compare results are the same + // eslint-disable-next-line no-restricted-syntax + for (const [serialization, expectedResult] of [ + [flattened, vector.output.json_flat], + [compact, vector.output.compact], + ]) { + if (!expectedResult) { + // eslint-disable-next-line no-continue + continue; + } + const encrypt = new serialization.Encrypt(encode(vector.input.plaintext)); + + if (vector.encrypting_content.protected) { + encrypt.setProtectedHeader(vector.encrypting_content.protected); + } + + if (vector.encrypting_content.unprotected) { + encrypt.setSharedUnprotectedHeader(vector.encrypting_content.unprotected); + } + + const { cek, iv } = vector.generated; + + if (cek) { + encrypt.setContentEncryptionKey(base64url.decode(cek)); + } + + if (iv) { + encrypt.setInitializationVector(base64url.decode(iv)); + } + + if (vector.input.aad) { + encrypt.setAdditionalAuthenticatedData(encode(vector.input.aad)); + } + + const keyManagementParameters = {}; + + if (vector.encrypting_key && vector.encrypting_key.iv) { + keyManagementParameters.iv = base64url.decode(vector.encrypting_key.iv); + } + + if (vector.encrypting_key && vector.encrypting_key.iteration_count) { + keyManagementParameters.p2c = vector.encrypting_key.iteration_count; + } + + if (vector.encrypting_key && vector.encrypting_key.salt) { + keyManagementParameters.p2s = base64url.decode(vector.encrypting_key.salt); + } + + if (vector.encrypting_key && vector.encrypting_key.epk) { + keyManagementParameters.epk = parseJwk(vector.encrypting_key.epk, 'ECDH'); + } + + if (Object.keys(keyManagementParameters) !== 0) { + encrypt.setKeyManagementParameters(keyManagementParameters); + } + + const publicKey = await parseJwk( + pubjwk(toJWK(vector.input.pwd || vector.input.key)), + dir ? vector.input.enc : vector.input.alg, + ); + + const result = await encrypt.encrypt(publicKey); + + if (typeof result === 'object') { + Object.entries(expectedResult).forEach(([prop, expected]) => { + t.is(JSON.stringify(result[prop]), JSON.stringify(expected)); + }); + } else { + t.is(result, expectedResult); + } + } + } else { + const encrypt = new flattened.Encrypt(encode(vector.input.plaintext)); + + if (vector.encrypting_content.protected) { + encrypt.setProtectedHeader(vector.encrypting_content.protected); + } + + if (vector.encrypting_content.unprotected) { + encrypt.setUnprotectedHeader(vector.encrypting_content.unprotected); + } + + const privateKey = await parseJwk( + toJWK(vector.input.pwd || vector.input.key), + dir ? vector.input.enc : vector.input.alg, + ); + let publicKey; + if (privateKey.type === 'secret') { + publicKey = privateKey; + } else { + publicKey = await parseJwk( + pubjwk(toJWK(vector.input.pwd || vector.input.key)), + dir ? vector.input.enc : vector.input.alg, + ); + } + + const result = await encrypt.encrypt(publicKey); + await t.notThrowsAsync(flattened.decrypt(result, privateKey)); + } + + const privateKey = await parseJwk( + toJWK(vector.input.pwd || vector.input.key), + dir ? vector.input.enc : vector.input.alg, + ); + if (vector.output.json_flat) { + await t.notThrowsAsync(flattened.decrypt(vector.output.json_flat, privateKey)); + } + if (vector.output.compact) { + await t.notThrowsAsync(compact.decrypt(vector.output.compact, privateKey)); + } + } + testCookbook.title = (title, vector) => `${vector.title}${title ? ` ${title}` : ''}`; + + const vectors = [ + { + title: + 'https://tools.ietf.org/html/rfc7520#section-5.1 - Key Encryption using RSA v1.5 and AES-HMAC-SHA2', + webcrypto: false, + reproducible: false, + input: { + plaintext: + 'You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.', + key: { + kty: 'RSA', + ext: false, + kid: 'frodo.baggins@hobbiton.example', + use: 'enc', + n: + 'maxhbsmBtdQ3CNrKvprUE6n9lYcregDMLYNeTAWcLj8NnPU9XIYegTHVHQjxKDSHP2l-F5jS7sppG1wgdAqZyhnWvXhYNvcM7RfgKxqNx_xAHx6f3yy7s-M9PSNCwPC2lh6UAkR4I00EhV9lrypM9Pi4lBUop9t5fS9W5UNwaAllhrd-osQGPjIeI1deHTwx-ZTHu3C60Pu_LJIl6hKn9wbwaUmA4cR5Bd2pgbaY7ASgsjCUbtYJaNIHSoHXprUdJZKUMAzV0WOKPfA6OPI4oypBadjvMZ4ZAj3BnXaSYsEZhaueTXvZB4eZOAjIyh2e_VOIKVMsnDrJYAVotGlvMQ', + e: 'AQAB', + d: + 'Kn9tgoHfiTVi8uPu5b9TnwyHwG5dK6RE0uFdlpCGnJN7ZEi963R7wybQ1PLAHmpIbNTztfrheoAniRV1NCIqXaW_qS461xiDTp4ntEPnqcKsyO5jMAji7-CL8vhpYYowNFvIesgMoVaPRYMYT9TW63hNM0aWs7USZ_hLg6Oe1mY0vHTI3FucjSM86Nff4oIENt43r2fspgEPGRrdE6fpLc9Oaq-qeP1GFULimrRdndm-P8q8kvN3KHlNAtEgrQAgTTgz80S-3VD0FgWfgnb1PNmiuPUxO8OpI9KDIfu_acc6fg14nsNaJqXe6RESvhGPH2afjHqSy_Fd2vpzj85bQQ', + p: + '2DwQmZ43FoTnQ8IkUj3BmKRf5Eh2mizZA5xEJ2MinUE3sdTYKSLtaEoekX9vbBZuWxHdVhM6UnKCJ_2iNk8Z0ayLYHL0_G21aXf9-unynEpUsH7HHTklLpYAzOOx1ZgVljoxAdWNn3hiEFrjZLZGS7lOH-a3QQlDDQoJOJ2VFmU', + q: + 'te8LY4-W7IyaqH1ExujjMqkTAlTeRbv0VLQnfLY2xINnrWdwiQ93_VF099aP1ESeLja2nw-6iKIe-qT7mtCPozKfVtUYfz5HrJ_XY2kfexJINb9lhZHMv5p1skZpeIS-GPHCC6gRlKo1q-idn_qxyusfWv7WAxlSVfQfk8d6Et0', + dp: + 'UfYKcL_or492vVc0PzwLSplbg4L3-Z5wL48mwiswbpzOyIgd2xHTHQmjJpFAIZ8q-zf9RmgJXkDrFs9rkdxPtAsL1WYdeCT5c125Fkdg317JVRDo1inX7x2Kdh8ERCreW8_4zXItuTl_KiXZNU5lvMQjWbIw2eTx1lpsflo0rYU', + dq: + 'iEgcO-QfpepdH8FWd7mUFyrXdnOkXJBCogChY6YKuIHGc_p8Le9MbpFKESzEaLlN1Ehf3B6oGBl5Iz_ayUlZj2IoQZ82znoUrpa9fVYNot87ACfzIG7q9Mv7RiPAderZi03tkVXAdaBau_9vs5rS-7HMtxkVrxSUvJY14TkXlHE', + qi: + 'kC-lzZOqoFaZCr5l0tOVtREKoVqaAYhQiqIRGL-MzS4sCmRkxm5vZlXYx6RtE1n_AagjqajlkjieGlxTTThHD8Iga6foGBMaAr5uR1hGQpSc7Gl7CF1DZkBJMTQN6EshYzZfxW08mIO8M6Rzuh0beL6fG9mkDcIyPrBXx2bQ_mM', + }, + alg: 'RSA1_5', + enc: 'A128CBC-HS256', + }, + generated: { + cek: '3qyTVhIWt5juqZUCpfRqpvauwB956MEJL2Rt-8qXKSo', + iv: 'bbd5sTkYwhAIqfHsx8DayA', + }, + encrypting_key: {}, + encrypting_content: { + protected: { + alg: 'RSA1_5', + kid: 'frodo.baggins@hobbiton.example', + enc: 'A128CBC-HS256', + }, + }, + output: { + compact: + 'eyJhbGciOiJSU0ExXzUiLCJraWQiOiJmcm9kby5iYWdnaW5zQGhvYmJpdG9uLmV4YW1wbGUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.laLxI0j-nLH-_BgLOXMozKxmy9gffy2gTdvqzfTihJBuuzxg0V7yk1WClnQePFvG2K-pvSlWc9BRIazDrn50RcRai__3TDON395H3c62tIouJJ4XaRvYHFjZTZ2GXfz8YAImcc91Tfk0WXC2F5Xbb71ClQ1DDH151tlpH77f2ff7xiSxh9oSewYrcGTSLUeeCt36r1Kt3OSj7EyBQXoZlN7IxbyhMAfgIe7Mv1rOTOI5I8NQqeXXW8VlzNmoxaGMny3YnGir5Wf6Qt2nBq4qDaPdnaAuuGUGEecelIO1wx1BpyIfgvfjOhMBs9M8XL223Fg47xlGsMXdfuY-4jaqVw.bbd5sTkYwhAIqfHsx8DayA.0fys_TY_na7f8dwSfXLiYdHaA2DxUjD67ieF7fcVbIR62JhJvGZ4_FNVSiGc_raa0HnLQ6s1P2sv3Xzl1p1l_o5wR_RsSzrS8Z-wnI3Jvo0mkpEEnlDmZvDu_k8OWzJv7eZVEqiWKdyVzFhPpiyQU28GLOpRc2VbVbK4dQKPdNTjPPEmRqcaGeTWZVyeSUvf5k59yJZxRuSvWFf6KrNtmRdZ8R4mDOjHSrM_s8uwIFcqt4r5GX8TKaI0zT5CbL5Qlw3sRc7u_hg0yKVOiRytEAEs3vZkcfLkP6nbXdC_PkMdNS-ohP78T2O6_7uInMGhFeX4ctHG7VelHGiT93JfWDEQi5_V9UN1rhXNrYu-0fVMkZAKX3VWi7lzA6BP430m.kvKuFBXHe5mQr4lqgobAUg', + json: { + recipients: [ + { + encrypted_key: + 'laLxI0j-nLH-_BgLOXMozKxmy9gffy2gTdvqzfTihJBuuzxg0V7yk1WClnQePFvG2K-pvSlWc9BRIazDrn50RcRai__3TDON395H3c62tIouJJ4XaRvYHFjZTZ2GXfz8YAImcc91Tfk0WXC2F5Xbb71ClQ1DDH151tlpH77f2ff7xiSxh9oSewYrcGTSLUeeCt36r1Kt3OSj7EyBQXoZlN7IxbyhMAfgIe7Mv1rOTOI5I8NQqeXXW8VlzNmoxaGMny3YnGir5Wf6Qt2nBq4qDaPdnaAuuGUGEecelIO1wx1BpyIfgvfjOhMBs9M8XL223Fg47xlGsMXdfuY-4jaqVw', + }, + ], + protected: + 'eyJhbGciOiJSU0ExXzUiLCJraWQiOiJmcm9kby5iYWdnaW5zQGhvYmJpdG9uLmV4YW1wbGUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0', + iv: 'bbd5sTkYwhAIqfHsx8DayA', + ciphertext: + '0fys_TY_na7f8dwSfXLiYdHaA2DxUjD67ieF7fcVbIR62JhJvGZ4_FNVSiGc_raa0HnLQ6s1P2sv3Xzl1p1l_o5wR_RsSzrS8Z-wnI3Jvo0mkpEEnlDmZvDu_k8OWzJv7eZVEqiWKdyVzFhPpiyQU28GLOpRc2VbVbK4dQKPdNTjPPEmRqcaGeTWZVyeSUvf5k59yJZxRuSvWFf6KrNtmRdZ8R4mDOjHSrM_s8uwIFcqt4r5GX8TKaI0zT5CbL5Qlw3sRc7u_hg0yKVOiRytEAEs3vZkcfLkP6nbXdC_PkMdNS-ohP78T2O6_7uInMGhFeX4ctHG7VelHGiT93JfWDEQi5_V9UN1rhXNrYu-0fVMkZAKX3VWi7lzA6BP430m', + tag: 'kvKuFBXHe5mQr4lqgobAUg', + }, + json_flat: { + protected: + 'eyJhbGciOiJSU0ExXzUiLCJraWQiOiJmcm9kby5iYWdnaW5zQGhvYmJpdG9uLmV4YW1wbGUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0', + encrypted_key: + 'laLxI0j-nLH-_BgLOXMozKxmy9gffy2gTdvqzfTihJBuuzxg0V7yk1WClnQePFvG2K-pvSlWc9BRIazDrn50RcRai__3TDON395H3c62tIouJJ4XaRvYHFjZTZ2GXfz8YAImcc91Tfk0WXC2F5Xbb71ClQ1DDH151tlpH77f2ff7xiSxh9oSewYrcGTSLUeeCt36r1Kt3OSj7EyBQXoZlN7IxbyhMAfgIe7Mv1rOTOI5I8NQqeXXW8VlzNmoxaGMny3YnGir5Wf6Qt2nBq4qDaPdnaAuuGUGEecelIO1wx1BpyIfgvfjOhMBs9M8XL223Fg47xlGsMXdfuY-4jaqVw', + iv: 'bbd5sTkYwhAIqfHsx8DayA', + ciphertext: + '0fys_TY_na7f8dwSfXLiYdHaA2DxUjD67ieF7fcVbIR62JhJvGZ4_FNVSiGc_raa0HnLQ6s1P2sv3Xzl1p1l_o5wR_RsSzrS8Z-wnI3Jvo0mkpEEnlDmZvDu_k8OWzJv7eZVEqiWKdyVzFhPpiyQU28GLOpRc2VbVbK4dQKPdNTjPPEmRqcaGeTWZVyeSUvf5k59yJZxRuSvWFf6KrNtmRdZ8R4mDOjHSrM_s8uwIFcqt4r5GX8TKaI0zT5CbL5Qlw3sRc7u_hg0yKVOiRytEAEs3vZkcfLkP6nbXdC_PkMdNS-ohP78T2O6_7uInMGhFeX4ctHG7VelHGiT93JfWDEQi5_V9UN1rhXNrYu-0fVMkZAKX3VWi7lzA6BP430m', + tag: 'kvKuFBXHe5mQr4lqgobAUg', + }, + }, + }, + { + title: + 'https://tools.ietf.org/html/rfc7520#section-5.2 - Key Encryption using RSA-OAEP with AES-GCM', + webcrypto: true, + input: { + plaintext: + 'You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.', + key: { + kty: 'RSA', + ext: false, + kid: 'samwise.gamgee@hobbiton.example', + use: 'enc', + n: + 'wbdxI55VaanZXPY29Lg5hdmv2XhvqAhoxUkanfzf2-5zVUxa6prHRrI4pP1AhoqJRlZfYtWWd5mmHRG2pAHIlh0ySJ9wi0BioZBl1XP2e-C-FyXJGcTy0HdKQWlrfhTm42EW7Vv04r4gfao6uxjLGwfpGrZLarohiWCPnkNrg71S2CuNZSQBIPGjXfkmIy2tl_VWgGnL22GplyXj5YlBLdxXp3XeStsqo571utNfoUTU8E4qdzJ3U1DItoVkPGsMwlmmnJiwA7sXRItBCivR4M5qnZtdw-7v4WuR4779ubDuJ5nalMv2S66-RPcnFAzWSKxtBDnFJJDGIUe7Tzizjg1nms0Xq_yPub_UOlWn0ec85FCft1hACpWG8schrOBeNqHBODFskYpUc2LC5JA2TaPF2dA67dg1TTsC_FupfQ2kNGcE1LgprxKHcVWYQb86B-HozjHZcqtauBzFNV5tbTuB-TpkcvJfNcFLlH3b8mb-H_ox35FjqBSAjLKyoeqfKTpVjvXhd09knwgJf6VKq6UC418_TOljMVfFTWXUxlnfhOOnzW6HSSzD1c9WrCuVzsUMv54szidQ9wf1cYWf3g5qFDxDQKis99gcDaiCAwM3yEBIzuNeeCa5dartHDb1xEB_HcHSeYbghbMjGfasvKn0aZRsnTyC0xhWBlsolZE', + e: 'AQAB', + alg: 'RSA-OAEP', + d: + 'n7fzJc3_WG59VEOBTkayzuSMM780OJQuZjN_KbH8lOZG25ZoA7T4Bxcc0xQn5oZE5uSCIwg91oCt0JvxPcpmqzaJZg1nirjcWZ-oBtVk7gCAWq-B3qhfF3izlbkosrzjHajIcY33HBhsy4_WerrXg4MDNE4HYojy68TcxT2LYQRxUOCf5TtJXvM8olexlSGtVnQnDRutxEUCwiewfmmrfveEogLx9EA-KMgAjTiISXxqIXQhWUQX1G7v_mV_Hr2YuImYcNcHkRvp9E7ook0876DhkO8v4UOZLwA1OlUX98mkoqwc58A_Y2lBYbVx1_s5lpPsEqbbH-nqIjh1fL0gdNfihLxnclWtW7pCztLnImZAyeCWAG7ZIfv-Rn9fLIv9jZ6r7r-MSH9sqbuziHN2grGjD_jfRluMHa0l84fFKl6bcqN1JWxPVhzNZo01yDF-1LiQnqUYSepPf6X3a2SOdkqBRiquE6EvLuSYIDpJq3jDIsgoL8Mo1LoomgiJxUwL_GWEOGu28gplyzm-9Q0U0nyhEf1uhSR8aJAQWAiFImWH5W_IQT9I7-yrindr_2fWQ_i1UgMsGzA7aOGzZfPljRy6z-tY_KuBG00-28S_aWvjyUc-Alp8AUyKjBZ-7CWH32fGWK48j1t-zomrwjL_mnhsPbGs0c9WsWgRzI-K8gE', + p: + '7_2v3OQZzlPFcHyYfLABQ3XP85Es4hCdwCkbDeltaUXgVy9l9etKghvM4hRkOvbb01kYVuLFmxIkCDtpi-zLCYAdXKrAK3PtSbtzld_XZ9nlsYa_QZWpXB_IrtFjVfdKUdMz94pHUhFGFj7nr6NNxfpiHSHWFE1zD_AC3mY46J961Y2LRnreVwAGNw53p07Db8yD_92pDa97vqcZOdgtybH9q6uma-RFNhO1AoiJhYZj69hjmMRXx-x56HO9cnXNbmzNSCFCKnQmn4GQLmRj9sfbZRqL94bbtE4_e0Zrpo8RNo8vxRLqQNwIy85fc6BRgBJomt8QdQvIgPgWCv5HoQ', + q: + 'zqOHk1P6WN_rHuM7ZF1cXH0x6RuOHq67WuHiSknqQeefGBA9PWs6ZyKQCO-O6mKXtcgE8_Q_hA2kMRcKOcvHil1hqMCNSXlflM7WPRPZu2qCDcqssd_uMbP-DqYthH_EzwL9KnYoH7JQFxxmcv5An8oXUtTwk4knKjkIYGRuUwfQTus0w1NfjFAyxOOiAQ37ussIcE6C6ZSsM3n41UlbJ7TCqewzVJaPJN5cxjySPZPD3Vp01a9YgAD6a3IIaKJdIxJS1ImnfPevSJQBE79-EXe2kSwVgOzvt-gsmM29QQ8veHy4uAqca5dZzMs7hkkHtw1z0jHV90epQJJlXXnH8Q', + dp: + '19oDkBh1AXelMIxQFm2zZTqUhAzCIr4xNIGEPNoDt1jK83_FJA-xnx5kA7-1erdHdms_Ef67HsONNv5A60JaR7w8LHnDiBGnjdaUmmuO8XAxQJ_ia5mxjxNjS6E2yD44USo2JmHvzeeNczq25elqbTPLhUpGo1IZuG72FZQ5gTjXoTXC2-xtCDEUZfaUNh4IeAipfLugbpe0JAFlFfrTDAMUFpC3iXjxqzbEanflwPvj6V9iDSgjj8SozSM0dLtxvu0LIeIQAeEgT_yXcrKGmpKdSO08kLBx8VUjkbv_3Pn20Gyu2YEuwpFlM_H1NikuxJNKFGmnAq9LcnwwT0jvoQ', + dq: + 'S6p59KrlmzGzaQYQM3o0XfHCGvfqHLYjCO557HYQf72O9kLMCfd_1VBEqeD-1jjwELKDjck8kOBl5UvohK1oDfSP1DleAy-cnmL29DqWmhgwM1ip0CCNmkmsmDSlqkUXDi6sAaZuntyukyflI-qSQ3C_BafPyFaKrt1fgdyEwYa08pESKwwWisy7KnmoUvaJ3SaHmohFS78TJ25cfc10wZ9hQNOrIChZlkiOdFCtxDqdmCqNacnhgE3bZQjGp3n83ODSz9zwJcSUvODlXBPc2AycH6Ci5yjbxt4Ppox_5pjm6xnQkiPgj01GpsUssMmBN7iHVsrE7N2iznBNCeOUIQ', + qi: + 'FZhClBMywVVjnuUud-05qd5CYU0dK79akAgy9oX6RX6I3IIIPckCciRrokxglZn-omAY5CnCe4KdrnjFOT5YUZE7G_Pg44XgCXaarLQf4hl80oPEf6-jJ5Iy6wPRx7G2e8qLxnh9cOdf-kRqgOS3F48Ucvw3ma5V6KGMwQqWFeV31XtZ8l5cVI-I3NzBS7qltpUVgz2Ju021eyc7IlqgzR98qKONl27DuEES0aK0WE97jnsyO27Yp88Wa2RiBrEocM89QZI1seJiGDizHRUP4UZxw9zsXww46wy0P6f9grnYp7t8LkyDDk8eoI4KX6SNMNVcyVS9IWjlq8EzqZEKIA', + }, + alg: 'RSA-OAEP', + enc: 'A256GCM', + }, + generated: { + cek: 'mYMfsggkTAm0TbvtlFh2hyoXnbEzJQjMxmgLN3d8xXA', + iv: '-nBoKLH0YkLZPSI9', + }, + encrypting_key: {}, + encrypting_content: { + protected: { + alg: 'RSA-OAEP', + kid: 'samwise.gamgee@hobbiton.example', + enc: 'A256GCM', + }, + }, + output: { + compact: + 'eyJhbGciOiJSU0EtT0FFUCIsImtpZCI6InNhbXdpc2UuZ2FtZ2VlQGhvYmJpdG9uLmV4YW1wbGUiLCJlbmMiOiJBMjU2R0NNIn0.rT99rwrBTbTI7IJM8fU3Eli7226HEB7IchCxNuh7lCiud48LxeolRdtFF4nzQibeYOl5S_PJsAXZwSXtDePz9hk-BbtsTBqC2UsPOdwjC9NhNupNNu9uHIVftDyucvI6hvALeZ6OGnhNV4v1zx2k7O1D89mAzfw-_kT3tkuorpDU-CpBENfIHX1Q58-Aad3FzMuo3Fn9buEP2yXakLXYa15BUXQsupM4A1GD4_H4Bd7V3u9h8Gkg8BpxKdUV9ScfJQTcYm6eJEBz3aSwIaK4T3-dwWpuBOhROQXBosJzS1asnuHtVMt2pKIIfux5BC6huIvmY7kzV7W7aIUrpYm_3H4zYvyMeq5pGqFmW2k8zpO878TRlZx7pZfPYDSXZyS0CfKKkMozT_qiCwZTSz4duYnt8hS4Z9sGthXn9uDqd6wycMagnQfOTs_lycTWmY-aqWVDKhjYNRf03NiwRtb5BE-tOdFwCASQj3uuAgPGrO2AWBe38UjQb0lvXn1SpyvYZ3WFc7WOJYaTa7A8DRn6MC6T-xDmMuxC0G7S2rscw5lQQU06MvZTlFOt0UvfuKBa03cxA_nIBIhLMjY2kOTxQMmpDPTr6Cbo8aKaOnx6ASE5Jx9paBpnNmOOKH35j_QlrQhDWUN6A2Gg8iFayJ69xDEdHAVCGRzN3woEI2ozDRs.-nBoKLH0YkLZPSI9.o4k2cnGN8rSSw3IDo1YuySkqeS_t2m1GXklSgqBdpACm6UJuJowOHC5ytjqYgRL-I-soPlwqMUf4UgRWWeaOGNw6vGW-xyM01lTYxrXfVzIIaRdhYtEMRBvBWbEwP7ua1DRfvaOjgZv6Ifa3brcAM64d8p5lhhNcizPersuhw5f-pGYzseva-TUaL8iWnctc-sSwy7SQmRkfhDjwbz0fz6kFovEgj64X1I5s7E6GLp5fnbYGLa1QUiML7Cc2GxgvI7zqWo0YIEc7aCflLG1-8BboVWFdZKLK9vNoycrYHumwzKluLWEbSVmaPpOslY2n525DxDfWaVFUfKQxMF56vn4B9QMpWAbnypNimbM8zVOw.UCGiqJxhBI3IFVdPalHHvA', + json: { + recipients: [ + { + encrypted_key: + 'rT99rwrBTbTI7IJM8fU3Eli7226HEB7IchCxNuh7lCiud48LxeolRdtFF4nzQibeYOl5S_PJsAXZwSXtDePz9hk-BbtsTBqC2UsPOdwjC9NhNupNNu9uHIVftDyucvI6hvALeZ6OGnhNV4v1zx2k7O1D89mAzfw-_kT3tkuorpDU-CpBENfIHX1Q58-Aad3FzMuo3Fn9buEP2yXakLXYa15BUXQsupM4A1GD4_H4Bd7V3u9h8Gkg8BpxKdUV9ScfJQTcYm6eJEBz3aSwIaK4T3-dwWpuBOhROQXBosJzS1asnuHtVMt2pKIIfux5BC6huIvmY7kzV7W7aIUrpYm_3H4zYvyMeq5pGqFmW2k8zpO878TRlZx7pZfPYDSXZyS0CfKKkMozT_qiCwZTSz4duYnt8hS4Z9sGthXn9uDqd6wycMagnQfOTs_lycTWmY-aqWVDKhjYNRf03NiwRtb5BE-tOdFwCASQj3uuAgPGrO2AWBe38UjQb0lvXn1SpyvYZ3WFc7WOJYaTa7A8DRn6MC6T-xDmMuxC0G7S2rscw5lQQU06MvZTlFOt0UvfuKBa03cxA_nIBIhLMjY2kOTxQMmpDPTr6Cbo8aKaOnx6ASE5Jx9paBpnNmOOKH35j_QlrQhDWUN6A2Gg8iFayJ69xDEdHAVCGRzN3woEI2ozDRs', + }, + ], + protected: + 'eyJhbGciOiJSU0EtT0FFUCIsImtpZCI6InNhbXdpc2UuZ2FtZ2VlQGhvYmJpdG9uLmV4YW1wbGUiLCJlbmMiOiJBMjU2R0NNIn0', + iv: '-nBoKLH0YkLZPSI9', + ciphertext: + 'o4k2cnGN8rSSw3IDo1YuySkqeS_t2m1GXklSgqBdpACm6UJuJowOHC5ytjqYgRL-I-soPlwqMUf4UgRWWeaOGNw6vGW-xyM01lTYxrXfVzIIaRdhYtEMRBvBWbEwP7ua1DRfvaOjgZv6Ifa3brcAM64d8p5lhhNcizPersuhw5f-pGYzseva-TUaL8iWnctc-sSwy7SQmRkfhDjwbz0fz6kFovEgj64X1I5s7E6GLp5fnbYGLa1QUiML7Cc2GxgvI7zqWo0YIEc7aCflLG1-8BboVWFdZKLK9vNoycrYHumwzKluLWEbSVmaPpOslY2n525DxDfWaVFUfKQxMF56vn4B9QMpWAbnypNimbM8zVOw', + tag: 'UCGiqJxhBI3IFVdPalHHvA', + }, + json_flat: { + protected: + 'eyJhbGciOiJSU0EtT0FFUCIsImtpZCI6InNhbXdpc2UuZ2FtZ2VlQGhvYmJpdG9uLmV4YW1wbGUiLCJlbmMiOiJBMjU2R0NNIn0', + encrypted_key: + 'rT99rwrBTbTI7IJM8fU3Eli7226HEB7IchCxNuh7lCiud48LxeolRdtFF4nzQibeYOl5S_PJsAXZwSXtDePz9hk-BbtsTBqC2UsPOdwjC9NhNupNNu9uHIVftDyucvI6hvALeZ6OGnhNV4v1zx2k7O1D89mAzfw-_kT3tkuorpDU-CpBENfIHX1Q58-Aad3FzMuo3Fn9buEP2yXakLXYa15BUXQsupM4A1GD4_H4Bd7V3u9h8Gkg8BpxKdUV9ScfJQTcYm6eJEBz3aSwIaK4T3-dwWpuBOhROQXBosJzS1asnuHtVMt2pKIIfux5BC6huIvmY7kzV7W7aIUrpYm_3H4zYvyMeq5pGqFmW2k8zpO878TRlZx7pZfPYDSXZyS0CfKKkMozT_qiCwZTSz4duYnt8hS4Z9sGthXn9uDqd6wycMagnQfOTs_lycTWmY-aqWVDKhjYNRf03NiwRtb5BE-tOdFwCASQj3uuAgPGrO2AWBe38UjQb0lvXn1SpyvYZ3WFc7WOJYaTa7A8DRn6MC6T-xDmMuxC0G7S2rscw5lQQU06MvZTlFOt0UvfuKBa03cxA_nIBIhLMjY2kOTxQMmpDPTr6Cbo8aKaOnx6ASE5Jx9paBpnNmOOKH35j_QlrQhDWUN6A2Gg8iFayJ69xDEdHAVCGRzN3woEI2ozDRs', + iv: '-nBoKLH0YkLZPSI9', + ciphertext: + 'o4k2cnGN8rSSw3IDo1YuySkqeS_t2m1GXklSgqBdpACm6UJuJowOHC5ytjqYgRL-I-soPlwqMUf4UgRWWeaOGNw6vGW-xyM01lTYxrXfVzIIaRdhYtEMRBvBWbEwP7ua1DRfvaOjgZv6Ifa3brcAM64d8p5lhhNcizPersuhw5f-pGYzseva-TUaL8iWnctc-sSwy7SQmRkfhDjwbz0fz6kFovEgj64X1I5s7E6GLp5fnbYGLa1QUiML7Cc2GxgvI7zqWo0YIEc7aCflLG1-8BboVWFdZKLK9vNoycrYHumwzKluLWEbSVmaPpOslY2n525DxDfWaVFUfKQxMF56vn4B9QMpWAbnypNimbM8zVOw', + tag: 'UCGiqJxhBI3IFVdPalHHvA', + }, + }, + }, + { + title: + 'https://tools.ietf.org/html/rfc7520#section-5.3 - Key Wrap using PBES2-AES-KeyWrap with AES-CBC-HMAC-SHA2', + webcrypto: true, + reproducible: true, + input: { + plaintext: + '{"keys":[{"kty":"oct","kid":"77c7e2b8-6e13-45cf-8672-617b5b45243a","use":"enc","alg":"A128GCM","k":"XctOhJAkA-pD9Lh7ZgW_2A"},{"kty":"oct","kid":"81b20965-8332-43d9-a468-82160ad91ac8","use":"enc","alg":"A128KW","k":"GZy6sIZ6wl9NJOKB-jnmVQ"},{"kty":"oct","kid":"18ec08e1-bfa9-4d95-b205-2b4dd1d4321d","use":"enc","alg":"A256GCMKW","k":"qC57l_uxcm7Nm3K-ct4GFjx8tM1U8CZ0NLBvdQstiS8"}]}', + pwd: 'entrap_o–peter_long–credit_tun', + alg: 'PBES2-HS512+A256KW', + enc: 'A128CBC-HS256', + }, + generated: { + cek: 'uwsjJXaBK407Qaf0_zpcpmr1Cs0CC50hIUEyGNEt3m0', + iv: 'VBiCzVHNoLiR3F4V82uoTQ', + }, + encrypting_key: { + salt: '8Q1SzinasR3xchYz6ZZcHA', + iteration_count: 8192, + }, + encrypting_content: { + protected: { + alg: 'PBES2-HS512+A256KW', + p2s: '8Q1SzinasR3xchYz6ZZcHA', + p2c: 8192, + cty: 'jwk-set+json', + enc: 'A128CBC-HS256', + }, + }, + output: { + compact: + 'eyJhbGciOiJQQkVTMi1IUzUxMitBMjU2S1ciLCJwMnMiOiI4UTFTemluYXNSM3hjaFl6NlpaY0hBIiwicDJjIjo4MTkyLCJjdHkiOiJqd2stc2V0K2pzb24iLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.d3qNhUWfqheyPp4H8sjOWsDYajoej4c5Je6rlUtFPWdgtURtmeDV1g.VBiCzVHNoLiR3F4V82uoTQ.23i-Tb1AV4n0WKVSSgcQrdg6GRqsUKxjruHXYsTHAJLZ2nsnGIX86vMXqIi6IRsfywCRFzLxEcZBRnTvG3nhzPk0GDD7FMyXhUHpDjEYCNA_XOmzg8yZR9oyjo6lTF6si4q9FZ2EhzgFQCLO_6h5EVg3vR75_hkBsnuoqoM3dwejXBtIodN84PeqMb6asmas_dpSsz7H10fC5ni9xIz424givB1YLldF6exVmL93R3fOoOJbmk2GBQZL_SEGllv2cQsBgeprARsaQ7Bq99tT80coH8ItBjgV08AtzXFFsx9qKvC982KLKdPQMTlVJKkqtV4Ru5LEVpBZXBnZrtViSOgyg6AiuwaS-rCrcD_ePOGSuxvgtrokAKYPqmXUeRdjFJwafkYEkiuDCV9vWGAi1DH2xTafhJwcmywIyzi4BqRpmdn_N-zl5tuJYyuvKhjKv6ihbsV_k1hJGPGAxJ6wUpmwC4PTQ2izEm0TuSE8oMKdTw8V3kobXZ77ulMwDs4p.0HlwodAhOCILG5SQ2LQ9dg', + json: { + recipients: [ + { + encrypted_key: 'd3qNhUWfqheyPp4H8sjOWsDYajoej4c5Je6rlUtFPWdgtURtmeDV1g', + }, + ], + protected: + 'eyJhbGciOiJQQkVTMi1IUzUxMitBMjU2S1ciLCJwMnMiOiI4UTFTemluYXNSM3hjaFl6NlpaY0hBIiwicDJjIjo4MTkyLCJjdHkiOiJqd2stc2V0K2pzb24iLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0', + iv: 'VBiCzVHNoLiR3F4V82uoTQ', + ciphertext: + '23i-Tb1AV4n0WKVSSgcQrdg6GRqsUKxjruHXYsTHAJLZ2nsnGIX86vMXqIi6IRsfywCRFzLxEcZBRnTvG3nhzPk0GDD7FMyXhUHpDjEYCNA_XOmzg8yZR9oyjo6lTF6si4q9FZ2EhzgFQCLO_6h5EVg3vR75_hkBsnuoqoM3dwejXBtIodN84PeqMb6asmas_dpSsz7H10fC5ni9xIz424givB1YLldF6exVmL93R3fOoOJbmk2GBQZL_SEGllv2cQsBgeprARsaQ7Bq99tT80coH8ItBjgV08AtzXFFsx9qKvC982KLKdPQMTlVJKkqtV4Ru5LEVpBZXBnZrtViSOgyg6AiuwaS-rCrcD_ePOGSuxvgtrokAKYPqmXUeRdjFJwafkYEkiuDCV9vWGAi1DH2xTafhJwcmywIyzi4BqRpmdn_N-zl5tuJYyuvKhjKv6ihbsV_k1hJGPGAxJ6wUpmwC4PTQ2izEm0TuSE8oMKdTw8V3kobXZ77ulMwDs4p', + tag: '0HlwodAhOCILG5SQ2LQ9dg', + }, + json_flat: { + protected: + 'eyJhbGciOiJQQkVTMi1IUzUxMitBMjU2S1ciLCJwMnMiOiI4UTFTemluYXNSM3hjaFl6NlpaY0hBIiwicDJjIjo4MTkyLCJjdHkiOiJqd2stc2V0K2pzb24iLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0', + encrypted_key: 'd3qNhUWfqheyPp4H8sjOWsDYajoej4c5Je6rlUtFPWdgtURtmeDV1g', + iv: 'VBiCzVHNoLiR3F4V82uoTQ', + ciphertext: + '23i-Tb1AV4n0WKVSSgcQrdg6GRqsUKxjruHXYsTHAJLZ2nsnGIX86vMXqIi6IRsfywCRFzLxEcZBRnTvG3nhzPk0GDD7FMyXhUHpDjEYCNA_XOmzg8yZR9oyjo6lTF6si4q9FZ2EhzgFQCLO_6h5EVg3vR75_hkBsnuoqoM3dwejXBtIodN84PeqMb6asmas_dpSsz7H10fC5ni9xIz424givB1YLldF6exVmL93R3fOoOJbmk2GBQZL_SEGllv2cQsBgeprARsaQ7Bq99tT80coH8ItBjgV08AtzXFFsx9qKvC982KLKdPQMTlVJKkqtV4Ru5LEVpBZXBnZrtViSOgyg6AiuwaS-rCrcD_ePOGSuxvgtrokAKYPqmXUeRdjFJwafkYEkiuDCV9vWGAi1DH2xTafhJwcmywIyzi4BqRpmdn_N-zl5tuJYyuvKhjKv6ihbsV_k1hJGPGAxJ6wUpmwC4PTQ2izEm0TuSE8oMKdTw8V3kobXZ77ulMwDs4p', + tag: '0HlwodAhOCILG5SQ2LQ9dg', + }, + }, + }, + { + title: + 'https://tools.ietf.org/html/rfc7520#section-5.4 - Key Agreement with Key Wrapping using ECDH-ES and AES-KeyWrap with AES-GCM', + webcrypto: true, + input: { + plaintext: + 'You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.', + key: { + kty: 'EC', + ext: false, + kid: 'peregrin.took@tuckborough.example', + use: 'enc', + crv: 'P-384', + x: 'YU4rRUzdmVqmRtWOs2OpDE_T5fsNIodcG8G5FWPrTPMyxpzsSOGaQLpe2FpxBmu2', + y: 'A8-yxCHxkfBz3hKZfI1jUYMjUhsEveZ9THuwFjH2sCNdtksRJU7D5-SkgaFL1ETP', + d: 'iTx2pk7wW-GqJkHcEkFQb2EFyYcO7RugmaW3mRrQVAOUiPommT0IdnYK2xDlZh-j', + }, + alg: 'ECDH-ES+A128KW', + enc: 'A128GCM', + }, + generated: { + cek: 'Nou2ueKlP70ZXDbq9UrRwg', + iv: 'mH-G2zVqgztUtnW_', + }, + encrypting_key: { + epk: { + kty: 'EC', + crv: 'P-384', + x: 'uBo4kHPw6kbjx5l0xowrd_oYzBmaz-GKFZu4xAFFkbYiWgutEK6iuEDsQ6wNdNg3', + y: 'sp3p5SGhZVC2faXumI-e9JU2Mo8KpoYrFDr5yPNVtW4PgEwZOyQTA-JdaY8tb7E0', + d: 'D5H4Y_5PSKZvhfVFbcCYJOtcGZygRgfZkpsBr59Icmmhe9sW6nkZ8WfwhinUfWJg', + }, + }, + encrypting_content: { + protected: { + alg: 'ECDH-ES+A128KW', + kid: 'peregrin.took@tuckborough.example', + epk: { + kty: 'EC', + crv: 'P-384', + x: 'uBo4kHPw6kbjx5l0xowrd_oYzBmaz-GKFZu4xAFFkbYiWgutEK6iuEDsQ6wNdNg3', + y: 'sp3p5SGhZVC2faXumI-e9JU2Mo8KpoYrFDr5yPNVtW4PgEwZOyQTA-JdaY8tb7E0', + }, + enc: 'A128GCM', + }, + }, + output: { + compact: + 'eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImtpZCI6InBlcmVncmluLnRvb2tAdHVja2Jvcm91Z2guZXhhbXBsZSIsImVwayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMzg0IiwieCI6InVCbzRrSFB3Nmtiang1bDB4b3dyZF9vWXpCbWF6LUdLRlp1NHhBRkZrYllpV2d1dEVLNml1RURzUTZ3TmROZzMiLCJ5Ijoic3AzcDVTR2haVkMyZmFYdW1JLWU5SlUyTW84S3BvWXJGRHI1eVBOVnRXNFBnRXdaT3lRVEEtSmRhWTh0YjdFMCJ9LCJlbmMiOiJBMTI4R0NNIn0.0DJjBXri_kBcC46IkU5_Jk9BqaQeHdv2.mH-G2zVqgztUtnW_.tkZuOO9h95OgHJmkkrfLBisku8rGf6nzVxhRM3sVOhXgz5NJ76oID7lpnAi_cPWJRCjSpAaUZ5dOR3Spy7QuEkmKx8-3RCMhSYMzsXaEwDdXta9Mn5B7cCBoJKB0IgEnj_qfo1hIi-uEkUpOZ8aLTZGHfpl05jMwbKkTe2yK3mjF6SBAsgicQDVCkcY9BLluzx1RmC3ORXaM0JaHPB93YcdSDGgpgBWMVrNU1ErkjcMqMoT_wtCex3w03XdLkjXIuEr2hWgeP-nkUZTPU9EoGSPj6fAS-bSz87RCPrxZdj_iVyC6QWcqAu07WNhjzJEPc4jVntRJ6K53NgPQ5p99l3Z408OUqj4ioYezbS6vTPlQ.WuGzxmcreYjpHGJoa17EBg', + json: { + recipients: [ + { + encrypted_key: '0DJjBXri_kBcC46IkU5_Jk9BqaQeHdv2', + }, + ], + protected: + 'eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImtpZCI6InBlcmVncmluLnRvb2tAdHVja2Jvcm91Z2guZXhhbXBsZSIsImVwayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMzg0IiwieCI6InVCbzRrSFB3Nmtiang1bDB4b3dyZF9vWXpCbWF6LUdLRlp1NHhBRkZrYllpV2d1dEVLNml1RURzUTZ3TmROZzMiLCJ5Ijoic3AzcDVTR2haVkMyZmFYdW1JLWU5SlUyTW84S3BvWXJGRHI1eVBOVnRXNFBnRXdaT3lRVEEtSmRhWTh0YjdFMCJ9LCJlbmMiOiJBMTI4R0NNIn0', + iv: 'mH-G2zVqgztUtnW_', + ciphertext: + 'tkZuOO9h95OgHJmkkrfLBisku8rGf6nzVxhRM3sVOhXgz5NJ76oID7lpnAi_cPWJRCjSpAaUZ5dOR3Spy7QuEkmKx8-3RCMhSYMzsXaEwDdXta9Mn5B7cCBoJKB0IgEnj_qfo1hIi-uEkUpOZ8aLTZGHfpl05jMwbKkTe2yK3mjF6SBAsgicQDVCkcY9BLluzx1RmC3ORXaM0JaHPB93YcdSDGgpgBWMVrNU1ErkjcMqMoT_wtCex3w03XdLkjXIuEr2hWgeP-nkUZTPU9EoGSPj6fAS-bSz87RCPrxZdj_iVyC6QWcqAu07WNhjzJEPc4jVntRJ6K53NgPQ5p99l3Z408OUqj4ioYezbS6vTPlQ', + tag: 'WuGzxmcreYjpHGJoa17EBg', + }, + json_flat: { + protected: + 'eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImtpZCI6InBlcmVncmluLnRvb2tAdHVja2Jvcm91Z2guZXhhbXBsZSIsImVwayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMzg0IiwieCI6InVCbzRrSFB3Nmtiang1bDB4b3dyZF9vWXpCbWF6LUdLRlp1NHhBRkZrYllpV2d1dEVLNml1RURzUTZ3TmROZzMiLCJ5Ijoic3AzcDVTR2haVkMyZmFYdW1JLWU5SlUyTW84S3BvWXJGRHI1eVBOVnRXNFBnRXdaT3lRVEEtSmRhWTh0YjdFMCJ9LCJlbmMiOiJBMTI4R0NNIn0', + encrypted_key: '0DJjBXri_kBcC46IkU5_Jk9BqaQeHdv2', + iv: 'mH-G2zVqgztUtnW_', + ciphertext: + 'tkZuOO9h95OgHJmkkrfLBisku8rGf6nzVxhRM3sVOhXgz5NJ76oID7lpnAi_cPWJRCjSpAaUZ5dOR3Spy7QuEkmKx8-3RCMhSYMzsXaEwDdXta9Mn5B7cCBoJKB0IgEnj_qfo1hIi-uEkUpOZ8aLTZGHfpl05jMwbKkTe2yK3mjF6SBAsgicQDVCkcY9BLluzx1RmC3ORXaM0JaHPB93YcdSDGgpgBWMVrNU1ErkjcMqMoT_wtCex3w03XdLkjXIuEr2hWgeP-nkUZTPU9EoGSPj6fAS-bSz87RCPrxZdj_iVyC6QWcqAu07WNhjzJEPc4jVntRJ6K53NgPQ5p99l3Z408OUqj4ioYezbS6vTPlQ', + tag: 'WuGzxmcreYjpHGJoa17EBg', + }, + }, + }, + { + title: + 'https://tools.ietf.org/html/rfc7520#section-5.5 - Key Agreement using ECDH-ES with AES-CBC-HMAC-SHA2', + webcrypto: true, + input: { + plaintext: + 'You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.', + key: { + kty: 'EC', + ext: false, + kid: 'meriadoc.brandybuck@buckland.example', + use: 'enc', + crv: 'P-256', + x: 'Ze2loSV3wrroKUN_4zhwGhCqo3Xhu1td4QjeQ5wIVR0', + y: 'HlLtdXARY_f55A3fnzQbPcm6hgr34Mp8p-nuzQCE0Zw', + d: 'r_kHyZ-a06rmxM3yESK84r1otSg-aQcVStkRhA-iCM8', + }, + alg: 'ECDH-ES', + enc: 'A128CBC-HS256', + }, + generated: { + iv: 'yc9N8v5sYyv3iGQT926IUg', + }, + encrypting_key: { + epk: { + kty: 'EC', + crv: 'P-256', + x: 'mPUKT_bAWGHIhg0TpjjqVsP1rXWQu_vwVOHHtNkdYoA', + y: '8BQAsImGeAS46fyWw5MhYfGTT0IjBpFw2SS34Dv4Irs', + d: 'AtH35vJsQ9SGjYfOsjUxYXQKrPH3FjZHmEtSKoSN8cM', + }, + cek: 'hzHdlfQIAEehb8Hrd_mFRhKsKLEzPfshfXs9l6areCc', + }, + encrypting_content: { + protected: { + alg: 'ECDH-ES', + kid: 'meriadoc.brandybuck@buckland.example', + epk: { + kty: 'EC', + crv: 'P-256', + x: 'mPUKT_bAWGHIhg0TpjjqVsP1rXWQu_vwVOHHtNkdYoA', + y: '8BQAsImGeAS46fyWw5MhYfGTT0IjBpFw2SS34Dv4Irs', + }, + enc: 'A128CBC-HS256', + }, + }, + output: { + compact: + 'eyJhbGciOiJFQ0RILUVTIiwia2lkIjoibWVyaWFkb2MuYnJhbmR5YnVja0BidWNrbGFuZC5leGFtcGxlIiwiZXBrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoibVBVS1RfYkFXR0hJaGcwVHBqanFWc1AxclhXUXVfdndWT0hIdE5rZFlvQSIsInkiOiI4QlFBc0ltR2VBUzQ2ZnlXdzVNaFlmR1RUMElqQnBGdzJTUzM0RHY0SXJzIn0sImVuYyI6IkExMjhDQkMtSFMyNTYifQ..yc9N8v5sYyv3iGQT926IUg.BoDlwPnTypYq-ivjmQvAYJLb5Q6l-F3LIgQomlz87yW4OPKbWE1zSTEFjDfhU9IPIOSA9Bml4m7iDFwA-1ZXvHteLDtw4R1XRGMEsDIqAYtskTTmzmzNa-_q4F_evAPUmwlO-ZG45Mnq4uhM1fm_D9rBtWolqZSF3xGNNkpOMQKF1Cl8i8wjzRli7-IXgyirlKQsbhhqRzkv8IcY6aHl24j03C-AR2le1r7URUhArM79BY8soZU0lzwI-sD5PZ3l4NDCCei9XkoIAfsXJWmySPoeRb2Ni5UZL4mYpvKDiwmyzGd65KqVw7MsFfI_K767G9C9Azp73gKZD0DyUn1mn0WW5LmyX_yJ-3AROq8p1WZBfG-ZyJ6195_JGG2m9Csg.WCCkNa-x4BeB9hIDIfFuhg', + json: { + protected: + 'eyJhbGciOiJFQ0RILUVTIiwia2lkIjoibWVyaWFkb2MuYnJhbmR5YnVja0BidWNrbGFuZC5leGFtcGxlIiwiZXBrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoibVBVS1RfYkFXR0hJaGcwVHBqanFWc1AxclhXUXVfdndWT0hIdE5rZFlvQSIsInkiOiI4QlFBc0ltR2VBUzQ2ZnlXdzVNaFlmR1RUMElqQnBGdzJTUzM0RHY0SXJzIn0sImVuYyI6IkExMjhDQkMtSFMyNTYifQ', + iv: 'yc9N8v5sYyv3iGQT926IUg', + ciphertext: + 'BoDlwPnTypYq-ivjmQvAYJLb5Q6l-F3LIgQomlz87yW4OPKbWE1zSTEFjDfhU9IPIOSA9Bml4m7iDFwA-1ZXvHteLDtw4R1XRGMEsDIqAYtskTTmzmzNa-_q4F_evAPUmwlO-ZG45Mnq4uhM1fm_D9rBtWolqZSF3xGNNkpOMQKF1Cl8i8wjzRli7-IXgyirlKQsbhhqRzkv8IcY6aHl24j03C-AR2le1r7URUhArM79BY8soZU0lzwI-sD5PZ3l4NDCCei9XkoIAfsXJWmySPoeRb2Ni5UZL4mYpvKDiwmyzGd65KqVw7MsFfI_K767G9C9Azp73gKZD0DyUn1mn0WW5LmyX_yJ-3AROq8p1WZBfG-ZyJ6195_JGG2m9Csg', + tag: 'WCCkNa-x4BeB9hIDIfFuhg', + }, + json_flat: { + protected: + 'eyJhbGciOiJFQ0RILUVTIiwia2lkIjoibWVyaWFkb2MuYnJhbmR5YnVja0BidWNrbGFuZC5leGFtcGxlIiwiZXBrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoibVBVS1RfYkFXR0hJaGcwVHBqanFWc1AxclhXUXVfdndWT0hIdE5rZFlvQSIsInkiOiI4QlFBc0ltR2VBUzQ2ZnlXdzVNaFlmR1RUMElqQnBGdzJTUzM0RHY0SXJzIn0sImVuYyI6IkExMjhDQkMtSFMyNTYifQ', + iv: 'yc9N8v5sYyv3iGQT926IUg', + ciphertext: + 'BoDlwPnTypYq-ivjmQvAYJLb5Q6l-F3LIgQomlz87yW4OPKbWE1zSTEFjDfhU9IPIOSA9Bml4m7iDFwA-1ZXvHteLDtw4R1XRGMEsDIqAYtskTTmzmzNa-_q4F_evAPUmwlO-ZG45Mnq4uhM1fm_D9rBtWolqZSF3xGNNkpOMQKF1Cl8i8wjzRli7-IXgyirlKQsbhhqRzkv8IcY6aHl24j03C-AR2le1r7URUhArM79BY8soZU0lzwI-sD5PZ3l4NDCCei9XkoIAfsXJWmySPoeRb2Ni5UZL4mYpvKDiwmyzGd65KqVw7MsFfI_K767G9C9Azp73gKZD0DyUn1mn0WW5LmyX_yJ-3AROq8p1WZBfG-ZyJ6195_JGG2m9Csg', + tag: 'WCCkNa-x4BeB9hIDIfFuhg', + }, + }, + }, + { + title: + 'https://tools.ietf.org/html/rfc7520#section-5.6 - Direction Encryption using AES-GCM', + webcrypto: true, + reproducible: true, + input: { + plaintext: + 'You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.', + key: { + kty: 'oct', + ext: false, + kid: '77c7e2b8-6e13-45cf-8672-617b5b45243a', + use: 'enc', + alg: 'A128GCM', + k: 'XctOhJAkA-pD9Lh7ZgW_2A', + }, + alg: 'dir', + enc: 'A128GCM', + }, + generated: { + iv: 'refa467QzzKx6QAB', + }, + encrypting_content: { + protected: { + alg: 'dir', + kid: '77c7e2b8-6e13-45cf-8672-617b5b45243a', + enc: 'A128GCM', + }, + }, + output: { + compact: + 'eyJhbGciOiJkaXIiLCJraWQiOiI3N2M3ZTJiOC02ZTEzLTQ1Y2YtODY3Mi02MTdiNWI0NTI0M2EiLCJlbmMiOiJBMTI4R0NNIn0..refa467QzzKx6QAB.JW_i_f52hww_ELQPGaYyeAB6HYGcR559l9TYnSovc23XJoBcW29rHP8yZOZG7YhLpT1bjFuvZPjQS-m0IFtVcXkZXdH_lr_FrdYt9HRUYkshtrMmIUAyGmUnd9zMDB2n0cRDIHAzFVeJUDxkUwVAE7_YGRPdcqMyiBoCO-FBdE-Nceb4h3-FtBP-c_BIwCPTjb9o0SbdcdREEMJMyZBH8ySWMVi1gPD9yxi-aQpGbSv_F9N4IZAxscj5g-NJsUPbjk29-s7LJAGb15wEBtXphVCgyy53CoIKLHHeJHXex45Uz9aKZSRSInZI-wjsY0yu3cT4_aQ3i1o-tiE-F8Ios61EKgyIQ4CWao8PFMj8TTnp.vbb32Xvllea2OtmHAdccRQ', + json: { + protected: + 'eyJhbGciOiJkaXIiLCJraWQiOiI3N2M3ZTJiOC02ZTEzLTQ1Y2YtODY3Mi02MTdiNWI0NTI0M2EiLCJlbmMiOiJBMTI4R0NNIn0', + iv: 'refa467QzzKx6QAB', + ciphertext: + 'JW_i_f52hww_ELQPGaYyeAB6HYGcR559l9TYnSovc23XJoBcW29rHP8yZOZG7YhLpT1bjFuvZPjQS-m0IFtVcXkZXdH_lr_FrdYt9HRUYkshtrMmIUAyGmUnd9zMDB2n0cRDIHAzFVeJUDxkUwVAE7_YGRPdcqMyiBoCO-FBdE-Nceb4h3-FtBP-c_BIwCPTjb9o0SbdcdREEMJMyZBH8ySWMVi1gPD9yxi-aQpGbSv_F9N4IZAxscj5g-NJsUPbjk29-s7LJAGb15wEBtXphVCgyy53CoIKLHHeJHXex45Uz9aKZSRSInZI-wjsY0yu3cT4_aQ3i1o-tiE-F8Ios61EKgyIQ4CWao8PFMj8TTnp', + tag: 'vbb32Xvllea2OtmHAdccRQ', + }, + json_flat: { + protected: + 'eyJhbGciOiJkaXIiLCJraWQiOiI3N2M3ZTJiOC02ZTEzLTQ1Y2YtODY3Mi02MTdiNWI0NTI0M2EiLCJlbmMiOiJBMTI4R0NNIn0', + iv: 'refa467QzzKx6QAB', + ciphertext: + 'JW_i_f52hww_ELQPGaYyeAB6HYGcR559l9TYnSovc23XJoBcW29rHP8yZOZG7YhLpT1bjFuvZPjQS-m0IFtVcXkZXdH_lr_FrdYt9HRUYkshtrMmIUAyGmUnd9zMDB2n0cRDIHAzFVeJUDxkUwVAE7_YGRPdcqMyiBoCO-FBdE-Nceb4h3-FtBP-c_BIwCPTjb9o0SbdcdREEMJMyZBH8ySWMVi1gPD9yxi-aQpGbSv_F9N4IZAxscj5g-NJsUPbjk29-s7LJAGb15wEBtXphVCgyy53CoIKLHHeJHXex45Uz9aKZSRSInZI-wjsY0yu3cT4_aQ3i1o-tiE-F8Ios61EKgyIQ4CWao8PFMj8TTnp', + tag: 'vbb32Xvllea2OtmHAdccRQ', + }, + }, + }, + { + title: + 'https://tools.ietf.org/html/rfc7520#section-5.6 - Key Wrap using AES-GCM KeyWrap with AES-CBC-HMAC-SHA2', + webcrypto: true, + reproducible: true, + input: { + plaintext: + 'You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.', + key: { + kty: 'oct', + ext: false, + kid: '18ec08e1-bfa9-4d95-b205-2b4dd1d4321d', + use: 'enc', + alg: 'A256GCMKW', + k: 'qC57l_uxcm7Nm3K-ct4GFjx8tM1U8CZ0NLBvdQstiS8', + }, + alg: 'A256GCMKW', + enc: 'A128CBC-HS256', + }, + generated: { + cek: 'UWxARpat23nL9ReIj4WG3D1ee9I4r-Mv5QLuFXdy_rE', + iv: 'gz6NjyEFNm_vm8Gj6FwoFQ', + }, + encrypting_key: { + iv: 'KkYT0GX_2jHlfqN_', + tag: 'kfPduVQ3T3H6vnewt--ksw', + }, + encrypting_content: { + protected: { + alg: 'A256GCMKW', + kid: '18ec08e1-bfa9-4d95-b205-2b4dd1d4321d', + tag: 'kfPduVQ3T3H6vnewt--ksw', + iv: 'KkYT0GX_2jHlfqN_', + enc: 'A128CBC-HS256', + }, + }, + output: { + compact: + 'eyJhbGciOiJBMjU2R0NNS1ciLCJraWQiOiIxOGVjMDhlMS1iZmE5LTRkOTUtYjIwNS0yYjRkZDFkNDMyMWQiLCJ0YWciOiJrZlBkdVZRM1QzSDZ2bmV3dC0ta3N3IiwiaXYiOiJLa1lUMEdYXzJqSGxmcU5fIiwiZW5jIjoiQTEyOENCQy1IUzI1NiJ9.lJf3HbOApxMEBkCMOoTnnABxs_CvTWUmZQ2ElLvYNok.gz6NjyEFNm_vm8Gj6FwoFQ.Jf5p9-ZhJlJy_IQ_byKFmI0Ro7w7G1QiaZpI8OaiVgD8EqoDZHyFKFBupS8iaEeVIgMqWmsuJKuoVgzR3YfzoMd3GxEm3VxNhzWyWtZKX0gxKdy6HgLvqoGNbZCzLjqcpDiF8q2_62EVAbr2uSc2oaxFmFuIQHLcqAHxy51449xkjZ7ewzZaGV3eFqhpco8o4DijXaG5_7kp3h2cajRfDgymuxUbWgLqaeNQaJtvJmSMFuEOSAzw9Hdeb6yhdTynCRmu-kqtO5Dec4lT2OMZKpnxc_F1_4yDJFcqb5CiDSmA-psB2k0JtjxAj4UPI61oONK7zzFIu4gBfjJCndsZfdvG7h8wGjV98QhrKEnR7xKZ3KCr0_qR1B-gxpNk3xWU.DKW7jrb4WaRSNfbXVPlT5g', + json: { + recipients: [ + { + encrypted_key: 'lJf3HbOApxMEBkCMOoTnnABxs_CvTWUmZQ2ElLvYNok', + }, + ], + protected: + 'eyJhbGciOiJBMjU2R0NNS1ciLCJraWQiOiIxOGVjMDhlMS1iZmE5LTRkOTUtYjIwNS0yYjRkZDFkNDMyMWQiLCJ0YWciOiJrZlBkdVZRM1QzSDZ2bmV3dC0ta3N3IiwiaXYiOiJLa1lUMEdYXzJqSGxmcU5fIiwiZW5jIjoiQTEyOENCQy1IUzI1NiJ9', + iv: 'gz6NjyEFNm_vm8Gj6FwoFQ', + ciphertext: + 'Jf5p9-ZhJlJy_IQ_byKFmI0Ro7w7G1QiaZpI8OaiVgD8EqoDZHyFKFBupS8iaEeVIgMqWmsuJKuoVgzR3YfzoMd3GxEm3VxNhzWyWtZKX0gxKdy6HgLvqoGNbZCzLjqcpDiF8q2_62EVAbr2uSc2oaxFmFuIQHLcqAHxy51449xkjZ7ewzZaGV3eFqhpco8o4DijXaG5_7kp3h2cajRfDgymuxUbWgLqaeNQaJtvJmSMFuEOSAzw9Hdeb6yhdTynCRmu-kqtO5Dec4lT2OMZKpnxc_F1_4yDJFcqb5CiDSmA-psB2k0JtjxAj4UPI61oONK7zzFIu4gBfjJCndsZfdvG7h8wGjV98QhrKEnR7xKZ3KCr0_qR1B-gxpNk3xWU', + tag: 'DKW7jrb4WaRSNfbXVPlT5g', + }, + json_flat: { + protected: + 'eyJhbGciOiJBMjU2R0NNS1ciLCJraWQiOiIxOGVjMDhlMS1iZmE5LTRkOTUtYjIwNS0yYjRkZDFkNDMyMWQiLCJ0YWciOiJrZlBkdVZRM1QzSDZ2bmV3dC0ta3N3IiwiaXYiOiJLa1lUMEdYXzJqSGxmcU5fIiwiZW5jIjoiQTEyOENCQy1IUzI1NiJ9', + encrypted_key: 'lJf3HbOApxMEBkCMOoTnnABxs_CvTWUmZQ2ElLvYNok', + iv: 'gz6NjyEFNm_vm8Gj6FwoFQ', + ciphertext: + 'Jf5p9-ZhJlJy_IQ_byKFmI0Ro7w7G1QiaZpI8OaiVgD8EqoDZHyFKFBupS8iaEeVIgMqWmsuJKuoVgzR3YfzoMd3GxEm3VxNhzWyWtZKX0gxKdy6HgLvqoGNbZCzLjqcpDiF8q2_62EVAbr2uSc2oaxFmFuIQHLcqAHxy51449xkjZ7ewzZaGV3eFqhpco8o4DijXaG5_7kp3h2cajRfDgymuxUbWgLqaeNQaJtvJmSMFuEOSAzw9Hdeb6yhdTynCRmu-kqtO5Dec4lT2OMZKpnxc_F1_4yDJFcqb5CiDSmA-psB2k0JtjxAj4UPI61oONK7zzFIu4gBfjJCndsZfdvG7h8wGjV98QhrKEnR7xKZ3KCr0_qR1B-gxpNk3xWU', + tag: 'DKW7jrb4WaRSNfbXVPlT5g', + }, + }, + }, + { + title: + 'https://tools.ietf.org/html/rfc7520#section-5.8 - Key Wrap using AES-KeyWrap with AES-GCM', + webcrypto: true, + reproducible: true, + input: { + plaintext: + 'You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.', + key: { + kty: 'oct', + ext: false, + kid: '81b20965-8332-43d9-a468-82160ad91ac8', + use: 'enc', + alg: 'A128KW', + k: 'GZy6sIZ6wl9NJOKB-jnmVQ', + }, + alg: 'A128KW', + enc: 'A128GCM', + }, + generated: { + cek: 'aY5_Ghmk9KxWPBLu_glx1w', + iv: 'Qx0pmsDa8KnJc9Jo', + }, + encrypting_key: {}, + encrypting_content: { + protected: { + alg: 'A128KW', + kid: '81b20965-8332-43d9-a468-82160ad91ac8', + enc: 'A128GCM', + }, + }, + output: { + compact: + 'eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIn0.CBI6oDw8MydIx1IBntf_lQcw2MmJKIQx.Qx0pmsDa8KnJc9Jo.AwliP-KmWgsZ37BvzCefNen6VTbRK3QMA4TkvRkH0tP1bTdhtFJgJxeVmJkLD61A1hnWGetdg11c9ADsnWgL56NyxwSYjU1ZEHcGkd3EkU0vjHi9gTlb90qSYFfeF0LwkcTtjbYKCsiNJQkcIp1yeM03OmuiYSoYJVSpf7ej6zaYcMv3WwdxDFl8REwOhNImk2Xld2JXq6BR53TSFkyT7PwVLuq-1GwtGHlQeg7gDT6xW0JqHDPn_H-puQsmthc9Zg0ojmJfqqFvETUxLAF-KjcBTS5dNy6egwkYtOt8EIHK-oEsKYtZRaa8Z7MOZ7UGxGIMvEmxrGCPeJa14slv2-gaqK0kEThkaSqdYw0FkQZF.ER7MWJZ1FBI_NKvn7Zb1Lw', + json: { + recipients: [ + { + encrypted_key: 'CBI6oDw8MydIx1IBntf_lQcw2MmJKIQx', + }, + ], + protected: + 'eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIn0', + iv: 'Qx0pmsDa8KnJc9Jo', + ciphertext: + 'AwliP-KmWgsZ37BvzCefNen6VTbRK3QMA4TkvRkH0tP1bTdhtFJgJxeVmJkLD61A1hnWGetdg11c9ADsnWgL56NyxwSYjU1ZEHcGkd3EkU0vjHi9gTlb90qSYFfeF0LwkcTtjbYKCsiNJQkcIp1yeM03OmuiYSoYJVSpf7ej6zaYcMv3WwdxDFl8REwOhNImk2Xld2JXq6BR53TSFkyT7PwVLuq-1GwtGHlQeg7gDT6xW0JqHDPn_H-puQsmthc9Zg0ojmJfqqFvETUxLAF-KjcBTS5dNy6egwkYtOt8EIHK-oEsKYtZRaa8Z7MOZ7UGxGIMvEmxrGCPeJa14slv2-gaqK0kEThkaSqdYw0FkQZF', + tag: 'ER7MWJZ1FBI_NKvn7Zb1Lw', + }, + json_flat: { + protected: + 'eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIn0', + encrypted_key: 'CBI6oDw8MydIx1IBntf_lQcw2MmJKIQx', + iv: 'Qx0pmsDa8KnJc9Jo', + ciphertext: + 'AwliP-KmWgsZ37BvzCefNen6VTbRK3QMA4TkvRkH0tP1bTdhtFJgJxeVmJkLD61A1hnWGetdg11c9ADsnWgL56NyxwSYjU1ZEHcGkd3EkU0vjHi9gTlb90qSYFfeF0LwkcTtjbYKCsiNJQkcIp1yeM03OmuiYSoYJVSpf7ej6zaYcMv3WwdxDFl8REwOhNImk2Xld2JXq6BR53TSFkyT7PwVLuq-1GwtGHlQeg7gDT6xW0JqHDPn_H-puQsmthc9Zg0ojmJfqqFvETUxLAF-KjcBTS5dNy6egwkYtOt8EIHK-oEsKYtZRaa8Z7MOZ7UGxGIMvEmxrGCPeJa14slv2-gaqK0kEThkaSqdYw0FkQZF', + tag: 'ER7MWJZ1FBI_NKvn7Zb1Lw', + }, + }, + }, + { + title: 'https://tools.ietf.org/html/rfc7520#section-5.9 - Compressed Content', + webcrypto: true, + reproducible: true, + input: { + plaintext: + 'You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.', + key: { + kty: 'oct', + ext: false, + kid: '81b20965-8332-43d9-a468-82160ad91ac8', + use: 'enc', + alg: 'A128KW', + k: 'GZy6sIZ6wl9NJOKB-jnmVQ', + }, + alg: 'A128KW', + enc: 'A128GCM', + zip: 'DEF', + }, + generated: { + plaintext_c: + 'bY_BDcIwDEVX-QNU3QEOrIA4pqlDokYxchxVvbEDGzIJbioOSJwc-f___HPjBu8KVFpVtAplVE1-wZo0YjNZo3C7R5v72pV5f5X382VWjYQpqZKAyjziZOr2B7kQPSy6oZIXUnDYbVKN4jNXi2u0yB7t1qSHTjmMODf9QgvrDzfTIQXnyQRuUya4zIWG3vTOdir0v7BRHFYWq3k1k1A_gSDJqtcBF-GZxw8', + cek: 'hC-MpLZSuwWv8sexS6ydfw', + iv: 'p9pUq6XHY0jfEZIl', + }, + encrypting_key: {}, + encrypting_content: { + protected: { + alg: 'A128KW', + kid: '81b20965-8332-43d9-a468-82160ad91ac8', + enc: 'A128GCM', + zip: 'DEF', + }, + }, + output: { + compact: + 'eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIiwiemlwIjoiREVGIn0.5vUT2WOtQxKWcekM_IzVQwkGgzlFDwPi.p9pUq6XHY0jfEZIl.HbDtOsdai1oYziSx25KEeTxmwnh8L8jKMFNc1k3zmMI6VB8hry57tDZ61jXyezSPt0fdLVfe6Jf5y5-JaCap_JQBcb5opbmT60uWGml8blyiMQmOn9J--XhhlYg0m-BHaqfDO5iTOWxPxFMUedx7WCy8mxgDHj0aBMG6152PsM-w5E_o2B3jDbrYBKhpYA7qi3AyijnCJ7BP9rr3U8kxExCpG3mK420TjOw.VILuUwuIxaLVmh5X-T7kmA', + json: { + recipients: [ + { + encrypted_key: '5vUT2WOtQxKWcekM_IzVQwkGgzlFDwPi', + }, + ], + protected: + 'eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIiwiemlwIjoiREVGIn0', + iv: 'p9pUq6XHY0jfEZIl', + ciphertext: + 'HbDtOsdai1oYziSx25KEeTxmwnh8L8jKMFNc1k3zmMI6VB8hry57tDZ61jXyezSPt0fdLVfe6Jf5y5-JaCap_JQBcb5opbmT60uWGml8blyiMQmOn9J--XhhlYg0m-BHaqfDO5iTOWxPxFMUedx7WCy8mxgDHj0aBMG6152PsM-w5E_o2B3jDbrYBKhpYA7qi3AyijnCJ7BP9rr3U8kxExCpG3mK420TjOw', + tag: 'VILuUwuIxaLVmh5X-T7kmA', + }, + json_flat: { + protected: + 'eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIiwiemlwIjoiREVGIn0', + encrypted_key: '5vUT2WOtQxKWcekM_IzVQwkGgzlFDwPi', + iv: 'p9pUq6XHY0jfEZIl', + ciphertext: + 'HbDtOsdai1oYziSx25KEeTxmwnh8L8jKMFNc1k3zmMI6VB8hry57tDZ61jXyezSPt0fdLVfe6Jf5y5-JaCap_JQBcb5opbmT60uWGml8blyiMQmOn9J--XhhlYg0m-BHaqfDO5iTOWxPxFMUedx7WCy8mxgDHj0aBMG6152PsM-w5E_o2B3jDbrYBKhpYA7qi3AyijnCJ7BP9rr3U8kxExCpG3mK420TjOw', + tag: 'VILuUwuIxaLVmh5X-T7kmA', + }, + }, + }, + { + title: + 'https://tools.ietf.org/html/rfc7520#section-5.10 - Including Additional Authenticated Data', + webcrypto: true, + reproducible: true, + input: { + plaintext: + 'You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.', + key: { + kty: 'oct', + ext: false, + kid: '81b20965-8332-43d9-a468-82160ad91ac8', + use: 'enc', + alg: 'A128KW', + k: 'GZy6sIZ6wl9NJOKB-jnmVQ', + }, + alg: 'A128KW', + enc: 'A128GCM', + aad: + '["vcard",[["version",{},"text","4.0"],["fn",{},"text","Meriadoc Brandybuck"],["n",{},"text",["Brandybuck","Meriadoc","Mr.",""]],["bday",{},"text","TA 2982"],["gender",{},"text","M"]]]', + }, + generated: { + cek: '75m1ALsYv10pZTKPWrsqdg', + iv: 'veCx9ece2orS7c_N', + aad_b64u: + 'WyJ2Y2FyZCIsW1sidmVyc2lvbiIse30sInRleHQiLCI0LjAiXSxbImZuIix7fSwidGV4dCIsIk1lcmlhZG9jIEJyYW5keWJ1Y2siXSxbIm4iLHt9LCJ0ZXh0IixbIkJyYW5keWJ1Y2siLCJNZXJpYWRvYyIsIk1yLiIsIiJdXSxbImJkYXkiLHt9LCJ0ZXh0IiwiVEEgMjk4MiJdLFsiZ2VuZGVyIix7fSwidGV4dCIsIk0iXV1d', + }, + encrypting_key: {}, + encrypting_content: { + protected: { + alg: 'A128KW', + kid: '81b20965-8332-43d9-a468-82160ad91ac8', + enc: 'A128GCM', + }, + }, + output: { + json: { + recipients: [ + { + encrypted_key: '4YiiQ_ZzH76TaIkJmYfRFgOV9MIpnx4X', + }, + ], + protected: + 'eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIn0', + iv: 'veCx9ece2orS7c_N', + aad: + 'WyJ2Y2FyZCIsW1sidmVyc2lvbiIse30sInRleHQiLCI0LjAiXSxbImZuIix7fSwidGV4dCIsIk1lcmlhZG9jIEJyYW5keWJ1Y2siXSxbIm4iLHt9LCJ0ZXh0IixbIkJyYW5keWJ1Y2siLCJNZXJpYWRvYyIsIk1yLiIsIiJdXSxbImJkYXkiLHt9LCJ0ZXh0IiwiVEEgMjk4MiJdLFsiZ2VuZGVyIix7fSwidGV4dCIsIk0iXV1d', + ciphertext: + 'Z_3cbr0k3bVM6N3oSNmHz7Lyf3iPppGf3Pj17wNZqteJ0Ui8p74SchQP8xygM1oFRWCNzeIa6s6BcEtp8qEFiqTUEyiNkOWDNoF14T_4NFqF-p2Mx8zkbKxI7oPK8KNarFbyxIDvICNqBLba-v3uzXBdB89fzOI-Lv4PjOFAQGHrgv1rjXAmKbgkft9cB4WeyZw8MldbBhc-V_KWZslrsLNygon_JJWd_ek6LQn5NRehvApqf9ZrxB4aq3FXBxOxCys35PhCdaggy2kfUfl2OkwKnWUbgXVD1C6HxLIlqHhCwXDG59weHrRDQeHyMRoBljoV3X_bUTJDnKBFOod7nLz-cj48JMx3SnCZTpbQAkFV', + tag: 'vOaH_Rajnpy_3hOtqvZHRA', + }, + json_flat: { + protected: + 'eyJhbGciOiJBMTI4S1ciLCJraWQiOiI4MWIyMDk2NS04MzMyLTQzZDktYTQ2OC04MjE2MGFkOTFhYzgiLCJlbmMiOiJBMTI4R0NNIn0', + encrypted_key: '4YiiQ_ZzH76TaIkJmYfRFgOV9MIpnx4X', + aad: + 'WyJ2Y2FyZCIsW1sidmVyc2lvbiIse30sInRleHQiLCI0LjAiXSxbImZuIix7fSwidGV4dCIsIk1lcmlhZG9jIEJyYW5keWJ1Y2siXSxbIm4iLHt9LCJ0ZXh0IixbIkJyYW5keWJ1Y2siLCJNZXJpYWRvYyIsIk1yLiIsIiJdXSxbImJkYXkiLHt9LCJ0ZXh0IiwiVEEgMjk4MiJdLFsiZ2VuZGVyIix7fSwidGV4dCIsIk0iXV1d', + iv: 'veCx9ece2orS7c_N', + ciphertext: + 'Z_3cbr0k3bVM6N3oSNmHz7Lyf3iPppGf3Pj17wNZqteJ0Ui8p74SchQP8xygM1oFRWCNzeIa6s6BcEtp8qEFiqTUEyiNkOWDNoF14T_4NFqF-p2Mx8zkbKxI7oPK8KNarFbyxIDvICNqBLba-v3uzXBdB89fzOI-Lv4PjOFAQGHrgv1rjXAmKbgkft9cB4WeyZw8MldbBhc-V_KWZslrsLNygon_JJWd_ek6LQn5NRehvApqf9ZrxB4aq3FXBxOxCys35PhCdaggy2kfUfl2OkwKnWUbgXVD1C6HxLIlqHhCwXDG59weHrRDQeHyMRoBljoV3X_bUTJDnKBFOod7nLz-cj48JMx3SnCZTpbQAkFV', + tag: 'vOaH_Rajnpy_3hOtqvZHRA', + }, + }, + }, + { + title: + 'https://tools.ietf.org/html/rfc7520#section-5.11 - Protecting Specific Header Fields', + webcrypto: true, + reproducible: true, + input: { + plaintext: + 'You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.', + key: { + kty: 'oct', + ext: false, + kid: '81b20965-8332-43d9-a468-82160ad91ac8', + use: 'enc', + alg: 'A128KW', + k: 'GZy6sIZ6wl9NJOKB-jnmVQ', + }, + alg: 'A128KW', + enc: 'A128GCM', + }, + generated: { + cek: 'WDgEptBmQs9ouUvArz6x6g', + iv: 'WgEJsDS9bkoXQ3nR', + }, + encrypting_key: {}, + encrypting_content: { + protected: { + enc: 'A128GCM', + }, + unprotected: { + alg: 'A128KW', + kid: '81b20965-8332-43d9-a468-82160ad91ac8', + }, + }, + output: { + json: { + recipients: [ + { + encrypted_key: 'jJIcM9J-hbx3wnqhf5FlkEYos0sHsF0H', + }, + ], + unprotected: { + alg: 'A128KW', + kid: '81b20965-8332-43d9-a468-82160ad91ac8', + }, + protected: 'eyJlbmMiOiJBMTI4R0NNIn0', + iv: 'WgEJsDS9bkoXQ3nR', + ciphertext: + 'lIbCyRmRJxnB2yLQOTqjCDKV3H30ossOw3uD9DPsqLL2DM3swKkjOwQyZtWsFLYMj5YeLht_StAn21tHmQJuuNt64T8D4t6C7kC9OCCJ1IHAolUv4MyOt80MoPb8fZYbNKqplzYJgIL58g8N2v46OgyG637d6uuKPwhAnTGm_zWhqc_srOvgiLkzyFXPq1hBAURbc3-8BqeRb48iR1-_5g5UjWVD3lgiLCN_P7AW8mIiFvUNXBPJK3nOWL4teUPS8yHLbWeL83olU4UAgL48x-8dDkH23JykibVSQju-f7e-1xreHWXzWLHs1NqBbre0dEwK3HX_xM0LjUz77Krppgegoutpf5qaKg3l-_xMINmf', + tag: 'fNYLqpUe84KD45lvDiaBAQ', + }, + json_flat: { + protected: 'eyJlbmMiOiJBMTI4R0NNIn0', + unprotected: { + alg: 'A128KW', + kid: '81b20965-8332-43d9-a468-82160ad91ac8', + }, + encrypted_key: 'jJIcM9J-hbx3wnqhf5FlkEYos0sHsF0H', + iv: 'WgEJsDS9bkoXQ3nR', + ciphertext: + 'lIbCyRmRJxnB2yLQOTqjCDKV3H30ossOw3uD9DPsqLL2DM3swKkjOwQyZtWsFLYMj5YeLht_StAn21tHmQJuuNt64T8D4t6C7kC9OCCJ1IHAolUv4MyOt80MoPb8fZYbNKqplzYJgIL58g8N2v46OgyG637d6uuKPwhAnTGm_zWhqc_srOvgiLkzyFXPq1hBAURbc3-8BqeRb48iR1-_5g5UjWVD3lgiLCN_P7AW8mIiFvUNXBPJK3nOWL4teUPS8yHLbWeL83olU4UAgL48x-8dDkH23JykibVSQju-f7e-1xreHWXzWLHs1NqBbre0dEwK3HX_xM0LjUz77Krppgegoutpf5qaKg3l-_xMINmf', + tag: 'fNYLqpUe84KD45lvDiaBAQ', + }, + }, + }, + { + title: 'https://tools.ietf.org/html/rfc7520#section-5.12 - Protecting Content Only', + webcrypto: true, + reproducible: true, + input: { + plaintext: + 'You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo.', + key: { + kty: 'oct', + ext: false, + kid: '81b20965-8332-43d9-a468-82160ad91ac8', + use: 'enc', + alg: 'A128KW', + k: 'GZy6sIZ6wl9NJOKB-jnmVQ', + }, + alg: 'A128KW', + enc: 'A128GCM', + }, + generated: { + cek: 'KBooAFl30QPV3vkcZlXnzQ', + iv: 'YihBoVOGsR1l7jCD', + }, + encrypting_key: {}, + encrypting_content: { + unprotected: { + alg: 'A128KW', + kid: '81b20965-8332-43d9-a468-82160ad91ac8', + enc: 'A128GCM', + }, + }, + output: { + json: { + recipients: [ + { + encrypted_key: '244YHfO_W7RMpQW81UjQrZcq5LSyqiPv', + }, + ], + unprotected: { + alg: 'A128KW', + kid: '81b20965-8332-43d9-a468-82160ad91ac8', + enc: 'A128GCM', + }, + iv: 'YihBoVOGsR1l7jCD', + ciphertext: + 'qtPIMMaOBRgASL10dNQhOa7Gqrk7Eal1vwht7R4TT1uq-arsVCPaIeFwQfzrSS6oEUWbBtxEasE0vC6r7sphyVziMCVJEuRJyoAHFSP3eqQPb4Ic1SDSqyXjw_L3svybhHYUGyQuTmUQEDjgjJfBOifwHIsDsRPeBz1NomqeifVPq5GTCWFo5k_MNIQURR2Wj0AHC2k7JZfu2iWjUHLF8ExFZLZ4nlmsvJu_mvifMYiikfNfsZAudISOa6O73yPZtL04k_1FI7WDfrb2w7OqKLWDXzlpcxohPVOLQwpA3mFNRKdY-bQz4Z4KX9lfz1cne31N4-8BKmojpw-OdQjKdLOGkC445Fb_K1tlDQXw2sBF', + tag: 'e2m0Vm7JvjK2VpCKXS-kyg', + }, + json_flat: { + unprotected: { + alg: 'A128KW', + kid: '81b20965-8332-43d9-a468-82160ad91ac8', + enc: 'A128GCM', + }, + encrypted_key: '244YHfO_W7RMpQW81UjQrZcq5LSyqiPv', + iv: 'YihBoVOGsR1l7jCD', + ciphertext: + 'qtPIMMaOBRgASL10dNQhOa7Gqrk7Eal1vwht7R4TT1uq-arsVCPaIeFwQfzrSS6oEUWbBtxEasE0vC6r7sphyVziMCVJEuRJyoAHFSP3eqQPb4Ic1SDSqyXjw_L3svybhHYUGyQuTmUQEDjgjJfBOifwHIsDsRPeBz1NomqeifVPq5GTCWFo5k_MNIQURR2Wj0AHC2k7JZfu2iWjUHLF8ExFZLZ4nlmsvJu_mvifMYiikfNfsZAudISOa6O73yPZtL04k_1FI7WDfrb2w7OqKLWDXzlpcxohPVOLQwpA3mFNRKdY-bQz4Z4KX9lfz1cne31N4-8BKmojpw-OdQjKdLOGkC445Fb_K1tlDQXw2sBF', + tag: 'e2m0Vm7JvjK2VpCKXS-kyg', + }, + }, + }, + ]; + + for (const vector of vectors) { + let conditional; + if ('WEBCRYPTO' in process.env && vector.webcrypto === false) { + conditional = test.failing; + } else { + conditional = test; + } + if (vector.skip) { + conditional = test.skip; + } + if (vector.only) { + conditional = test.only; + } + conditional(testCookbook, vector); + } + }, +); diff --git a/test/jwe/crit.test.js b/test/jwe/crit.test.js deleted file mode 100644 index 8f167ce82b..0000000000 --- a/test/jwe/crit.test.js +++ /dev/null @@ -1,84 +0,0 @@ -const test = require('ava') - -const base64url = require('../../lib/help/base64url') -const { JWK: { generateSync }, JWE, errors } = require('../..') - -const UNDEFINED = 'http://example.invalid/UNDEFINED' - -test('crit must be understood', t => { - const k = generateSync('oct') - const jws = JWE.encrypt('foo', k, { crit: [UNDEFINED], [UNDEFINED]: true }) - t.throws(() => { - JWE.decrypt(jws, k) - }, { instanceOf: errors.JOSECritNotUnderstood, code: 'ERR_JOSE_CRIT_NOT_UNDERSTOOD', message: `critical "${UNDEFINED}" is not understood` }) - JWE.decrypt(jws, k, { crit: [UNDEFINED] }) -}) - -test('crit must be present', t => { - const k = generateSync('oct') - t.throws(() => { - JWE.encrypt('foo', k, { crit: [UNDEFINED] }) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: `critical parameter "${UNDEFINED}" is missing` }) - t.throws(() => { - JWE.decrypt( - `${base64url.JSON.encode({ alg: 'HS256', crit: [UNDEFINED] })}.${base64url.JSON.encode({})}...`, - k, - { crit: [UNDEFINED] } - ) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: `critical parameter "${UNDEFINED}" is missing` }) -}) - -test('crit must be integrity protected', t => { - const k = generateSync('oct') - t.throws(() => { - JWE.encrypt.flattened('foo', k, undefined, undefined, { crit: [UNDEFINED] }) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: '"crit" Header Parameter MUST be integrity protected when present' }) - const jws = JWE.encrypt.flattened('foo', k) - jws.header = { crit: [UNDEFINED] } - t.throws(() => { - JWE.decrypt(jws, k, { crit: [UNDEFINED] }) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: '"crit" Header Parameter MUST be integrity protected when present' }) -}) - -test('crit must be an array of strings', t => { - const k = generateSync('oct') - ;[{}, new Object(), false, null, Infinity, 0, '', Buffer.from('foo'), []].forEach((val) => { // eslint-disable-line no-new-object - t.throws(() => { - JWE.encrypt('foo', k, { crit: val }) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: '"crit" Header Parameter MUST be an array of non-empty strings when present' }) - t.throws(() => { - JWE.encrypt('foo', k, { crit: [val] }) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: '"crit" Header Parameter MUST be an array of non-empty strings when present' }) - }) -}) - -test('crit option be an array of strings', t => { - ;[{}, new Object(), false, null, Infinity, 0, '', Buffer.from('foo')].forEach((val) => { // eslint-disable-line no-new-object - t.throws(() => { - JWE.decrypt({ - header: { alg: 'HS256' }, - payload: 'foo', - ciphertext: 'bar' - }, generateSync('oct'), { crit: val }) - }, { instanceOf: TypeError, message: '"crit" option must be an array of non-empty strings' }) - t.throws(() => { - JWE.decrypt({ - header: { alg: 'HS256' }, - payload: 'foo', - ciphertext: 'bar' - }, generateSync('oct'), { crit: [val] }) - }, { instanceOf: TypeError, message: '"crit" option must be an array of non-empty strings' }) - }) -}) - -test('crit must not contain JWE/JWS/JWA defined header parameters', t => { - const k = generateSync('oct') - ;[ - 'alg', 'jku', 'jwk', 'kid', 'x5u', 'x5c', 'x5t', 'x5t#S256', 'typ', 'cty', - 'crit', 'enc', 'zip', 'epk', 'apu', 'apv', 'iv', 'tag', 'p2s', 'p2c' - ].forEach((crit) => { - t.throws(() => { - JWE.encrypt('foo', k, { crit: [crit] }) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: `The critical list contains a non-extension Header Parameter ${crit}` }) - }) -}) diff --git a/test/jwe/ecdh_derive.test.js b/test/jwe/ecdh_derive.test.js deleted file mode 100644 index 0d493c5b9b..0000000000 --- a/test/jwe/ecdh_derive.test.js +++ /dev/null @@ -1,33 +0,0 @@ -const test = require('ava') - -const derive = require('../../lib/jwa/ecdh/derive') -const JWK = require('../../lib/jwk') -const base64url = require('../../lib/help/base64url') - -test('https://tools.ietf.org/html/rfc7518#appendix-C', t => { - const alice = JWK.asKey({ - kty: 'EC', - crv: 'P-256', - x: 'gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0', - y: 'SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps', - d: '0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo' - }) - - const bob = JWK.asKey({ - kty: 'EC', - crv: 'P-256', - x: 'weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ', - y: 'e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck', - d: 'VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw' - }) - - t.deepEqual( - derive('A128GCM', 128, alice, bob, { apu: Buffer.from('Alice'), apv: Buffer.from('Bob') }), - base64url.decodeToBuffer('VqqN6vgjbSBcIijNcacQGg') - ) - - t.deepEqual( - derive('A128GCM', 128, bob, alice, { apu: Buffer.from('Alice'), apv: Buffer.from('Bob') }), - base64url.decodeToBuffer('VqqN6vgjbSBcIijNcacQGg') - ) -}) diff --git a/test/jwe/flattened.decrypt.test.mjs b/test/jwe/flattened.decrypt.test.mjs new file mode 100644 index 0000000000..73effd80cb --- /dev/null +++ b/test/jwe/flattened.decrypt.test.mjs @@ -0,0 +1,227 @@ +/* eslint-disable no-param-reassign */ +import test from 'ava'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +Promise.all([ + import(`${root}/jwe/flattened/encrypt`), + import(`${root}/jwe/flattened/decrypt`), +]).then( + ([{ default: FlattenedEncrypt }, { default: flattenedDecrypt }]) => { + test.before(async (t) => { + const encode = TextEncoder.prototype.encode.bind(new TextEncoder()); + t.context.plaintext = encode('It’s a dangerous business, Frodo, going out your door.'); + t.context.additionalAuthenticatedData = encode('The Fellowship of the Ring'); + t.context.initializationVector = new Uint8Array(12); + t.context.secret = new Uint8Array(16); + }); + + test('JWE format validation', async (t) => { + const fullJwe = await new FlattenedEncrypt(t.context.plaintext) + .setProtectedHeader({ bar: 'baz' }) + .setUnprotectedHeader({ foo: 'bar' }) + .setSharedUnprotectedHeader({ alg: 'dir', enc: 'A128GCM' }) + .setAdditionalAuthenticatedData(t.context.additionalAuthenticatedData) + .encrypt(t.context.secret); + + { + await t.throwsAsync(flattenedDecrypt(null, t.context.secret), { + message: 'Flattened JWE must be an object', + code: 'ERR_JWE_INVALID', + }); + } + + { + const jwe = { ...fullJwe }; + delete jwe.protected; + delete jwe.header; + delete jwe.unprotected; + + await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), { + message: 'JOSE Header missing', + code: 'ERR_JWE_INVALID', + }); + } + + { + const jwe = { ...fullJwe }; + delete jwe.iv; + const assertion = { + message: 'JWE Initialization Vector missing or incorrect type', + code: 'ERR_JWE_INVALID', + }; + + await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), assertion); + jwe.iv = null; + + await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), assertion); + } + + { + const jwe = { ...fullJwe }; + delete jwe.ciphertext; + const assertion = { + message: 'JWE Ciphertext missing or incorrect type', + code: 'ERR_JWE_INVALID', + }; + + await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), assertion); + jwe.ciphertext = null; + + await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), assertion); + } + + { + const jwe = { ...fullJwe }; + delete jwe.tag; + const assertion = { + message: 'JWE Authentication Tag missing or incorrect type', + code: 'ERR_JWE_INVALID', + }; + + await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), assertion); + jwe.tag = null; + + await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), assertion); + } + + { + const jwe = { ...fullJwe }; + jwe.protected = null; + + await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), { + message: 'JWE Protected Header incorrect type', + code: 'ERR_JWE_INVALID', + }); + } + + { + const jwe = { ...fullJwe }; + jwe.encrypted_key = null; + + await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), { + message: 'JWE Encrypted Key incorrect type', + code: 'ERR_JWE_INVALID', + }); + } + + { + const jwe = { ...fullJwe }; + jwe.aad = null; + + await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), { + message: 'JWE AAD incorrect type', + code: 'ERR_JWE_INVALID', + }); + } + + { + const jwe = { ...fullJwe }; + jwe.header = null; + + await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), { + message: 'JWE Shared Unprotected Header incorrect type', + code: 'ERR_JWE_INVALID', + }); + } + + { + const jwe = { ...fullJwe }; + jwe.unprotected = null; + + await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), { + message: 'JWE Per-Recipient Unprotected Header incorrect type', + code: 'ERR_JWE_INVALID', + }); + } + + { + const jwe = { ...fullJwe }; + jwe.unprotected = { foo: 'bar' }; + + await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), { + message: + 'JWE Protected, JWE Unprotected Header, and JWE Per-Recipient Unprotected Header Parameter names must be disjoint', + code: 'ERR_JWE_INVALID', + }); + } + + { + const jwe = { ...fullJwe }; + jwe.unprotected = { enc: 'A128GCM' }; + + await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), { + message: 'missing JWE Algorithm (alg) in JWE Header', + code: 'ERR_JWE_INVALID', + }); + } + + { + const jwe = { ...fullJwe }; + jwe.unprotected = { alg: 'dir' }; + + await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), { + message: 'missing JWE Encryption Algorithm (enc) in JWE Header', + code: 'ERR_JWE_INVALID', + }); + } + + { + const jwe = { ...fullJwe }; + jwe.encrypted_key = 'foo'; + + await t.throwsAsync(flattenedDecrypt(jwe, t.context.secret), { + message: 'decryption operation failed', + code: 'ERR_JWE_DECRYPTION_FAILED', + }); + } + }); + + test('AES CBC + HMAC', async (t) => { + const jwe = await new FlattenedEncrypt(t.context.plaintext) + .setProtectedHeader({ alg: 'dir', enc: 'A128CBC-HS256' }) + .encrypt(new Uint8Array(32)); + + { + const secret = new Uint8Array(32); + secret[0] += 1; + await t.throwsAsync(flattenedDecrypt(jwe, secret), { + code: 'ERR_JWE_DECRYPTION_FAILED', + message: 'decryption operation failed', + }); + } + + { + const secret = new Uint8Array(32); + secret[31] += 1; + await t.throwsAsync(flattenedDecrypt(jwe, secret), { + code: 'ERR_JWE_DECRYPTION_FAILED', + message: 'decryption operation failed', + }); + } + + { + const jweBadTag = { ...jwe }; + jweBadTag.tag = 'foo'; + await t.throwsAsync(flattenedDecrypt(jweBadTag, new Uint8Array(32)), { + code: 'ERR_JWE_DECRYPTION_FAILED', + message: 'decryption operation failed', + }); + } + + { + const jweBadEnc = { ...jwe }; + jweBadEnc.ciphertext = 'foo'; + await t.throwsAsync(flattenedDecrypt(jweBadEnc, new Uint8Array(32)), { + code: 'ERR_JWE_DECRYPTION_FAILED', + message: 'decryption operation failed', + }); + } + }); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jwe/flattened.encrypt.test.mjs b/test/jwe/flattened.encrypt.test.mjs new file mode 100644 index 0000000000..cd169fa21d --- /dev/null +++ b/test/jwe/flattened.encrypt.test.mjs @@ -0,0 +1,209 @@ +/* eslint-disable no-param-reassign */ +import test from 'ava'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +import(`${root}/jwe/flattened/encrypt`).then( + ({ default: FlattenedEncrypt }) => { + test.before(async (t) => { + const encode = TextEncoder.prototype.encode.bind(new TextEncoder()); + t.context.plaintext = encode('It’s a dangerous business, Frodo, going out your door.'); + t.context.additionalAuthenticatedData = encode('The Fellowship of the Ring'); + t.context.initializationVector = new Uint8Array(12); + t.context.secret = new Uint8Array(16); + }); + + test('FlattenedEncrypt', async (t) => { + { + const jwe = await new FlattenedEncrypt(t.context.plaintext) + .setInitializationVector(t.context.initializationVector) + .setProtectedHeader({ alg: 'dir' }) + .setUnprotectedHeader({ enc: 'A128GCM' }) + .encrypt(t.context.secret); + t.deepEqual(jwe, { + ciphertext: 'Svw4TvnFg_PTTKPXFteMF4Lmisk8ODBNko7607TNs49EbT0BKRz9tEep2dmks9KPvD-CfX7hW1M', + header: { + enc: 'A128GCM', + }, + iv: 'AAAAAAAAAAAAAAAA', + protected: 'eyJhbGciOiJkaXIifQ', + tag: 'OYBq53cJNorm8LoZf4SwsA', + }); + } + { + const jwe = await new FlattenedEncrypt(t.context.plaintext) + .setInitializationVector(t.context.initializationVector) + .setProtectedHeader({ alg: 'dir' }) + .setSharedUnprotectedHeader({ enc: 'A128GCM' }) + .encrypt(t.context.secret); + t.deepEqual(jwe, { + ciphertext: 'Svw4TvnFg_PTTKPXFteMF4Lmisk8ODBNko7607TNs49EbT0BKRz9tEep2dmks9KPvD-CfX7hW1M', + unprotected: { + enc: 'A128GCM', + }, + iv: 'AAAAAAAAAAAAAAAA', + protected: 'eyJhbGciOiJkaXIifQ', + tag: 'OYBq53cJNorm8LoZf4SwsA', + }); + } + { + const jwe = await new FlattenedEncrypt(t.context.plaintext) + .setInitializationVector(t.context.initializationVector) + .setSharedUnprotectedHeader({ alg: 'dir', enc: 'A128GCM' }) + .encrypt(t.context.secret); + t.deepEqual(jwe, { + ciphertext: 'Svw4TvnFg_PTTKPXFteMF4Lmisk8ODBNko7607TNs49EbT0BKRz9tEep2dmks9KPvD-CfX7hW1M', + unprotected: { + alg: 'dir', + enc: 'A128GCM', + }, + iv: 'AAAAAAAAAAAAAAAA', + tag: 'vrBCoJmYwG3M6xCZ5VSR3g', + }); + } + { + const jwe = await new FlattenedEncrypt(t.context.plaintext) + .setInitializationVector(t.context.initializationVector) + .setProtectedHeader({ alg: 'dir' }) + .setAdditionalAuthenticatedData(t.context.additionalAuthenticatedData) + .setSharedUnprotectedHeader({ enc: 'A128GCM' }) + .encrypt(t.context.secret); + t.deepEqual(jwe, { + aad: 'VGhlIEZlbGxvd3NoaXAgb2YgdGhlIFJpbmc', + ciphertext: 'Svw4TvnFg_PTTKPXFteMF4Lmisk8ODBNko7607TNs49EbT0BKRz9tEep2dmks9KPvD-CfX7hW1M', + unprotected: { + enc: 'A128GCM', + }, + iv: 'AAAAAAAAAAAAAAAA', + protected: 'eyJhbGciOiJkaXIifQ', + tag: 'gEwNlfPZ-O-dG7dTFkhMyQ', + }); + } + }); + + test('FlattenedEncrypt.prototype.setProtectedHeader', (t) => { + t.throws( + () => + new FlattenedEncrypt(t.context.plaintext).setProtectedHeader({}).setProtectedHeader({}), + { + instanceOf: TypeError, + message: 'setProtectedHeader can only be called once', + }, + ); + }); + + test('FlattenedEncrypt.prototype.setUnprotectedHeader', (t) => { + t.throws( + () => + new FlattenedEncrypt(t.context.plaintext) + .setUnprotectedHeader({}) + .setUnprotectedHeader({}), + { + instanceOf: TypeError, + message: 'setUnprotectedHeader can only be called once', + }, + ); + }); + + test('FlattenedEncrypt.prototype.setSharedUnprotectedHeader', (t) => { + t.throws( + () => + new FlattenedEncrypt(t.context.plaintext) + .setSharedUnprotectedHeader({}) + .setSharedUnprotectedHeader({}), + { + instanceOf: TypeError, + message: 'setSharedUnprotectedHeader can only be called once', + }, + ); + }); + + test('FlattenedEncrypt.prototype.setInitializationVector', (t) => { + t.throws( + () => + new FlattenedEncrypt(t.context.plaintext) + .setInitializationVector(t.context.initializationVector) + .setInitializationVector(t.context.initializationVector), + { + instanceOf: TypeError, + message: 'setInitializationVector can only be called once', + }, + ); + }); + + test('FlattenedEncrypt.prototype.setContentEncryptionKey', (t) => { + t.throws( + () => + new FlattenedEncrypt(t.context.plaintext) + .setContentEncryptionKey(t.context.secret) + .setContentEncryptionKey(t.context.secret), + { + instanceOf: TypeError, + message: 'setContentEncryptionKey can only be called once', + }, + ); + }); + + test('FlattenedEncrypt.prototype.encrypt must have a JOSE header', async (t) => { + await t.throwsAsync(new FlattenedEncrypt(t.context.plaintext).encrypt(t.context.secret), { + code: 'ERR_JWE_INVALID', + message: + 'either setProtectedHeader, setUnprotectedHeader, or sharedUnprotectedHeader must be called before #encrypt()', + }); + }); + + test('FlattenedEncrypt.prototype.encrypt JOSE header must be disjoint', async (t) => { + await t.throwsAsync( + new FlattenedEncrypt(t.context.plaintext) + .setProtectedHeader({ alg: 'dir', enc: 'A128GCM' }) + .setUnprotectedHeader({ alg: 'dir' }) + .encrypt(t.context.secret), + { + code: 'ERR_JWE_INVALID', + message: + 'JWE Shared Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint', + }, + ); + await t.throwsAsync( + new FlattenedEncrypt(t.context.plaintext) + .setProtectedHeader({ alg: 'dir', enc: 'A128GCM' }) + .setSharedUnprotectedHeader({ alg: 'dir' }) + .encrypt(t.context.secret), + { + code: 'ERR_JWE_INVALID', + message: + 'JWE Shared Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint', + }, + ); + }); + + test('FlattenedEncrypt.prototype.encrypt JOSE header have an alg', async (t) => { + await t.throwsAsync( + new FlattenedEncrypt(t.context.plaintext) + .setProtectedHeader({ enc: 'A128GCM' }) + .encrypt(t.context.secret), + { + code: 'ERR_JWE_INVALID', + message: 'JWE "alg" (Algorithm) Header Parameter missing', + }, + ); + }); + + test('FlattenedEncrypt.prototype.encrypt JOSE header have an enc', async (t) => { + await t.throwsAsync( + new FlattenedEncrypt(t.context.plaintext) + .setProtectedHeader({ alg: 'dir' }) + .encrypt(t.context.secret), + { + code: 'ERR_JWE_INVALID', + message: 'JWE "enc" (Encryption Algorithm) Header Parameter missing', + }, + ); + }); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jwe/sanity.test.js b/test/jwe/sanity.test.js deleted file mode 100644 index edfa4bb945..0000000000 --- a/test/jwe/sanity.test.js +++ /dev/null @@ -1,608 +0,0 @@ -const test = require('ava') - -const base64url = require('../../lib/help/base64url') -const { JWKS, JWK: { generateSync }, JWE, errors } = require('../..') - -test('keyManagementAlgorithms option be an array of strings', t => { - ;[{}, new Object(), false, null, Infinity, 0, '', Buffer.from('foo')].forEach((val) => { // eslint-disable-line no-new-object - t.throws(() => { - JWE.decrypt({ - header: { alg: 'HS256' }, - payload: 'foo', - ciphertext: 'bar' - }, generateSync('oct'), { keyManagementAlgorithms: val }) - }, { instanceOf: TypeError, message: '"keyManagementAlgorithms" option must be an array of non-empty strings' }) - t.throws(() => { - JWE.decrypt({ - header: { alg: 'HS256' }, - payload: 'foo', - ciphertext: 'bar' - }, generateSync('oct'), { keyManagementAlgorithms: [val] }) - }, { instanceOf: TypeError, message: '"keyManagementAlgorithms" option must be an array of non-empty strings' }) - }) -}) - -test('contentEncryptionAlgorithms option be an array of strings', t => { - ;[{}, new Object(), false, null, Infinity, 0, '', Buffer.from('foo')].forEach((val) => { // eslint-disable-line no-new-object - t.throws(() => { - JWE.decrypt({ - header: { alg: 'HS256' }, - payload: 'foo', - ciphertext: 'bar' - }, generateSync('oct'), { contentEncryptionAlgorithms: val }) - }, { instanceOf: TypeError, message: '"contentEncryptionAlgorithms" option must be an array of non-empty strings' }) - t.throws(() => { - JWE.decrypt({ - header: { alg: 'HS256' }, - payload: 'foo', - ciphertext: 'bar' - }, generateSync('oct'), { contentEncryptionAlgorithms: [val] }) - }, { instanceOf: TypeError, message: '"contentEncryptionAlgorithms" option must be an array of non-empty strings' }) - }) -}) - -test('compact parts length check', t => { - t.throws(() => { - JWE.decrypt('', generateSync('oct')) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE malformed or invalid serialization' }) - t.throws(() => { - JWE.decrypt('...', generateSync('oct')) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE malformed or invalid serialization' }) - t.throws(() => { - JWE.decrypt('.....', generateSync('oct')) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE malformed or invalid serialization' }) -}) - -test('JWE no alg specified but cannot resolve', t => { - const k1 = generateSync('oct', undefined, { key_ops: ['sign'] }) - t.throws(() => { - JWE.encrypt('foo', k1) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'could not resolve a usable "alg" for a recipient' }) -}) - -test('JWE no alg/enc specified (multi recipient)', t => { - const encrypt = new JWE.Encrypt('foo') - encrypt.recipient(generateSync('RSA')) - encrypt.recipient(generateSync('oct', 256)) - if (!('electron' in process.versions)) { - encrypt.recipient(generateSync('EC')) - } - - const jwe = encrypt.encrypt('general') - t.is(jwe.unprotected, undefined) - t.deepEqual(base64url.JSON.decode(jwe.protected), { enc: 'A128CBC-HS256' }) - t.deepEqual(jwe.recipients[0].header, { alg: 'RSA-OAEP' }) - if (!('electron' in process.versions)) { - t.deepEqual(jwe.recipients[1].header, { alg: 'A256KW' }) - const { epk, ...rest } = jwe.recipients[2].header - t.deepEqual(rest, { alg: 'ECDH-ES+A128KW' }) - } else { - const { alg, ...rest } = jwe.recipients[1].header - t.is(alg, 'A256GCMKW') - t.true('iv' in rest) - t.true('tag' in rest) - } -}) - -test('JWE no alg/enc specified (multi recipient) with per-recipient headers', t => { - const encrypt = new JWE.Encrypt('foo') - const k1 = generateSync('RSA', undefined, { kid: 'kid_1' }) - encrypt.recipient(k1, { kid: k1.kid }) - const k2 = generateSync('oct', 256, { kid: 'kid_3' }) - encrypt.recipient(k2, { kid: k2.kid }) - if (!('electron' in process.versions)) { - const k3 = generateSync('EC', undefined, { kid: 'kid_2' }) - encrypt.recipient(k3, { kid: k3.kid }) - } - - const jwe = encrypt.encrypt('general') - t.is(jwe.unprotected, undefined) - t.deepEqual(base64url.JSON.decode(jwe.protected), { enc: 'A128CBC-HS256' }) - t.deepEqual(jwe.recipients[0].header, { alg: 'RSA-OAEP', kid: 'kid_1' }) - if (!('electron' in process.versions)) { - t.deepEqual(jwe.recipients[1].header, { alg: 'A256KW', kid: 'kid_3' }) - const { epk, ...rest } = jwe.recipients[2].header - t.deepEqual(rest, { alg: 'ECDH-ES+A128KW', kid: 'kid_2' }) - } else { - const { alg, kid, ...rest } = jwe.recipients[1].header - t.is(alg, 'A256GCMKW') - t.is(kid, 'kid_3') - t.true('iv' in rest) - t.true('tag' in rest) - } -}) - -test('JWE no alg/enc specified (single rsa), no protected header', t => { - const encrypt = new JWE.Encrypt('foo') - encrypt.recipient(generateSync('RSA')) - - const jwe = encrypt.encrypt('flattened') - t.is(jwe.unprotected, undefined) - t.is(jwe.header, undefined) - t.deepEqual(base64url.JSON.decode(jwe.protected), { alg: 'RSA-OAEP', enc: 'A128CBC-HS256' }) -}) - -test('JWE no alg/enc specified (single rsa), with protected header', t => { - const k = generateSync('RSA', undefined, { kid: 'jwk key id' }) - const encrypt = new JWE.Encrypt('foo', { kid: k.kid }) - encrypt.recipient(k) - - const jwe = encrypt.encrypt('flattened') - t.is(jwe.unprotected, undefined) - t.is(jwe.header, undefined) - t.deepEqual(base64url.JSON.decode(jwe.protected), { alg: 'RSA-OAEP', enc: 'A128CBC-HS256', kid: 'jwk key id' }) -}) - -test('JWE no alg specified (single rsa), with protected header', t => { - const k = generateSync('RSA') - const encrypt = new JWE.Encrypt('foo', { enc: 'A256CBC-HS512' }) - encrypt.recipient(k) - - const jwe = encrypt.encrypt('flattened') - t.is(jwe.unprotected, undefined) - t.is(jwe.header, undefined) - t.deepEqual(base64url.JSON.decode(jwe.protected), { alg: 'RSA-OAEP', enc: 'A256CBC-HS512' }) -}) - -test('JWE no alg specified (single rsa), with unprotected header', t => { - const k = generateSync('RSA') - const encrypt = new JWE.Encrypt('foo', undefined, undefined, { enc: 'A256CBC-HS512' }) - encrypt.recipient(k) - - const jwe = encrypt.encrypt('flattened') - t.deepEqual(jwe.unprotected, { enc: 'A256CBC-HS512' }) - t.is(jwe.header, undefined) - t.deepEqual(base64url.JSON.decode(jwe.protected), { alg: 'RSA-OAEP' }) -}) - -test('JWE no alg/enc specified (single oct)', t => { - const encrypt = new JWE.Encrypt('foo') - encrypt.recipient(generateSync('oct', 128)) - - const jwe = encrypt.encrypt('flattened') - t.is(jwe.unprotected, undefined) - t.is(jwe.header, undefined) - if (!('electron' in process.versions)) { - t.deepEqual(base64url.JSON.decode(jwe.protected), { alg: 'A128KW', enc: 'A128CBC-HS256' }) - } else { - const { iv, tag, ...rest } = base64url.JSON.decode(jwe.protected) - t.deepEqual(rest, { alg: 'A128GCMKW', enc: 'A128CBC-HS256' }) - t.truthy(iv) - t.truthy(tag) - } -}) - -test('JWE no alg/enc specified (single ec)', t => { - const encrypt = new JWE.Encrypt('foo') - encrypt.recipient(generateSync('EC')) - - const jwe = encrypt.encrypt('flattened') - t.is(jwe.unprotected, undefined) - t.is(jwe.header, undefined) - const { epk, ...rest } = base64url.JSON.decode(jwe.protected) - t.deepEqual(rest, { alg: 'ECDH-ES', enc: 'A128CBC-HS256' }) -}) - -test('JWE no alg/enc specified (only on a key)', t => { - const encrypt = new JWE.Encrypt('foo') - encrypt.recipient(generateSync('RSA', undefined, { alg: 'RSA1_5', use: 'enc' })) - - const jwe = encrypt.encrypt('flattened') - t.is(jwe.unprotected, undefined) - t.is(jwe.header, undefined) - t.deepEqual(base64url.JSON.decode(jwe.protected), { alg: 'RSA1_5', enc: 'A128CBC-HS256' }) -}) - -test('aes_cbc_hmac_sha2 decrypt iv check (missing)', t => { - const k = generateSync('oct', undefined, { alg: 'A128CBC-HS256' }) - const encrypted = JWE.encrypt.flattened('foo', k, { alg: 'dir', enc: k.alg }) - delete encrypted.iv - t.throws(() => { - JWE.decrypt(encrypted, k) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE malformed or invalid serialization' }) -}) - -test('aes_cbc_hmac_sha2 decrypt iv check (invalid length)', t => { - const k = generateSync('oct', undefined, { alg: 'A128CBC-HS256' }) - const encrypted = JWE.encrypt.flattened('foo', k, { alg: 'dir', enc: k.alg }) - encrypted.iv = base64url.encode(base64url.decodeToBuffer(encrypted.iv).slice(1)) - t.throws(() => { - JWE.decrypt(encrypted, k) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'invalid iv' }) -}) - -test('aes_cbc_hmac_sha2 decrypt tag check (missing)', t => { - const k = generateSync('oct', undefined, { alg: 'A128CBC-HS256' }) - const encrypted = JWE.encrypt.flattened('foo', k, { alg: 'dir', enc: k.alg }) - delete encrypted.tag - t.throws(() => { - JWE.decrypt(encrypted, k) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE malformed or invalid serialization' }) -}) - -test('aes_cbc_hmac_sha2 decrypt tag check (invalid length)', t => { - const k = generateSync('oct', undefined, { alg: 'A128CBC-HS256' }) - const encrypted = JWE.encrypt.flattened('foo', k, { alg: 'dir', enc: k.alg }) - encrypted.tag = base64url.encode(base64url.decodeToBuffer(encrypted.tag).slice(1)) - t.throws(() => { - JWE.decrypt(encrypted, k) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'invalid tag' }) -}) - -test('aes_gcm decrypt iv check (missing)', t => { - const k = generateSync('oct', 128, { alg: 'A128GCM' }) - const encrypted = JWE.encrypt.flattened('foo', k, { alg: 'dir', enc: k.alg }) - delete encrypted.iv - t.throws(() => { - JWE.decrypt(encrypted, k) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE malformed or invalid serialization' }) -}) - -test('aes_gcm decrypt iv check (invalid length)', t => { - const k = generateSync('oct', 128, { alg: 'A128GCM' }) - const encrypted = JWE.encrypt.flattened('foo', k, { alg: 'dir', enc: k.alg }) - encrypted.iv = base64url.encode(base64url.decodeToBuffer(encrypted.iv).slice(1)) - t.throws(() => { - JWE.decrypt(encrypted, k) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'invalid iv' }) -}) - -test('aes_gcm decrypt tag check (missing)', t => { - const k = generateSync('oct', 128, { alg: 'A128GCM' }) - const encrypted = JWE.encrypt.flattened('foo', k, { alg: 'dir', enc: k.alg }) - delete encrypted.tag - t.throws(() => { - JWE.decrypt(encrypted, k) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE malformed or invalid serialization' }) -}) - -test('aes_gcm decrypt tag check (invalid length)', t => { - const k = generateSync('oct', 128, { alg: 'A128GCM' }) - const encrypted = JWE.encrypt.flattened('foo', k, { alg: 'dir', enc: k.alg }) - encrypted.tag = base64url.encode(base64url.decodeToBuffer(encrypted.tag).slice(1)) - t.throws(() => { - JWE.decrypt(encrypted, k) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'invalid tag' }) -}) - -test('JWE encrypt accepts buffer', t => { - const k = generateSync('oct') - JWE.encrypt(Buffer.from('foo'), k) - t.pass() -}) - -test('JWE encrypt accepts string', t => { - const k = generateSync('oct') - JWE.encrypt('foo', k) - t.pass() -}) - -test('JWE encrypt rejects other', t => { - const k = generateSync('oct') - ;[[], {}, false, true, undefined, null, Infinity, 0].forEach((val) => { - t.throws(() => { - JWE.encrypt(val, k) - }, { instanceOf: TypeError, message: 'cleartext argument must be a Buffer or a string' }) - }) -}) - -test('JWE encrypt protectedHeader rejects non objects if provided', t => { - const k = generateSync('oct') - ;[[], false, true, null, Infinity, 0, Buffer.from('foo')].forEach((val) => { - t.throws(() => { - JWE.encrypt('foo', k, val) - }, { instanceOf: TypeError, message: 'protectedHeader argument must be a plain object when provided' }) - }) -}) - -test('JWE encrypt unprotectedHeader rejects non objects if provided', t => { - ;[[], false, true, null, Infinity, 0, Buffer.from('foo')].forEach((val) => { - t.throws(() => { - new JWE.Encrypt('foo', undefined, undefined, val) // eslint-disable-line no-new - }, { instanceOf: TypeError, message: 'unprotectedHeader argument must be a plain object when provided' }) - }) -}) - -test('JWE encrypt per-recipient header rejects non objects if provided', t => { - const k = generateSync('oct') - const enc = new JWE.Encrypt('foo') - ;[[], false, true, null, Infinity, 0, Buffer.from('foo')].forEach((val) => { - t.throws(() => { - enc.recipient(k, val) - }, { instanceOf: TypeError, message: 'header argument must be a plain object when provided' }) - }) -}) - -test('JWE encrypt aad rejects non buffers and non strings', t => { - ;[[], false, true, null, Infinity, 0].forEach((val) => { - t.throws(() => { - new JWE.Encrypt('foo', undefined, val) // eslint-disable-line no-new - }, { instanceOf: TypeError, message: 'aad argument must be a Buffer or a string when provided' }) - }) -}) - -test('JWE must have recipients', t => { - const encrypt = new JWE.Encrypt('foo') - t.throws(() => { - encrypt.encrypt('compact') - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'missing recipients' }) -}) - -test('JWE valid serialization must be provided', t => { - ;[[], false, true, null, Infinity, 0, 'foo', ''].forEach((val) => { - const encrypt = new JWE.Encrypt('foo') - t.throws(() => { - encrypt.encrypt(val) - }, { instanceOf: TypeError, message: 'serialization must be one of "compact", "flattened", "general"' }) - }) -}) - -test('JWE compact does not support multiple recipients', t => { - const k = generateSync('oct') - const k2 = generateSync('EC') - const encrypt = new JWE.Encrypt('foo') - encrypt.recipient(k) - encrypt.recipient(k2) - t.throws(() => { - encrypt.encrypt('compact') - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE Compact Serialization doesn\'t support multiple recipients, JWE unprotected headers or AAD' }) -}) - -test('JWE compact does not support unprotected header', t => { - const k = generateSync('oct') - t.throws(() => { - JWE.encrypt('foo', k, undefined, undefined, { foo: 1 }) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE Compact Serialization doesn\'t support multiple recipients, JWE unprotected headers or AAD' }) -}) - -test('JWE compact does not support aad', t => { - const k = generateSync('oct') - t.throws(() => { - JWE.encrypt('foo', k, undefined, 'aad') - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE Compact Serialization doesn\'t support multiple recipients, JWE unprotected headers or AAD' }) -}) - -test('JWE flattened does not support multiple recipients', t => { - const k = generateSync('oct') - const k2 = generateSync('EC') - const encrypt = new JWE.Encrypt('foo') - encrypt.recipient(k) - encrypt.recipient(k2) - t.throws(() => { - encrypt.encrypt('flattened') - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'Flattened JWE JSON Serialization doesn\'t support multiple recipients' }) -}) - -test('JWE must only have one Content Encryption algorithm (encrypt)', t => { - const k = generateSync('oct') - const k2 = generateSync('RSA') - const encrypt = new JWE.Encrypt('foo') - encrypt.recipient(k, { enc: 'A128CBC-HS256' }) - encrypt.recipient(k2, { enc: 'A128GCM' }) - t.throws(() => { - encrypt.encrypt('general') - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'there must only be one Content Encryption algorithm' }) -}) - -test('JWE must only have one Content Encryption algorithm (decrypt)', t => { - const k = generateSync('oct') - const k2 = generateSync('RSA') - const encrypt = new JWE.Encrypt('foo') - encrypt.recipient(k, { enc: 'A128GCM' }) - encrypt.recipient(k2, { enc: 'A128GCM' }) - const jwe = encrypt.encrypt('general') - t.throws(() => { - jwe.recipients[0].header.enc = 'A128CBC-HS256' - JWE.decrypt(jwe, k) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'there must only be one Content Encryption algorithm' }) -}) - -test('JWE must have a Content Encryption algorithm (decrypt)', t => { - const k = generateSync('oct') - const k2 = generateSync('RSA') - const encrypt = new JWE.Encrypt('foo') - encrypt.recipient(k, { enc: 'A128GCM' }) - encrypt.recipient(k2, { enc: 'A128GCM' }) - const jwe = encrypt.encrypt('general') - t.throws(() => { - delete jwe.recipients[0].header.enc - delete jwe.recipients[1].header.enc - JWE.decrypt(jwe, k) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'missing Content Encryption algorithm' }) -}) - -test('JWE oct dir is only usable with a single recipient', t => { - const k = generateSync('oct', undefined, { alg: 'A128CBC-HS256', use: 'enc' }) - const k2 = generateSync('RSA') - const encrypt = new JWE.Encrypt('foo') - encrypt.recipient(k, { alg: 'dir' }) - encrypt.recipient(k2) - t.throws(() => { - encrypt.encrypt('general') - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'dir and ECDH-ES alg may only be used with a single recipient' }) -}) - -test('JWE EC ECDH-ES is only usable with a single recipient', t => { - const k = generateSync('EC', undefined, { alg: 'ECDH-ES', use: 'enc' }) - const k2 = generateSync('RSA') - const encrypt = new JWE.Encrypt('foo') - encrypt.recipient(k, { alg: 'ECDH-ES' }) - encrypt.recipient(k2) - t.throws(() => { - encrypt.encrypt('general') - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'dir and ECDH-ES alg may only be used with a single recipient' }) -}) - -test('JWE prot, unprot and per-recipient headers must be disjoint', t => { - const k = generateSync('oct') - t.throws(() => { - const encrypt = new JWE.Encrypt('foo', { foo: 1 }, undefined, { foo: 2 }) - encrypt.recipient(k) - encrypt.encrypt('flattened') - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE Shared Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint' }) - t.throws(() => { - const encrypt = new JWE.Encrypt('foo', { foo: 1 }) - encrypt.recipient(k, { foo: 2 }) - encrypt.encrypt('flattened') - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE Shared Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint' }) - t.throws(() => { - const encrypt = new JWE.Encrypt('foo', undefined, undefined, { foo: 1 }) - encrypt.recipient(k, { foo: 2 }) - encrypt.encrypt('flattened') - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'JWE Shared Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint' }) -}) - -test('JWE decrypt keyManagementAlgorithms whitelist', t => { - const k = generateSync('oct', 128) - const jwe = JWE.encrypt('foo', k, { alg: 'A128GCMKW' }) - JWE.decrypt(jwe, k, { keyManagementAlgorithms: ['A128GCMKW', 'A192GCMKW'] }) - - t.throws(() => { - JWE.decrypt(jwe, k, { keyManagementAlgorithms: ['A192GCMKW'] }) - }, { instanceOf: errors.JOSEAlgNotWhitelisted, code: 'ERR_JOSE_ALG_NOT_WHITELISTED', message: 'key management algorithm not whitelisted' }) -}) - -test('JWE decrypt keyManagementAlgorithms whitelist with a keystore', t => { - const k = generateSync('oct') - const k2 = generateSync('oct', 128) - const ks = new JWKS.KeyStore(k, k2) - - const jwe = JWE.encrypt('foo', k2, { alg: 'A128GCMKW' }) - JWE.decrypt(jwe, ks, { keyManagementAlgorithms: ['A128GCMKW', 'A192GCMKW'] }) - - t.throws(() => { - JWE.decrypt(jwe, ks, { keyManagementAlgorithms: ['A192GCMKW'] }) - }, { instanceOf: errors.JOSEAlgNotWhitelisted, code: 'ERR_JOSE_ALG_NOT_WHITELISTED' }) -}) - -test('JWE decrypt contentEncryptionAlgorithms whitelist', t => { - const k = generateSync('oct') - const jwe = JWE.encrypt('foo', k, { alg: 'dir' }) - JWE.decrypt(jwe, k, { contentEncryptionAlgorithms: ['A128CBC-HS256'] }) - - t.throws(() => { - JWE.decrypt(jwe, k, { contentEncryptionAlgorithms: ['PBES2-HS384+A192KW'] }) - }, { instanceOf: errors.JOSEAlgNotWhitelisted, code: 'ERR_JOSE_ALG_NOT_WHITELISTED' }) -}) - -test('JWE decrypt keyManagementAlgorithms whitelist (multi-recipient)', t => { - const k = generateSync('oct') - const k2 = generateSync('RSA') - - const encrypt = new JWE.Encrypt('foo') - encrypt.recipient(k) - encrypt.recipient(k2) - const jwe = encrypt.encrypt('general') - - JWE.decrypt(jwe, k, { keyManagementAlgorithms: ['electron' in process.versions ? 'A256GCMKW' : 'A256KW'] }) - JWE.decrypt(jwe, k2, { keyManagementAlgorithms: ['RSA-OAEP'] }) - let err - - err = t.throws(() => { - JWE.decrypt(jwe, k, { keyManagementAlgorithms: ['RSA-OAEP'] }) - }, { instanceOf: errors.JOSEMultiError, code: 'ERR_JOSE_MULTIPLE_ERRORS' }) - ;[...err].forEach((e, i) => { - if (i === 0) { - t.is(e.constructor, errors.JOSEAlgNotWhitelisted) - } else { - t.is(e.constructor, errors.JWKKeySupport) - } - }) - - err = t.throws(() => { - JWE.decrypt(jwe, k2, { keyManagementAlgorithms: ['electron' in process.versions ? 'A256GCMKW' : 'A256KW'] }) - }, { instanceOf: errors.JOSEMultiError, code: 'ERR_JOSE_MULTIPLE_ERRORS' }) - ;[...err].forEach((e, i) => { - if (i === 0) { - t.is(e.constructor, errors.JWKKeySupport) - } else { - t.is(e.constructor, errors.JOSEAlgNotWhitelisted) - } - }) -}) - -test('JWE "zip" must be integrity protected', t => { - const k = generateSync('oct') - - t.throws(() => { - JWE.encrypt.flattened('foo', k, undefined, undefined, { zip: 'DEF' }) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: '"zip" Header Parameter MUST be integrity protected' }) -}) - -test('JWE "zip" only DEF is supported', t => { - const k = generateSync('oct') - - t.throws(() => { - JWE.encrypt.flattened('foo', k, { zip: 'FOO' }) - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'only "DEF" compression algorithm is supported' }) -}) - -test('JWE "zip" must be integrity protected (decrypt)', t => { - const k = generateSync('oct') - const jwe = JWE.encrypt.flattened('foo', k, { zip: 'DEF' }) - const prot = base64url.JSON.decode(jwe.protected) - delete prot.zip - jwe.protected = base64url.JSON.encode(prot) - jwe.unprotected = { zip: 'DEF' } - - t.throws(() => { - JWE.decrypt(jwe, k) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: '"zip" Header Parameter MUST be integrity protected' }) -}) - -test('JWE "zip" only DEF is supported (decrypt)', t => { - const k = generateSync('oct') - const jwe = JWE.encrypt.flattened('foo', k, { zip: 'DEF' }) - const prot = base64url.JSON.decode(jwe.protected) - prot.zip = 'foo' - jwe.protected = base64url.JSON.encode(prot) - - t.throws(() => { - JWE.decrypt(jwe, k) - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'only "DEF" compression algorithm is supported' }) -}) - -test('JWE keystore match multi but fails with decryption error', t => { - const k = generateSync('oct') - const ks = new JWKS.KeyStore(generateSync('oct'), generateSync('oct')) - const jwe = JWE.encrypt('foo', k) - - t.throws(() => { - JWE.decrypt(jwe, ks) - }, { instanceOf: errors.JWEDecryptionFailed, code: 'ERR_JWE_DECRYPTION_FAILED' }) -}) - -test('JWE general fails with decryption error', t => { - const k = generateSync('oct') - const k2 = generateSync('oct') - const k3 = generateSync('oct') - const encrypt = new JWE.Encrypt('foo') - encrypt.recipient(k) - encrypt.recipient(k2) - const jwe = encrypt.encrypt('general') - - t.throws(() => { - JWE.decrypt(jwe, k3) - }, { instanceOf: errors.JWEDecryptionFailed, code: 'ERR_JWE_DECRYPTION_FAILED' }) -}) - -test('"sig" key is not usable for signing', t => { - const k = generateSync('oct', 256, { use: 'sig' }) - t.throws(() => { - JWE.encrypt('foo', k) - }, { instanceOf: TypeError, message: 'a key with "use":"sig" is not usable for encryption' }) -}) - -test('"enc" value must be supported error', t => { - const k = generateSync('oct', 256) - t.throws(() => { - JWE.encrypt('foo', k, { alg: 'dir', enc: 'foo' }) - }, { instanceOf: errors.JOSENotSupported, message: 'unsupported encrypt alg: foo' }) -}) - -test('"enc" value must be supported error (when no alg was specified)', t => { - const k = generateSync('oct', 256) - t.throws(() => { - JWE.encrypt('foo', k, { enc: 'foo' }) - }, { instanceOf: errors.JOSENotSupported, message: 'unsupported encrypt alg: foo' }) -}) diff --git a/test/jwe/smoke.oct.test.js b/test/jwe/smoke.oct.test.js deleted file mode 100644 index ba80fe0ebc..0000000000 --- a/test/jwe/smoke.oct.test.js +++ /dev/null @@ -1,52 +0,0 @@ -const test = require('ava') - -const { randomBytes } = require('crypto') - -const { keyObjectSupported } = require('../../lib/help/runtime_support') -const { JWK: { asKey } } = require('../..') -const registry = require('../../lib/registry') - -const { JWE: { success, failure } } = require('../macros') - -const ENCS = [...registry.JWA.encrypt.keys()] - -;[16, 24, 32, 48, 64].forEach((len) => { - const sk = randomBytes(len) - const sym = asKey(sk) - ;[...sym.algorithms('wrapKey'), 'dir'].forEach((alg) => { - (alg === 'dir' ? sym.algorithms('encrypt') : ENCS).forEach((enc) => { - test(`key ${sym.kty}(${len * 8} bits) > alg ${alg} > ${enc}`, success, sym, sym, alg, enc) - test(`key ${sym.kty}(${len * 8} bits) > alg ${alg} > ${enc} (key as bare input)`, success, sk, sk, alg, enc) - if (keyObjectSupported) { - test(`key ${sym.kty}(${len * 8} bits) > alg ${alg} > ${enc} (key as keyobject)`, success, sym.keyObject, sym.keyObject, alg, enc) - } - test(`key ${sym.kty}(${len * 8} bits) > alg ${alg} > ${enc} (key as JWK)`, success, sym.toJWK(true), sym.toJWK(true), alg, enc) - test(`key ${sym.kty}(${len * 8} bits) > alg ${alg} > ${enc} (negative cases, key as bare input)`, failure, sk, sk, alg, enc) - if (keyObjectSupported) { - test(`key ${sym.kty}(${len * 8} bits) > alg ${alg} > ${enc} (negative cases, key as keyobject)`, failure, sym.keyObject, sym.keyObject, alg, enc) - } - test(`key ${sym.kty}(${len * 8} bits) > alg ${alg} > ${enc} (negative cases, key as JWK)`, failure, sym.toJWK(true), sym.toJWK(true), alg, enc) - }) - }) -}) - -{ - // PBES2 derive only - const sk = Buffer.from('hunter2', 'utf-8') - const sym = asKey(sk) - sym.algorithms('deriveKey').forEach((alg) => { - ENCS.forEach((enc) => { - test(`key ${sym.kty}(password) > alg ${alg} > ${enc}`, success, sym, sym, alg, enc) - test(`key ${sym.kty}(password) > alg ${alg} > ${enc} (key as bare input)`, success, sk, sk, alg, enc) - if (keyObjectSupported) { - test(`key ${sym.kty}(password) > alg ${alg} > ${enc} (key as keyobject)`, success, sym.keyObject, sym.keyObject, alg, enc) - } - test(`key ${sym.kty}(password) > alg ${alg} > ${enc} (key as JWK)`, success, sym.toJWK(true), sym.toJWK(true), alg, enc) - test(`key ${sym.kty}(password) > alg ${alg} > ${enc} (negative cases, key as bare input)`, failure, sk, sk, alg, enc) - if (keyObjectSupported) { - test(`key ${sym.kty}(password) > alg ${alg} > ${enc} (negative cases, key as keyobject)`, failure, sym.keyObject, sym.keyObject, alg, enc) - } - test(`key ${sym.kty}(password) > alg ${alg} > ${enc} (negative cases, key as JWK)`, failure, sym.toJWK(true), sym.toJWK(true), alg, enc) - }) - }) -} diff --git a/test/jwe/smoke.p256.test.js b/test/jwe/smoke.p256.test.js deleted file mode 100644 index 40baefc60a..0000000000 --- a/test/jwe/smoke.p256.test.js +++ /dev/null @@ -1 +0,0 @@ -require('../macros/test_asymm_enc')('P-256') diff --git a/test/jwe/smoke.p384.test.js b/test/jwe/smoke.p384.test.js deleted file mode 100644 index 009034e51b..0000000000 --- a/test/jwe/smoke.p384.test.js +++ /dev/null @@ -1 +0,0 @@ -require('../macros/test_asymm_enc')('P-384') diff --git a/test/jwe/smoke.p521.test.js b/test/jwe/smoke.p521.test.js deleted file mode 100644 index 089b1fbb5a..0000000000 --- a/test/jwe/smoke.p521.test.js +++ /dev/null @@ -1 +0,0 @@ -require('../macros/test_asymm_enc')('P-521') diff --git a/test/jwe/smoke.rsa.test.js b/test/jwe/smoke.rsa.test.js deleted file mode 100644 index 8353d3412a..0000000000 --- a/test/jwe/smoke.rsa.test.js +++ /dev/null @@ -1 +0,0 @@ -require('../macros/test_asymm_enc')('RSA') diff --git a/test/jwe/smoke.rsamin.test.js b/test/jwe/smoke.rsamin.test.js deleted file mode 100644 index 0e15689ed8..0000000000 --- a/test/jwe/smoke.rsamin.test.js +++ /dev/null @@ -1,20 +0,0 @@ -const test = require('ava') - -const { JWK: { asKey, generateSync } } = require('../..') -const registry = require('../../lib/registry') - -const { JWE: { success, failure } } = require('../macros') - -const ENCS = [...registry.JWA.encrypt.keys()] - -{ - const rsa = generateSync('RSA') - const dKey = asKey({ kty: 'RSA', e: rsa.e, n: rsa.n, d: rsa.d }, { calculateMissingRSAPrimes: true }) - const eKey = asKey({ kty: 'RSA', e: rsa.e, n: rsa.n }) - eKey.algorithms('wrapKey').forEach((alg) => { - ENCS.forEach((enc) => { - test(`key RSA (min) > alg ${alg} > ${enc}`, success, eKey, dKey, alg, enc) - test(`key RSA (min) > alg ${alg} > ${enc} (negative cases)`, failure, eKey, dKey, alg, enc) - }) - }) -} diff --git a/test/jwe/smoke.test.js b/test/jwe/smoke.test.js deleted file mode 100644 index e5f5a6b485..0000000000 --- a/test/jwe/smoke.test.js +++ /dev/null @@ -1,15 +0,0 @@ -const test = require('ava') - -const { existsSync } = require('fs') -const path = require('path') - -const fixtures = require('../fixtures') - -Object.entries(fixtures.PEM).forEach(([type, { testEnc = true }]) => { - if (testEnc) { - const filename = `smoke.${type.toLowerCase().replace('-', '')}.test.js` - test(`${type} is tested`, t => { - t.true(existsSync(path.join(__dirname, filename))) - }) - } -}) diff --git a/test/jwe/smoke.test.mjs b/test/jwe/smoke.test.mjs new file mode 100644 index 0000000000..c29e3b3ebb --- /dev/null +++ b/test/jwe/smoke.test.mjs @@ -0,0 +1,296 @@ +/* eslint-disable no-await-in-loop */ +/* eslint-disable no-restricted-syntax */ +/* eslint-disable no-bitwise */ +/* eslint-disable no-param-reassign */ + +import test from 'ava'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +Promise.all([ + import(`${root}/jwe/flattened/encrypt`), + import(`${root}/jwe/flattened/decrypt`), + import(`${root}/util/random`), + import(`${root}/util/base64url`), + import(`${root}/jwk/parse`), + import(`${root}/util/generate_key_pair`), + import(`${root}/util/generate_secret`), +]).then( + ([ + { default: FlattenedEncrypt }, + { default: decryptFlattened }, + { default: random }, + { encode: base64url }, + { default: parseJwk }, + { default: generateKeyPair }, + { default: generateSecret }, + ]) => { + function pubjwk(jwk) { + const { d, p, q, dp, dq, qi, ...publicJwk } = jwk; + return publicJwk; + } + test.before(async (t) => { + const p256 = { + ext: false, + crv: 'P-256', + x: 'Sp3KpzPjwcCF04_W2GvSSf-vGDvp3Iv2kQYqAjnMB-Y', + y: 'lZmecT2quXe0i9f7b4qHvDAFDpxs0oxCoJx4tOOqsks', + d: 'hRVo5TGE_d_4tQC1KEQIlCdo9rteZmLSmaMPpFOjeDI', + kty: 'EC', + }; + const p384 = { + ext: false, + crv: 'P-384', + x: 'H50cO3PJnVhAoF6_jPKpCl60cnvmoygN2u29jVN19x8C2PymixZS4Y5d1FfMMK3L', + y: 'ATQ-4QWyYTtEaBW3CFQZEX0NdDE5g_9F24B0y2xxQgVmWa5Uz0QerlhzFoYU7Z_F', + d: 'HDUcH8y8xr22EroPYBK3PvpNjA3pCJjvHpBXKejxOiQCoXhZ5PhX_nxb7lU0mlDE', + kty: 'EC', + }; + const p521 = { + ext: false, + crv: 'P-521', + x: + 'AFy8VTdHeJx7rrUajpeqIjGZsjtx0tftQ7pdL1qkTRpnvY0WVVKXjib3HINNLMA72gA7JujbvEtGvkvoo0P7pGVK', + y: + 'AfMRSFv9qfcH_XMHfPoltBMYLhDbS3Pw1GL7NO9SI_vF4JsiAta1Bq6teCl2z8klFtRCWXHfPqEF3cmXS8bDQVoT', + d: + 'AL123tYK7y-iViaReLOHe7XxKNSeoUMk4RRmcP6nSVuZrYJHtyYPak4gUmWB6A_GzED3zXkrkcssZEzHrYQILw5c', + kty: 'EC', + }; + const rsa = { + ext: false, + e: 'AQAB', + n: + 'rPOe2kdmQY1wN2ADn-EIKsPO_kXotIqPjbZQOoW6sIHPGS8xJqrR60JLTBir5jG8Prrp4_KoEDGm3zYlWb5EJr9BMAVHAUYB2ZMXjdojpIkKeJ_cMI0lLcSUTkKkOA6u2DnVJBlnQgeyVZ927h65cJ5zsnSqG6MHh5tVPAwocEsfH27Tik_Fp-dCidmr_-rCrPfoAuASadvuFr5oAa7aAKdlLz6P0GgmCs2KzTAR6FiBMm48hd1YkrIaGzljKOwCgh0KYA3tnetbOCFEuzsmn9wmQHUA0iPQqYGlFJVfQ64949hQk42uWxCXtaO_wlXqy_TVki5LTQ7hO4reUiMXpQ', + d: + 'qhn97b91khmS-dOkHPYNu0nUZv_JDPCOmhlqtPRcFkfFsYZZuCcfyVvthM1rHD9kXuolKf26UBsVfcnaWHaqvtUyPxGhsV3yadSiwPCAR85FDzhjLxlTLL2AA6zFqSC_1Iik2hlmFmpNeqsZJL_xMROWxTi7Ke1hdX1QCnwGtdF-Emdqgf1wqBWv6VTQVd2qslQySQN8RLTYmlkHBmOHU1jc0e2QP5xbLD4-pPr7RW17WbOkW2aLsC0YYebqFaqVgLNZJIVDKetRCCgi1RcdieQ0zSuUfRc9wzhZW7HHCECASqjeFqHopG05ge-DwAcc62-H7EbKr0XWz-7SLqjTrQ', + p: + '3wSG2cBBbo6FZ0GiRucHhJhSx1U6ZRhwhrbJmSpiFG5rvHvZn-DWnOmurvO5jc1V2Qj4QAEO4w7YQh3A9PFBry_42Od5zof1GIeAOVT3REiMTOSCxMVEMWQ74UBUM2T2R_TDrBgVSuaRmX14mcZM6_SYu7JLpqeSDzZEy2cqOBs', + q: + 'xoeWkL7oZ488PsJ6_lkjCmrlxouKJgHqMHI_RVE-MGSYHDNrJ_iS4wp8CK4xhAdGukqxDm5ChqFECgdg5QfdLoCseAIC-aHrrylYrmka5_8ke-ObpW9iGFcZy-5cEH5NCr6iSb-KS6fZkxJl7g3Az6XmLoEHHmyy8QxG9Yikaz8', + dp: + 'DKUxED-6dg5Wuhgan3KSFo6cgvjuKrVMDBdpLuocTZRFP5a2LD6PbK5DXWAscUHnUDsV-GsW8QDyei09t6XGV6ycq4_UdEV5PD7Som2S56hFbEa4s3eL-lD4pDkFjTR4UnQqdCOZcXnJX66hm_aGfgqMbngZmgV-XqZxGCdtWWk', + dq: + 'uX6ijefyWiCZF8K7DL_YX7l1q8dhcxXC7TUyLOA2DR1Qirj4XEaDaCO5tJqdpVDvIsz7FhKrkgNIAV7Xh-eLIBIWE6M9iGVkQyuMspl-DFp2ilMmcLLbowZvEf5KgxafgXSRSfrvirTwM9yy5HRxPRMzOSxRrHm_0D26Z1we1B0', + qi: + 'htPHLViOVG6QrldfuHn9evfdlD-UEuViOWNx8aKR3IBv0qegpJ78vYB4hdAcJZtBslKI97En5rzOAN3Y6Y8MbI4oN77WeiePJl2cMrS64evmlERvjJ6ZTs8jK0iV5q_gIZ9Qg9drmolUgb_CccQOBFbqSL6YkXwCBxlkCrzTlhc', + kty: 'RSA', + }; + const x25519 = { + ext: false, + crv: 'X25519', + x: 'i0CfuN5lAHXdv-_OeozwEDIL0-TAC47Gx1iFb6Si6wc', + d: 'UEmf0e90dkN0jc1VW2k9Ensb03r5wbuQfYs5xNrT7Xw', + kty: 'OKP', + }; + const x448 = { + ext: false, + crv: 'X448', + x: 'FXL1VnZUBAAXhO7I2BrECCQGQmTzPzcsB3G-5VCgqOrBHDIWUqhg4hgisgF3EOuV87RjfjR43FE', + d: 'YETRz89J2Di6UTLBE_qZtENzsb5YoBjl_Hh7sR69YkP0mDhnndkzEyIZuo6kbqPMtqlLDXKrSbI', + kty: 'OKP', + }; + t.context.keys = { + rsa: { + public: pubjwk(rsa), + private: rsa, + algs: ['RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512'], + }, + rsa1_5: { + public: pubjwk(rsa), + private: rsa, + algs: ['RSA1_5'], + }, + x25519: { + public: pubjwk(x25519), + private: x25519, + algs: ['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW'], + generate: { crv: 'X25519' }, + }, + x448: { + public: pubjwk(x448), + private: x448, + algs: ['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW'], + generate: { crv: 'X448' }, + }, + p256: { + public: pubjwk(p256), + private: p256, + algs: ['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW'], + generate: { crv: 'P-256' }, + }, + p384: { + public: pubjwk(p384), + private: p384, + algs: ['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW'], + generate: { crv: 'P-384' }, + }, + p521: { + public: pubjwk(p521), + private: p521, + algs: ['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW'], + generate: { crv: 'P-521' }, + }, + octAny: { + secret: { ext: false, kty: 'oct', k: base64url(random(new Uint8Array(160 >> 3))) }, + algs: ['PBES2-HS256+A128KW', 'PBES2-HS384+A192KW', 'PBES2-HS512+A256KW'], + generate: false, + }, + oct128: { + secret: { ext: false, kty: 'oct', k: base64url(random(new Uint8Array(128 >> 3))) }, + algs: ['A128KW'], + }, + oct192: { + secret: { ext: false, kty: 'oct', k: base64url(random(new Uint8Array(192 >> 3))) }, + algs: ['A192KW'], + }, + oct256: { + secret: { ext: false, kty: 'oct', k: base64url(random(new Uint8Array(256 >> 3))) }, + algs: ['A256KW'], + }, + oct128gcm: { + secret: { ext: false, kty: 'oct', k: base64url(random(new Uint8Array(128 >> 3))) }, + algs: ['A128GCM', 'A128GCMKW'], + }, + oct192gcm: { + secret: { ext: false, kty: 'oct', k: base64url(random(new Uint8Array(192 >> 3))) }, + algs: ['A192GCM', 'A192GCMKW'], + }, + oct256gcm: { + secret: { ext: false, kty: 'oct', k: base64url(random(new Uint8Array(256 >> 3))) }, + algs: ['A256GCM', 'A256GCMKW'], + }, + oct256c: { + secret: { kty: 'oct', k: base64url(random(new Uint8Array(256 >> 3))) }, + algs: ['A128CBC-HS256'], + }, + oct384c: { + secret: { kty: 'oct', k: base64url(random(new Uint8Array(384 >> 3))) }, + algs: ['A192CBC-HS384'], + }, + oct512c: { + secret: { kty: 'oct', k: base64url(random(new Uint8Array(512 >> 3))) }, + algs: ['A256CBC-HS512'], + }, + }; + }); + + async function smoke(t, ref, publicKeyUsages, privateKeyUsage, octAsKeyObject = false) { + const fixtures = t.context.keys[ref]; + await Promise.all([ + ...fixtures.algs.map(async (alg) => { + let priv; + let pub; + if ('secret' in fixtures) { + const key_ops = + publicKeyUsages || privateKeyUsage + ? [...new Set([...publicKeyUsages, ...privateKeyUsage])] + : undefined; + const secret = await parseJwk({ ...fixtures.secret, key_ops }, alg, octAsKeyObject); + if (octAsKeyObject) { + t.false(secret instanceof Uint8Array); + } else { + t.true(secret instanceof Uint8Array); + } + pub = secret; + priv = secret; + } else { + [pub, priv] = await Promise.all([ + parseJwk({ ...fixtures.public, key_ops: publicKeyUsages }, alg), + parseJwk({ ...fixtures.private, key_ops: privateKeyUsage }, alg), + ]); + } + + const jwe = await new FlattenedEncrypt(random(new Uint8Array(256 >> 3))) + .setProtectedHeader({ 'urn:example:protected': true }) + .setUnprotectedHeader( + alg.startsWith('A') && !alg.endsWith('KW') + ? { enc: alg } + : { enc: 'A256GCM', 'urn:example:header': true }, + ) + .setSharedUnprotectedHeader( + alg.startsWith('A') && !alg.endsWith('KW') + ? { alg: 'dir' } + : { alg, 'urn:example:unprotected': true }, + ) + .setAdditionalAuthenticatedData(random(new Uint8Array(128 >> 3))) + .encrypt(pub); + await decryptFlattened(jwe, priv); + }), + ...fixtures.algs.map(async (alg) => { + let priv; + let pub; + if ('secret' in fixtures) { + if (fixtures.generate === false) return; + const secret = await generateSecret(alg); + pub = secret; + priv = secret; + } else { + ({ privateKey: priv, publicKey: pub } = await generateKeyPair(alg, fixtures.generate)); + } + + const jwe = await new FlattenedEncrypt(random(new Uint8Array(256 >> 3))) + .setProtectedHeader({ 'urn:example:protected': true }) + .setUnprotectedHeader( + alg.startsWith('A') && !alg.endsWith('KW') + ? { enc: alg } + : { enc: 'A256GCM', 'urn:example:header': true }, + ) + .setSharedUnprotectedHeader( + alg.startsWith('A') && !alg.endsWith('KW') + ? { alg: 'dir' } + : { alg, 'urn:example:unprotected': true }, + ) + .setAdditionalAuthenticatedData(random(new Uint8Array(128 >> 3))) + .encrypt(pub); + await decryptFlattened(jwe, priv); + }), + ]); + t.pass(); + } + smoke.title = (title, ref) => `${ref.toUpperCase()}${title ? ` ${title}` : ''}`; + + test(smoke, 'rsa'); + test('with wrap ops', smoke, 'rsa', ['wrapKey'], ['unwrapKey']); + test('with enc ops', smoke, 'rsa', ['encrypt'], ['decrypt']); + test(smoke, 'p256'); + test(smoke, 'p384'); + test(smoke, 'p521'); + test(smoke, 'oct128'); + test('as keyobject', smoke, 'oct128', ['wrapKey'], ['unwrapKey'], true); + test(smoke, 'oct128gcm'); + test('as keyobject', smoke, 'oct128gcm', ['encrypt'], ['decrypt'], true); + test(smoke, 'oct192'); + test('as keyobject', smoke, 'oct192', ['wrapKey'], ['unwrapKey'], true); + test(smoke, 'oct192gcm'); + test('as keyobject', smoke, 'oct192gcm', ['encrypt'], ['decrypt'], true); + test(smoke, 'oct256'); + test('as keyobject', smoke, 'oct256', ['wrapKey'], ['unwrapKey'], true); + test(smoke, 'oct256gcm'); + test('as keyobject', smoke, 'oct256gcm', ['encrypt'], ['decrypt'], true); + test(smoke, 'oct256c'); + test(smoke, 'oct384c'); + test(smoke, 'oct512c'); + test(smoke, 'octAny'); + test('as keyobject (deriveBits)', smoke, 'octAny', ['deriveBits'], ['deriveBits'], true); + test('as keyobject (deriveKey)', smoke, 'octAny', ['deriveKey'], ['deriveKey'], true); + + let conditional; + if ('WEBCRYPTO' in process.env) { + conditional = test.failing; + } else { + conditional = test; + } + conditional(smoke, 'rsa1_5'); + conditional(smoke, 'x25519'); + conditional(smoke, 'x448'); + conditional('as keyobject', smoke, 'oct256c', undefined, undefined, true); + conditional('as keyobject', smoke, 'oct384c', undefined, undefined, true); + conditional('as keyobject', smoke, 'oct512c', undefined, undefined, true); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jwe/smoke.x25519.test.js b/test/jwe/smoke.x25519.test.js deleted file mode 100644 index da7d29aec8..0000000000 --- a/test/jwe/smoke.x25519.test.js +++ /dev/null @@ -1 +0,0 @@ -require('../macros/test_asymm_enc')('X25519') diff --git a/test/jwe/smoke.x448.test.js b/test/jwe/smoke.x448.test.js deleted file mode 100644 index 2e03d65cf8..0000000000 --- a/test/jwe/smoke.x448.test.js +++ /dev/null @@ -1 +0,0 @@ -require('../macros/test_asymm_enc')('X448') diff --git a/test/jwk/ec.test.js b/test/jwk/ec.test.js deleted file mode 100644 index 2b9e87616c..0000000000 --- a/test/jwk/ec.test.js +++ /dev/null @@ -1,332 +0,0 @@ -const test = require('ava') -const { createPrivateKey, createPublicKey } = require('../../lib/help/key_object') -const { hasProperty, hasNoProperties, hasProperties } = require('../macros') -const { generateKeyPairSync } = require('../macros/generate') -const fixtures = require('../fixtures') -const errors = require('../../lib/errors') - -const ECKey = require('../../lib/jwk/key/ec') - -test('EC key .algorithms invalid operation', t => { - const key = new ECKey(createPrivateKey(fixtures.PEM['P-256'].private)) - t.throws(() => key.algorithms('foo'), { instanceOf: TypeError, message: 'invalid key operation' }) -}) - -if (!('electron' in process.versions)) { - test('Unusable with unsupported curves', t => { - const kp = generateKeyPairSync('ec', { namedCurve: 'secp224k1' }) - t.throws( - () => new ECKey(kp.privateKey), - { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported EC key curve' } - ) - t.throws( - () => new ECKey(kp.publicKey), - { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported EC key curve' } - ) - }) -} - -Object.entries({ - 'P-256': ['ES256', 'rDd6H6t9-nJUoz72nTpz8tInvypVWhE2iQoPznj8ZY8'], - secp256k1: ['ES256K', 'kWx_DzFzKNHUQz1FkNzj8KmSRingv9EQQzdVY3td21w'], - 'P-384': ['ES384', '5gebayAhpztJCs4Pxo-z1hhsN0upoyG2NAoKpiiH2b0'], - 'P-521': ['ES512', 'BQtkbSY3xgN4M2ZP3IHMLG7-Rp1L29teCMfNqgJHtTY'] -}).forEach(([crv, [alg, kid]]) => { - let ECDH = ['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW'] - if ('electron' in process.versions) { - if (crv === 'secp256k1') return - ECDH.splice(1, ECDH.length - 1) - } - if (crv === 'secp256k1') { - ECDH = [] - } - if (crv === 'secp256k1' && 'electron' in process.versions) return - // private - ;(() => { - const keyObject = createPrivateKey(fixtures.PEM[crv].private) - const key = new ECKey(keyObject) - - test(`${crv} EC Private key`, hasProperty, key, 'crv', crv) - test(`${crv} EC Private key (with alg)`, hasProperty, new ECKey(keyObject, { alg }), 'alg', alg) - test(`${crv} EC Private key (with kid)`, hasProperty, new ECKey(keyObject, { kid: 'foobar' }), 'kid', 'foobar') - test(`${crv} EC Private key (with use)`, hasProperty, new ECKey(keyObject, { use: 'sig' }), 'use', 'sig') - test(`${crv} EC Private key`, hasNoProperties, key, 'k', 'e', 'n', 'p', 'q', 'dp', 'dq', 'qi') - test(`${crv} EC Private key`, hasProperties, key, 'x', 'y', 'd') - test(`${crv} EC Private key`, hasProperty, key, 'alg', undefined) - test(`${crv} EC Private key`, hasProperty, key, 'kid', kid) - test(`${crv} EC Private key`, hasProperty, key, 'kty', 'EC') - test(`${crv} EC Private key`, hasProperty, key, 'private', true) - test(`${crv} EC Private key`, hasProperty, key, 'public', false) - test(`${crv} EC Private key`, hasProperty, key, 'secret', false) - test(`${crv} EC Private key`, hasProperty, key, 'type', 'private') - test(`${crv} EC Private key`, hasProperty, key, 'use', undefined) - - if (crv === 'secp256k1') { - test(`${crv} EC Private key algorithms (no operation)`, t => { - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - } else { - test(`${crv} EC Private key algorithms (no operation)`, t => { - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], [alg, ...ECDH]) - }) - } - - test(`${crv} EC Private key algorithms (no operation, w/ alg)`, t => { - const key = new ECKey(keyObject, { alg }) - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} EC Private key supports sign alg (no use)`, t => { - const result = key.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} EC Private key supports verify alg (no use)`, t => { - const result = key.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} EC Private key supports sign alg when \`use\` is "sig")`, t => { - const sigKey = new ECKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} EC Private key supports verify alg when \`use\` is "sig")`, t => { - const sigKey = new ECKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} EC Private key supports single sign alg when \`alg\` is set)`, t => { - const sigKey = new ECKey(keyObject, { alg }) - const result = sigKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} EC Private key supports single verify alg when \`alg\` is set)`, t => { - const sigKey = new ECKey(keyObject, { alg }) - const result = sigKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} EC Private key no sign support when \`use\` is "enc"`, t => { - const encKey = new ECKey(keyObject, { use: 'enc' }) - const result = encKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} EC Private key no verify support when \`use\` is "enc"`, t => { - const encKey = new ECKey(keyObject, { use: 'enc' }) - const result = encKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} EC Private key .algorithms("encrypt")`, t => { - const result = key.algorithms('encrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} EC Private key .algorithms("decrypt")`, t => { - const result = key.algorithms('decrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} EC Private key .algorithms("wrapKey")`, t => { - const result = key.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - if (crv === 'secp256k1') { - test(`${crv} EC Private key .algorithms("deriveKey")`, t => { - const result = key.algorithms('deriveKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - } else { - test(`${crv} EC Private key .algorithms("deriveKey")`, t => { - const result = key.algorithms('deriveKey') - t.is(result.constructor, Set) - t.deepEqual([...result], ECDH) - }) - } - - test(`${crv} EC Private key .algorithms("wrapKey") when use is sig`, t => { - const sigKey = new ECKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} EC Private key .algorithms("unwrapKey")`, t => { - const result = key.algorithms('unwrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} EC Private key .algorithms("deriveKey") when use is sig`, t => { - const sigKey = new ECKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('deriveKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - })() - - // public - ;(() => { - const keyObject = createPublicKey(fixtures.PEM[crv].public) - const key = new ECKey(keyObject) - - test(`${crv} EC Public key`, hasProperty, key, 'crv', crv) - test(`${crv} EC Public key (with alg)`, hasProperty, new ECKey(keyObject, { alg }), 'alg', alg) - test(`${crv} EC Public key (with kid)`, hasProperty, new ECKey(keyObject, { kid: 'foobar' }), 'kid', 'foobar') - test(`${crv} EC Public key (with use)`, hasProperty, new ECKey(keyObject, { use: 'sig' }), 'use', 'sig') - test(`${crv} EC Public key`, hasNoProperties, key, 'k', 'e', 'n', 'p', 'q', 'dp', 'dq', 'qi', 'd') - test(`${crv} EC Public key`, hasProperties, key, 'x', 'y') - test(`${crv} EC Public key`, hasProperty, key, 'alg', undefined) - test(`${crv} EC Public key`, hasProperty, key, 'kid', kid) - test(`${crv} EC Public key`, hasProperty, key, 'kty', 'EC') - test(`${crv} EC Public key`, hasProperty, key, 'private', false) - test(`${crv} EC Public key`, hasProperty, key, 'public', true) - test(`${crv} EC Public key`, hasProperty, key, 'secret', false) - test(`${crv} EC Public key`, hasProperty, key, 'type', 'public') - test(`${crv} EC Public key`, hasProperty, key, 'use', undefined) - - if (crv === 'secp256k1') { - test(`${crv} EC Public key algorithms (no operation)`, t => { - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - } else { - test(`${crv} EC Public key algorithms (no operation)`, t => { - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], [alg, ...ECDH]) - }) - } - - test(`${crv} EC Public key algorithms (no operation, w/ alg)`, t => { - const key = new ECKey(keyObject, { alg }) - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} EC Public key cannot sign`, t => { - const result = key.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} EC Public key supports verify alg (no use)`, t => { - const result = key.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} EC Public key cannot sign even when \`use\` is "sig")`, t => { - const sigKey = new ECKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} EC Public key supports verify alg when \`use\` is "sig")`, t => { - const sigKey = new ECKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} EC Public key cannot sign even when \`alg\` is set)`, t => { - const sigKey = new ECKey(keyObject, { alg }) - const result = sigKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} EC Public key supports single verify alg when \`alg\` is set)`, t => { - const sigKey = new ECKey(keyObject, { alg }) - const result = sigKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} EC Public key no sign support when \`use\` is "enc"`, t => { - const encKey = new ECKey(keyObject, { use: 'enc' }) - const result = encKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} EC Public key no verify support when \`use\` is "enc"`, t => { - const encKey = new ECKey(keyObject, { use: 'enc' }) - const result = encKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} EC Public key .algorithms("encrypt")`, t => { - const result = key.algorithms('encrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} EC Public key .algorithms("decrypt")`, t => { - const result = key.algorithms('decrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} EC Public key .algorithms("wrapKey")`, t => { - const result = key.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - if (crv === 'secp256k1') { - test(`${crv} EC Public key .algorithms("deriveKey")`, t => { - const result = key.algorithms('deriveKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - } else { - test(`${crv} EC Public key .algorithms("deriveKey")`, t => { - const result = key.algorithms('deriveKey') - t.is(result.constructor, Set) - t.deepEqual([...result], ECDH) - }) - } - - test(`${crv} EC Public key .algorithms("wrapKey") when use is sig`, t => { - const sigKey = new ECKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} EC Public key .algorithms("unwrapKey")`, t => { - const result = key.algorithms('unwrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - })() -}) diff --git a/test/jwk/embedded.test.js b/test/jwk/embedded.test.js deleted file mode 100644 index 7fc1283c00..0000000000 --- a/test/jwk/embedded.test.js +++ /dev/null @@ -1,189 +0,0 @@ -const test = require('ava') - -const { errors, JWK, JWS, JWT, JWKS } = require('../..') -const { keyObjectSupported } = require('../../lib/help/runtime_support') - -test('JWK.EmbeddedJWK', t => { - const k = JWK.EmbeddedJWK - t.truthy(k) - t.true(JWK.isKey(k)) - t.is(k.kty, undefined) - for (const prop of ['kid', 'kty', 'thumbprint', 'toJWK', 'toPEM']) { - k[prop] = 'foo' - t.is(k[prop], undefined) - } - t.deepEqual([...k.algorithms()], []) - k.type = 'foo' - t.is(k.type, 'embedded') - t.throws(() => new JWKS.KeyStore(k), { instanceOf: TypeError }) - const ks = new JWKS.KeyStore() - t.throws(() => ks.add(k), { instanceOf: TypeError }) -}) - -test('JWK.EmbeddedJWK JWS.verify pass', async t => { - const key = await JWK.generate('EC', 'P-256') - const { kid, ...jwk } = key.toJWK() - const jws = JWS.sign('foo', key, { jwk }) - t.notThrows(() => JWS.verify(jws, JWK.EmbeddedJWK)) - t.throws( - () => JWS.verify(jws, JWK.EmbeddedJWK, { algorithms: ['EdDSA'] }), - { instanceOf: errors.JOSEAlgNotWhitelisted, code: 'ERR_JOSE_ALG_NOT_WHITELISTED', message: 'alg not whitelisted' } - ) - const { key: embedded } = JWS.verify(jws, JWK.EmbeddedJWK, { complete: true }) - t.false(key === embedded) - t.deepEqual(key.toJWK(), embedded.toJWK()) -}) - -test('JWK.EmbeddedJWK JWT.verify pass', async t => { - const key = await JWK.generate('EC', 'P-256') - const { kid, ...jwk } = key.toJWK() - const jws = JWT.sign({}, key, { header: { jwk } }) - t.notThrows(() => JWT.verify(jws, JWK.EmbeddedJWK)) - t.throws( - () => JWT.verify(jws, JWK.EmbeddedJWK, { algorithms: ['EdDSA'] }), - { instanceOf: errors.JOSEAlgNotWhitelisted, code: 'ERR_JOSE_ALG_NOT_WHITELISTED', message: 'alg not whitelisted' } - ) - const { key: embedded } = JWT.verify(jws, JWK.EmbeddedJWK, { complete: true }) - t.false(key === embedded) - t.deepEqual(key.toJWK(), embedded.toJWK()) -}) - -test('JWK.EmbeddedJWK key must be a public key', async t => { - const key = await JWK.generate('EC', 'P-256') - const { kid, ...jwk } = key.toJWK(true) - { - const jws = JWS.sign('foo', key, { jwk }) - t.throws( - () => JWS.verify(jws, JWK.EmbeddedJWK), - { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'JWS Header Parameter "jwk" must be a public key' } - ) - } - { - const jws = JWS.sign('foo', key, { jwk: { kty: 'oct', k: 'foo' } }) - t.throws( - () => JWS.verify(jws, JWK.EmbeddedJWK), - { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'JWS Header Parameter "jwk" must be a public key' } - ) - } - { - const jws = JWS.sign('foo', key, { jwk: { kty: 'oct' } }) - t.throws( - () => JWS.verify(jws, JWK.EmbeddedJWK), - { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'JWS Header Parameter "jwk" must be a public key' } - ) - } - { - const jws = JWS.sign('foo', key, { jwk: { kty: 'foo' } }) - t.throws( - () => JWS.verify(jws, JWK.EmbeddedJWK), - { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported key type: foo' } - ) - } - { - const invalidEc = key.toJWK() - delete invalidEc.y - const jws = JWS.sign('foo', key, { jwk: invalidEc }) - t.throws( - () => JWS.verify(jws, JWK.EmbeddedJWK), - { instanceOf: errors.JWKImportFailed, code: 'ERR_JWK_IMPORT_FAILED', message: 'key import failed' } - ) - } -}) - -test('JWK.EmbeddedJWK key invalid inputs', async t => { - const key = await JWK.generate('EC', 'P-256') - for (const jwk of [undefined, '', null, false, true, 1, 3.14, 'pi']) { - const jws = JWS.sign('foo', key, { jwk }) - t.throws( - () => JWS.verify(jws, JWK.EmbeddedJWK), - { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'JWS Header Parameter "jwk" must be a JSON object' } - ) - } -}) - -if (keyObjectSupported) { - test('JWK.EmbeddedX5C', t => { - const k = JWK.EmbeddedX5C - t.truthy(k) - t.true(JWK.isKey(k)) - t.is(k.kty, undefined) - for (const prop of ['kid', 'kty', 'thumbprint', 'toJWK', 'toPEM']) { - k[prop] = 'foo' - t.is(k[prop], undefined) - } - t.deepEqual([...k.algorithms()], []) - k.type = 'foo' - t.is(k.type, 'embedded') - t.throws(() => new JWKS.KeyStore(k), { instanceOf: TypeError }) - const ks = new JWKS.KeyStore() - t.throws(() => ks.add(k), { instanceOf: TypeError }) - }) - - const rsa = { - e: 'AQAB', - n: 'u4kSwZDMd93b1fvd6CXUfHa-rF0DBd03tCCpWN31giKCskP09c7VigwkyHu34X__1rA7CNMaSrXQn4ChkhulSxzQyojBc3t06AjyKe_Nzpd72zaGFjaLfN-C2U5QmmaXn_2dOiQTH3aTaHDA5I8zd7ZEwrln9G6DD9KtbAcal-RWN_XT-dD-hHUSH4X4iHIvVC1El6lOtu9yjpmQtAvU3mpvxKK6AUGEA9wCWmIEcpfosOCpgHiwVeuPwJwAmuHRFA-h5N4wWw1KQuW66ocgeTzwKZ33DuMWeLap3AEeDVErInAwPPjzLSj3i3DvtveGlGZQH10wAZMAQrcUhHS06Q', - d: 'e_PUztXbH5snc58fBBMFCCMgUiLEHbsi108DP7atUA9pXVRnc5T7NVxjb5O-bTDCM--VhXaqmRjlRJerszvMnAH2yvdrDd5a3gcTsL5MxLEBb1nxdHsm5SmCfgkyY2tN6rShmE1BynkAY3arOCaieQyjFCWh3UCyJeI1OALWA_AJP1kOrmrM9Cpd3FYNkKN163_D7Nv5g2PuMMO1T6Zx8xdgC1C6OxXfmVpvNtOI4pnkODRcQhTspHJLzGTtp2yYPRHCsBhF7i3XsbQ4D8a8t_vZ3yLt-3ZkJnHnRQeCeyBlALUcnFFo43CA96ohOk6NhjYNbi8uJbZyxWVXllwV5Q', - p: '5kZFOcFl6jrZ7XQWDoHipOqHyACKRCdk1V-JBi8_iOZYpDXiTWCAdl_XAqMLI8vrcceOi2TLbdFBASVQVWwvOPUkpZ5BvNI6Zpzvv7PRjQlhBBogC06zwCcMi0f1RVZrvtt1_URwMgSuc7OaJFEIcIllVaXKa2KhmBBlQnDVSXc', - q: '0Hx9Ccd1iaESKbfv6Wsx1emCaKcIBpxYe41jNWbmtGNixaZHyCr0_FFAOwzbfe_W_kuX6Tk5rmDDivG92Rm0QcRas70CvXP8m64R3Z3qV7mKY8QZpwooPFoOaZfjl0--w_HEdtf-epm43kCIXtqgaIj4aUFEEdEe4AVnTyZpjJ8', - dp: '1zYhiKLpXwn1lukBnDlj2wGeORvYHW473PdWlsMdvBKcEYySngJszTUxO7Opu6DfwQziegCP52jEOg_njo53a-Igh_DqO1C3aCOQJjgmxotXcoAAJtE9SX61SI7N-imUtWFiWnvV58lcSaI3k21wV8zxOiSik84wfHAGUxwlGm0', - dq: 'Q9_DdWOSSHQ_zYUsffmAB_w1kIyQeFZ-F_s3yTLu-NtCVMaFqA0UJPDu0EqnSqDChZdmpW8T8ElgX-PDwuIzZRXf0ZQ_SB5yptxMxLGckWK-QyycjV0pLDzFZGsmlSRJHtGe_HHlT1Sscu7fdsIGZwHwnZO57XL_cj9QGtyOkFE', - qi: 'qhNTCBRZi6zC-2nyVuleB5DAfzza_HSqa_FvSZpzbxv_cIgI52FIB2Vn6u6c8M-n0PEVpCOwVOD2VuRqWhidfOJsFbGLyGtEg9ZRE-bQoOPvRIeUqOt5jTe3bqboG84vNcmw5m0zbCw8upUmu2LK0NIFDxrjognJEwIlMoAgALE', - kty: 'RSA' - } - const x5c = ['MIIDmjCCAoKgAwIBAgIJfEZch1k3018JMA0GCSqGSIb3DQEBBQUAMGkxFDASBgNVBAMTC2V4YW1wbGUub3JnMQswCQYDVQQGEwJVUzERMA8GA1UECBMIVmlyZ2luaWExEzARBgNVBAcTCkJsYWNrc2J1cmcxDTALBgNVBAoTBFRlc3QxDTALBgNVBAsTBFRlc3QwHhcNMjAwNTA1MTI0MTQ2WhcNMjEwNTA1MTI0MTQ2WjBpMRQwEgYDVQQDEwtleGFtcGxlLm9yZzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCFZpcmdpbmlhMRMwEQYDVQQHEwpCbGFja3NidXJnMQ0wCwYDVQQKEwRUZXN0MQ0wCwYDVQQLEwRUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu4kSwZDMd93b1fvd6CXUfHa+rF0DBd03tCCpWN31giKCskP09c7VigwkyHu34X//1rA7CNMaSrXQn4ChkhulSxzQyojBc3t06AjyKe/Nzpd72zaGFjaLfN+C2U5QmmaXn/2dOiQTH3aTaHDA5I8zd7ZEwrln9G6DD9KtbAcal+RWN/XT+dD+hHUSH4X4iHIvVC1El6lOtu9yjpmQtAvU3mpvxKK6AUGEA9wCWmIEcpfosOCpgHiwVeuPwJwAmuHRFA+h5N4wWw1KQuW66ocgeTzwKZ33DuMWeLap3AEeDVErInAwPPjzLSj3i3DvtveGlGZQH10wAZMAQrcUhHS06QIDAQABo0UwQzAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIC9DAmBgNVHREEHzAdhhtodHRwOi8vZXhhbXBsZS5vcmcvd2ViaWQjbWUwDQYJKoZIhvcNAQEFBQADggEBAA3oxXuMEXdi/5ndPuoJYe1eK3KHIFRajZOrMxSz65ErlkiIt9K0weoYSywufuIdP71kc+S/x/NUpXzaZ1XvUDK3IvwKxf/dnLgtDJRABCWHBQ+81YvtxJVzDSq9grVdGby7IRzuDaayvEo0YFc5xh0r8Jc/Dlaz4ZUhXLxpKZeyT47aPyk6Ys+d/2vEFDhOwyipqKI+xtfrdPaBi9FXk/QA+Th16DKx9Uxau+sXbAVSG3YZtUUkadi1sP/oKqQcJ6VTSGt+8Yg+DJwY8ZnX+QgVyEtqpTwfJNjt3G4qOtAr8LpNTN+r2BG4XYN3bck9SVfjDky5dXJo3NY2pT9AO58='] - - test('JWK.EmbeddedX5C JWS.verify pass', async t => { - const key = JWK.asKey({ ...rsa, x5c }) - const jws = JWS.sign('foo', key, { x5c }) - t.notThrows(() => JWS.verify(jws, JWK.EmbeddedX5C)) - t.throws( - () => JWS.verify(jws, JWK.EmbeddedX5C, { algorithms: ['EdDSA'] }), - { instanceOf: errors.JOSEAlgNotWhitelisted, code: 'ERR_JOSE_ALG_NOT_WHITELISTED', message: 'alg not whitelisted' } - ) - const { key: embedded } = JWS.verify(jws, JWK.EmbeddedX5C, { complete: true }) - t.false(key === embedded) - t.deepEqual(key.toJWK(), embedded.toJWK()) - }) - - test('JWK.EmbeddedX5C JWT.verify pass', async t => { - const key = JWK.asKey({ ...rsa, x5c }) - const jws = JWT.sign({}, key, { header: { x5c } }) - t.notThrows(() => JWT.verify(jws, JWK.EmbeddedX5C)) - t.throws( - () => JWT.verify(jws, JWK.EmbeddedX5C, { algorithms: ['EdDSA'] }), - { instanceOf: errors.JOSEAlgNotWhitelisted, code: 'ERR_JOSE_ALG_NOT_WHITELISTED', message: 'alg not whitelisted' } - ) - const { key: embedded } = JWT.verify(jws, JWK.EmbeddedX5C, { complete: true }) - t.false(key === embedded) - t.deepEqual(key.toJWK(), embedded.toJWK()) - }) - - test('JWK.EmbeddedJWK key must be a properly formatted cert value', async t => { - const key = JWK.asKey({ ...rsa, x5c }) - const jws = JWS.sign('foo', key, { x5c: [x5c[0].slice(0, 16)] }) - t.throws( - () => JWS.verify(jws, JWK.EmbeddedX5C), - { instanceOf: errors.JWKImportFailed, code: 'ERR_JWK_IMPORT_FAILED', message: 'key import failed' } - ) - }) - - test('JWK.EmbeddedX5C key invalid inputs', async t => { - const key = JWK.asKey({ ...rsa, x5c }) - for (const x5c of [undefined, '', null, false, true, 1, 3.14, []]) { - { - const jws = JWS.sign('foo', key, { x5c }) - t.throws( - () => JWS.verify(jws, JWK.EmbeddedX5C), - { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'JWS Header Parameter "x5c" must be a JSON array of certificate value strings' } - ) - } - { - const jws = JWS.sign('foo', key, { x5c: [x5c] }) - t.throws( - () => JWS.verify(jws, JWK.EmbeddedX5C), - { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'JWS Header Parameter "x5c" must be a JSON array of certificate value strings' } - ) - } - } - }) -} diff --git a/test/jwk/embedded.test.mjs b/test/jwk/embedded.test.mjs new file mode 100644 index 0000000000..e2072adf43 --- /dev/null +++ b/test/jwk/embedded.test.mjs @@ -0,0 +1,85 @@ +/* eslint-disable no-param-reassign */ +import test from 'ava'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +Promise.all([ + import(`${root}/jws/flattened/sign`), + import(`${root}/jws/flattened/verify`), + import(`${root}/jwk/parse`), + import(`${root}/jwk/embedded`), +]).then( + ([ + { default: FlattenedSign }, + { default: flattenedVerify }, + { default: parseJwk }, + { default: EmbeddedJWK }, + ]) => { + function pubjwk(jwk) { + const { d, p, q, dp, dq, qi, ext, alg, ...publicJwk } = jwk; + return publicJwk; + } + + test.before(async (t) => { + const encode = TextEncoder.prototype.encode.bind(new TextEncoder()); + t.context.key = { + crv: 'P-256', + alg: 'ES256', + ext: false, + x: 'Sp3KpzPjwcCF04_W2GvSSf-vGDvp3Iv2kQYqAjnMB-Y', + y: 'lZmecT2quXe0i9f7b4qHvDAFDpxs0oxCoJx4tOOqsks', + d: 'hRVo5TGE_d_4tQC1KEQIlCdo9rteZmLSmaMPpFOjeDI', + kty: 'EC', + }; + + const privateKey = await parseJwk(t.context.key); + t.context.token = await new FlattenedSign( + encode('It’s a dangerous business, Frodo, going out your door.'), + ) + .setProtectedHeader({ alg: 'ES256', jwk: pubjwk(t.context.key) }) + .sign(privateKey); + t.context.tokenMissingJwk = await new FlattenedSign( + encode('It’s a dangerous business, Frodo, going out your door.'), + ) + .setProtectedHeader({ alg: 'ES256' }) + .sign(privateKey); + t.context.tokenInvalidJWK = await new FlattenedSign( + encode('It’s a dangerous business, Frodo, going out your door.'), + ) + .setProtectedHeader({ alg: 'ES256', jwk: null }) + .sign(privateKey); + t.context.tokenPrivateJWK = await new FlattenedSign( + encode('It’s a dangerous business, Frodo, going out your door.'), + ) + .setProtectedHeader({ alg: 'ES256', jwk: t.context.key }) + .sign(privateKey); + }); + + test('EmbeddedJWK', async (t) => { + await t.notThrowsAsync(flattenedVerify(t.context.token, EmbeddedJWK)); + }); + + test('EmbeddedJWK requires "jwk" to be an object', async (t) => { + await t.throwsAsync(flattenedVerify(t.context.tokenMissingJwk, EmbeddedJWK), { + code: 'ERR_JWS_INVALID', + message: '"jwk" (JSON Web Key) Header Parameter must be a JSON object', + }); + await t.throwsAsync(flattenedVerify(t.context.tokenInvalidJWK, EmbeddedJWK), { + code: 'ERR_JWS_INVALID', + message: '"jwk" (JSON Web Key) Header Parameter must be a JSON object', + }); + }); + + test('EmbeddedJWK requires "jwk" to be a public one', async (t) => { + await t.throwsAsync(flattenedVerify(t.context.tokenPrivateJWK, EmbeddedJWK), { + code: 'ERR_JWS_INVALID', + message: '"jwk" (JSON Web Key) Header Parameter must be a public key', + }); + }); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jwk/general.test.js b/test/jwk/general.test.js deleted file mode 100644 index a3c75041d0..0000000000 --- a/test/jwk/general.test.js +++ /dev/null @@ -1,46 +0,0 @@ -const test = require('ava') - -const { JWK: { generateSync, isKey, asKey } } = require('../..') - -test('.isKey() only key objects return true', t => { - ;[[], false, true, null, Infinity, 0].forEach((val) => { - t.false(isKey(val)) - }) - ;['RSA', 'EC', 'oct'].forEach((kty) => { - t.true(isKey(generateSync(kty))) - }) -}) - -test('"use" must be either `alg` or `enc`', t => { - ;[[], false, true, null, Infinity, 0].forEach((val) => { - t.throws( - () => generateSync('oct', undefined, { use: val }), - { instanceOf: TypeError, message: '`use` must be either "sig" or "enc" string when provided' } - ) - }) -}) - -test('"alg" must be a non-empty string', t => { - ;[[], false, true, null, '', Infinity, 0].forEach((val) => { - t.throws( - () => generateSync('oct', undefined, { alg: val }), - { instanceOf: TypeError, message: '`alg` must be a non-empty string when provided' } - ) - }) -}) - -test('"kid" must be a non-empty string', t => { - ;[[], false, true, null, '', Infinity, 0].forEach((val) => { - t.throws( - () => generateSync('oct', undefined, { kid: val }), - { instanceOf: TypeError, message: '`kid` must be a non-empty string when provided' } - ) - }) -}) - -test('"kid" from JWK is used when available and its different from thumbprint', t => { - const { kid: generatedThumbprint, ...jwk } = generateSync('oct').toJWK(true) - const key = asKey({ ...jwk, kid: 'foo' }) - t.is(key.kid, 'foo') - t.is(key.thumbprint, generatedThumbprint) -}) diff --git a/test/jwk/generate.test.js b/test/jwk/generate.test.js deleted file mode 100644 index d3aa5d8625..0000000000 --- a/test/jwk/generate.test.js +++ /dev/null @@ -1,254 +0,0 @@ -const test = require('ava') - -const crypto = require('crypto') - -const { edDSASupported, keyObjectSupported } = require('../../lib/help/runtime_support') - -const { JWK: { generate, generateSync }, errors } = require('../..') - -;[ - ['RSA'], - ['RSA', undefined, undefined, true], - ['RSA', undefined, undefined, false], - ['RSA', 2048], - ['RSA', 2048, { use: 'sig' }], - ['RSA', 2048, { use: 'enc' }], - ['RSA', 2048, { use: 'sig', alg: 'PS256' }], - ['RSA', 2048, { use: 'enc', alg: 'RSA-OAEP' }], - ['RSA', 2048, { alg: 'PS256' }], - ['RSA', 2048, { alg: 'RSA-OAEP' }], - edDSASupported ? ['OKP'] : undefined, - edDSASupported ? ['OKP', undefined, undefined, true] : undefined, - edDSASupported ? ['OKP', undefined, undefined, false] : undefined, - edDSASupported ? ['OKP', 'Ed25519'] : undefined, - edDSASupported ? ['OKP', 'Ed25519', { use: 'sig' }] : undefined, - // ['OKP', 'Ed25519', { use: 'sig', alg: 'EdDSA' }], - // ['OKP', 'Ed25519', { alg: 'EdDSA' }], - edDSASupported ? ['OKP', 'Ed448'] : undefined, - edDSASupported ? ['OKP', 'Ed448', { use: 'sig' }] : undefined, - // ['OKP', 'Ed448', { use: 'sig', alg: 'EdDSA' }], - // ['OKP', 'Ed448', { alg: 'EdDSA' }], - edDSASupported ? ['OKP', 'X25519'] : undefined, - edDSASupported ? ['OKP', 'X25519', { use: 'enc' }] : undefined, - // ['OKP', 'X25519', { use: 'enc', alg: 'ECDH-ES' }], - // ['OKP', 'X25519', { alg: 'ECDH-ES' }], - edDSASupported ? ['OKP', 'X448'] : undefined, - edDSASupported ? ['OKP', 'X448', { use: 'enc' }] : undefined, - // ['OKP', 'X448', { use: 'enc', alg: 'ECDH-ES' }], - // ['OKP', 'X448', { alg: 'ECDH-ES' }], - ['EC'], - ['EC', undefined, undefined, true], - ['EC', undefined, undefined, false], - ['EC', 'P-256'], - ['EC', 'P-256', { use: 'sig' }], - ['EC', 'P-256', { use: 'enc' }], - ['EC', 'P-256', { use: 'sig', alg: 'ES256' }], - ['EC', 'P-256', { use: 'enc', alg: 'ECDH-ES' }], - ['EC', 'P-256', { alg: 'ES256' }], - ['EC', 'P-256', { alg: 'ECDH-ES' }], - ['EC', 'secp256k1'], - ['EC', 'secp256k1', { use: 'sig' }], - ['EC', 'secp256k1', { use: 'enc' }], - ['EC', 'secp256k1', { use: 'sig', alg: 'ES256K' }], - ['EC', 'secp256k1', { alg: 'ES256K' }], - ['EC', 'P-384'], - ['EC', 'P-384', { use: 'sig' }], - ['EC', 'P-384', { use: 'enc' }], - ['EC', 'P-384', { use: 'sig', alg: 'ES384' }], - ['EC', 'P-384', { use: 'enc', alg: 'ECDH-ES' }], - ['EC', 'P-384', { alg: 'ES384' }], - ['EC', 'P-384', { alg: 'ECDH-ES' }], - ['EC', 'P-521'], - ['EC', 'P-521', { use: 'sig' }], - ['EC', 'P-521', { use: 'enc' }], - ['EC', 'P-521', { use: 'sig', alg: 'ES512' }], - ['EC', 'P-521', { use: 'enc', alg: 'ECDH-ES' }], - ['EC', 'P-521', { alg: 'ES512' }], - ['EC', 'P-521', { alg: 'ECDH-ES' }], - ['oct'], - ['oct', 192], - ['oct', 192, { use: 'sig' }], - ['oct', 192, { use: 'enc' }], - ['oct', 192, { use: 'sig', alg: 'HS256' }], - ['oct', 192, { use: 'enc', alg: 'A192GCM' }], - ['oct', 192, { alg: 'HS256' }], - ['oct', 192, { alg: 'A192GCM' }] -].filter(Boolean).forEach((args) => { - if ('electron' in process.versions) { - const [, crv] = args - if (crv === 'secp256k1' || String(crv).startsWith('X') || crv === 'Ed448') return - } - test(`sync generates ${args[0]}(${args[1]}) with options ${JSON.stringify(args[2])}${typeof args[3] === 'boolean' ? ` and private=${args[3]}` : ''}`, t => { - const key = generateSync(args[0], args[1], args[2], args[3]) - t.truthy(key) - - if (keyObjectSupported) { - t.true(key.keyObject instanceof crypto.KeyObject) - } else { - t.throws(() => { - return key.keyObject - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'KeyObject class is not supported in your Node.js runtime version' }) - } - - if (key.kty !== 'oct') { - if (args.length === 4) { - if (args[3] === true) { - t.true(key.private) - t.false(key.public) - } else { - t.true(key.public) - t.false(key.private) - } - } else { - t.true(key.private) - t.false(key.public) - } - } - - if (args[2]) { - const { use, alg } = args[2] - t.is(key.use, use) - t.is(key.alg, alg) - - if (alg) { - t.deepEqual([...key.algorithms()], [alg]) - } - } - }) - - test(`async generates ${args[0]}(${args[1]}) with options ${JSON.stringify(args[2])}${typeof args[3] === 'boolean' ? ` and private=${args[3]}` : ''}`, async t => { - const key = await generate(args[0], args[1], args[2], args[3]) - t.truthy(key) - - if (keyObjectSupported) { - t.true(key.keyObject instanceof crypto.KeyObject) - } else { - t.throws(() => { - return key.keyObject - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'KeyObject class is not supported in your Node.js runtime version' }) - } - - if (key.kty !== 'oct') { - if (args.length === 4) { - if (args[3] === true) { - t.true(key.private) - t.false(key.public) - } else { - t.true(key.public) - t.false(key.private) - } - } else { - t.true(key.private) - t.false(key.public) - } - } - - if (args[2]) { - const { use, alg } = args[2] - t.is(key.use, use) - t.is(key.alg, alg) - - if (alg) { - t.deepEqual([...key.algorithms()], [alg]) - } - } - }) -}) - -test('fails to generateSync unsupported kty', t => { - t.throws(() => { - generateSync('foo') - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported key type: foo' }) -}) - -test('fails to generate unsupported kty', async t => { - await t.throwsAsync(() => { - return generate('foo') - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported key type: foo' }) -}) - -if (edDSASupported) { - test('fails to generate unsupported OKP crv', async t => { - await t.throwsAsync(() => { - return generate('OKP', 'foo') - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported OKP key curve: foo' }) - }) - - test('fails to generateSync unsupported OKP crv', async t => { - await t.throws(() => { - return generateSync('OKP', 'foo') - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported OKP key curve: foo' }) - }) -} else { - test('fails to generate OKP when not supported', async t => { - await t.throwsAsync(() => { - return generate('OKP') - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'OKP keys are not supported in your Node.js runtime version' }) - }) - - test('fails to generateSync OKP when not supported', async t => { - await t.throws(() => { - return generateSync('OKP') - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'OKP keys are not supported in your Node.js runtime version' }) - }) -} - -test('fails to generateSync unsupported EC crv', t => { - t.throws(() => { - generateSync('EC', 'foo') - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported EC key curve: foo' }) -}) - -test('fails to generate unsupported EC crv', async t => { - await t.throwsAsync(() => { - return generate('EC', 'foo') - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported EC key curve: foo' }) -}) - -test('fails to generateSync RSA with invalid bit lengths', t => { - t.throws(() => { - generateSync('RSA', 2048 + 1) - }, { instanceOf: TypeError, message: 'invalid bit length' }) -}) - -test('fails to generate RSA with invalid bit lengths', async t => { - await t.throwsAsync(() => { - return generate('RSA', 2048 + 1) - }, { instanceOf: TypeError, message: 'invalid bit length' }) -}) - -test('fails to generateSync RSA with less than 512 bits', t => { - t.throws(() => { - generateSync('RSA', 512 - 8) - }, { instanceOf: TypeError, message: 'invalid bit length' }) -}) - -test('fails to generate RSA with less than 512 bits', async t => { - await t.throwsAsync(() => { - return generate('RSA', 512 - 8) - }, { instanceOf: TypeError, message: 'invalid bit length' }) -}) - -test('fails to generateSync oct with invalid bit lengths', t => { - t.throws(() => { - generateSync('oct', 256 + 1) - }, { instanceOf: TypeError, message: 'invalid bit length' }) -}) - -test('fails to generate oct with invalid bit lengths', async t => { - await t.throwsAsync(() => { - return generate('oct', 256 + 1) - }, { instanceOf: TypeError, message: 'invalid bit length' }) -}) - -test('fails to generateSync oct with less than 512 bits', t => { - t.throws(() => { - generateSync('oct', 0) - }, { instanceOf: TypeError, message: 'invalid bit length' }) -}) - -test('fails to generate oct with less than 512 bits', async t => { - await t.throwsAsync(() => { - return generate('oct', 0) - }, { instanceOf: TypeError, message: 'invalid bit length' }) -}) diff --git a/test/jwk/import.test.js b/test/jwk/import.test.js deleted file mode 100644 index 3c5c4ba679..0000000000 --- a/test/jwk/import.test.js +++ /dev/null @@ -1,203 +0,0 @@ -const test = require('ava') - -const { JWS, JWE, JWK: { asKey, generate }, errors } = require('../..') - -const { edDSASupported, keyObjectSupported } = require('../../lib/help/runtime_support') -const { createSecretKey, createPrivateKey } = require('../../lib/help/key_object') -const { generateKeyPairSync } = require('../macros/generate') -const fixtures = require('../fixtures') - -test('imports PrivateKeyObject and then its Key instance', t => { - const k = asKey(generateKeyPairSync('ec', { namedCurve: 'P-256' }).privateKey) - t.deepEqual(asKey(k).toJWK(), k.toJWK()) -}) - -test('imports PublicKeyObject and then its Key instance', t => { - const k = asKey(generateKeyPairSync('ec', { namedCurve: 'P-256' }).publicKey) - t.deepEqual(asKey(k).toJWK(), k.toJWK()) -}) - -test('imports SecretKeyObject and then its Key instance', t => { - const k = asKey(createSecretKey(Buffer.from('foo'))) - t.deepEqual(asKey(k).toJWK(), k.toJWK()) -}) - -test('only imports string, object or buffer', t => { - ;[Buffer, () => {}, async () => {}, true, Infinity, 1].forEach((val) => { - t.throws(() => { - asKey(val) - }, { instanceOf: TypeError, message: 'key argument must be a string, buffer or an object' }) - }) -}) - -test('parameters must be a plain object', t => { - ;[Buffer, () => {}, async () => {}, true, Infinity, 1, [], Buffer.from('foo')].forEach((val) => { - t.throws(() => { - asKey('foo', val) - }, { instanceOf: TypeError, message: 'parameters argument must be a plain object when provided' }) - }) -}) - -Object.entries(fixtures.PEM).forEach(([type, { private: priv, public: pub }]) => { - if (type === 'P-256K') return - if ('electron' in process.versions && (type.startsWith('X') || type === 'Ed448' || type === 'secp256k1')) return - if (!edDSASupported && (type.startsWith('Ed') || type.startsWith('X'))) return - - test(`fails to import ${type} as invalid string`, t => { - t.throws(() => { - asKey(priv.toString('ascii').replace(/\n/g, '')) - }, { instanceOf: errors.JWKImportFailed, code: 'ERR_JWK_IMPORT_FAILED' }) - }) - test(`fails to import ${type} as invalid buffer`, t => { - t.throws(() => { - asKey(Buffer.from(priv.toString('ascii').replace(/\n/g, ''))) - }, { instanceOf: errors.JWKImportFailed, code: 'ERR_JWK_IMPORT_FAILED' }) - }) - test(`${type} private can be imported as a string`, t => { - const k = asKey(priv.toString('ascii')) - t.true(k.private) - }) - test(`${type} public can be imported as a string`, t => { - const k = asKey(pub.toString('ascii')) - t.true(k.public) - }) - test(`${type} private can be imported as a buffer`, t => { - const k = asKey(priv) - t.true(k.private) - }) - test(`${type} public can be imported as a buffer`, t => { - const k = asKey(pub) - t.true(k.public) - }) -}) - -test('failed to import throws an error', t => { - t.throws(() => { - asKey({ - key: fixtures.PEM.RSA.public, - format: 'der' - }) - }, { instanceOf: errors.JWKImportFailed, code: 'ERR_JWK_IMPORT_FAILED' }) -}) - -if (!('electron' in process.versions) && keyObjectSupported) { - ;[ - '-----BEGIN PUBLIC KEY-----\nMIIBtjCCASsGByqGSM44BAEwggEeAoGBANuHjLdqQcKozzWf9fUfe/mw4i5NLT8k\nCIA75k+GNYNbBaGZ2lGNeKsrjHzM8w7mE5k6qx5hDB4n88qFoauqCsUZ4knbTybn\nYV08gfWS375l/EGSpt3c/1dezVZuT/FmEeXbMhOIDORf/9f/6PpEMFN3eghszLvN\ng+L/19HVpWAXAhUAnOFG9vvOiZIz/ZxdpR+EVv8o4T8CgYBDk/ChY3fo4DrxzLZT\n7AjsAiJOzO8QnsV07Gh8gSzUCBsb+Hb4GvMs2U6rB5mxOMib3S2HGbs791uBva2a\nA6pzNzRmgV/w6CyOcxhCkZdVL7MwO9y5iq6V65R4GgfkCrIAYi/BW6XdXOyw/7J0\nt/4wB0/wKtsXf541NLfmUprJ+QOBhAACgYBGbXflbrGGg02+w8Xo6RO+tHoekREZ\nlJA0KKBN4jT0S3/OsLQeHtO7k/gkdMMbXD1J1fae9tIxy1SwYVTR6csgydGuvuyG\nB4A/ZtXEb+dumCBbtw8dyred4Okhl44Fdrs79F1rjSWEcwKqJghxS+GsbA0vcTaf\nAHDL6OblN04uzg==\n-----END PUBLIC KEY-----', - generateKeyPairSync('dsa', { modulusLength: 1024 }).publicKey, - generateKeyPairSync('dsa', { modulusLength: 1024 }).privateKey - ].forEach((unsupported, i) => { - test(`fails to import unsupported PEM ${i + 1}/4`, t => { - t.throws(() => { - asKey(unsupported) - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'only RSA, EC and OKP asymmetric keys are supported' }) - }) - }) -} - -test('minimal RSA test', async t => { - const key = await generate('RSA') - const { d, e, n } = key.toJWK(true) - const minKey = asKey({ kty: 'RSA', d, e, n }, { calculateMissingRSAPrimes: true }) - key.algorithms('sign').forEach((alg) => { - JWS.verify(JWS.sign({}, key), minKey, { alg }) - JWS.verify(JWS.sign({}, minKey), key, { alg }) - }) - key.algorithms('wrapKey').forEach((alg) => { - JWE.decrypt(JWE.encrypt('foo', key), minKey, { alg }) - JWE.decrypt(JWE.encrypt('foo', minKey), key, { alg }) - }) - t.throws(() => { - asKey({ kty: 'RSA', d: d.substr(3), e, n }, { calculateMissingRSAPrimes: true }) - }, { instanceOf: errors.JWKImportFailed, code: 'ERR_JWK_IMPORT_FAILED', message: 'failed to calculate missing primes' }) - t.throws(() => { - asKey({ kty: 'RSA', d, e, n }) - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'importing private RSA keys without all other private key parameters is not enabled, see documentation and its advisory on how and when its ok to enable it' }) - const jwk = { - kty: 'RSA', - d: 'YN1ucKFpCsgMuIfTynTbNwEXp2lBkrJYfsVOIGdK3bZMblZqxWElm8HTE06-JH_BC5drAAv1Hu-6SE6-sehq9blG-vMJ0wi-jBYfkhlOLEZJXHPb4aJyS8oWKhVO14qyfS_m2BtAW9Wh5vEOXy7HLgrZWjctm0t1Ipb-b_nfNfisGIMjPdWzu_nTfbzIIwM7wQBGnHLqfQq6iD7I8nSPjsc_gZUeeKYkU_Q6K8tIY0gr850-6wk-Nh9JsPA93lR0woTqqMG6UiFE4Y4Jj3M6puBUSU-R3n-gL35I1Cwa5m0IREG8Bz0RPpAEcRQB1xRuM22xD4yE0I4LDegtH056lw', - e: 'AQAB', - n: '1hZ73O4axgytljzb8gCXxdk3Uov_f7U6c_hKH5EtGtr8XdWce1XLLjARqAQfOpbYqkm1ONiIvhQvxvW0a7gXgEw4no9c_Gi8a803O9LZmYAYDxErlvPQPg9KC5cLPChM-Uyxy4TOakjw1ysUKBX7zXpb_1TIOnlhOYeDbejLkp8sR7BJIsDNxqtkV4KHLWQ9pKsMU28itblQ8nN8UJI5Js4UbR-b417uQ9jIVRhWlDjp11sXYqfnqShCDYGYmLL2IHTVf8tTmEOWsNWcE2nT-qMTGMOq2DBkyr31lxc-4eQXZuwcrk_58xQ69xSrdrsy8J11O50nbvwcqFhjeMV2VQ' - } - t.throws(() => { - asKey({ kty: 'RSA', d: `${jwk.d}FF`, e: jwk.e, n: jwk.n }, { calculateMissingRSAPrimes: true }) - }, { instanceOf: errors.JWKInvalid, code: 'ERR_JWK_INVALID', message: 'invalid RSA private exponent' }) -}) - -test('fails to import RSA without all optimization parameters', async t => { - const full = (await generate('RSA')).toJWK(true) - for (const param of ['p', 'q', 'dp', 'dq', 'qi']) { - const { [param]: omit, ...jwk } = full - t.throws(() => { - asKey(jwk) - }, { instanceOf: errors.JWKInvalid, code: 'ERR_JWK_INVALID', message: 'all other private key parameters must be present when any one of them is present' }) - } -}) - -test('fails to import JWK RSA with oth', async t => { - const jwk = (await generate('RSA')).toJWK(true) - t.throws(() => { - asKey({ - ...jwk, - oth: [] - }) - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'Private RSA keys with more than two primes are not supported' }) -}) - -const cert = `-----BEGIN CERTIFICATE----- -MIIC4DCCAcgCCQDO8JBSH914NDANBgkqhkiG9w0BAQsFADAyMQswCQYDVQQGEwJD -WjEPMA0GA1UEBwwGUHJhZ3VlMRIwEAYDVQQDDAlwa210bHN0d28wHhcNMTkwNjE4 -MTIzMjAxWhcNMjAwNjE3MTIzMjAxWjAyMQswCQYDVQQGEwJDWjEPMA0GA1UEBwwG -UHJhZ3VlMRIwEAYDVQQDDAlwa210bHN0d28wggEiMA0GCSqGSIb3DQEBAQUAA4IB -DwAwggEKAoIBAQDhqVAaMsvnCETzDtKwfKxZC1jwIOhIyUp8xp+2oN+pJwtqP0Up -kLlTV7MD94HZSL3n3f9hsG6appRQGGAJ2ThOw1N9zlAr7Sk9YH6Gtu3bYSDvS6wa -KjVoxGrrmLfyuoEbv3PDqMWuOjE3MT/G1nwUBgIEKYAr8hizY8dUE0Z2qWvKFZJj -6etjCXEppjXuwlSusHWw/tj/ePMMxMAJMPPhzJeh6AL7iUKBisJysPuaWrS9ntdP -xv9PS40sv6cZT4woxmE6tpTCkAxabXqA25SgJOyKOjnvg+BPNlrucLqHw3ErWrxY -TL99cHqhexO6K4FaspW3+1kuWd3fY4Cm+zkTAgMBAAEwDQYJKoZIhvcNAQELBQAD -ggEBALsB6MGWke5vS1TB3Z+NJkC29bEIb3XGC9WaxRovH0jqaaua2AfAF7VZzUyW -S/+r6hvWOtqUVy7YF1ThnEJXuXJG9ra2B2+F5RYNCtrVj6Bi+zDTSJ4IvQfrF0XB -KwwOdRu7VJpAxvweA/3woKl6Cjfy20ZupPH9mxr1R78BMKgEtdFsiLwbB7MOdDbT -LsrUcEcupXv+gZek22upQKrAk/XFP067KIqKmCEhDidxhP251SloUaruv9cHEx0a -DKol9eR465FAiBLvg2N7qJHCKlWdn99SgN4Y3kINsuFR7Tj4QIJZNubOjV0YeOgn -AWzRJlZD89KZAQgjj4Z215QeLxA= ------END CERTIFICATE-----` - -if (keyObjectSupported) { - test('importing a certificate file populates the certificate properties', t => { - const key = asKey(cert) - t.truthy(key.x5c) - t.truthy(key.x5t) - t.truthy(key['x5t#S256']) - }) -} else { - test('cannot import a certificate', t => { - t.throws(() => { - asKey(cert) - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'X.509 certificates are not supported in your Node.js runtime version' }) - }) -} - -// https://github.com/panva/jose/issues/85 -{ - const pem = `-----BEGIN PRIVATE KEY----- -MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCCXpUVoM4DfOtMyRVtC -eGSpVL+1tMBirnUGJHY6Y7mSHg== ------END PRIVATE KEY-----` - - if (keyObjectSupported) { - test('EC private keys without public one', t => { - asKey(createPrivateKey(pem)) - asKey(pem) - t.pass() - }) - } else { - test('EC private keys without public one', t => { - t.throws(() => { - asKey(createPrivateKey(pem)) - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'Private EC keys without the public key embedded are not supported in your Node.js runtime version' }) - t.throws(() => { - asKey(pem) - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'Private EC keys without the public key embedded are not supported in your Node.js runtime version' }) - }) - } -} diff --git a/test/jwk/jwk2key.test.mjs b/test/jwk/jwk2key.test.mjs new file mode 100644 index 0000000000..90f53ba279 --- /dev/null +++ b/test/jwk/jwk2key.test.mjs @@ -0,0 +1,206 @@ +import test from 'ava'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +import(`${root}/jwk/parse`).then( + ({ default: parseJwk }) => { + test('JWK must be an object', async (t) => { + await t.throwsAsync(parseJwk(true), { + instanceOf: TypeError, + message: 'JWK must be an object', + }); + await t.throwsAsync(parseJwk(null), { + instanceOf: TypeError, + message: 'JWK must be an object', + }); + await t.throwsAsync(parseJwk(Boolean), { + instanceOf: TypeError, + message: 'JWK must be an object', + }); + await t.throwsAsync(parseJwk([]), { + instanceOf: TypeError, + message: 'JWK must be an object', + }); + await t.throwsAsync(parseJwk(''), { + instanceOf: TypeError, + message: 'JWK must be an object', + }); + await t.throwsAsync(parseJwk(Object.create(null)), { + instanceOf: TypeError, + message: 'JWK must be an object', + }); + }); + + test('JWK kty must be recognized', async (t) => { + await t.throwsAsync(parseJwk({ kty: 'unrecognized' }, 'HS256'), { + code: 'ERR_JOSE_NOT_SUPPORTED', + message: 'unsupported "kty" (Key Type) Parameter value', + }); + }); + + test('alg argument must be present if jwk does not have alg', async (t) => { + const oct = { + k: 'FyCq1CKBflh3I5gikEjpYrdOXllzxB_yc02za8ERknI', + kty: 'oct', + }; + await t.throwsAsync(parseJwk(oct), { + instanceOf: TypeError, + message: '"alg" argument is required when "jwk.alg" is not present', + }); + await t.notThrowsAsync(parseJwk(oct, 'HS256')); + await t.notThrowsAsync(parseJwk({ ...oct, alg: 'HS256' })); + }); + + test('oct JWK must have "k"', async (t) => { + await t.throwsAsync(parseJwk({ kty: 'oct' }, 'HS256'), { + instanceOf: TypeError, + message: 'missing "k" (Key Value) Parameter value', + }); + }); + + test('RSA JWK with oth is unsupported', async (t) => { + await t.throwsAsync(parseJwk({ kty: 'RSA', oth: [] }, 'RS256'), { + code: 'ERR_JOSE_NOT_SUPPORTED', + message: 'RSA JWK "oth" (Other Primes Info) Parameter value is unsupported', + }); + }); + + test('oct JWK (ext: true)', async (t) => { + const oct = { + k: 'FyCq1CKBflh3I5gikEjpYrdOXllzxB_yc02za8ERknI', + kty: 'oct', + ext: true, + }; + + t.deepEqual( + await parseJwk(oct, 'HS256'), + Uint8Array.from([ + 23, + 32, + 170, + 212, + 34, + 129, + 126, + 88, + 119, + 35, + 152, + 34, + 144, + 72, + 233, + 98, + 183, + 78, + 94, + 89, + 115, + 196, + 31, + 242, + 115, + 77, + 179, + 107, + 193, + 17, + 146, + 114, + ]), + ); + }); + + test('oct JWK (ext: false)', async (t) => { + const oct = { + k: 'FyCq1CKBflh3I5gikEjpYrdOXllzxB_yc02za8ERknI', + kty: 'oct', + ext: false, + }; + + const k = await parseJwk(oct, 'HS256'); + + t.true('type' in k); + t.is(k.type, 'secret'); + }); + + test('oct JWK (ext missing)', async (t) => { + const oct = { + k: 'FyCq1CKBflh3I5gikEjpYrdOXllzxB_yc02za8ERknI', + kty: 'oct', + }; + + const k = await parseJwk(oct, 'HS256'); + + t.true('type' in k); + t.is(k.type, 'secret'); + }); + + async function testKeyImport(t, jwk) { + await t.notThrowsAsync(async () => { + const key = await parseJwk(jwk); + t.is(key.type, 'private'); + }); + await t.notThrowsAsync(async () => { + const { d, p, q, dp, dq, qi, ...publicJwk } = jwk; + const key = await parseJwk(publicJwk); + t.is(key.type, 'public'); + }); + } + testKeyImport.title = (_, jwk) => `${jwk.kty} ${jwk.crv} JWK (${jwk.alg})`; + + const ec = { + crv: 'P-256', + x: 'Sp3KpzPjwcCF04_W2GvSSf-vGDvp3Iv2kQYqAjnMB-Y', + y: 'lZmecT2quXe0i9f7b4qHvDAFDpxs0oxCoJx4tOOqsks', + d: 'hRVo5TGE_d_4tQC1KEQIlCdo9rteZmLSmaMPpFOjeDI', + kty: 'EC', + }; + test(testKeyImport, { ...ec, alg: 'ES256' }); + test(testKeyImport, { ...ec, alg: 'ECDH-ES' }); + test(testKeyImport, { ...ec, alg: 'ECDH-ES+A128KW' }); + test(testKeyImport, { + crv: 'P-384', + x: 'H50cO3PJnVhAoF6_jPKpCl60cnvmoygN2u29jVN19x8C2PymixZS4Y5d1FfMMK3L', + y: 'ATQ-4QWyYTtEaBW3CFQZEX0NdDE5g_9F24B0y2xxQgVmWa5Uz0QerlhzFoYU7Z_F', + d: 'HDUcH8y8xr22EroPYBK3PvpNjA3pCJjvHpBXKejxOiQCoXhZ5PhX_nxb7lU0mlDE', + kty: 'EC', + alg: 'ES384', + }); + test(testKeyImport, { + crv: 'P-521', + x: 'AFy8VTdHeJx7rrUajpeqIjGZsjtx0tftQ7pdL1qkTRpnvY0WVVKXjib3HINNLMA72gA7JujbvEtGvkvoo0P7pGVK', + y: 'AfMRSFv9qfcH_XMHfPoltBMYLhDbS3Pw1GL7NO9SI_vF4JsiAta1Bq6teCl2z8klFtRCWXHfPqEF3cmXS8bDQVoT', + d: 'AL123tYK7y-iViaReLOHe7XxKNSeoUMk4RRmcP6nSVuZrYJHtyYPak4gUmWB6A_GzED3zXkrkcssZEzHrYQILw5c', + kty: 'EC', + alg: 'ES512', + }); + const rsa = { + e: 'AQAB', + n: + 'rPOe2kdmQY1wN2ADn-EIKsPO_kXotIqPjbZQOoW6sIHPGS8xJqrR60JLTBir5jG8Prrp4_KoEDGm3zYlWb5EJr9BMAVHAUYB2ZMXjdojpIkKeJ_cMI0lLcSUTkKkOA6u2DnVJBlnQgeyVZ927h65cJ5zsnSqG6MHh5tVPAwocEsfH27Tik_Fp-dCidmr_-rCrPfoAuASadvuFr5oAa7aAKdlLz6P0GgmCs2KzTAR6FiBMm48hd1YkrIaGzljKOwCgh0KYA3tnetbOCFEuzsmn9wmQHUA0iPQqYGlFJVfQ64949hQk42uWxCXtaO_wlXqy_TVki5LTQ7hO4reUiMXpQ', + d: + 'qhn97b91khmS-dOkHPYNu0nUZv_JDPCOmhlqtPRcFkfFsYZZuCcfyVvthM1rHD9kXuolKf26UBsVfcnaWHaqvtUyPxGhsV3yadSiwPCAR85FDzhjLxlTLL2AA6zFqSC_1Iik2hlmFmpNeqsZJL_xMROWxTi7Ke1hdX1QCnwGtdF-Emdqgf1wqBWv6VTQVd2qslQySQN8RLTYmlkHBmOHU1jc0e2QP5xbLD4-pPr7RW17WbOkW2aLsC0YYebqFaqVgLNZJIVDKetRCCgi1RcdieQ0zSuUfRc9wzhZW7HHCECASqjeFqHopG05ge-DwAcc62-H7EbKr0XWz-7SLqjTrQ', + p: + '3wSG2cBBbo6FZ0GiRucHhJhSx1U6ZRhwhrbJmSpiFG5rvHvZn-DWnOmurvO5jc1V2Qj4QAEO4w7YQh3A9PFBry_42Od5zof1GIeAOVT3REiMTOSCxMVEMWQ74UBUM2T2R_TDrBgVSuaRmX14mcZM6_SYu7JLpqeSDzZEy2cqOBs', + q: + 'xoeWkL7oZ488PsJ6_lkjCmrlxouKJgHqMHI_RVE-MGSYHDNrJ_iS4wp8CK4xhAdGukqxDm5ChqFECgdg5QfdLoCseAIC-aHrrylYrmka5_8ke-ObpW9iGFcZy-5cEH5NCr6iSb-KS6fZkxJl7g3Az6XmLoEHHmyy8QxG9Yikaz8', + dp: + 'DKUxED-6dg5Wuhgan3KSFo6cgvjuKrVMDBdpLuocTZRFP5a2LD6PbK5DXWAscUHnUDsV-GsW8QDyei09t6XGV6ycq4_UdEV5PD7Som2S56hFbEa4s3eL-lD4pDkFjTR4UnQqdCOZcXnJX66hm_aGfgqMbngZmgV-XqZxGCdtWWk', + dq: + 'uX6ijefyWiCZF8K7DL_YX7l1q8dhcxXC7TUyLOA2DR1Qirj4XEaDaCO5tJqdpVDvIsz7FhKrkgNIAV7Xh-eLIBIWE6M9iGVkQyuMspl-DFp2ilMmcLLbowZvEf5KgxafgXSRSfrvirTwM9yy5HRxPRMzOSxRrHm_0D26Z1we1B0', + qi: + 'htPHLViOVG6QrldfuHn9evfdlD-UEuViOWNx8aKR3IBv0qegpJ78vYB4hdAcJZtBslKI97En5rzOAN3Y6Y8MbI4oN77WeiePJl2cMrS64evmlERvjJ6ZTs8jK0iV5q_gIZ9Qg9drmolUgb_CccQOBFbqSL6YkXwCBxlkCrzTlhc', + kty: 'RSA', + }; + test(testKeyImport, { ...rsa, alg: 'RS256' }); + test(testKeyImport, { ...rsa, alg: 'PS256' }); + test(testKeyImport, { ...rsa, alg: 'RSA-OAEP' }); + test(testKeyImport, { ...rsa, alg: 'RSA-OAEP-256' }); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jwk/key_ops.test.js b/test/jwk/key_ops.test.js deleted file mode 100644 index 72c5f9fa37..0000000000 --- a/test/jwk/key_ops.test.js +++ /dev/null @@ -1,107 +0,0 @@ -const test = require('ava') - -const { errors, JWK: { asKey, generateSync } } = require('../../lib') -const { generateKeyPairSync } = require('../macros/generate') - -const { edDSASupported } = require('../../lib/help/runtime_support') - -const jwk = asKey('foo').toJWK(true) - -test('key_ops ignores unrecognized values', t => { - asKey({ ...jwk, key_ops: ['sign', 'verify', 'foo'] }) - t.pass() -}) - -test('key_ops ignores duplicate values', t => { - const k = asKey({ ...jwk, key_ops: ['sign', 'verify', 'sign'] }) - t.deepEqual(k.key_ops, ['sign', 'verify']) -}) - -test('key_ops can be combined with use if consistent', t => { - asKey({ ...jwk, key_ops: ['sign', 'verify'], use: 'sig' }) - t.pass() -}) - -test('key_ops are part of toJWK', t => { - const k = asKey({ ...jwk, key_ops: ['sign', 'verify'], use: 'sig' }) - t.deepEqual(k.toJWK().key_ops, ['sign', 'verify']) - t.deepEqual(k.toJWK(true).key_ops, ['sign', 'verify']) -}) - -test('key_ops must be an array', t => { - t.throws(() => { - asKey({ ...jwk, key_ops: 'wrapKey' }) - }, { instanceOf: TypeError, message: '`key_ops` must be a non-empty array of strings when provided' }) -}) - -test('key_ops must not be empty', t => { - t.throws(() => { - asKey({ ...jwk, key_ops: [] }) - }, { instanceOf: TypeError, message: '`key_ops` must be a non-empty array of strings when provided' }) -}) - -test('key_ops must only contain strings', t => { - t.throws(() => { - asKey({ ...jwk, key_ops: ['wrapKey', true] }) - }, { instanceOf: TypeError, message: '`key_ops` must be a non-empty array of strings when provided' }) -}) - -test('JWK asKey with invalid use / key_ops throws', t => { - t.throws(() => { - asKey({ ...jwk, use: 'sig', key_ops: ['wrapKey'] }) - }, { instanceOf: errors.JWKInvalid, code: 'ERR_JWK_INVALID' }) -}) - -test('keyObject asKey with invalid use / key_ops throws 1/2', t => { - const { publicKey } = generateKeyPairSync('ec', { namedCurve: 'P-256' }) - - t.throws(() => { - asKey(publicKey, { use: 'sig', key_ops: ['wrapKey'] }) - }, { instanceOf: errors.JWKInvalid, code: 'ERR_JWK_INVALID' }) -}) - -test('keyObject asKey with invalid use / key_ops throws 2/2', t => { - const { publicKey } = generateKeyPairSync('ec', { namedCurve: 'P-256' }) - - t.throws(() => { - asKey(publicKey, { use: 'enc', key_ops: ['sign'] }) - }, { instanceOf: errors.JWKInvalid, code: 'ERR_JWK_INVALID' }) -}) - -test('PEM asKey with invalid use / key_ops throws', t => { - const { publicKey } = generateKeyPairSync('ec', { namedCurve: 'P-256' }) - - t.throws(() => { - asKey(publicKey.export({ type: 'spki', format: 'pem' }), { use: 'sig', key_ops: ['wrapKey'] }) - }, { instanceOf: errors.JWKInvalid, code: 'ERR_JWK_INVALID' }) -}) - -test('RSA key key_ops', t => { - const k = generateSync('RSA', 2048, { key_ops: ['sign'] }) - t.deepEqual([...k.algorithms()], ['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512']) - t.deepEqual([...k.algorithms('sign')], ['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512']) - t.deepEqual([...k.algorithms('verify')], []) -}) - -test('EC key key_ops', t => { - const k = generateSync('EC', 'P-256', { key_ops: ['verify'] }) - t.deepEqual([...k.algorithms()], ['ES256']) - t.deepEqual([...k.algorithms('verify')], ['ES256']) - t.deepEqual([...k.algorithms('sign')], []) -}) - -test('oct key key_ops', t => { - const k = generateSync('oct', 256, { key_ops: ['verify'] }) - t.deepEqual([...k.algorithms()], ['HS256', 'HS384', 'HS512']) - t.deepEqual([...k.algorithms('verify')], ['HS256', 'HS384', 'HS512']) - t.deepEqual([...k.algorithms('sign')], []) -}) - -if (edDSASupported) { - test('OKP key key_ops', t => { - const k = generateSync('OKP', 'Ed25519', { key_ops: ['verify'] }) - t.deepEqual([...k.algorithms()], ['EdDSA']) - t.deepEqual([...k.algorithms('verify')], ['EdDSA']) - t.deepEqual([...k.algorithms('sign')], []) - }) -} diff --git a/test/jwk/keyobject.test.js b/test/jwk/keyobject.test.js deleted file mode 100644 index 6b9d36a9cd..0000000000 --- a/test/jwk/keyobject.test.js +++ /dev/null @@ -1,135 +0,0 @@ -const test = require('ava') - -const { keyObjectSupported } = require('../../lib/help/runtime_support') - -if (!keyObjectSupported) { - const fixtures = require('../fixtures') - const { createPrivateKey, createPublicKey, createSecretKey } = require('../../lib/help/key_object') - const errors = require('../../lib/errors') - - const types = { - RSA: { - private: ['pkcs8', 'pkcs1'], - public: ['pkcs1', 'spki'] - }, - EC: { - private: ['pkcs8', 'sec1'], - public: ['spki'] - } - } - - test('secret KeyObject is not a valid input for createPublicKey', t => { - t.throws(() => { - createPublicKey(createSecretKey(Buffer.from('foo'))) - }, { instanceOf: TypeError, message: 'Invalid key object type secret, expected private.' }) - }) - - test('invalid create*Key inputs', t => { - [Buffer.alloc(0), 'foo', 1, true, false, Number].forEach((input) => { - t.throws(() => { - createSecretKey(input) - }, { instanceOf: TypeError, message: 'input must be a non-empty Buffer instance' }) - }) - - ;[1, true, false, Number].forEach((input) => { - t.throws(() => { - createPublicKey(input) - }, { instanceOf: TypeError, message: 'input must be a string, Buffer or an object' }) - }) - - ;[1, true, false, Number].forEach((input) => { - t.throws(() => { - createPrivateKey(input) - }, { instanceOf: TypeError, message: 'input must be a string, Buffer or an object' }) - }) - - t.throws(() => { - createPrivateKey({ key: 'foo', passphrase: 'foo' }) - }, { instanceOf: errors.JOSENotSupported, message: 'encrypted private keys are not supported in your Node.js runtime version' }) - }) - - test('createPublicKey format option must be recognized', t => { - t.throws(() => { - createPublicKey({ key: 'foo', type: 'foo', format: 'spki' }) - }, { instanceOf: TypeError, message: 'format must be one of "pem" or "der"' }) - }) - - test('createPrivateKey format option must be recognized', t => { - t.throws(() => { - createPrivateKey({ key: 'foo', type: 'foo', format: 'spki' }) - }, { instanceOf: TypeError, message: 'format must be one of "pem" or "der"' }) - }) - - Object.entries({ - RSA: fixtures.PEM.RSA, - EC: fixtures.PEM['P-256'] - }).forEach(([kty, { private: priv, public: pub }]) => { - types[kty].private.forEach((type) => { - test(`${kty} private can get re-exported as PEM ${type}`, t => { - const ko = createPrivateKey(priv) - t.throws(() => { - ko.export({ type: 'foo' }) - }, { instanceOf: TypeError, message: 'The value foo is invalid for option "type"' }) - let key - t.notThrows(() => { - key = ko.export({ format: 'pem', type }) - }) - t.notThrows(() => { - createPrivateKey({ key, format: 'pem', type }) - createPublicKey({ key, format: 'pem', type }) - }) - }) - - test(`${kty} private can get re-exported as DER ${type}`, t => { - const ko = createPrivateKey(priv) - let key - t.notThrows(() => { - key = ko.export({ format: 'der', type }) - }) - t.notThrows(() => { - createPrivateKey({ key, format: 'der', type }) - createPublicKey({ key, format: 'der', type }) - }) - }) - }) - - types[kty].public.forEach((type) => { - test(`${kty} public can get re-exported as PEM ${type}`, t => { - const ko = createPublicKey(pub) - t.throws(() => { - ko.export({ type: 'foo' }) - }, { instanceOf: TypeError, message: 'The value foo is invalid for option "type"' }) - let key - t.notThrows(() => { - key = ko.export({ format: 'pem', type }) - }) - t.notThrows(() => { - createPublicKey({ key, format: 'pem', type }) - }) - t.throws(() => { - createPrivateKey(pub) - }) - t.throws(() => { - createPrivateKey({ key, format: 'pem', type }) - }) - }) - - test(`${kty} public can get re-exported as DER ${type}`, t => { - const ko = createPublicKey(pub) - let key - t.notThrows(() => { - key = ko.export({ format: 'der', type }) - }) - t.notThrows(() => { - createPublicKey({ key, format: 'der', type }) - }) - t.throws(() => { - createPrivateKey(pub) - }) - t.throws(() => { - createPrivateKey({ key, format: 'der', type }) - }) - }) - }) - }) -} diff --git a/test/jwk/none.test.js b/test/jwk/none.test.js deleted file mode 100644 index c8c287f658..0000000000 --- a/test/jwk/none.test.js +++ /dev/null @@ -1,20 +0,0 @@ -const test = require('ava') - -const { JWK, JWKS } = require('../..') - -test('JWK.None', t => { - const k = JWK.None - t.truthy(k) - t.true(JWK.isKey(k)) - t.is(k.kty, undefined) - for (const prop of ['kid', 'kty', 'thumbprint', 'toJWK', 'toPEM']) { - k[prop] = 'foo' - t.is(k[prop], undefined) - } - t.deepEqual([...k.algorithms()], ['none']) - k.type = 'foo' - t.is(k.type, 'unsecured') - t.throws(() => new JWKS.KeyStore(k), { instanceOf: TypeError }) - const ks = new JWKS.KeyStore() - t.throws(() => ks.add(k), { instanceOf: TypeError }) -}) diff --git a/test/jwk/oct.test.js b/test/jwk/oct.test.js deleted file mode 100644 index 27244884d7..0000000000 --- a/test/jwk/oct.test.js +++ /dev/null @@ -1,214 +0,0 @@ -const test = require('ava') -const { EOL } = require('os') - -const { createSecretKey } = require('../../lib/help/key_object') -const { hasProperty, hasNoProperties } = require('../macros') -const { keyObjectSupported } = require('../../lib/help/runtime_support') - -const errors = require('../../lib/errors') -const OctKey = require('../../lib/jwk/key/oct') -const { JWK: { asKey } } = require('../..') -const { generateSync } = require('../../lib/jwk/generate') - -const keyObject = createSecretKey(Buffer.from('secret')) -const key = new OctKey(keyObject) - -test('RSA key .algorithms invalid operation', t => { - t.throws(() => key.algorithms('foo'), { instanceOf: TypeError, message: 'invalid key operation' }) -}) - -test('oct key (with alg)', hasProperty, new OctKey(keyObject, { alg: 'HS256' }), 'alg', 'HS256') -test('oct key (with kid)', hasProperty, new OctKey(keyObject, { kid: 'foobar' }), 'kid', 'foobar') -test('oct key (with use)', hasProperty, new OctKey(keyObject, { use: 'sig' }), 'use', 'sig') -test('oct key', hasNoProperties, key, 'e', 'n', 'd', 'p', 'q', 'dp', 'dq', 'qi', 'crv', 'x', 'y') -test('oct key', hasProperty, key, 'alg', undefined) -test('oct key', hasProperty, key, 'k', 'c2VjcmV0') -test('oct key', hasProperty, key, 'kid', 'DWBh0SEIAPYh1x5uvot4z3AhaikHkxNJa3Ada2fT-Cg') -test('oct key', hasProperty, key, 'kty', 'oct') -test('oct key', hasProperty, key, 'length', 48) -test('oct key', hasProperty, key, 'private', false) -test('oct key', hasProperty, key, 'type', 'secret') -test('oct key', hasProperty, key, 'public', false) -test('oct key', hasProperty, key, 'secret', true) -test('oct key', hasProperty, key, 'use', undefined) - -test('supports all sign algs (no use)', t => { - const result = key.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], ['HS256', 'HS384', 'HS512']) -}) - -test('supports all verify algs (no use)', t => { - const result = key.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], ['HS256', 'HS384', 'HS512']) -}) - -test('supports all sign algs when `use` is "sig")', t => { - const sigKey = new OctKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], ['HS256', 'HS384', 'HS512']) -}) - -test('supports all verify algs when `use` is "sig")', t => { - const sigKey = new OctKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], ['HS256', 'HS384', 'HS512']) -}) - -test('supports single sign alg when `alg` is set)', t => { - const sigKey = new OctKey(keyObject, { alg: 'HS256' }) - const result = sigKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], ['HS256']) -}) - -test('supports single verify alg when `alg` is set)', t => { - const sigKey = new OctKey(keyObject, { alg: 'HS256' }) - const result = sigKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], ['HS256']) -}) - -test('no sign support when `use` is "enc"', t => { - const encKey = new OctKey(keyObject, { use: 'enc' }) - const result = encKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) -}) - -test('no verify support when `use` is "enc"', t => { - const encKey = new OctKey(keyObject, { use: 'enc' }) - const result = encKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], []) -}) - -if (!('electron' in process.versions)) { - test('oct keys (odd bits) deriveKey algorithms only have "PBES2"', t => { - const key = generateSync('oct', 136) - const result = key.algorithms('deriveKey') - t.is(result.constructor, Set) - t.deepEqual([...result], ['PBES2-HS256+A128KW', 'PBES2-HS384+A192KW', 'PBES2-HS512+A256KW']) - }) -} else { - test('oct keys (odd bits) deriveKey don\'t even have "PBES2"', t => { - const key = generateSync('oct', 136) - const result = key.algorithms('deriveKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) -} - -test('oct keys (odd bits) wrap/unwrap algorithms cant wrap', t => { - const key = generateSync('oct', 136) - const result = key.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) -}) - -;[128, 192, 256].forEach((len) => { - test(`oct keys (${len} bits) wrap/unwrap algorithms have "GCMKW"`, t => { - const key = generateSync('oct', len) - t.true(key.algorithms().has(`A${len}GCMKW`)) - }) - - if (!('electron' in process.versions)) { - test(`oct keys (${len} bits) wrap/unwrap algorithms have "KW"`, t => { - const key = generateSync('oct', len) - t.true(key.algorithms().has(`A${len}KW`)) - }) - } else { - test(`oct keys (${len} bits) wrap/unwrap algorithms dont have "KW"`, t => { - const key = generateSync('oct', len) - t.false(key.algorithms().has(`A${len}KW`)) - }) - } -}) - -test('oct keys may not be generated as public', t => { - t.throws(() => { - generateSync('oct', undefined, undefined, false) - }, { instanceOf: TypeError, message: '"oct" keys cannot be generated as public' }) -}) - -test('they may be imported from', t => { - const key = asKey({ - kty: 'oct', - kid: '4p9o4_DcKoT6Qg2BI_mSgMP_MsXwFqogKuI26CunKAM' - }) - - t.is(key.kid, '4p9o4_DcKoT6Qg2BI_mSgMP_MsXwFqogKuI26CunKAM') - t.is(key.k, undefined) - t.false(key.private) - t.false(key.public) - t.deepEqual([...key.algorithms()], []) -}) - -test('they may be imported from (no kid)', t => { - const key = asKey({ - kty: 'oct' - }) - - t.is(key.k, undefined) - if (keyObjectSupported) { - t.is(key.keyObject, undefined) - } - t.false(key.private) - t.false(key.public) - t.deepEqual([...key.algorithms()], []) - t.throws(() => { - key.kid // eslint-disable-line no-unused-expressions - }, { instanceOf: TypeError, message: 'reference "oct" keys without "k" cannot have their thumbprint calculated' }) -}) - -test('they may be imported so long as there was no k', t => { - t.throws(() => { - asKey({ - kty: 'oct', - kid: '4p9o4_DcKoT6Qg2BI_mSgMP_MsXwFqogKuI26CunKAM', - k: undefined - }) - }, { instanceOf: errors.JWKImportFailed, message: 'key import failed' }) -}) - -;[ - 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6ZsprTWFF+fOG0mrdIQ+HxXnb5pAazkvSff1d49tgc73VKkrStsNSq9ss3j65p6gn6un8DZht0zP58iMqgK9YjfTC1OOGKFCtXzJsY9XwhFoSvhaI0iC2NH+aGu8OFfYXiQs/UZGe9acvFgViTSa/qYvh3NYTVPPf4EaaUndMIVz6scwuPji4w/n5dYXk5PF58k0Dq52ID6yQVk2QBRf8JcL+dPy3YztPTB2kcu7e0N9VopC5Qq2TsCb2H9ooHlgMerJ0WjlCv1ADC/8I+Cj7K1dj/3dcrMK/YR+2Muey5aQufPWoxtFpUv/2ieIAi19hhLeUOZbOlkwD/k/DO9Ht panva@local', - 'ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJS61dYMKR7grCcg2wLzkQZs4ok5VVZ6Oc+TlOSrz6s5WLl4WdN2hPCpYs/PtbyGcW0a8CAEKik3guStuMGCN1I= panva@local', - 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL5wJKRxgAdYUPm7gfP9eP4MKnWahgALTRDgMHt0VMj7 panva@local', - `-----BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW` -].forEach((openSSH, i, { length }) => { - test(`openssh keys do not fall through to oct keys ${i + 1}/${length}`, t => { - // strings - t.throws(() => { - asKey(openSSH) - }, { instanceOf: errors.JWKImportFailed, message: 'key import failed' }) - t.throws(() => { - asKey(openSSH.replace(' panva@local', '')) - }, { instanceOf: errors.JWKImportFailed, message: 'key import failed' }) - t.throws(() => { - asKey(openSSH.match(/.{1,64}/g).join(EOL)) - }, { instanceOf: errors.JWKImportFailed, message: 'key import failed' }) - // buffers - t.throws(() => { - asKey(Buffer.from(openSSH)) - }, { instanceOf: errors.JWKImportFailed, message: 'key import failed' }) - t.throws(() => { - asKey(Buffer.from(openSSH.replace(' panva@local', ''))) - }, { instanceOf: errors.JWKImportFailed, message: 'key import failed' }) - t.throws(() => { - asKey(Buffer.from(openSSH.match(/.{1,64}/g).join(EOL))) - }, { instanceOf: errors.JWKImportFailed, message: 'key import failed' }) - }) -}) - -test('some phrases do not fall through to openssh check', t => { - asKey('secret') - asKey('secret phrase') - asKey('longer secret phrase') - asKey('very long secret phrase') - t.pass() -}) diff --git a/test/jwk/okp_enc.test.js b/test/jwk/okp_enc.test.js deleted file mode 100644 index aafecd2e38..0000000000 --- a/test/jwk/okp_enc.test.js +++ /dev/null @@ -1,172 +0,0 @@ -const test = require('ava') - -const { improvedDH, keyObjectSupported } = require('../../lib/help/runtime_support') - -if (!('electron' in process.versions) && keyObjectSupported) { - if (!improvedDH) { - require('./okp_enc_no_dh') - } else { - const { createPrivateKey, createPublicKey } = require('crypto') - const { hasProperty, hasNoProperties, hasProperties } = require('../macros') - const fixtures = require('../fixtures') - - const OKPKey = require('../../lib/jwk/key/okp') - - test('OKP key .algorithms invalid operation', t => { - const key = new OKPKey(createPrivateKey(fixtures.PEM.X25519.private)) - t.throws(() => key.algorithms('foo'), { instanceOf: TypeError, message: 'invalid key operation' }) - }) - - Object.entries({ - X25519: 'P-c1F5P-1BckI7vasmrM8384J2IBYaYc_EtEXxOZYuI', - X448: 'a-2MwPMAhM3QY0zU0YBP9lzipRk67tsOY9uUhiT2Fos' - }).forEach(([crv, kid]) => { - const alg = 'ECDH-ES' - - // private - ;(() => { - const keyObject = createPrivateKey(fixtures.PEM[crv].private) - const key = new OKPKey(keyObject) - - test(`${crv} OKP Private key (with alg)`, hasProperty, new OKPKey(keyObject, { alg }), 'alg', alg) - test(`${crv} OKP Private key (with kid)`, hasProperty, new OKPKey(keyObject, { kid: 'foobar' }), 'kid', 'foobar') - test(`${crv} OKP Private key (with use)`, hasProperty, new OKPKey(keyObject, { use: 'enc' }), 'use', 'enc') - test(`${crv} OKP Private key`, hasNoProperties, key, 'k', 'e', 'n', 'p', 'q', 'dp', 'dq', 'qi', 'y') - test(`${crv} OKP Private key`, hasProperties, key, 'x', 'd') - test(`${crv} OKP Private key`, hasProperty, key, 'alg', undefined) - test(`${crv} OKP Private key`, hasProperty, key, 'kid', kid) - test(`${crv} OKP Private key`, hasProperty, key, 'kty', 'OKP') - test(`${crv} OKP Private key`, hasProperty, key, 'private', true) - test(`${crv} OKP Private key`, hasProperty, key, 'public', false) - test(`${crv} OKP Private key`, hasProperty, key, 'secret', false) - test(`${crv} OKP Private key`, hasProperty, key, 'type', 'private') - test(`${crv} OKP Private key`, hasProperty, key, 'use', undefined) - - test(`${crv} OKP Private key algorithms (no operation)`, t => { - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], ['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW']) - }) - - test(`${crv} OKP Private key algorithms (no operation, w/ alg)`, t => { - const key = new OKPKey(keyObject, { alg }) - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} OKP Private key does not support sign alg (no use)`, t => { - const result = key.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Private key does not support verify alg (no use)`, t => { - const result = key.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Private key .algorithms("encrypt")`, t => { - const result = key.algorithms('encrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Private key .algorithms("decrypt")`, t => { - const result = key.algorithms('decrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Private key .algorithms("wrapKey")`, t => { - const result = key.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Private key .algorithms("wrapKey") when use is sig`, t => { - const sigKey = new OKPKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Private key .algorithms("unwrapKey")`, t => { - const result = key.algorithms('unwrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - })() - - // public - ;(() => { - const keyObject = createPublicKey(fixtures.PEM[crv].public) - const key = new OKPKey(keyObject) - - test(`${crv} OKP Public key (with alg)`, hasProperty, new OKPKey(keyObject, { alg }), 'alg', alg) - test(`${crv} OKP Public key (with kid)`, hasProperty, new OKPKey(keyObject, { kid: 'foobar' }), 'kid', 'foobar') - test(`${crv} OKP Public key (with use)`, hasProperty, new OKPKey(keyObject, { use: 'sig' }), 'use', 'sig') - test(`${crv} OKP Public key`, hasNoProperties, key, 'k', 'e', 'n', 'p', 'q', 'dp', 'dq', 'qi', 'd', 'y') - test(`${crv} OKP Public key`, hasProperties, key, 'x') - test(`${crv} OKP Public key`, hasProperty, key, 'alg', undefined) - test(`${crv} OKP Public key`, hasProperty, key, 'kid', kid) - test(`${crv} OKP Public key`, hasProperty, key, 'kty', 'OKP') - test(`${crv} OKP Public key`, hasProperty, key, 'private', false) - test(`${crv} OKP Public key`, hasProperty, key, 'public', true) - test(`${crv} OKP Public key`, hasProperty, key, 'secret', false) - test(`${crv} OKP Public key`, hasProperty, key, 'type', 'public') - test(`${crv} OKP Public key`, hasProperty, key, 'use', undefined) - - test(`${crv} OKP Public key algorithms (no operation)`, t => { - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], ['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW']) - }) - - test(`${crv} OKP Public key algorithms (no operation, w/ alg)`, t => { - const key = new OKPKey(keyObject, { alg }) - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} OKP Public key cannot sign`, t => { - const result = key.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Public key does not support verify alg (no use)`, t => { - const result = key.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Public key .algorithms("encrypt")`, t => { - const result = key.algorithms('encrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Public key .algorithms("decrypt")`, t => { - const result = key.algorithms('decrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Public key .algorithms("wrapKey")`, t => { - const result = key.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Public key .algorithms("unwrapKey")`, t => { - const result = key.algorithms('unwrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - })() - }) - } -} diff --git a/test/jwk/okp_enc_no_dh.js b/test/jwk/okp_enc_no_dh.js deleted file mode 100644 index fbef72e2cd..0000000000 --- a/test/jwk/okp_enc_no_dh.js +++ /dev/null @@ -1,164 +0,0 @@ -const test = require('ava') - -const { createPrivateKey, createPublicKey } = require('crypto') -const { hasProperty, hasNoProperties, hasProperties } = require('../macros') -const fixtures = require('../fixtures') - -const OKPKey = require('../../lib/jwk/key/okp') - -test('OKP key .algorithms invalid operation', t => { - const key = new OKPKey(createPrivateKey(fixtures.PEM.X25519.private)) - t.throws(() => key.algorithms('foo'), { instanceOf: TypeError, message: 'invalid key operation' }) -}) - -Object.entries({ - X25519: 'P-c1F5P-1BckI7vasmrM8384J2IBYaYc_EtEXxOZYuI', - X448: 'a-2MwPMAhM3QY0zU0YBP9lzipRk67tsOY9uUhiT2Fos' -}).forEach(([crv, kid]) => { - const alg = 'ECDH-ES' - - // private - ;(() => { - const keyObject = createPrivateKey(fixtures.PEM[crv].private) - const key = new OKPKey(keyObject) - - test(`${crv} OKP Private key (with alg)`, hasProperty, new OKPKey(keyObject, { alg }), 'alg', alg) - test(`${crv} OKP Private key (with kid)`, hasProperty, new OKPKey(keyObject, { kid: 'foobar' }), 'kid', 'foobar') - test(`${crv} OKP Private key (with use)`, hasProperty, new OKPKey(keyObject, { use: 'enc' }), 'use', 'enc') - test(`${crv} OKP Private key`, hasNoProperties, key, 'k', 'e', 'n', 'p', 'q', 'dp', 'dq', 'qi', 'y') - test(`${crv} OKP Private key`, hasProperties, key, 'x', 'd') - test(`${crv} OKP Private key`, hasProperty, key, 'alg', undefined) - test(`${crv} OKP Private key`, hasProperty, key, 'kid', kid) - test(`${crv} OKP Private key`, hasProperty, key, 'kty', 'OKP') - test(`${crv} OKP Private key`, hasProperty, key, 'private', true) - test(`${crv} OKP Private key`, hasProperty, key, 'public', false) - test(`${crv} OKP Private key`, hasProperty, key, 'secret', false) - test(`${crv} OKP Private key`, hasProperty, key, 'type', 'private') - test(`${crv} OKP Private key`, hasProperty, key, 'use', undefined) - - test(`${crv} OKP Private key algorithms (no operation)`, t => { - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], [])//, 'ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW']) - }) - - test(`${crv} OKP Private key algorithms (no operation, w/ alg)`, t => { - const key = new OKPKey(keyObject, { alg }) - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], [])// [alg]) - }) - - test(`${crv} OKP Private key does not support sign alg (no use)`, t => { - const result = key.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Private key does not support verify alg (no use)`, t => { - const result = key.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Private key .algorithms("encrypt")`, t => { - const result = key.algorithms('encrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Private key .algorithms("decrypt")`, t => { - const result = key.algorithms('decrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Private key .algorithms("wrapKey")`, t => { - const result = key.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], [])// ['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW']) - }) - - test(`${crv} OKP Private key .algorithms("wrapKey") when use is sig`, t => { - const sigKey = new OKPKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Private key .algorithms("unwrapKey")`, t => { - const result = key.algorithms('unwrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], [])// ['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW']) - }) - })() - - // public - ;(() => { - const keyObject = createPublicKey(fixtures.PEM[crv].public) - const key = new OKPKey(keyObject) - - test(`${crv} OKP Public key (with alg)`, hasProperty, new OKPKey(keyObject, { alg }), 'alg', alg) - test(`${crv} OKP Public key (with kid)`, hasProperty, new OKPKey(keyObject, { kid: 'foobar' }), 'kid', 'foobar') - test(`${crv} OKP Public key (with use)`, hasProperty, new OKPKey(keyObject, { use: 'sig' }), 'use', 'sig') - test(`${crv} OKP Public key`, hasNoProperties, key, 'k', 'e', 'n', 'p', 'q', 'dp', 'dq', 'qi', 'd', 'y') - test(`${crv} OKP Public key`, hasProperties, key, 'x') - test(`${crv} OKP Public key`, hasProperty, key, 'alg', undefined) - test(`${crv} OKP Public key`, hasProperty, key, 'kid', kid) - test(`${crv} OKP Public key`, hasProperty, key, 'kty', 'OKP') - test(`${crv} OKP Public key`, hasProperty, key, 'private', false) - test(`${crv} OKP Public key`, hasProperty, key, 'public', true) - test(`${crv} OKP Public key`, hasProperty, key, 'secret', false) - test(`${crv} OKP Public key`, hasProperty, key, 'type', 'public') - test(`${crv} OKP Public key`, hasProperty, key, 'use', undefined) - - test(`${crv} OKP Public key algorithms (no operation)`, t => { - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], [])//, 'ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW']) - }) - - test(`${crv} OKP Public key algorithms (no operation, w/ alg)`, t => { - const key = new OKPKey(keyObject, { alg }) - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], [])// [alg]) - }) - - test(`${crv} OKP Public key cannot sign`, t => { - const result = key.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Public key does not support verify alg (no use)`, t => { - const result = key.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Public key .algorithms("encrypt")`, t => { - const result = key.algorithms('encrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Public key .algorithms("decrypt")`, t => { - const result = key.algorithms('decrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Public key .algorithms("wrapKey")`, t => { - const result = key.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], [])// ['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW']) - }) - - test(`${crv} OKP Public key .algorithms("unwrapKey")`, t => { - const result = key.algorithms('unwrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - })() -}) diff --git a/test/jwk/okp_sig.test.js b/test/jwk/okp_sig.test.js deleted file mode 100644 index 5983862c36..0000000000 --- a/test/jwk/okp_sig.test.js +++ /dev/null @@ -1,267 +0,0 @@ -const test = require('ava') - -const { keyObjectSupported } = require('../../lib/help/runtime_support') -const errors = require('../../lib/errors') - -const fixtures = require('../fixtures') - -if (!keyObjectSupported) { - const JWK = require('../../lib/jwk') - ;[ - [fixtures.PEM.Ed25519.public, 'Ed25519'], - [fixtures.PEM.Ed25519.private, 'Ed25519'], - [fixtures.PEM.Ed448.public, 'Ed448'], - [fixtures.PEM.Ed448.private, 'Ed448'], - [fixtures.PEM.X25519.public, 'X25519'], - [fixtures.PEM.X25519.private, 'X25519'], - [fixtures.PEM.X448.public, 'X448'], - [fixtures.PEM.X448.private, 'X448'], - [fixtures.JWK.Ed25519, 'Ed25519'], - [fixtures.JWK.Ed448, 'Ed448'], - [fixtures.JWK.X25519, 'X25519'], - [fixtures.JWK.X448, 'X448'], - [{ ...fixtures.JWK.Ed25519, d: undefined }, 'Ed25519'], - [{ ...fixtures.JWK.Ed448, d: undefined }, 'Ed448'], - [{ ...fixtures.JWK.X25519, d: undefined }, 'X25519'], - [{ ...fixtures.JWK.X448, d: undefined }, 'X448'] - ].forEach(([input, label], i, { length }) => { - test(`OKP ${i + 1} / ${length}`, t => { - t.throws(() => { - JWK.asKey(input) - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: `${label} is not supported in your Node.js runtime version` }) - }) - }) -} else { - const { createPrivateKey, createPublicKey } = require('crypto') - const { hasProperty, hasNoProperties, hasProperties } = require('../macros') - - const OKPKey = require('../../lib/jwk/key/okp') - - test('OKP key .algorithms invalid operation', t => { - const key = new OKPKey(createPrivateKey(fixtures.PEM.Ed25519.private)) - t.throws(() => key.algorithms('foo'), { instanceOf: TypeError, message: 'invalid key operation' }) - }) - - Object.entries({ - Ed25519: 'YeOxXoX_a0317nVDSwtlinj0RuJnSI0lYnxCM6qSC4c', - Ed448: 'eaEfshTya3PWdLWK4CfotnZcHKNJbpQviiTOqwOyFfE' - }).forEach(([crv, kid]) => { - if ('electron' in process.versions && crv === 'Ed448') return - const alg = 'EdDSA' - - // private - ;(() => { - const keyObject = createPrivateKey(fixtures.PEM[crv].private) - const key = new OKPKey(keyObject) - - test(`${crv} OKP Private key (with alg)`, hasProperty, new OKPKey(keyObject, { alg }), 'alg', alg) - test(`${crv} OKP Private key (with kid)`, hasProperty, new OKPKey(keyObject, { kid: 'foobar' }), 'kid', 'foobar') - test(`${crv} OKP Private key (with use)`, hasProperty, new OKPKey(keyObject, { use: 'sig' }), 'use', 'sig') - test(`${crv} OKP Private key`, hasNoProperties, key, 'k', 'e', 'n', 'p', 'q', 'dp', 'dq', 'qi', 'y') - test(`${crv} OKP Private key`, hasProperties, key, 'x', 'd') - test(`${crv} OKP Private key`, hasProperty, key, 'alg', undefined) - test(`${crv} OKP Private key`, hasProperty, key, 'kid', kid) - test(`${crv} OKP Private key`, hasProperty, key, 'kty', 'OKP') - test(`${crv} OKP Private key`, hasProperty, key, 'private', true) - test(`${crv} OKP Private key`, hasProperty, key, 'public', false) - test(`${crv} OKP Private key`, hasProperty, key, 'secret', false) - test(`${crv} OKP Private key`, hasProperty, key, 'type', 'private') - test(`${crv} OKP Private key`, hasProperty, key, 'use', undefined) - - test(`${crv} OKP Private key algorithms (no operation)`, t => { - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} OKP Private key algorithms (no operation, w/ alg)`, t => { - const key = new OKPKey(keyObject, { alg }) - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} OKP Private key supports sign alg (no use)`, t => { - const result = key.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} OKP Private key supports verify alg (no use)`, t => { - const result = key.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} OKP Private key supports sign alg when \`use\` is "sig")`, t => { - const sigKey = new OKPKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} OKP Private key supports verify alg when \`use\` is "sig")`, t => { - const sigKey = new OKPKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} OKP Private key supports single sign alg when \`alg\` is set)`, t => { - const sigKey = new OKPKey(keyObject, { alg }) - const result = sigKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} OKP Private key supports single verify alg when \`alg\` is set)`, t => { - const sigKey = new OKPKey(keyObject, { alg }) - const result = sigKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} OKP Private key .algorithms("encrypt")`, t => { - const result = key.algorithms('encrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Private key .algorithms("decrypt")`, t => { - const result = key.algorithms('decrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Private key .algorithms("wrapKey")`, t => { - const result = key.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Private key .algorithms("wrapKey") when use is sig`, t => { - const sigKey = new OKPKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Private key .algorithms("unwrapKey")`, t => { - const result = key.algorithms('unwrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Private key .algorithms("unwrapKey") when use is sig`, t => { - const sigKey = new OKPKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('unwrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - })() - - // public - ;(() => { - const keyObject = createPublicKey(fixtures.PEM[crv].public) - const key = new OKPKey(keyObject) - - test(`${crv} OKP Public key (with alg)`, hasProperty, new OKPKey(keyObject, { alg }), 'alg', alg) - test(`${crv} OKP Public key (with kid)`, hasProperty, new OKPKey(keyObject, { kid: 'foobar' }), 'kid', 'foobar') - test(`${crv} OKP Public key (with use)`, hasProperty, new OKPKey(keyObject, { use: 'sig' }), 'use', 'sig') - test(`${crv} OKP Public key`, hasNoProperties, key, 'k', 'e', 'n', 'p', 'q', 'dp', 'dq', 'qi', 'd', 'y') - test(`${crv} OKP Public key`, hasProperties, key, 'x') - test(`${crv} OKP Public key`, hasProperty, key, 'alg', undefined) - test(`${crv} OKP Public key`, hasProperty, key, 'kid', kid) - test(`${crv} OKP Public key`, hasProperty, key, 'kty', 'OKP') - test(`${crv} OKP Public key`, hasProperty, key, 'private', false) - test(`${crv} OKP Public key`, hasProperty, key, 'public', true) - test(`${crv} OKP Public key`, hasProperty, key, 'secret', false) - test(`${crv} OKP Public key`, hasProperty, key, 'type', 'public') - test(`${crv} OKP Public key`, hasProperty, key, 'use', undefined) - - test(`${crv} OKP Public key algorithms (no operation)`, t => { - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} OKP Public key algorithms (no operation, w/ alg)`, t => { - const key = new OKPKey(keyObject, { alg }) - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} OKP Public key cannot sign`, t => { - const result = key.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Public key supports verify alg (no use)`, t => { - const result = key.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} OKP Public key cannot sign even when \`use\` is "sig")`, t => { - const sigKey = new OKPKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Public key supports verify alg when \`use\` is "sig")`, t => { - const sigKey = new OKPKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} OKP Public key cannot sign even when \`alg\` is set)`, t => { - const sigKey = new OKPKey(keyObject, { alg }) - const result = sigKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Public key supports single verify alg when \`alg\` is set)`, t => { - const sigKey = new OKPKey(keyObject, { alg }) - const result = sigKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], [alg]) - }) - - test(`${crv} OKP Public key .algorithms("encrypt")`, t => { - const result = key.algorithms('encrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Public key .algorithms("decrypt")`, t => { - const result = key.algorithms('decrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Public key .algorithms("wrapKey")`, t => { - const result = key.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Public key .algorithms("wrapKey") when use is sig`, t => { - const sigKey = new OKPKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test(`${crv} OKP Public key .algorithms("unwrapKey")`, t => { - const result = key.algorithms('unwrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - })() - }) -} diff --git a/test/jwk/rsa.test.js b/test/jwk/rsa.test.js deleted file mode 100644 index 84bb21e9f6..0000000000 --- a/test/jwk/rsa.test.js +++ /dev/null @@ -1,405 +0,0 @@ -const test = require('ava') -const { createPrivateKey, createPublicKey } = require('../../lib/help/key_object') -const { hasProperty, hasNoProperties, hasProperties } = require('../macros') -const fixtures = require('../fixtures') - -const { oaepHashSupported } = require('../../lib/help/runtime_support') -const { generateSync } = require('../../lib/jwk/generate') -const RSAKey = require('../../lib/jwk/key/rsa') - -test('RSA key .algorithms invalid operation', t => { - const key = new RSAKey(createPrivateKey(fixtures.PEM.RSA.private)) - t.throws(() => key.algorithms('foo'), { instanceOf: TypeError, message: 'invalid key operation' }) -}) - -// private -;(() => { - const keyObject = createPrivateKey(fixtures.PEM.RSA.private) - const key = new RSAKey(keyObject) - - test('RSA Private key (with alg)', hasProperty, new RSAKey(keyObject, { alg: 'RS256' }), 'alg', 'RS256') - test('RSA Private key (with kid)', hasProperty, new RSAKey(keyObject, { kid: 'foobar' }), 'kid', 'foobar') - test('RSA Private key (with use)', hasProperty, new RSAKey(keyObject, { use: 'sig' }), 'use', 'sig') - test('RSA Private key', hasNoProperties, key, 'k', 'x', 'y') - test('RSA Private key', hasProperties, key, 'e', 'n', 'p', 'q', 'dp', 'dq', 'qi', 'd') - test('RSA Private key', hasProperty, key, 'alg', undefined) - test('RSA Private key', hasProperty, key, 'kid', 'Bj1ccHv-y_ZoejJKWhAhBHLpnGSlawNAQUAMEQBd5L8') - test('RSA Private key', hasProperty, key, 'kty', 'RSA') - test('RSA Private key', hasProperty, key, 'length', 2048) - test('RSA Private key', hasProperty, key, 'private', true) - test('RSA Private key', hasProperty, key, 'public', false) - test('RSA Private key', hasProperty, key, 'secret', false) - test('RSA Private key', hasProperty, key, 'type', 'private') - test('RSA Private key', hasProperty, key, 'use', undefined) - - if (oaepHashSupported) { - test('RSA Private key algorithms (no operation)', t => { - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], ['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512', 'RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512', 'RSA1_5']) - }) - } else { - test('RSA Private key algorithms (no operation)', t => { - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], ['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512', 'RSA-OAEP', 'RSA1_5']) - }) - } - - test('RSA Private key algorithms (no operation, w/ alg)', t => { - const key = new RSAKey(keyObject, { alg: 'RS256' }) - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], ['RS256']) - }) - - test('RSA Private key supports sign alg (no use)', t => { - const result = key.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], ['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512']) - }) - - test('RSA Private key supports verify alg (no use)', t => { - const result = key.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], ['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512']) - }) - - test('RSA Private key supports sign alg when `use` is "sig")', t => { - const sigKey = new RSAKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], ['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512']) - }) - - test('RSA Private key supports verify alg when `use` is "sig")', t => { - const sigKey = new RSAKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], ['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512']) - }) - - test('RSA Private key supports single sign alg when `alg` is set)', t => { - const sigKey = new RSAKey(keyObject, { alg: 'RS256' }) - const result = sigKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], ['RS256']) - }) - - test('RSA Private key supports single verify alg when `alg` is set)', t => { - const sigKey = new RSAKey(keyObject, { alg: 'RS256' }) - const result = sigKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], ['RS256']) - }) - - test('RSA Private key no sign support when `use` is "enc"', t => { - const encKey = new RSAKey(keyObject, { use: 'enc' }) - const result = encKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test('RSA Private key no verify support when `use` is "enc"', t => { - const encKey = new RSAKey(keyObject, { use: 'enc' }) - const result = encKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test('RSA Private key .algorithms("encrypt")', t => { - const result = key.algorithms('encrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test('RSA Private key .algorithms("deriveKey")', t => { - const result = key.algorithms('deriveKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test('RSA Private key .algorithms("decrypt")', t => { - const result = key.algorithms('decrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - if (oaepHashSupported) { - test('RSA Private key .algorithms("wrapKey")', t => { - const result = key.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], ['RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512', 'RSA1_5']) - }) - } else { - test('RSA Private key .algorithms("wrapKey")', t => { - const result = key.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], ['RSA-OAEP', 'RSA1_5']) - }) - } - - test('RSA Private key .algorithms("wrapKey") when use is sig', t => { - const sigKey = new RSAKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - if (oaepHashSupported) { - test('RSA Private key .algorithms("unwrapKey")', t => { - const result = key.algorithms('unwrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], ['RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512', 'RSA1_5']) - }) - } else { - test('RSA Private key .algorithms("unwrapKey")', t => { - const result = key.algorithms('unwrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], ['RSA-OAEP', 'RSA1_5']) - }) - } - - test('RSA Private key .algorithms("unwrapKey") when use is sig', t => { - const sigKey = new RSAKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('unwrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) -})() - -// public -;(() => { - const keyObject = createPublicKey(fixtures.PEM.RSA.public) - const key = new RSAKey(keyObject) - - test('RSA Public key (with alg)', hasProperty, new RSAKey(keyObject, { alg: 'RS256' }), 'alg', 'RS256') - test('RSA Public key (with kid)', hasProperty, new RSAKey(keyObject, { kid: 'foobar' }), 'kid', 'foobar') - test('RSA Public key (with use)', hasProperty, new RSAKey(keyObject, { use: 'sig' }), 'use', 'sig') - test('RSA Public key', hasNoProperties, key, 'k', 'x', 'y', 'd', 'p', 'q', 'dp', 'dq', 'qi') - test('RSA Public key', hasProperties, key, 'e', 'n') - test('RSA Public key', hasProperty, key, 'alg', undefined) - test('RSA Public key', hasProperty, key, 'kid', 'Bj1ccHv-y_ZoejJKWhAhBHLpnGSlawNAQUAMEQBd5L8') - test('RSA Public key', hasProperty, key, 'kty', 'RSA') - test('RSA Public key', hasProperty, key, 'length', 2048) - test('RSA Public key', hasProperty, key, 'private', false) - test('RSA Public key', hasProperty, key, 'public', true) - test('RSA Public key', hasProperty, key, 'secret', false) - test('RSA Public key', hasProperty, key, 'type', 'public') - test('RSA Public key', hasProperty, key, 'use', undefined) - - if (oaepHashSupported) { - test('RSA EC Public key algorithms (no operation)', t => { - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], ['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512', 'RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512', 'RSA1_5']) - }) - } else { - test('RSA EC Public key algorithms (no operation)', t => { - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], ['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512', 'RSA-OAEP', 'RSA1_5']) - }) - } - - test('RSA EC Public key algorithms (no operation, w/ alg)', t => { - const key = new RSAKey(keyObject, { alg: 'RS256' }) - const result = key.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], ['RS256']) - }) - - test('RSA Public key cannot sign', t => { - const result = key.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test('RSA Public key supports verify alg (no use)', t => { - const result = key.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], ['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512']) - }) - - test('RSA Public key cannot sign even when `use` is "sig")', t => { - const sigKey = new RSAKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test('RSA Public key supports verify alg when `use` is "sig")', t => { - const sigKey = new RSAKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], ['PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512']) - }) - - test('RSA Public key cannot sign even when `alg` is set)', t => { - const sigKey = new RSAKey(keyObject, { alg: 'RS256' }) - const result = sigKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test('RSA Public key supports single verify alg when `alg` is set)', t => { - const sigKey = new RSAKey(keyObject, { alg: 'RS256' }) - const result = sigKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], ['RS256']) - }) - - test('RSA Public key no sign support when `use` is "enc"', t => { - const encKey = new RSAKey(keyObject, { use: 'enc' }) - const result = encKey.algorithms('sign') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test('RSA Public key no verify support when `use` is "enc"', t => { - const encKey = new RSAKey(keyObject, { use: 'enc' }) - const result = encKey.algorithms('verify') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test('RSA Public key .algorithms("encrypt")', t => { - const result = key.algorithms('encrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test('RSA Public key .algorithms("deriveKey")', t => { - const result = key.algorithms('deriveKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test('RSA Public key .algorithms("decrypt")', t => { - const result = key.algorithms('decrypt') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - if (oaepHashSupported) { - test('RSA Public key .algorithms("wrapKey")', t => { - const result = key.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], ['RSA-OAEP', 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512', 'RSA1_5']) - }) - } else { - test('RSA Public key .algorithms("wrapKey")', t => { - const result = key.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], ['RSA-OAEP', 'RSA1_5']) - }) - } - - test('RSA Public key .algorithms("wrapKey") when use is sig', t => { - const sigKey = new RSAKey(keyObject, { use: 'sig' }) - const result = sigKey.algorithms('wrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test('RSA Public key .algorithms("unwrapKey")', t => { - const result = key.algorithms('unwrapKey') - t.is(result.constructor, Set) - t.deepEqual([...result], []) - }) - - test('any RSA key can do RS256 and RSA1_5', t => { - const k = generateSync('RSA', 512) - const result = k.algorithms() - t.is(result.constructor, Set) - t.deepEqual([...result], ['RS256', 'RSA1_5']) - }) - - if (!('electron' in process.versions)) { - test('RSA key >= 528 bits can do PS256', t => { - const k = generateSync('RSA', 528) - t.true(k.algorithms().has('PS256')) - }) - - test('RSA key >= 592 bits can do RSA-OAEP', t => { - const k = generateSync('RSA', 592) - t.true(k.algorithms().has('RSA-OAEP')) - }) - - test('RSA key >= 624 bits can do RS384', t => { - const k = generateSync('RSA', 624) - t.true(k.algorithms().has('RS384')) - }) - - test('RSA key >= 752 bits can do RS512', t => { - const k = generateSync('RSA', 752) - t.true(k.algorithms().has('RS512')) - }) - - if (oaepHashSupported) { - test('RSA key >= 784 bits can do RSA-OAEP-256', t => { - const k = generateSync('RSA', 784) - t.true(k.algorithms().has('RSA-OAEP-256')) - }) - - test('RSA key >= 1040 bits can do RSA-OAEP-256', t => { - const k = generateSync('RSA', 1040) - t.true(k.algorithms().has('RSA-OAEP-384')) - }) - - test('RSA key >= 1296 bits can do RSA-OAEP-256', t => { - const k = generateSync('RSA', 1296) - t.true(k.algorithms().has('RSA-OAEP-512')) - }) - } - - test('RSA key >= 784 bits can do PS384', t => { - const k = generateSync('RSA', 784) - t.true(k.algorithms().has('PS384')) - }) - - test('RSA key >= 1040 bits can do PS512', t => { - const k = generateSync('RSA', 1040) - t.true(k.algorithms().has('PS512')) - }) - } else { - test('RSA key >= 640 bits can do RS384, RSA-OAEP and PS256', t => { - const k = generateSync('RSA', 640) - t.true(k.algorithms().has('RS384')) - t.true(k.algorithms().has('PS256')) - t.true(k.algorithms().has('RSA-OAEP')) - }) - - test('RSA key >= 768 bits can do RS512', t => { - const k = generateSync('RSA', 768) - t.true(k.algorithms().has('RS512')) - }) - - test('RSA key >= 896 bits can do PS384', t => { - const k = generateSync('RSA', 896) - t.true(k.algorithms().has('PS384')) - }) - - if (oaepHashSupported) { - test('RSA key >= 896 bits can do RSA-OAEP-256', t => { - const k = generateSync('RSA', 896) - t.true(k.algorithms().has('RSA-OAEP-256')) - }) - - test('RSA key >= 1040 bits can do RSA-OAEP-256', t => { - const k = generateSync('RSA', 1152) - t.true(k.algorithms().has('RSA-OAEP-384')) - }) - - test('RSA key >= 1408 bits can do RSA-OAEP-256', t => { - const k = generateSync('RSA', 1408) - t.true(k.algorithms().has('RSA-OAEP-512')) - }) - } - - test('RSA key >= 1152 bits can do PS512', t => { - const k = generateSync('RSA', 1152) - t.true(k.algorithms().has('PS512')) - }) - } -})() diff --git a/test/jwk/thumbprint.test.mjs b/test/jwk/thumbprint.test.mjs new file mode 100644 index 0000000000..d74621a767 --- /dev/null +++ b/test/jwk/thumbprint.test.mjs @@ -0,0 +1,132 @@ +import test from 'ava'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +import(`${root}/jwk/thumbprint`).then( + ({ default: thumbprint }) => { + test('https://tools.ietf.org/html/rfc7638#section-3.1', async (t) => { + t.is( + await thumbprint({ + kty: 'RSA', + n: + '0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw', + e: 'AQAB', + alg: 'RS256', + }), + 'NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs', + ); + }); + + test('JWK must be an object', async (t) => { + await t.throwsAsync(thumbprint(true), { + instanceOf: TypeError, + message: 'JWK must be an object', + }); + await t.throwsAsync(thumbprint(null), { + instanceOf: TypeError, + message: 'JWK must be an object', + }); + await t.throwsAsync(thumbprint(Boolean), { + instanceOf: TypeError, + message: 'JWK must be an object', + }); + await t.throwsAsync(thumbprint([]), { + instanceOf: TypeError, + message: 'JWK must be an object', + }); + await t.throwsAsync(thumbprint(''), { + instanceOf: TypeError, + message: 'JWK must be an object', + }); + await t.throwsAsync(thumbprint(Object.create(null)), { + instanceOf: TypeError, + message: 'JWK must be an object', + }); + }); + + test('JWK kty must be recognized', async (t) => { + await t.throwsAsync(thumbprint({ kty: 'unrecognized' }), { + code: 'ERR_JOSE_NOT_SUPPORTED', + message: '"kty" (Key Type) Parameter missing or unsupported', + }); + }); + + test('EC JWK', async (t) => { + const ec = { + crv: 'P-256', + kty: 'EC', + x: 'q3zAwR_kUwtdLEwtB2oVfucXiLHmEhu9bJUFYjJxYGs', + y: '8h0D-ONoU-iZqrq28TyUxEULxuGwJZGMJYTMbeMshvI', + }; + + await t.throwsAsync(thumbprint({ ...ec, crv: undefined }), { + code: 'ERR_JWK_INVALID', + message: '"crv" (Curve) Parameter missing or invalid', + }); + await t.throwsAsync(thumbprint({ ...ec, x: undefined }), { + code: 'ERR_JWK_INVALID', + message: '"x" (X Coordinate) Parameter missing or invalid', + }); + await t.throwsAsync(thumbprint({ ...ec, y: undefined }), { + code: 'ERR_JWK_INVALID', + message: '"y" (Y Coordinate) Parameter missing or invalid', + }); + t.is(await thumbprint(ec), 'ZrBaai73Hi8Fg4MElvDGzIne2NsbI75RHubOViHYE5Q'); + }); + + test('OKP JWK', async (t) => { + const okp = { + crv: 'Ed25519', + kty: 'OKP', + x: '5fL1GDeyNTIxtuzTeFnvZTo4Oz0EkMfAdhIJA-EFn0w', + }; + + await t.throwsAsync(thumbprint({ ...okp, crv: undefined }), { + code: 'ERR_JWK_INVALID', + message: '"crv" (Subtype of Key Pair) Parameter missing or invalid', + }); + await t.throwsAsync(thumbprint({ ...okp, x: undefined }), { + code: 'ERR_JWK_INVALID', + message: '"x" (Public Key) Parameter missing or invalid', + }); + t.is(await thumbprint(okp), '1OzNmMHhNzbSJyoePAtdoVedRZlFvER3K3RAzCrfX0k'); + }); + + test('RSA JWK', async (t) => { + const rsa = { + e: 'AQAB', + kty: 'RSA', + n: + 'ok6WYUlmj2J1p-Sm0kwaZlAbWetUooe2LR6iAOJfntavWlyBO0shK_550YG3lQ6R1YeKisNAqbQ1pjqo3vwvR_v_AWtZ1gY1h6KX4DhCv0nNMexZ4g67LxEweoQ4_InMMiwMyQ3CRVJ3P1w0TQZYqzfSye-llY39tyzHeHeuotgrZrM427iUuIJdN38nZ2vW9VpK3bo_Nsvl12ZBe6x7DBzWEFHqQDFyjy8lH8EZyxqDArLA7T5OAcEdkm3RI8jBbsrUD9IySCE5SdEU3n0VGNGkT88DFU85QGvLpL2ITbGX0amaJvxYjIRhIYTfZS6Mqoxr6K1LIwP8pu0VD2Ca5Q', + }; + + await t.throwsAsync(thumbprint({ ...rsa, e: undefined }), { + code: 'ERR_JWK_INVALID', + message: '"e" (Exponent) Parameter missing or invalid', + }); + await t.throwsAsync(thumbprint({ ...rsa, n: undefined }), { + code: 'ERR_JWK_INVALID', + message: '"n" (Modulus) Parameter missing or invalid', + }); + t.is(await thumbprint(rsa), 'dQiQXSGtV4XcPK143Cu2-ZSsQtVNjQZrleUMs9nLnKQ'); + }); + + test('oct JWK', async (t) => { + const oct = { + k: 'FyCq1CKBflh3I5gikEjpYrdOXllzxB_yc02za8ERknI', + kty: 'oct', + }; + + await t.throwsAsync(thumbprint({ ...oct, k: undefined }), { + code: 'ERR_JWK_INVALID', + message: '"k" (Key Value) Parameter missing or invalid', + }); + t.is(await thumbprint(oct), 'prDKy90VJzrDTpm8-W2Q_pv_kzrX_zyZ7ANjRAasDxc'); + }); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jwk/x5c_thumbprints.test.js b/test/jwk/x5c_thumbprints.test.js deleted file mode 100644 index 694f9f232b..0000000000 --- a/test/jwk/x5c_thumbprints.test.js +++ /dev/null @@ -1,69 +0,0 @@ -const test = require('ava') - -const { keyObjectSupported } = require('../../lib/help/runtime_support') - -if (keyObjectSupported) { - const errors = require('../../lib/errors') - - const { JWK: { asKey } } = require('../..') - - const jwk = { - kty: 'RSA', - use: 'sig', - kid: '1b94c', - n: 'vrjOfz9Ccdgx5nQudyhdoR17V-IubWMeOZCwX_jj0hgAsz2J_pqYW08PLbK_PdiVGKPrqzmDIsLI7sA25VEnHU1uCLNwBuUiCO11_-7dYbsr4iJmG0Qu2j8DsVyT1azpJC_NG84Ty5KKthuCaPod7iI7w0LK9orSMhBEwwZDCxTWq4aYWAchc8t-emd9qOvWtVMDC2BXksRngh6X5bUYLy6AyHKvj-nUy1wgzjYQDwHMTplCoLtU-o-8SNnZ1tmRoGE9uJkBLdh5gFENabWnU5m1ZqZPdwS-qo-meMvVfJb6jJVWRpl2SUtCnYG2C32qvbWbjZ_jBPD5eunqsIo1vQ', - e: 'AQAB', - x5c: [ - 'MIIDQjCCAiqgAwIBAgIGATz/FuLiMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYDVQQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1wYmVsbDAeFw0xMzAyMjEyMzI5MTVaFw0xODA4MTQyMjI5MTVaMGIxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYDVQQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1wYmVsbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64zn8/QnHYMeZ0LncoXaEde1fiLm1jHjmQsF/449IYALM9if6amFtPDy2yvz3YlRij66s5gyLCyO7ANuVRJx1NbgizcAblIgjtdf/u3WG7K+IiZhtELto/A7Fck9Ws6SQvzRvOE8uSirYbgmj6He4iO8NCyvaK0jIQRMMGQwsU1quGmFgHIXPLfnpnfajr1rVTAwtgV5LEZ4Iel+W1GC8ugMhyr4/p1MtcIM42EA8BzE6ZQqC7VPqPvEjZ2dbZkaBhPbiZAS3YeYBRDWm1p1OZtWamT3cEvqqPpnjL1XyW+oyVVkaZdklLQp2Btgt9qr21m42f4wTw+Xrp6rCKNb0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAh8zGlfSlcI0o3rYDPBB07aXNswb4ECNIKG0CETTUxmXl9KUL+9gGlqCz5iWLOgWsnrcKcY0vXPG9J1r9AqBNTqNgHq2G03X09266X5CpOe1zFo+Owb1zxtp3PehFdfQJ610CDLEaS9V9Rqp17hCyybEpOGVwe8fnk+fbEL2Bo3UPGrpsHzUoaGpDftmWssZkhpBJKVMJyf/RuP2SmmaIzmnw9JiSlYhzo4tpzd5rFXhjRbg4zW9C+2qok+2+qDM1iJ684gPHMIY8aLWrdgQTxkumGmTqgawR+N5MDtdPTEQ0XfIBc2cJEUyMTY5MPvACWpkA6SdS4xSvdXK3IVfOWA==' - ] - } - - test('x5c can be imported and have their X.509 cert thumbprints calculated', t => { - let key - t.notThrows(() => { key = asKey(jwk) }) - t.deepEqual(key.x5c, jwk.x5c) - const asJWK = key.toJWK() - t.deepEqual(asJWK.x5c, jwk.x5c) - ;[key.x5t, asJWK.x5t, key['x5t#S256'], asJWK['x5t#S256']].forEach((prop) => { - t.truthy(prop) - t.is(typeof prop, 'string') - }) - }) - - test('checks that x5c is an array of valid PKIX certificates', t => { - ;[[], {}, false, 1].forEach((value) => { - t.throws(() => { - asKey({ - ...jwk, - x5c: value - }) - }, { instanceOf: TypeError, message: '`x5c` must be an array of one or more PKIX certificates when provided' }) - t.throws(() => { - asKey({ - ...jwk, - x5c: [value] - }) - }, { instanceOf: TypeError, message: '`x5c` must be an array of one or more PKIX certificates when provided' }) - }) - }) - - test('checks that first x5c member must represent the key', t => { - t.throws(() => { - asKey({ - ...jwk, - x5c: [ - 'MIIC/zCCAeegAwIBAgIJYdZUZz2rikftMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNVBAMTEnBhbnZhLmV1LmF1dGgwLmNvbTAeFw0xNzEwMTgxNTExMjBaFw0zMTA2MjcxNTExMjBaMB0xGzAZBgNVBAMTEnBhbnZhLmV1LmF1dGgwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKROvB+A+ZlFV1AXl75tVegjaCuBE7CiXHNstVZ/F6fKl6OvIRhAW3YKnJEglzVvHw0q46Nw48yBdbbKjdwGo1jbrI15D2+MYPy8xlMfDzEqNWBjOsgnA1nhFFDXD7wITwFRMtlRKVvKMa19QCmMFrpQ2qcloMne/DzSvxlEnVA6DG1SYqHR/gdK5hoRATJkwHXQ5F/nUxD3BOAyyjsU5RsGJAeVVS4Yf532xmziIbda3iV4LMUiHUb1v8Oy2sDncYF+imq/sbHGgE7dyv5R5AsYHGANgvIPMHJ1QTFSQVU0lxPy+EWnLk9abVOZYzD6O5YRdJ29UWVtQ1q5UcyrF18CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSUcoPFHi/vm7dw1rt/IRmxvLMyowDgYDVR0PAQH/BAQDAgKEMA0GCSqGSIb3DQEBCwUAA4IBAQBcBXXBcbqliVOHkTgxocSYNUajcgIKjgeqG9RKFkbHfPuK/Hn80vQhd6mBKJTIyM7fY7DPh1/PjRsAyDQEwouHWItcM6iJBSdAkPq2DPfCkpUOi7MHrhXSouU1X4IOBvAl94k9Z8oj5k12KWVH8jZn5G03lwkWUgSfkLJ0Dh86+4sF2W4Dz2qZUXZuQbUL5eJcWRpfEZowff+T8xsiRjcIEpgfLz4nWonijtvEWESEa3bYpI9pI5OXLImgVJLGxVaUktsGIexQ6eM1AoxBYE7E+nbN/rwo30XWGbTkYecisySSYuzVn2c0xnC/8ZvW+gJ4SkzRDjlOAbm3R0r5j7b1' - ] - }) - }, { instanceOf: errors.JWKInvalid, code: 'ERR_JWK_INVALID', message: 'The key in the first `x5c` certificate MUST match the public key represented by the JWK' }) - t.throws(() => { - asKey({ - ...jwk, - x5c: [ - jwk.x5c[0], - 'MIIC/zCCAeegAwIBAgIJYdZUZz2rikftMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNVBAMTEnBhbnZhLmV1LmF1dGgwLmNvbTAeFw0xNzEwMTgxNTExMjBaFw0zMTA2MjcxNTExMjBaMB0xGzAZBgNVBAMTEnBhbnZhLmV1LmF1dGgwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKROvB+A+ZlFV1AXl75tVegjaCuBE7CiXHNstVZ/F6fKl6OvIRhAW3YKnJEglzVvHw0q46Nw48yBdbbKjdwGo1jbrI15D2+MYPy8xlMfDzEqNWBjOsgnA1nhFFDXD7wITwFRMtlRKVvKMa19QCmMFrpQ2qcloMne/DzSvxlEnVA6DG1SYqHR/gdK5hoRATJkwHXQ5F/nUxD3BOAyyjsU5RsGJAeVVS4Yf532xmziIbda3iV4LMUiHUb1v8Oy2sDncYF+imq/sbHGgE7dyv5R5AsYHGANgvIPMHJ1QTFSQVU0lxPy+EWnLk9abVOZYzD6O5YRdJ29UWVtQ1q5UcyrF18CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSUcoPFHi/vm7dw1rt/IRmxvLMyowDgYDVR0PAQH/BAQDAgKEMA0GCSqGSIb3DQEBCwUAA4IBAQBcBXXBcbqliVOHkTgxocSYNUajcgIKjgeqG9RKFkbHfPuK/Hn80vQhd6mBKJTIyM7fY7DPh1/PjRsAyDQEwouHWItcM6iJBSdAkPq2DPfCkpUOi7MHrhXSouU1X4IOBvAl94k9Z8oj5k12KWVH8jZn5G03lwkWUgSfkLJ0Dh86+4sF2W4Dz2qZUXZuQbUL5eJcWRpfEZowff+T8xsiRjcIEpgfLz4nWonijtvEWESEa3bYpI9pI5OXLImgVJLGxVaUktsGIexQ6eM1AoxBYE7E+nbN/rwo30XWGbTkYecisySSYuzVn2c0xnC/8ZvW+gJ4SkzRDjlOAbm3R0r5j7b1f' - ] - }) - }, { instanceOf: errors.JWKInvalid, code: 'ERR_JWK_INVALID', message: '`x5c` member at index 1 is not a valid base64-encoded DER PKIX certificate' }) - }) -} diff --git a/test/jwks/keystore.test.js b/test/jwks/keystore.test.js deleted file mode 100644 index af3d914a34..0000000000 --- a/test/jwks/keystore.test.js +++ /dev/null @@ -1,287 +0,0 @@ -const test = require('ava') - -const { JWK: { asKey, generateSync }, JWKS: { KeyStore, asKeyStore } } = require('../../lib') -const errors = require('../../lib/errors') - -const withX5C = { - kty: 'RSA', - n: 'vrjOfz9Ccdgx5nQudyhdoR17V-IubWMeOZCwX_jj0hgAsz2J_pqYW08PLbK_PdiVGKPrqzmDIsLI7sA25VEnHU1uCLNwBuUiCO11_-7dYbsr4iJmG0Qu2j8DsVyT1azpJC_NG84Ty5KKthuCaPod7iI7w0LK9orSMhBEwwZDCxTWq4aYWAchc8t-emd9qOvWtVMDC2BXksRngh6X5bUYLy6AyHKvj-nUy1wgzjYQDwHMTplCoLtU-o-8SNnZ1tmRoGE9uJkBLdh5gFENabWnU5m1ZqZPdwS-qo-meMvVfJb6jJVWRpl2SUtCnYG2C32qvbWbjZ_jBPD5eunqsIo1vQ', - e: 'AQAB', - x5c: [ - 'MIIDQjCCAiqgAwIBAgIGATz/FuLiMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYDVQQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1wYmVsbDAeFw0xMzAyMjEyMzI5MTVaFw0xODA4MTQyMjI5MTVaMGIxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYDVQQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1wYmVsbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64zn8/QnHYMeZ0LncoXaEde1fiLm1jHjmQsF/449IYALM9if6amFtPDy2yvz3YlRij66s5gyLCyO7ANuVRJx1NbgizcAblIgjtdf/u3WG7K+IiZhtELto/A7Fck9Ws6SQvzRvOE8uSirYbgmj6He4iO8NCyvaK0jIQRMMGQwsU1quGmFgHIXPLfnpnfajr1rVTAwtgV5LEZ4Iel+W1GC8ugMhyr4/p1MtcIM42EA8BzE6ZQqC7VPqPvEjZ2dbZkaBhPbiZAS3YeYBRDWm1p1OZtWamT3cEvqqPpnjL1XyW+oyVVkaZdklLQp2Btgt9qr21m42f4wTw+Xrp6rCKNb0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAh8zGlfSlcI0o3rYDPBB07aXNswb4ECNIKG0CETTUxmXl9KUL+9gGlqCz5iWLOgWsnrcKcY0vXPG9J1r9AqBNTqNgHq2G03X09266X5CpOe1zFo+Owb1zxtp3PehFdfQJ610CDLEaS9V9Rqp17hCyybEpOGVwe8fnk+fbEL2Bo3UPGrpsHzUoaGpDftmWssZkhpBJKVMJyf/RuP2SmmaIzmnw9JiSlYhzo4tpzd5rFXhjRbg4zW9C+2qok+2+qDM1iJ684gPHMIY8aLWrdgQTxkumGmTqgawR+N5MDtdPTEQ0XfIBc2cJEUyMTY5MPvACWpkA6SdS4xSvdXK3IVfOWA==' - ] -} - -test('constructor', t => { - t.notThrows(() => { - new KeyStore() // eslint-disable-line no-new - }) - t.notThrows(() => { - new KeyStore(generateSync('EC')) // eslint-disable-line no-new - }) - t.notThrows(() => { - new KeyStore(generateSync('EC'), generateSync('EC')) // eslint-disable-line no-new - }) - t.notThrows(() => { - new KeyStore([generateSync('EC')], generateSync('EC')) // eslint-disable-line no-new - }) - t.notThrows(() => { - new KeyStore([[generateSync('EC')], generateSync('EC')]) // eslint-disable-line no-new - }) -}) - -test('constructor only accepts Key instances created through JWK.asKey', t => { - t.throws(() => { - new KeyStore({}) // eslint-disable-line no-new - }, { instanceOf: TypeError, message: 'all keys must be instances of a key instantiated by JWK.asKey' }) -}) - -test('.generate()', async t => { - const ks = new KeyStore() - await ks.generate('EC') - t.is(ks.size, 1) -}) - -test('.generateSync()', t => { - const ks = new KeyStore() - ks.generateSync('EC') - t.is(ks.size, 1) -}) - -test('.add()', t => { - const ks = new KeyStore() - const k = generateSync('EC') - ks.add(k) - ks.add(k) - t.is(ks.size, 1) - t.throws(() => { - ks.add({}) - }, { instanceOf: TypeError, message: 'key must be an instance of a key instantiated by JWK.asKey' }) -}) - -test('.remove()', t => { - const k = generateSync('EC') - const ks = new KeyStore(k) - ks.remove(k) - t.is(ks.size, 0) - ks.remove(k) - t.throws(() => { - ks.remove({}) - }, { instanceOf: TypeError, message: 'key must be an instance of a key instantiated by JWK.asKey' }) -}) - -test('.all() key_ops must be an array', t => { - const ks = new KeyStore() - t.throws(() => { - ks.all({ key_ops: 'wrapKey' }) - }, { instanceOf: TypeError, message: '`key_ops` must be a non-empty array of strings' }) -}) - -test('.all() key_ops must not be empty', t => { - const ks = new KeyStore() - t.throws(() => { - ks.all({ key_ops: [] }) - }, { instanceOf: TypeError, message: '`key_ops` must be a non-empty array of strings' }) -}) - -test('.all() key_ops must only contain strings', t => { - const ks = new KeyStore() - t.throws(() => { - ks.all({ key_ops: ['wrapKey', true] }) - }, { instanceOf: TypeError, message: '`key_ops` must be a non-empty array of strings' }) -}) - -test('.all() with key_ops when keys have key_ops', t => { - const k = generateSync('RSA', undefined, { key_ops: ['sign', 'verify'] }) - const ks = new KeyStore(k) - t.deepEqual(ks.all({ key_ops: ['wrapKey'] }), []) - t.deepEqual(ks.all({ key_ops: ['sign', 'wrapKey'] }), []) - t.deepEqual(ks.all({ key_ops: ['sign'] }), [k]) - t.deepEqual(ks.all({ key_ops: ['verify'] }), [k]) - t.deepEqual(ks.all({ key_ops: ['sign', 'verify'] }), [k]) - t.is(ks.get({ key_ops: ['wrapKey'] }), undefined) - t.is(ks.get({ key_ops: ['sign', 'wrapKey'] }), undefined) - t.is(ks.get({ key_ops: ['sign'] }), k) - t.is(ks.get({ key_ops: ['verify'] }), k) - t.is(ks.get({ key_ops: ['sign', 'verify'] }), k) -}) - -test('.all() with key_ops when keys have derived key_ops from use', t => { - const k = generateSync('RSA', undefined, { use: 'sig' }) - const ks = new KeyStore(k) - t.deepEqual(ks.all({ key_ops: ['wrapKey'] }), []) - t.deepEqual(ks.all({ key_ops: ['sign', 'wrapKey'] }), []) - t.deepEqual(ks.all({ key_ops: ['sign'] }), [k]) - t.deepEqual(ks.all({ key_ops: ['verify'] }), [k]) - t.deepEqual(ks.all({ key_ops: ['sign', 'verify'] }), [k]) - t.is(ks.get({ key_ops: ['wrapKey'] }), undefined) - t.is(ks.get({ key_ops: ['sign', 'wrapKey'] }), undefined) - t.is(ks.get({ key_ops: ['sign'] }), k) - t.is(ks.get({ key_ops: ['verify'] }), k) - t.is(ks.get({ key_ops: ['sign', 'verify'] }), k) -}) - -test('.get() with key_ops ranks keys with defined key_ops higher', t => { - const k = generateSync('RSA') - const k2 = generateSync('RSA', undefined, { use: 'sig' }) - const k3 = generateSync('RSA', undefined, { key_ops: ['sign', 'verify'] }) - const ks = new KeyStore(k, k2, k3) - - t.deepEqual(ks.all({ key_ops: ['sign'] }), [k3, k, k2]) - t.deepEqual(ks.get({ key_ops: ['sign'] }), k3) -}) - -test('.all() and .get() use filter', t => { - const k = generateSync('RSA', undefined, { use: 'sig' }) - const ks = new KeyStore(k) - t.deepEqual(ks.all({ use: 'enc' }), []) - t.deepEqual(ks.all({ use: 'sig' }), [k]) - t.is(ks.get({ use: 'enc' }), undefined) - t.is(ks.get({ use: 'sig' }), k) -}) - -test('.all() and .get() use sort', t => { - const k = generateSync('RSA') - const k2 = generateSync('RSA', undefined, { use: 'sig' }) - const ks = new KeyStore(k, k2) - t.deepEqual(ks.all({ use: 'sig' }), [k2, k]) - t.is(ks.get({ use: 'sig' }), k2) -}) - -test('.all() and .get() crv filter', t => { - const k = generateSync('EC', 'P-256') - const k2 = generateSync('EC', 'P-384') - const ks = new KeyStore(k, k2) - t.deepEqual(ks.all({ crv: 'P-256' }), [k]) - t.deepEqual(ks.all({ crv: 'P-384' }), [k2]) - t.deepEqual(ks.all({ crv: 'P-521' }), []) - t.is(ks.get({ crv: 'P-256' }), k) - t.is(ks.get({ crv: 'P-384' }), k2) - t.is(ks.get({ crv: 'P-521' }), undefined) -}) - -test('.all() and .get() kid filter', t => { - const k = generateSync('RSA', undefined, { kid: 'foobar' }) - const ks = new KeyStore(k) - t.deepEqual(ks.all({ kid: 'baz' }), []) - t.deepEqual(ks.all({ kid: 'foobar' }), [k]) - t.is(ks.get({ kid: 'baz' }), undefined) - t.is(ks.get({ kid: 'foobar' }), k) -}) - -test('.all() and .get() thumbprint filter', t => { - const k = generateSync('RSA') - const ks = new KeyStore(k) - t.deepEqual(ks.all({ thumbprint: 'baz' }), []) - t.deepEqual(ks.all({ thumbprint: k.thumbprint }), [k]) - t.is(ks.get({ thumbprint: 'baz' }), undefined) - t.is(ks.get({ thumbprint: k.thumbprint }), k) -}) - -test('.all() and .get() x5t filter and sort', t => { - const k = asKey(withX5C) - const ks = new KeyStore(k) - t.deepEqual(ks.all({ x5t: 'baz' }), []) - t.deepEqual(ks.all({ x5t: '4pNenEBLv0JpLIdugWxQkOsZcK0' }), [k]) - t.is(ks.get({ x5t: 'baz' }), undefined) - t.is(ks.get({ x5t: '4pNenEBLv0JpLIdugWxQkOsZcK0' }), k) - const k2 = asKey({ ...withX5C, alg: 'RS256' }) - ks.add(k2) - t.is(ks.get({ x5t: '4pNenEBLv0JpLIdugWxQkOsZcK0', alg: 'RS256' }), k2) -}) - -test('.all() and .get() x5t#S256 filter and sort', t => { - const k = asKey(withX5C) - const ks = new KeyStore(k) - t.deepEqual(ks.all({ 'x5t#S256': 'baz' }), []) - t.deepEqual(ks.all({ 'x5t#S256': 'pJm2BBpkB8y7tCqrWM0X37WOmQTO8zQw-VpxVgBb21I' }), [k]) - t.is(ks.get({ 'x5t#S256': 'baz' }), undefined) - t.is(ks.get({ 'x5t#S256': 'pJm2BBpkB8y7tCqrWM0X37WOmQTO8zQw-VpxVgBb21I' }), k) - const k2 = asKey({ ...withX5C, alg: 'RS256' }) - ks.add(k2) - t.is(ks.get({ 'x5t#S256': 'pJm2BBpkB8y7tCqrWM0X37WOmQTO8zQw-VpxVgBb21I', alg: 'RS256' }), k2) -}) - -test('.all() and .get() kty filter', t => { - const ks = new KeyStore() - ks.generateSync('RSA') - ks.generateSync('EC') - ks.generateSync('oct') - t.is(ks.all({ kty: 'oct' }).length, 1) - t.is(ks.all({ kty: 'RSA' }).length, 1) - t.is(ks.all({ kty: 'EC' }).length, 1) -}) - -test('.all() and .get() alg filter', t => { - const k = generateSync('RSA') - const ks = new KeyStore(k) - t.deepEqual(ks.all({ alg: 'HS256' }), []) - t.deepEqual(ks.all({ alg: 'RS256' }), [k]) - t.is(ks.get({ alg: 'HS256' }), undefined) - t.is(ks.get({ alg: 'RS256' }), k) -}) - -test('.all() and .get() alg sort', t => { - const k = generateSync('RSA') - const k2 = generateSync('RSA', undefined, { alg: 'RS256' }) - const ks = new KeyStore(k, k2) - t.deepEqual(ks.all({ alg: 'HS256' }), []) - t.deepEqual(ks.all({ alg: 'RS256' }), [k2, k]) - t.is(ks.get({ alg: 'HS256' }), undefined) - t.is(ks.get({ alg: 'RS256' }), k2) -}) - -test('.asKeyStore()', t => { - const ks = new KeyStore() - ks.generateSync('EC') - ks.generateSync('RSA') - - const ks2 = asKeyStore(ks.toJWKS()) - t.true(ks2 instanceof KeyStore) - t.is(ks2.size, 2) -}) - -test('.asKeyStore() input validation', t => { - [Buffer, 1, false, '', 'foo', {}, { foo: 'bar' }].forEach((val) => { - t.throws(() => { - asKeyStore(val) - }, { instanceOf: TypeError, message: 'jwks must be a JSON Web Key Set formatted object' }) - t.throws(() => { - asKeyStore({ keys: val }) - }, { instanceOf: TypeError, message: 'jwks must be a JSON Web Key Set formatted object' }) - t.throws(() => { - asKeyStore({ keys: [val] }) - }, { instanceOf: TypeError, message: 'jwks must be a JSON Web Key Set formatted object' }) - }) -}) - -test('keystore instance is an iterator', t => { - const ks = new KeyStore() - ks.generateSync('EC') - ks.generateSync('RSA') - for (const key of ks) { - t.truthy(key) - } - t.pass() -}) - -test('minimal RSA test', async t => { - const key = generateSync('RSA') - const { d, e, n } = key.toJWK(true) - asKeyStore({ keys: [{ kty: 'RSA', d, e, n }] }, { calculateMissingRSAPrimes: true }) - t.throws(() => { - asKeyStore({ keys: [{ kty: 'RSA', d: d.substr(3), e, n }] }, { calculateMissingRSAPrimes: true }) - }, { instanceOf: errors.JWKImportFailed, code: 'ERR_JWK_IMPORT_FAILED', message: 'failed to calculate missing primes' }) - t.throws(() => { - asKeyStore({ keys: [{ kty: 'RSA', d, e, n }] }) - }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'importing private RSA keys without all other private key parameters is not enabled, see documentation and its advisory on how and when its ok to enable it' }) - const jwk = { - kty: 'RSA', - d: 'YN1ucKFpCsgMuIfTynTbNwEXp2lBkrJYfsVOIGdK3bZMblZqxWElm8HTE06-JH_BC5drAAv1Hu-6SE6-sehq9blG-vMJ0wi-jBYfkhlOLEZJXHPb4aJyS8oWKhVO14qyfS_m2BtAW9Wh5vEOXy7HLgrZWjctm0t1Ipb-b_nfNfisGIMjPdWzu_nTfbzIIwM7wQBGnHLqfQq6iD7I8nSPjsc_gZUeeKYkU_Q6K8tIY0gr850-6wk-Nh9JsPA93lR0woTqqMG6UiFE4Y4Jj3M6puBUSU-R3n-gL35I1Cwa5m0IREG8Bz0RPpAEcRQB1xRuM22xD4yE0I4LDegtH056lw', - e: 'AQAB', - n: '1hZ73O4axgytljzb8gCXxdk3Uov_f7U6c_hKH5EtGtr8XdWce1XLLjARqAQfOpbYqkm1ONiIvhQvxvW0a7gXgEw4no9c_Gi8a803O9LZmYAYDxErlvPQPg9KC5cLPChM-Uyxy4TOakjw1ysUKBX7zXpb_1TIOnlhOYeDbejLkp8sR7BJIsDNxqtkV4KHLWQ9pKsMU28itblQ8nN8UJI5Js4UbR-b417uQ9jIVRhWlDjp11sXYqfnqShCDYGYmLL2IHTVf8tTmEOWsNWcE2nT-qMTGMOq2DBkyr31lxc-4eQXZuwcrk_58xQ69xSrdrsy8J11O50nbvwcqFhjeMV2VQ' - } - t.throws(() => { - asKeyStore({ keys: [{ kty: 'RSA', d: `${jwk.d}FF`, e: jwk.e, n: jwk.n }] }, { calculateMissingRSAPrimes: true }) - }, { instanceOf: errors.JWKInvalid, code: 'ERR_JWK_INVALID', message: 'invalid RSA private exponent' }) -}) diff --git a/test/jwks/remote.test.mjs b/test/jwks/remote.test.mjs new file mode 100644 index 0000000000..bd62c9bf18 --- /dev/null +++ b/test/jwks/remote.test.mjs @@ -0,0 +1,262 @@ +/* eslint-disable no-param-reassign */ +import test from 'ava'; +import nock from 'nock'; +import timekeeper from 'timekeeper'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +Promise.all([ + import(`${root}/jwt/verify`), + import(`${root}/jwt/sign`), + import(`${root}/jwk/parse`), + import(`${root}/jwks/remote`), +]).then( + ([ + { default: jwtVerify }, + { default: SignJWT }, + { default: parseJwk }, + { default: createRemoteJWKSet }, + ]) => { + const now = 1604416038; + + test.beforeEach(() => { + timekeeper.freeze(now * 1000); + }); + + test.afterEach((t) => { + t.true(nock.isDone()); + nock.cleanAll(); + }); + + test.afterEach(timekeeper.reset); + + test.serial('RemoteJWKSet', async (t) => { + const keys = [ + { + e: 'AQAB', + n: + 'wAR7gpvDJx2cUR15R1gyBYxEXanhOIDzk7evzadBpNCEpf6HA6utqMrf8dZ3EXSslKPSPBD5Qrz63kc2u8y7NqzwJQIi_i5xR6AxAyWLG3_kOHBwxnct6talLCZqgr8pDwnyP1BPnIaNf2hZxgS-UZbHCAVycd1n2qCdyb4FzFhcaNtiOLg5VSfgvtOdhHQlDXW-DBvwatpd9HzzTP6l5MZRyQ-N_AoGbIfhNCZRUfnb-A8IBPSqXBWN4TEpt-0yHAOIhWnSpu66AYE4f1efZdHVFCTQZ13e5bS-5RQra4pfmGqU9hog1j1SpHnDTia-s__qGi43rev2MqzY-qeUlw', + d: + 'buWn14TSLtMhJo_ZLWU4bo_WJCoq0xFWm-eodyOz-9YZ5iycGXibcTLKJ8fvOHuj-KysjNhYvTybvqhuagQR08AJabZUM2zrK6zO4bxbHOS-EAKQf27xbAHPnzIIrb5tnivmZr6hXAsxyXWg84ZlzIVCKdXLhQuUIWZF-u_uNVeJSUTDMRVTL2J0mzAGTXqi-yHejapEeLS7lFXDe6cpDnBVXauJfB4GmSUOjxtdAEVW7uGNQJGarGwRz6l3Tpy_xQiYl8e_IrU1N6qAN_HJEBrdgfK7js93RcsxHGbtdnj1ylevZqGFpB1UXrWE4JSz3sJgyXrmKNFFWOCjalMccQ', + p: + '98OCXxur1omXdjfWkDubqkI3xRehVQryIhqt0go-1yLS4Nwa7KyrdAbzTo81bCHN0A-NlmIvHA4YZc8QUHftq65s4nCbb3g_CwTfGCJEVCvoaTO2EE6Pd8VrGu2PVsN4SM52Gc0TNJGS54yUhyCWDTi1onUBEg8gnqpMSoWuaVM', + q: + 'xmaRdSJf4wN5Vse5jiIjZy5jy9veHHhzXxTmW25epr9KTMERUDDCzX0bNbnF8jCvDFN5ebzcEe-9nkWyzJ17wVcJTouEfw8A5pBPcx6Gr8Kd8WIrUjuom4xu-4619kMItoV4j62_nq3p0QUGot_6CgUdq63PCp9Fh-sHv8wViy0', + dp: + '0OCXwbzfYu_-rCCpGFHYi3Jl-BhS4BJpTc02K3SNw-vM4ttNK6jqptfRObLMNAxPqg_iqxy9YKaVdQdbVqu0yF811rVepVw3sf96YatJ9bhKqJ566EaC91ONV1dd16TVfHPq5xeYEGKF-gXvlfgn6J-dqYeAzovIUVt7E_ydrJc', + dq: + 'sYDOnqe0dhyDkNp77ugoGIZujtMVcw9o2SaPujmSwUjfprANV1tozgQiNf0RVk-sLTD5u6r2ka2WTmY5Q8uaDy5Zi0ZTsoGv4pg2HN6wzcsnF_EmpRnvDcuk97eEoOD0iKf9Zz6h88vRJ0qB13Lf99r_4rtMQ0qgIKxscHKcy7k', + qi: + '7uvpgL15VFjd_zjhU0fPVeTzAa6Vg3P3Q2v5DLwLkAIlQDqF50maTYztxtxssVNJtEMIxKefwrmGkyVCXNhrGHZDoj7wj-2o0k878bQqtltCO2TPm9TSYZgW7dR3ji0t4Msc5DcrQL002M_Vxqr9MAunQcAsnulRTepQM2n-aOc', + kty: 'RSA', + kid: 'ZuLUAgyr6RQV3ERjDukHzOO_90rVbrPiE1vD_HtPFuM', + }, + { + e: 'AQAB', + n: + '0PjQVV2ZAT27Y0h7hfAWWcnPetORCvR1_gHvEUxtlrlnhZia7utHl7BCJH9HP17YHMMBeeEkmUDflYoUL6MDl4DYHgVDq8jZfu1pxH1XqrpeswqOVoReknEe0F5kRt_mPtIoShI2Qv-pxGAw392akAXTirVRLL4Fn_0Oiifxp182P7eTPy41rlKDevLHuKHBZzzaes_33YE2epY2YCLp9k3mZ-tJEei2qiq0T1fERQicGUL8kppOnz0cDNuKRBHyYtXWhjhuDQ8OZQHNLfte9cqzTJMJ4Leu4MGjikSZMsk-_aRFnXtYHH0orwY-giSenRnwNaReAXaR1Px9ReljAQ', + d: + 'LXGufKH6IBb4pUKh-iKX-ba1dBSGOkenUTHCd5STUG_JX3gsWUC5NPeTqrQzHkjV3otZytN3TgyZkr-QXDurEEtotD6Y1Ma85aljkuNfKTWWWoE1KwNmPZp0BQRB8lfGjmrNcC49tpw6owX4GvbqId_ifQupN32rY3t4qfq9xpO9SAqZF0oUMoS7xE0zChsCJmNYpD9jx87p5Vud1naeaZPlvwWW0ITV4kp2zjYSbBh5DkI52rSrGjkuzlsJ_lKJk5YB557OHhN9XTRBnjqlwwWevh6QAoUivqpcelcplgmfxTHoII1opovYXn8AVt-DbGSO_7LLJ0Sw9sJR5GAqcQ', + p: + '9RdDqZ3O73lH6nWUGi0abQRRfgvj-HM0zP7GSDQ185l-ZByletl1VuJ86qYJTUY8Q3Gagv6_eXmQMo_14-0wT_FPUMiTMYsjw5QNgFgjlJTM1AayS_U5ddix_Ut7Kti7EXgM0gsavsIazv2-xwCrFzD4sa-t2FWELzzWxgt8wbs', + q: + '2kX8MN8ItGnn7NnPx-0iqe8kkhy5s9gJRiD3mxN9E6xzRCnf488yhc3aBwI9kZzQtV0XVjX5VhCws5vnJv9b7KA8NATDhpGNrqy2h9ncmsjTTjafUg3jb6QG08kIKDR-A97Mc-MJbIUNzYs10BAG4z9wk7t1bdo4gZJEvjiXVHM', + dp: + 'Ahggy-I9Um6G3soCafbYsvXGfH09hXH2kYnbx-IqU9qL6e8UuugAyK1Gw_qHOdHP0gO2fkgO-sq_IK96OmhccVJuixIrr9CwjYtGUkJui2Z6GZW1EFEYHJmta6ypcMRJVOzhrynJILgn4nzolGq9C4WvmlUV9zND3eN3MloGxuE', + dq: + 'uXKWlusX2TjVvM0-FO2r8tdkqeNP_7XAA15FIPOI5Cszb6loOIQ0t6wy3puPteSXClBCYJPQ-MeLab4-wUpaTovBOq0FdpK53ruNBZUbMkMIDL6p1CxKnPKufkeh747RtfYYnSk7O4E8PfNV0CWdxHuE6W9ukNvEAIpGb5tjL3M', + qi: + '3BLQ03cHEmO8nUT7U8M_H_JciEWAH8XWh_9nihIhXzLKYbNmWM16Ah0F9DUg0GPeiG7e_08ZJ4X3oK1bHnnXdns6NSOEoULWfHl5LUY5PoFPYaBDy3f6td2SCTE83p1YzegXKysWEk1snA2ROq4UEfz1vL8v64RtwR3SvNrAyOI', + kty: 'RSA', + alg: 'RS256', + kid: 'hJU8GvYjtifxLVuBDSNmhLBF19wQHaZvQhfpT3wKzpE', + }, + { + crv: 'P-256', + x: 'fqCXPnWs3sSfwztvwYU9SthmRdoT4WCXxS8eD8icF6U', + y: 'nP6GIc42c61hoKqPcZqkvzhzIJkBV3Jw3g8sGG7UeP8', + d: 'XikZvoy8ayRpOnuz7ont2DkgMxp_kmmg1EKcuIJWX_E', + kty: 'EC', + kid: 'a-5xuiQoRqlLBtec9jRpXoGTVOP10SGnj2Und0CHHxw', + }, + ]; + const jwks = { + keys: [ + { + e: 'AQAB', + n: + 'wAR7gpvDJx2cUR15R1gyBYxEXanhOIDzk7evzadBpNCEpf6HA6utqMrf8dZ3EXSslKPSPBD5Qrz63kc2u8y7NqzwJQIi_i5xR6AxAyWLG3_kOHBwxnct6talLCZqgr8pDwnyP1BPnIaNf2hZxgS-UZbHCAVycd1n2qCdyb4FzFhcaNtiOLg5VSfgvtOdhHQlDXW-DBvwatpd9HzzTP6l5MZRyQ-N_AoGbIfhNCZRUfnb-A8IBPSqXBWN4TEpt-0yHAOIhWnSpu66AYE4f1efZdHVFCTQZ13e5bS-5RQra4pfmGqU9hog1j1SpHnDTia-s__qGi43rev2MqzY-qeUlw', + kty: 'RSA', + kid: 'ZuLUAgyr6RQV3ERjDukHzOO_90rVbrPiE1vD_HtPFuM', + }, + { + e: 'AQAB', + n: + '0PjQVV2ZAT27Y0h7hfAWWcnPetORCvR1_gHvEUxtlrlnhZia7utHl7BCJH9HP17YHMMBeeEkmUDflYoUL6MDl4DYHgVDq8jZfu1pxH1XqrpeswqOVoReknEe0F5kRt_mPtIoShI2Qv-pxGAw392akAXTirVRLL4Fn_0Oiifxp182P7eTPy41rlKDevLHuKHBZzzaes_33YE2epY2YCLp9k3mZ-tJEei2qiq0T1fERQicGUL8kppOnz0cDNuKRBHyYtXWhjhuDQ8OZQHNLfte9cqzTJMJ4Leu4MGjikSZMsk-_aRFnXtYHH0orwY-giSenRnwNaReAXaR1Px9ReljAQ', + alg: 'RS256', + kty: 'RSA', + kid: 'hJU8GvYjtifxLVuBDSNmhLBF19wQHaZvQhfpT3wKzpE', + }, + { + crv: 'P-256', + x: 'fqCXPnWs3sSfwztvwYU9SthmRdoT4WCXxS8eD8icF6U', + y: 'nP6GIc42c61hoKqPcZqkvzhzIJkBV3Jw3g8sGG7UeP8', + kty: 'EC', + kid: 'a-5xuiQoRqlLBtec9jRpXoGTVOP10SGnj2Und0CHHxw', + }, + { + e: 'AQAB', + n: + '0PjQVV2ZAT27Y0h7hfAWWcnPetORCvR1_gHvEUxtlrlnhZia7utHl7BCJH9HP17YHMMBeeEkmUDflYoUL6MDl4DYHgVDq8jZfu1pxH1XqrpeswqOVoReknEe0F5kRt_mPtIoShI2Qv-pxGAw392akAXTirVRLL4Fn_0Oiifxp182P7eTPy41rlKDevLHuKHBZzzaes_33YE2epY2YCLp9k3mZ-tJEei2qiq0T1fERQicGUL8kppOnz0cDNuKRBHyYtXWhjhuDQ8OZQHNLfte9cqzTJMJ4Leu4MGjikSZMsk-_aRFnXtYHH0orwY-giSenRnwNaReAXaR1Px9ReljAQ', + alg: 'RS256', + kty: 'RSA', + use: 'enc', + }, + { + e: 'AQAB', + n: + '0PjQVV2ZAT27Y0h7hfAWWcnPetORCvR1_gHvEUxtlrlnhZia7utHl7BCJH9HP17YHMMBeeEkmUDflYoUL6MDl4DYHgVDq8jZfu1pxH1XqrpeswqOVoReknEe0F5kRt_mPtIoShI2Qv-pxGAw392akAXTirVRLL4Fn_0Oiifxp182P7eTPy41rlKDevLHuKHBZzzaes_33YE2epY2YCLp9k3mZ-tJEei2qiq0T1fERQicGUL8kppOnz0cDNuKRBHyYtXWhjhuDQ8OZQHNLfte9cqzTJMJ4Leu4MGjikSZMsk-_aRFnXtYHH0orwY-giSenRnwNaReAXaR1Px9ReljAQ', + alg: 'RS256', + kty: 'RSA', + use: 'sig', + key_ops: [], + }, + ], + }; + + nock('https://as.example.com').get('/jwks').reply(200, jwks); + const url = new URL('https://as.example.com/jwks'); + const JWKS = createRemoteJWKSet(url); + { + const [jwk] = keys; + const key = await parseJwk({ ...jwk, alg: 'PS256' }); + const jwt = await new SignJWT({}) + .setProtectedHeader({ alg: 'PS256', kid: jwk.kid }) + .sign(key); + await t.notThrowsAsync(jwtVerify(jwt, JWKS)); + } + { + const [jwk] = keys; + const key = await parseJwk({ ...jwk, alg: 'RS256' }); + const jwt = await new SignJWT({}).setProtectedHeader({ alg: 'RS256' }).sign(key); + await t.throwsAsync(jwtVerify(jwt, JWKS), { + code: 'ERR_JWKS_MULTIPLE_MATCHING_KEYS', + message: 'multiple matching keys found in the JSON Web Key Set', + }); + } + { + const [, jwk] = keys; + const key = await parseJwk({ ...jwk, alg: 'PS256' }); + const jwt = await new SignJWT({}) + .setProtectedHeader({ alg: 'PS256', kid: jwk.kid }) + .sign(key); + await t.throwsAsync(jwtVerify(jwt, JWKS), { + code: 'ERR_JWKS_NO_MATCHING_KEY', + message: 'no applicable key found in the JSON Web Key Set', + }); + } + { + const [, , jwk] = keys; + const key = await parseJwk({ ...jwk, alg: 'ES256' }); + const jwt = await new SignJWT({}).setProtectedHeader({ alg: 'ES256' }).sign(key); + await t.notThrowsAsync(jwtVerify(jwt, JWKS)); + } + }); + + test.serial('refreshes the JWKS once off cooldown', async (t) => { + let jwk = { + crv: 'P-256', + x: 'fqCXPnWs3sSfwztvwYU9SthmRdoT4WCXxS8eD8icF6U', + y: 'nP6GIc42c61hoKqPcZqkvzhzIJkBV3Jw3g8sGG7UeP8', + d: 'XikZvoy8ayRpOnuz7ont2DkgMxp_kmmg1EKcuIJWX_E', + kty: 'EC', + }; + const jwks = { + keys: [ + { + crv: 'P-256', + x: 'fqCXPnWs3sSfwztvwYU9SthmRdoT4WCXxS8eD8icF6U', + y: 'nP6GIc42c61hoKqPcZqkvzhzIJkBV3Jw3g8sGG7UeP8', + kty: 'EC', + kid: 'one', + }, + ], + }; + + const scope = nock('https://as.example.com').get('/jwks').once().reply(200, jwks); + + const url = new URL('https://as.example.com/jwks'); + const JWKS = createRemoteJWKSet(url); + const key = await parseJwk({ ...jwk, alg: 'ES256' }); + { + const jwt = await new SignJWT({}) + .setProtectedHeader({ alg: 'ES256', kid: 'one' }) + .sign(key); + await t.notThrowsAsync(jwtVerify(jwt, JWKS)); + await t.notThrowsAsync(jwtVerify(jwt, JWKS)); + } + { + const jwt = await new SignJWT({}) + .setProtectedHeader({ alg: 'ES256', kid: 'two' }) + .sign(key); + await t.throwsAsync(jwtVerify(jwt, JWKS), { + code: 'ERR_JWKS_NO_MATCHING_KEY', + message: 'no applicable key found in the JSON Web Key Set', + }); + jwks.keys[0].kid = 'two'; + scope.get('/jwks').once().reply(200, jwks); + timekeeper.travel((now + 30) * 1000); + await t.notThrowsAsync(jwtVerify(jwt, JWKS)); + } + }); + + test.serial('throws on invalid JWKSet', async (t) => { + const scope = nock('https://as.example.com').get('/jwks').once().reply(200, 'null'); + + const url = new URL('https://as.example.com/jwks'); + const JWKS = createRemoteJWKSet(url); + await t.throwsAsync(JWKS({ alg: 'RS256' }), { + code: 'ERR_JWKS_INVALID', + message: 'JSON Web Key Set malformed', + }); + + scope.get('/jwks').once().reply(200, {}); + await t.throwsAsync(JWKS({ alg: 'RS256' }), { + code: 'ERR_JWKS_INVALID', + message: 'JSON Web Key Set malformed', + }); + + scope.get('/jwks').once().reply(200, { keys: null }); + await t.throwsAsync(JWKS({ alg: 'RS256' }), { + code: 'ERR_JWKS_INVALID', + message: 'JSON Web Key Set malformed', + }); + + scope + .get('/jwks') + .once() + .reply(200, { keys: [null] }); + await t.throwsAsync(JWKS({ alg: 'RS256' }), { + code: 'ERR_JWKS_INVALID', + message: 'JSON Web Key Set malformed', + }); + + scope.get('/jwks').once().reply(404); + await t.throwsAsync(JWKS({ alg: 'RS256' }), { + code: 'ERR_JOSE_GENERIC', + message: 'Expected 200 OK from the JSON Web Key Set HTTP response', + }); + + scope.get('/jwks').once().reply(200, '{'); + await t.throwsAsync(JWKS({ alg: 'RS256' }), { + code: 'ERR_JOSE_GENERIC', + message: 'Failed to parse the JSON Web Key Set HTTP response as JSON', + }); + }); + }, + (err) => { + test.serial('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jws/b64.test.js b/test/jws/b64.test.js deleted file mode 100644 index 8e720102db..0000000000 --- a/test/jws/b64.test.js +++ /dev/null @@ -1,131 +0,0 @@ -const test = require('ava') - -const { randomBytes } = require('crypto') -const { JWK, JWS, errors } = require('../..') - -const k = JWK.asKey({ - kty: 'oct', - k: 'AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow' -}) - -const FIXTURE = { - protected: 'eyJhbGciOiJIUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19', - payload: '$.02', - signature: 'A5dxf2s96_n5FLueVuW1Z_vh161FwXZC4YLPff6dmDY' -} - -test('b64=false is supported for JWS', t => { - t.deepEqual( - JWS.sign.flattened('$.02', k, { alg: 'HS256', b64: false, crit: ['b64'] }), - FIXTURE - ) - - t.deepEqual(JWS.verify(FIXTURE, k, { crit: ['b64'] }), Buffer.from(FIXTURE.payload)) -}) - -test('b64=false is supported for JWS with multiple recipients (buffer input)', t => { - const s = new JWS.Sign(Buffer.from(FIXTURE.payload)) - s.recipient(k, { alg: 'HS256', b64: false, crit: ['b64'] }) - s.recipient(k, { alg: 'HS256', b64: false, crit: ['b64'] }) - - t.deepEqual( - s.sign('general'), - { - payload: Buffer.from(FIXTURE.payload), - signatures: [ - { protected: FIXTURE.protected, signature: FIXTURE.signature }, - { protected: FIXTURE.protected, signature: FIXTURE.signature } - ] - } - ) -}) - -test('b64=false is supported for JWS with multiple recipients (string input)', t => { - const s = new JWS.Sign(FIXTURE.payload) - s.recipient(k, { alg: 'HS256', b64: false, crit: ['b64'] }) - s.recipient(k, { alg: 'HS256', b64: false, crit: ['b64'] }) - - t.deepEqual( - s.sign('general'), - { - payload: FIXTURE.payload, - signatures: [ - { protected: FIXTURE.protected, signature: FIXTURE.signature }, - { protected: FIXTURE.protected, signature: FIXTURE.signature } - ] - } - ) -}) - -test('b64=false with buffers', t => { - const payload = randomBytes(32) - const { payload: _, ...detached } = JWS.sign.flattened(payload, k, { alg: 'HS256', b64: false, crit: ['b64'] }) - - t.deepEqual(JWS.verify({ ...detached, payload }, k, { crit: ['b64'] }), payload) -}) - -test('b64=true is also allowed', t => { - const jws = JWS.sign.flattened('$.02', k, { alg: 'HS256', b64: true, crit: ['b64'] }) - t.is(jws.payload, 'JC4wMg') - t.deepEqual(JWS.verify(FIXTURE, k, { crit: ['b64'] }), Buffer.from(FIXTURE.payload)) -}) - -test('b64 must be integrity protected', t => { - t.throws(() => { - JWS.sign.flattened('foo', k, { alg: 'HS256', crit: ['b64'] }, { b64: true }) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: '"b64" critical parameter must be integrity protected' }) -}) - -test('b64 must be a boolean', t => { - t.throws(() => { - JWS.sign.flattened('foo', k, { alg: 'HS256', crit: ['b64'], b64: 'true' }) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: '"b64" critical parameter must be a boolean' }) -}) - -test('b64 must be the same for all recipients', t => { - { - const sign = new JWS.Sign('$.02') - sign.recipient(k, { crit: ['b64'], b64: false }) - sign.recipient(k, { crit: ['b64'], b64: true }) - - t.throws(() => { - sign.sign('general') - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'the "b64" Header Parameter value MUST be the same for all recipients' }) - } - - { - const sign = new JWS.Sign('$.02') - sign.recipient(k) - sign.recipient(k, { crit: ['b64'], b64: true }) - t.throws(() => { - sign.sign('general') - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'the "b64" Header Parameter value MUST be the same for all recipients' }) - } - - { - const sign = new JWS.Sign('$.02') - sign.recipient(k, { crit: ['b64'], b64: true }) - sign.recipient(k) - t.throws(() => { - sign.sign('general') - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'the "b64" Header Parameter value MUST be the same for all recipients' }) - } - - { - const sign = new JWS.Sign('$.02') - sign.recipient(k) - sign.recipient(k, { crit: ['b64'], b64: false }) - t.throws(() => { - sign.sign('general') - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'the "b64" Header Parameter value MUST be the same for all recipients' }) - } - - { - const sign = new JWS.Sign('$.02') - sign.recipient(k, { crit: ['b64'], b64: false }) - sign.recipient(k) - t.throws(() => { - sign.sign('general') - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'the "b64" Header Parameter value MUST be the same for all recipients' }) - } -}) diff --git a/test/jws/compact.sign.test.mjs b/test/jws/compact.sign.test.mjs new file mode 100644 index 0000000000..08c33a70ce --- /dev/null +++ b/test/jws/compact.sign.test.mjs @@ -0,0 +1,56 @@ +/* eslint-disable no-param-reassign */ +import test from 'ava'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +import(`${root}/jws/compact/sign`).then( + ({ default: CompactSign }) => { + test.before((t) => { + const encode = TextEncoder.prototype.encode.bind(new TextEncoder()); + t.context.payload = encode('It’s a dangerous business, Frodo, going out your door.'); + t.context.secret = new Uint8Array(32); + }); + + test('CompactSign', async (t) => { + const jws = await new CompactSign(t.context.payload) + .setProtectedHeader({ alg: 'HS256' }) + .sign(t.context.secret); + t.is( + jws, + 'eyJhbGciOiJIUzI1NiJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4.UKohvCM6JaKEJlDt7ApBPgcQMW4lmp-UGXfwPmCfUaA', + ); + }); + + test('CompactSign.prototype.setProtectedHeader', (t) => { + t.throws( + () => new CompactSign(t.context.payload).setProtectedHeader({}).setProtectedHeader({}), + { + instanceOf: TypeError, + message: 'setProtectedHeader can only be called once', + }, + ); + }); + + test('CompactSign.prototype.sign must have a JOSE header', async (t) => { + await t.throwsAsync(new CompactSign(t.context.payload).sign(t.context.secret), { + code: 'ERR_JWS_INVALID', + message: 'either setProtectedHeader or setUnprotectedHeader must be called before #sign()', + }); + }); + + test('CompactSign.prototype.sign JOSE header have an alg', async (t) => { + await t.throwsAsync( + new CompactSign(t.context.payload).setProtectedHeader({}).sign(t.context.secret), + { + code: 'ERR_JWS_INVALID', + message: 'missing JWS signature algorithm in JWS Header', + }, + ); + }); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jws/compact.verify.test.mjs b/test/jws/compact.verify.test.mjs new file mode 100644 index 0000000000..cb0a4129c5 --- /dev/null +++ b/test/jws/compact.verify.test.mjs @@ -0,0 +1,24 @@ +/* eslint-disable no-param-reassign */ +import test from 'ava'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +import(`${root}/jws/compact/verify`).then( + ({ default: flattenedVerify }) => { + test('JWS format validation', async (t) => { + await t.throwsAsync(flattenedVerify(null, new Uint8Array()), { + message: 'Compact JWS must be a string', + code: 'ERR_JWS_INVALID', + }); + await t.throwsAsync(flattenedVerify('.....', new Uint8Array()), { + message: 'Invalid Compact JWS', + code: 'ERR_JWS_INVALID', + }); + }); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jws/complete.test.js b/test/jws/complete.test.js deleted file mode 100644 index 90b942917c..0000000000 --- a/test/jws/complete.test.js +++ /dev/null @@ -1,39 +0,0 @@ -const test = require('ava') - -const { JWKS, JWK: { generateSync }, JWS } = require('../..') -const Key = require('../../lib/jwk/key/base') -const key = generateSync('oct') -const ks = new JWKS.KeyStore(generateSync('EC'), key) - -const complete = (t, jws, k, ...keys) => { - if (typeof k === 'string') { - keys.unshift(k) - k = key - } - const verified = JWS.verify(jws(), k, { complete: true }) - t.is(Object.values(verified).length, keys.length) - if (k instanceof Key) { - t.is(verified.key, k) - } else { - t.is(verified.key, ks.get(verified.protected)) - } - if (keys.includes('header')) { - t.is(typeof verified.header, 'object') - } - if (keys.includes('protected')) { - t.is(typeof verified.protected, 'object') - } - t.is(typeof verified.payload, 'object') -} - -test('compact', complete, () => JWS.sign({}, key), 'payload', 'protected', 'key') -test('flattened', complete, () => JWS.sign.flattened({}, key), 'payload', 'protected', 'key') -test('flattened w/ header', complete, () => JWS.sign.flattened({}, key, undefined, { foo: 'bar' }), 'payload', 'protected', 'header', 'key') -test('general', complete, () => JWS.sign.general({}, key), 'payload', 'protected', 'key') -test('general w/ header', complete, () => JWS.sign.general({}, key, undefined, { foo: 'bar' }), 'payload', 'protected', 'header', 'key') - -test('with keystore > compact', complete, () => JWS.sign({}, key), ks, 'payload', 'protected', 'key') -test('with keystore > flattened', complete, () => JWS.sign.flattened({}, key), ks, 'payload', 'protected', 'key') -test('with keystore > flattened w/ header', complete, () => JWS.sign.flattened({}, key, undefined, { foo: 'bar' }), ks, 'payload', 'protected', 'header', 'key') -test('with keystore > general', complete, () => JWS.sign.general({}, key), ks, 'payload', 'protected', 'key') -test('with keystore > general w/ header', complete, () => JWS.sign.general({}, key, undefined, { foo: 'bar' }), ks, 'payload', 'protected', 'header', 'key') diff --git a/test/jws/cookbook.test.mjs b/test/jws/cookbook.test.mjs new file mode 100644 index 0000000000..106b841cee --- /dev/null +++ b/test/jws/cookbook.test.mjs @@ -0,0 +1,520 @@ +import test from 'ava'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; + +Promise.all([ + import(`${root}/jws/flattened/sign`), + import(`${root}/jws/flattened/verify`), + import(`${root}/jws/compact/sign`), + import(`${root}/jws/compact/verify`), + import(`${root}/jwk/parse`), +]).then( + ([ + { default: FlattenedSign }, + { default: flattenedVerify }, + { default: CompactSign }, + { default: compactVerify }, + { default: parseJwk }, + ]) => { + const flattened = { + Sign: FlattenedSign, + verify: flattenedVerify, + }; + const compact = { + Sign: CompactSign, + verify: compactVerify, + }; + + const encode = TextEncoder.prototype.encode.bind(new TextEncoder()); + + const pubjwk = ({ d, p, q, dp, dq, qi, ...jwk }) => jwk; + + async function testCookbook(t, vector) { + const reproducible = !!vector.reproducible; + + if (reproducible) { + // sign and compare results are the same + const runs = [[flattened, vector.output.json_flat]]; + if ( + !vector.signing.protected || + !('b64' in vector.signing.protected) || + vector.signing.protected.b64 === true + ) { + runs.push([compact, vector.output.compact]); + } + for (const [serialization, expectedResult] of runs) { + if (!expectedResult) { + // eslint-disable-next-line no-continue + continue; + } + const sign = new serialization.Sign(encode(vector.input.payload)); + + if (vector.signing.protected) { + sign.setProtectedHeader(vector.signing.protected); + } + + if (vector.signing.unprotected) { + sign.setUnprotectedHeader(vector.signing.unprotected); + } + + const privateKey = await parseJwk(vector.input.key, vector.input.alg); + + const result = await sign.sign(privateKey); + + if (typeof result === 'object') { + Object.entries(expectedResult).forEach(([prop, expected]) => { + if ( + prop === 'payload' && + vector.signing.protected && + vector.signing.protected.b64 === false + ) + return; + t.is(JSON.stringify(result[prop]), JSON.stringify(expected)); + }); + } else { + t.is(result, expectedResult); + } + } + } else { + const sign = new flattened.Sign(encode(vector.input.payload)); + + if (vector.signing.protected) { + sign.setProtectedHeader(vector.signing.protected); + } + + if (vector.signing.unprotected) { + sign.setUnprotectedHeader(vector.signing.unprotected); + } + + const privateKey = await parseJwk(vector.input.key, vector.input.alg); + const publicKey = await parseJwk(pubjwk(vector.input.key), vector.input.alg); + + const result = await sign.sign(privateKey); + await t.notThrowsAsync(flattened.verify(result, publicKey)); + } + + const publicKey = await parseJwk(pubjwk(vector.input.key), vector.input.alg); + + if (vector.output.json_flat) { + await t.notThrowsAsync(flattened.verify(vector.output.json_flat, publicKey)); + } + if (vector.output.compact) { + await t.notThrowsAsync(compact.verify(vector.output.compact, publicKey)); + } + } + testCookbook.title = (title, vector) => `${vector.title}${title ? ` ${title}` : ''}`; + + const vectors = [ + { + title: 'https://tools.ietf.org/html/rfc7520#section-4.1 - RSA v1.5 Signature', + webcrypto: true, + reproducible: true, + input: { + payload: + "It’s a dangerous business, Frodo, going out your door. You step onto the road, and if you don't keep your feet, there’s no knowing where you might be swept off to.", + key: { + kty: 'RSA', + ext: false, + kid: 'bilbo.baggins@hobbiton.example', + use: 'sig', + n: + 'n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw', + e: 'AQAB', + d: + 'bWUC9B-EFRIo8kpGfh0ZuyGPvMNKvYWNtB_ikiH9k20eT-O1q_I78eiZkpXxXQ0UTEs2LsNRS-8uJbvQ-A1irkwMSMkK1J3XTGgdrhCku9gRldY7sNA_AKZGh-Q661_42rINLRCe8W-nZ34ui_qOfkLnK9QWDDqpaIsA-bMwWWSDFu2MUBYwkHTMEzLYGqOe04noqeq1hExBTHBOBdkMXiuFhUq1BU6l-DqEiWxqg82sXt2h-LMnT3046AOYJoRioz75tSUQfGCshWTBnP5uDjd18kKhyv07lhfSJdrPdM5Plyl21hsFf4L_mHCuoFau7gdsPfHPxxjVOcOpBrQzwQ', + p: + '3Slxg_DwTXJcb6095RoXygQCAZ5RnAvZlno1yhHtnUex_fp7AZ_9nRaO7HX_-SFfGQeutao2TDjDAWU4Vupk8rw9JR0AzZ0N2fvuIAmr_WCsmGpeNqQnev1T7IyEsnh8UMt-n5CafhkikzhEsrmndH6LxOrvRJlsPp6Zv8bUq0k', + q: + 'uKE2dh-cTf6ERF4k4e_jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR_cu0Dm1MZwWmtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7z4yMkuUwFWoBvyY898EXvRD-hdqRxHlSqAZ192zB3pVFJ0s7pFc', + dp: + 'B8PVvXkvJrj2L-GYQ7v3y9r6Kw5g9SahXBwsWUzp19TVlgI-YV85q1NIb1rxQtD-IsXXR3-TanevuRPRt5OBOdiMGQp8pbt26gljYfKU_E9xn-RULHz0-ed9E9gXLKD4VGngpz-PfQ_q29pk5xWHoJp009Qf1HvChixRX59ehik', + dq: + 'CLDmDGduhylc9o7r84rEUVn7pzQ6PF83Y-iBZx5NT-TpnOZKF1pErAMVeKzFEl41DlHHqqBLSM0W1sOFbwTxYWZDm6sI6og5iTbwQGIC3gnJKbi_7k_vJgGHwHxgPaX2PnvP-zyEkDERuf-ry4c_Z11Cq9AqC2yeL6kdKT1cYF8', + qi: + '3PiqvXQN0zwMeE-sBvZgi289XP9XCQF3VWqPzMKnIgQp7_Tugo6-NZBKCQsMf3HaEGBjTVJs_jcK8-TRXvaKe-7ZMaQj8VfBdYkssbu0NKDDhjJ-GtiseaDVWt7dcH0cfwxgFUHpQh7FoCrjFJ6h6ZEpMF6xmujs4qMpPz8aaI4', + }, + alg: 'RS256', + }, + signing: { + protected: { + alg: 'RS256', + kid: 'bilbo.baggins@hobbiton.example', + }, + }, + output: { + compact: + 'eyJhbGciOiJSUzI1NiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4.MRjdkly7_-oTPTS3AXP41iQIGKa80A0ZmTuV5MEaHoxnW2e5CZ5NlKtainoFmKZopdHM1O2U4mwzJdQx996ivp83xuglII7PNDi84wnB-BDkoBwA78185hX-Es4JIwmDLJK3lfWRa-XtL0RnltuYv746iYTh_qHRD68BNt1uSNCrUCTJDt5aAE6x8wW1Kt9eRo4QPocSadnHXFxnt8Is9UzpERV0ePPQdLuW3IS_de3xyIrDaLGdjluPxUAhb6L2aXic1U12podGU0KLUQSE_oI-ZnmKJ3F4uOZDnd6QZWJushZ41Axf_fcIe8u9ipH84ogoree7vjbU5y18kDquDg', + json: { + payload: + 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', + signatures: [ + { + protected: + 'eyJhbGciOiJSUzI1NiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9', + signature: + 'MRjdkly7_-oTPTS3AXP41iQIGKa80A0ZmTuV5MEaHoxnW2e5CZ5NlKtainoFmKZopdHM1O2U4mwzJdQx996ivp83xuglII7PNDi84wnB-BDkoBwA78185hX-Es4JIwmDLJK3lfWRa-XtL0RnltuYv746iYTh_qHRD68BNt1uSNCrUCTJDt5aAE6x8wW1Kt9eRo4QPocSadnHXFxnt8Is9UzpERV0ePPQdLuW3IS_de3xyIrDaLGdjluPxUAhb6L2aXic1U12podGU0KLUQSE_oI-ZnmKJ3F4uOZDnd6QZWJushZ41Axf_fcIe8u9ipH84ogoree7vjbU5y18kDquDg', + }, + ], + }, + json_flat: { + payload: + 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', + protected: 'eyJhbGciOiJSUzI1NiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9', + signature: + 'MRjdkly7_-oTPTS3AXP41iQIGKa80A0ZmTuV5MEaHoxnW2e5CZ5NlKtainoFmKZopdHM1O2U4mwzJdQx996ivp83xuglII7PNDi84wnB-BDkoBwA78185hX-Es4JIwmDLJK3lfWRa-XtL0RnltuYv746iYTh_qHRD68BNt1uSNCrUCTJDt5aAE6x8wW1Kt9eRo4QPocSadnHXFxnt8Is9UzpERV0ePPQdLuW3IS_de3xyIrDaLGdjluPxUAhb6L2aXic1U12podGU0KLUQSE_oI-ZnmKJ3F4uOZDnd6QZWJushZ41Axf_fcIe8u9ipH84ogoree7vjbU5y18kDquDg', + }, + }, + }, + { + title: 'https://tools.ietf.org/html/rfc8037#appendix-A.4 - Ed25519 Signing', + webcrypto: false, + reproducible: true, + input: { + payload: 'Example of Ed25519 signing', + key: { + kty: 'OKP', + ext: false, + crv: 'Ed25519', + d: 'nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A', + x: '11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo', + }, + alg: 'EdDSA', + }, + signing: { + protected: { + alg: 'EdDSA', + }, + }, + output: { + compact: + 'eyJhbGciOiJFZERTQSJ9.RXhhbXBsZSBvZiBFZDI1NTE5IHNpZ25pbmc.hgyY0il_MGCjP0JzlnLWG1PPOt7-09PGcvMg3AIbQR6dWbhijcNR4ki4iylGjg5BhVsPt9g7sVvpAr_MuM0KAg', + json: { + payload: 'RXhhbXBsZSBvZiBFZDI1NTE5IHNpZ25pbmc', + signatures: [ + { + protected: 'eyJhbGciOiJFZERTQSJ9', + signature: + 'hgyY0il_MGCjP0JzlnLWG1PPOt7-09PGcvMg3AIbQR6dWbhijcNR4ki4iylGjg5BhVsPt9g7sVvpAr_MuM0KAg', + }, + ], + }, + json_flat: { + payload: 'RXhhbXBsZSBvZiBFZDI1NTE5IHNpZ25pbmc', + protected: 'eyJhbGciOiJFZERTQSJ9', + signature: + 'hgyY0il_MGCjP0JzlnLWG1PPOt7-09PGcvMg3AIbQR6dWbhijcNR4ki4iylGjg5BhVsPt9g7sVvpAr_MuM0KAg', + }, + }, + }, + { + title: 'https://tools.ietf.org/html/rfc7520#section-4.2 - RSA-PSS Signature', + webcrypto: true, + input: { + payload: + "It’s a dangerous business, Frodo, going out your door. You step onto the road, and if you don't keep your feet, there’s no knowing where you might be swept off to.", + key: { + kty: 'RSA', + ext: false, + kid: 'bilbo.baggins@hobbiton.example', + use: 'sig', + n: + 'n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw', + e: 'AQAB', + d: + 'bWUC9B-EFRIo8kpGfh0ZuyGPvMNKvYWNtB_ikiH9k20eT-O1q_I78eiZkpXxXQ0UTEs2LsNRS-8uJbvQ-A1irkwMSMkK1J3XTGgdrhCku9gRldY7sNA_AKZGh-Q661_42rINLRCe8W-nZ34ui_qOfkLnK9QWDDqpaIsA-bMwWWSDFu2MUBYwkHTMEzLYGqOe04noqeq1hExBTHBOBdkMXiuFhUq1BU6l-DqEiWxqg82sXt2h-LMnT3046AOYJoRioz75tSUQfGCshWTBnP5uDjd18kKhyv07lhfSJdrPdM5Plyl21hsFf4L_mHCuoFau7gdsPfHPxxjVOcOpBrQzwQ', + p: + '3Slxg_DwTXJcb6095RoXygQCAZ5RnAvZlno1yhHtnUex_fp7AZ_9nRaO7HX_-SFfGQeutao2TDjDAWU4Vupk8rw9JR0AzZ0N2fvuIAmr_WCsmGpeNqQnev1T7IyEsnh8UMt-n5CafhkikzhEsrmndH6LxOrvRJlsPp6Zv8bUq0k', + q: + 'uKE2dh-cTf6ERF4k4e_jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR_cu0Dm1MZwWmtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7z4yMkuUwFWoBvyY898EXvRD-hdqRxHlSqAZ192zB3pVFJ0s7pFc', + dp: + 'B8PVvXkvJrj2L-GYQ7v3y9r6Kw5g9SahXBwsWUzp19TVlgI-YV85q1NIb1rxQtD-IsXXR3-TanevuRPRt5OBOdiMGQp8pbt26gljYfKU_E9xn-RULHz0-ed9E9gXLKD4VGngpz-PfQ_q29pk5xWHoJp009Qf1HvChixRX59ehik', + dq: + 'CLDmDGduhylc9o7r84rEUVn7pzQ6PF83Y-iBZx5NT-TpnOZKF1pErAMVeKzFEl41DlHHqqBLSM0W1sOFbwTxYWZDm6sI6og5iTbwQGIC3gnJKbi_7k_vJgGHwHxgPaX2PnvP-zyEkDERuf-ry4c_Z11Cq9AqC2yeL6kdKT1cYF8', + qi: + '3PiqvXQN0zwMeE-sBvZgi289XP9XCQF3VWqPzMKnIgQp7_Tugo6-NZBKCQsMf3HaEGBjTVJs_jcK8-TRXvaKe-7ZMaQj8VfBdYkssbu0NKDDhjJ-GtiseaDVWt7dcH0cfwxgFUHpQh7FoCrjFJ6h6ZEpMF6xmujs4qMpPz8aaI4', + }, + alg: 'PS384', + }, + signing: { + protected: { + alg: 'PS384', + kid: 'bilbo.baggins@hobbiton.example', + }, + }, + output: { + compact: + 'eyJhbGciOiJQUzM4NCIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4.cu22eBqkYDKgIlTpzDXGvaFfz6WGoz7fUDcfT0kkOy42miAh2qyBzk1xEsnk2IpN6-tPid6VrklHkqsGqDqHCdP6O8TTB5dDDItllVo6_1OLPpcbUrhiUSMxbbXUvdvWXzg-UD8biiReQFlfz28zGWVsdiNAUf8ZnyPEgVFn442ZdNqiVJRmBqrYRXe8P_ijQ7p8Vdz0TTrxUeT3lm8d9shnr2lfJT8ImUjvAA2Xez2Mlp8cBE5awDzT0qI0n6uiP1aCN_2_jLAeQTlqRHtfa64QQSUmFAAjVKPbByi7xho0uTOcbH510a6GYmJUAfmWjwZ6oD4ifKo8DYM-X72Eaw', + json: { + payload: + 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', + signatures: [ + { + protected: + 'eyJhbGciOiJQUzM4NCIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9', + signature: + 'cu22eBqkYDKgIlTpzDXGvaFfz6WGoz7fUDcfT0kkOy42miAh2qyBzk1xEsnk2IpN6-tPid6VrklHkqsGqDqHCdP6O8TTB5dDDItllVo6_1OLPpcbUrhiUSMxbbXUvdvWXzg-UD8biiReQFlfz28zGWVsdiNAUf8ZnyPEgVFn442ZdNqiVJRmBqrYRXe8P_ijQ7p8Vdz0TTrxUeT3lm8d9shnr2lfJT8ImUjvAA2Xez2Mlp8cBE5awDzT0qI0n6uiP1aCN_2_jLAeQTlqRHtfa64QQSUmFAAjVKPbByi7xho0uTOcbH510a6GYmJUAfmWjwZ6oD4ifKo8DYM-X72Eaw', + }, + ], + }, + json_flat: { + payload: + 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', + protected: 'eyJhbGciOiJQUzM4NCIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9', + signature: + 'cu22eBqkYDKgIlTpzDXGvaFfz6WGoz7fUDcfT0kkOy42miAh2qyBzk1xEsnk2IpN6-tPid6VrklHkqsGqDqHCdP6O8TTB5dDDItllVo6_1OLPpcbUrhiUSMxbbXUvdvWXzg-UD8biiReQFlfz28zGWVsdiNAUf8ZnyPEgVFn442ZdNqiVJRmBqrYRXe8P_ijQ7p8Vdz0TTrxUeT3lm8d9shnr2lfJT8ImUjvAA2Xez2Mlp8cBE5awDzT0qI0n6uiP1aCN_2_jLAeQTlqRHtfa64QQSUmFAAjVKPbByi7xho0uTOcbH510a6GYmJUAfmWjwZ6oD4ifKo8DYM-X72Eaw', + }, + }, + }, + { + title: 'https://tools.ietf.org/html/rfc7520#section-4.3 - ECDSA Signature', + webcrypto: true, + input: { + payload: + "It’s a dangerous business, Frodo, going out your door. You step onto the road, and if you don't keep your feet, there’s no knowing where you might be swept off to.", + key: { + kty: 'EC', + ext: false, + kid: 'bilbo.baggins@hobbiton.example', + use: 'sig', + crv: 'P-521', + x: + 'AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt', + y: + 'AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVySsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1', + d: + 'AAhRON2r9cqXX1hg-RoI6R1tX5p2rUAYdmpHZoC1XNM56KtscrX6zbKipQrCW9CGZH3T4ubpnoTKLDYJ_fF3_rJt', + }, + alg: 'ES512', + }, + signing: { + protected: { + alg: 'ES512', + kid: 'bilbo.baggins@hobbiton.example', + }, + }, + output: { + compact: + 'eyJhbGciOiJFUzUxMiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4.AE_R_YZCChjn4791jSQCrdPZCNYqHXCTZH0-JZGYNlaAjP2kqaluUIIUnC9qvbu9Plon7KRTzoNEuT4Va2cmL1eJAQy3mtPBu_u_sDDyYjnAMDxXPn7XrT0lw-kvAD890jl8e2puQens_IEKBpHABlsbEPX6sFY8OcGDqoRuBomu9xQ2', + json: { + payload: + 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', + signatures: [ + { + protected: + 'eyJhbGciOiJFUzUxMiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9', + signature: + 'AE_R_YZCChjn4791jSQCrdPZCNYqHXCTZH0-JZGYNlaAjP2kqaluUIIUnC9qvbu9Plon7KRTzoNEuT4Va2cmL1eJAQy3mtPBu_u_sDDyYjnAMDxXPn7XrT0lw-kvAD890jl8e2puQens_IEKBpHABlsbEPX6sFY8OcGDqoRuBomu9xQ2', + }, + ], + }, + json_flat: { + payload: + 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', + protected: 'eyJhbGciOiJFUzUxMiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9', + signature: + 'AE_R_YZCChjn4791jSQCrdPZCNYqHXCTZH0-JZGYNlaAjP2kqaluUIIUnC9qvbu9Plon7KRTzoNEuT4Va2cmL1eJAQy3mtPBu_u_sDDyYjnAMDxXPn7XrT0lw-kvAD890jl8e2puQens_IEKBpHABlsbEPX6sFY8OcGDqoRuBomu9xQ2', + }, + }, + }, + { + title: 'https://tools.ietf.org/html/rfc7520#section-4.4 - HMAC-SHA2 Integrity Protection', + webcrypto: true, + reproducible: true, + input: { + payload: + "It’s a dangerous business, Frodo, going out your door. You step onto the road, and if you don't keep your feet, there’s no knowing where you might be swept off to.", + key: { + kty: 'oct', + ext: false, + kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037', + use: 'sig', + alg: 'HS256', + k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg', + }, + alg: 'HS256', + }, + signing: { + protected: { + alg: 'HS256', + kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037', + }, + }, + output: { + compact: + 'eyJhbGciOiJIUzI1NiIsImtpZCI6IjAxOGMwYWU1LTRkOWItNDcxYi1iZmQ2LWVlZjMxNGJjNzAzNyJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4.s0h6KThzkfBBBkLspW1h84VsJZFTsPPqMDA7g1Md7p0', + json: { + payload: + 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', + signatures: [ + { + protected: + 'eyJhbGciOiJIUzI1NiIsImtpZCI6IjAxOGMwYWU1LTRkOWItNDcxYi1iZmQ2LWVlZjMxNGJjNzAzNyJ9', + signature: 's0h6KThzkfBBBkLspW1h84VsJZFTsPPqMDA7g1Md7p0', + }, + ], + }, + json_flat: { + payload: + 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', + protected: + 'eyJhbGciOiJIUzI1NiIsImtpZCI6IjAxOGMwYWU1LTRkOWItNDcxYi1iZmQ2LWVlZjMxNGJjNzAzNyJ9', + signature: 's0h6KThzkfBBBkLspW1h84VsJZFTsPPqMDA7g1Md7p0', + }, + }, + }, + { + title: + 'https://tools.ietf.org/html/rfc7520#section-4.6 - Protecting Specific Header Fields', + reproducible: true, + input: { + payload: + "It’s a dangerous business, Frodo, going out your door. You step onto the road, and if you don't keep your feet, there’s no knowing where you might be swept off to.", + key: { + kty: 'oct', + ext: false, + kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037', + use: 'sig', + alg: 'HS256', + k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg', + }, + alg: 'HS256', + }, + signing: { + protected: { + alg: 'HS256', + }, + unprotected: { + kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037', + }, + }, + output: { + json: { + payload: + 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', + signatures: [ + { + protected: 'eyJhbGciOiJIUzI1NiJ9', + header: { + kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037', + }, + signature: 'bWUSVaxorn7bEF1djytBd0kHv70Ly5pvbomzMWSOr20', + }, + ], + }, + json_flat: { + payload: + 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', + protected: 'eyJhbGciOiJIUzI1NiJ9', + header: { + kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037', + }, + signature: 'bWUSVaxorn7bEF1djytBd0kHv70Ly5pvbomzMWSOr20', + }, + }, + }, + { + title: 'https://tools.ietf.org/html/rfc7520#section-4.7 - Protecting Content Only', + webcrypto: true, + reproducible: true, + input: { + payload: + "It’s a dangerous business, Frodo, going out your door. You step onto the road, and if you don't keep your feet, there’s no knowing where you might be swept off to.", + key: { + kty: 'oct', + ext: false, + kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037', + use: 'sig', + alg: 'HS256', + k: 'hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg', + }, + alg: 'HS256', + }, + signing: { + unprotected: { + alg: 'HS256', + kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037', + }, + }, + output: { + json: { + payload: + 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', + signatures: [ + { + header: { + alg: 'HS256', + kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037', + }, + signature: 'xuLifqLGiblpv9zBpuZczWhNj1gARaLV3UxvxhJxZuk', + }, + ], + }, + json_flat: { + payload: + 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4', + header: { + alg: 'HS256', + kid: '018c0ae5-4d9b-471b-bfd6-eef314bc7037', + }, + signature: 'xuLifqLGiblpv9zBpuZczWhNj1gARaLV3UxvxhJxZuk', + }, + }, + }, + { + title: 'https://tools.ietf.org/html/rfc7797#section-4.1 - { "b64": false } JSON only', + webcrypto: true, + reproducible: true, + input: { + payload: '$.02', + key: { + kty: 'oct', + ext: false, + alg: 'HS256', + k: + 'AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow', + }, + alg: 'HS256', + }, + signing: { + protected: { + alg: 'HS256', + b64: false, + crit: ['b64'], + }, + }, + output: { + json: { + payload: '$.02', + signatures: [ + { + protected: 'eyJhbGciOiJIUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19', + signature: 'A5dxf2s96_n5FLueVuW1Z_vh161FwXZC4YLPff6dmDY', + }, + ], + }, + json_flat: { + payload: '$.02', + protected: 'eyJhbGciOiJIUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19', + signature: 'A5dxf2s96_n5FLueVuW1Z_vh161FwXZC4YLPff6dmDY', + }, + }, + }, + ]; + + for (const vector of vectors) { + let conditional; + if ('WEBCRYPTO' in process.env && vector.webcrypto === false) { + conditional = test.failing; + } else { + conditional = test; + } + if (vector.skip) { + conditional = test.skip; + } + if (vector.only) { + conditional = test.only; + } + conditional(testCookbook, vector); + } + }, +); diff --git a/test/jws/crit.test.js b/test/jws/crit.test.js deleted file mode 100644 index c14464b4fe..0000000000 --- a/test/jws/crit.test.js +++ /dev/null @@ -1,84 +0,0 @@ -const test = require('ava') - -const base64url = require('../../lib/help/base64url') -const { JWK: { generateSync }, JWS, errors } = require('../..') - -const UNDEFINED = 'http://example.invalid/UNDEFINED' - -test('crit must be understood', t => { - const k = generateSync('oct') - const jws = JWS.sign({}, k, { crit: [UNDEFINED], [UNDEFINED]: true }) - t.throws(() => { - JWS.verify(jws, k) - }, { instanceOf: errors.JOSECritNotUnderstood, code: 'ERR_JOSE_CRIT_NOT_UNDERSTOOD', message: `critical "${UNDEFINED}" is not understood` }) - JWS.verify(jws, k, { crit: [UNDEFINED] }) -}) - -test('crit must be present', t => { - const k = generateSync('oct') - t.throws(() => { - JWS.sign({}, k, { crit: [UNDEFINED] }) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: `critical parameter "${UNDEFINED}" is missing` }) - t.throws(() => { - JWS.verify( - `${base64url.JSON.encode({ alg: 'HS256', crit: [UNDEFINED] })}.${base64url.JSON.encode({})}.`, - k, - { crit: [UNDEFINED] } - ) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: `critical parameter "${UNDEFINED}" is missing` }) -}) - -test('crit must be integrity protected', t => { - const k = generateSync('oct') - t.throws(() => { - JWS.sign.flattened({}, k, undefined, { crit: [UNDEFINED] }) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: '"crit" Header Parameter MUST be integrity protected when present' }) - const jws = JWS.sign.flattened({}, k) - jws.header = { crit: [UNDEFINED] } - t.throws(() => { - JWS.verify(jws, k, { crit: [UNDEFINED] }) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: '"crit" Header Parameter MUST be integrity protected when present' }) -}) - -test('crit must be an array of strings', t => { - const k = generateSync('oct') - ;[{}, new Object(), false, null, Infinity, 0, Buffer.from('foo'), '', []].forEach((val) => { // eslint-disable-line no-new-object - t.throws(() => { - JWS.sign({}, k, { crit: val }) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: '"crit" Header Parameter MUST be an array of non-empty strings when present' }) - t.throws(() => { - JWS.sign({}, k, { crit: [val] }) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: '"crit" Header Parameter MUST be an array of non-empty strings when present' }) - }) -}) - -test('crit option be an array of strings', t => { - ;[{}, new Object(), false, null, Infinity, 0, '', Buffer.from('foo')].forEach((val) => { // eslint-disable-line no-new-object - t.throws(() => { - JWS.verify({ - header: { alg: 'HS256' }, - payload: 'foo', - signature: 'bar' - }, generateSync('oct'), { crit: val }) - }, { instanceOf: TypeError, message: '"crit" option must be an array of non-empty strings' }) - t.throws(() => { - JWS.verify({ - header: { alg: 'HS256' }, - payload: 'foo', - signature: 'bar' - }, generateSync('oct'), { crit: [val] }) - }, { instanceOf: TypeError, message: '"crit" option must be an array of non-empty strings' }) - }) -}) - -test('crit must not contain JWE/JWS/JWA defined header parameters', t => { - const k = generateSync('oct') - ;[ - 'alg', 'jku', 'jwk', 'kid', 'x5u', 'x5c', 'x5t', 'x5t#S256', 'typ', 'cty', - 'crit', 'enc', 'zip', 'epk', 'apu', 'apv', 'iv', 'tag', 'p2s', 'p2c' - ].forEach((crit) => { - t.throws(() => { - JWS.sign({}, k, { crit: [crit] }) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: `The critical list contains a non-extension Header Parameter ${crit}` }) - }) -}) diff --git a/test/jws/flattened.sign.test.mjs b/test/jws/flattened.sign.test.mjs new file mode 100644 index 0000000000..5220af4202 --- /dev/null +++ b/test/jws/flattened.sign.test.mjs @@ -0,0 +1,134 @@ +/* eslint-disable no-param-reassign */ +import test from 'ava'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +import(`${root}/jws/flattened/sign`).then( + ({ default: FlattenedSign }) => { + test.before(async (t) => { + const encode = TextEncoder.prototype.encode.bind(new TextEncoder()); + t.context.payload = encode('It’s a dangerous business, Frodo, going out your door.'); + t.context.secret = new Uint8Array(32); + }); + + test('FlattenedSign', async (t) => { + { + const jws = await new FlattenedSign(t.context.payload) + .setProtectedHeader({ alg: 'HS256' }) + .setUnprotectedHeader({ foo: 'bar' }) + .sign(t.context.secret); + t.deepEqual(jws, { + header: { + foo: 'bar', + }, + payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4', + protected: 'eyJhbGciOiJIUzI1NiJ9', + signature: 'UKohvCM6JaKEJlDt7ApBPgcQMW4lmp-UGXfwPmCfUaA', + }); + } + { + const jws = await new FlattenedSign(t.context.payload) + .setProtectedHeader({ alg: 'HS256' }) + .sign(t.context.secret); + t.deepEqual(jws, { + protected: 'eyJhbGciOiJIUzI1NiJ9', + payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4', + signature: 'UKohvCM6JaKEJlDt7ApBPgcQMW4lmp-UGXfwPmCfUaA', + }); + } + { + const jws = await new FlattenedSign(t.context.payload) + .setUnprotectedHeader({ alg: 'HS256' }) + .sign(t.context.secret); + t.deepEqual(jws, { + header: { + alg: 'HS256', + }, + payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4', + signature: 'O7HdMZ_6_aEQWLGGItmCKN3pf8-nZ9mHnPfT7rrPCwk', + }); + } + }); + + test('FlattenedSign.prototype.setProtectedHeader', (t) => { + t.throws( + () => new FlattenedSign(t.context.payload).setProtectedHeader({}).setProtectedHeader({}), + { + instanceOf: TypeError, + message: 'setProtectedHeader can only be called once', + }, + ); + }); + + test('FlattenedSign.prototype.setUnprotectedHeader', (t) => { + t.throws( + () => + new FlattenedSign(t.context.payload).setUnprotectedHeader({}).setUnprotectedHeader({}), + { + instanceOf: TypeError, + message: 'setUnprotectedHeader can only be called once', + }, + ); + }); + + test('FlattenedSign.prototype.sign must have a JOSE header', async (t) => { + await t.throwsAsync(new FlattenedSign(t.context.payload).sign(t.context.secret), { + code: 'ERR_JWS_INVALID', + message: 'either setProtectedHeader or setUnprotectedHeader must be called before #sign()', + }); + }); + + test('FlattenedSign.prototype.sign JOSE header must be disjoint', async (t) => { + await t.throwsAsync( + new FlattenedSign(t.context.payload) + .setProtectedHeader({ alg: 'HS256' }) + .setUnprotectedHeader({ alg: 'HS256' }) + .sign(t.context.secret), + { + code: 'ERR_JWS_INVALID', + message: 'JWS Protected and JWS Unprotected Header Parameter names must be disjoint', + }, + ); + }); + + test('FlattenedSign.prototype.sign JOSE header have an alg', async (t) => { + await t.throwsAsync( + new FlattenedSign(t.context.payload) + .setProtectedHeader({}) + .setUnprotectedHeader({}) + .sign(t.context.secret), + { + code: 'ERR_JWS_INVALID', + message: 'missing JWS signature algorithm in JWS Header', + }, + ); + await t.notThrowsAsync( + new FlattenedSign(t.context.payload) + .setProtectedHeader({ alg: 'HS256' }) + .setUnprotectedHeader({ foo: 'bar' }) + .sign(t.context.secret), + ); + await t.notThrowsAsync( + new FlattenedSign(t.context.payload) + .setProtectedHeader({ alg: 'HS256' }) + .sign(t.context.secret), + ); + await t.notThrowsAsync( + new FlattenedSign(t.context.payload) + .setProtectedHeader({ foo: 'bar' }) + .setUnprotectedHeader({ alg: 'HS256' }) + .sign(t.context.secret), + ); + await t.notThrowsAsync( + new FlattenedSign(t.context.payload) + .setUnprotectedHeader({ alg: 'HS256' }) + .sign(t.context.secret), + ); + }); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jws/flattened.verify.test.mjs b/test/jws/flattened.verify.test.mjs new file mode 100644 index 0000000000..a03930e704 --- /dev/null +++ b/test/jws/flattened.verify.test.mjs @@ -0,0 +1,131 @@ +/* eslint-disable no-param-reassign */ +import test from 'ava'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +Promise.all([ + import(`${root}/jws/flattened/sign`), + import(`${root}/jws/flattened/verify`), + import(`${root}/util/random`), +]).then( + ([{ default: FlattenedSign }, { default: flattenedVerify }, { default: random }]) => { + test.before(async (t) => { + const encode = TextEncoder.prototype.encode.bind(new TextEncoder()); + t.context.plaintext = encode('It’s a dangerous business, Frodo, going out your door.'); + t.context.secret = random(new Uint8Array(32)); + }); + + test('JWS format validation', async (t) => { + const fullJws = await new FlattenedSign(t.context.plaintext) + .setProtectedHeader({ bar: 'baz' }) + .setUnprotectedHeader({ alg: 'HS256' }) + .sign(t.context.secret); + + { + await t.throwsAsync(flattenedVerify(null, t.context.secret), { + message: 'Flattened JWS must be an object', + code: 'ERR_JWS_INVALID', + }); + } + + { + const jws = { ...fullJws }; + delete jws.protected; + delete jws.header; + + await t.throwsAsync(flattenedVerify(jws, t.context.secret), { + message: 'Flattened JWS must have either of the "protected" or "header" members', + code: 'ERR_JWS_INVALID', + }); + } + + { + const jws = { ...fullJws }; + delete jws.signature; + const assertion = { + message: 'JWS Signature missing or incorrect type', + code: 'ERR_JWS_INVALID', + }; + + await t.throwsAsync(flattenedVerify(jws, t.context.secret), assertion); + jws.signature = null; + + await t.throwsAsync(flattenedVerify(jws, t.context.secret), assertion); + } + + { + const jws = { ...fullJws }; + const assertion = { + message: 'JWS Protected Header incorrect type', + code: 'ERR_JWS_INVALID', + }; + jws.protected = null; + await t.throwsAsync(flattenedVerify(jws, t.context.secret), assertion); + } + + { + const jws = { ...fullJws }; + const assertion = { + message: 'JWS Unprotected Header incorrect type', + code: 'ERR_JWS_INVALID', + }; + jws.header = null; + await t.throwsAsync(flattenedVerify(jws, t.context.secret), assertion); + } + + { + const jws = { ...fullJws }; + const assertion = { + message: 'JWS Payload missing', + code: 'ERR_JWS_INVALID', + }; + delete jws.payload; + await t.throwsAsync(flattenedVerify(jws, t.context.secret), assertion); + } + + { + const jws = { ...fullJws }; + jws.header = { alg: 'HS256', bar: 'bar' }; + const assertion = { + message: 'JWS Protected and JWS Unprotected Header Parameter names must be disjoint', + code: 'ERR_JWS_INVALID', + }; + await t.throwsAsync(flattenedVerify(jws, t.context.secret), assertion); + } + + { + const jws = { ...fullJws }; + delete jws.header; + const assertion = { + message: 'missing JWS signature algorithm in JWS Header', + code: 'ERR_JWS_INVALID', + }; + await t.throwsAsync(flattenedVerify(jws, t.context.secret), assertion); + } + + { + const jws = { ...fullJws }; + jws.payload = null; + const assertion = { + message: 'JWS Payload must be a string', + code: 'ERR_JWS_INVALID', + }; + await t.throwsAsync(flattenedVerify(jws, t.context.secret), assertion); + } + + { + const jws = { ...fullJws }; + const assertion = { + message: 'signature verification failed', + code: 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED', + }; + await t.throwsAsync(flattenedVerify(jws, random(new Uint8Array(32))), assertion); + } + }); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jws/restrictions.test.mjs b/test/jws/restrictions.test.mjs new file mode 100644 index 0000000000..461a4bba2e --- /dev/null +++ b/test/jws/restrictions.test.mjs @@ -0,0 +1,161 @@ +/* eslint-disable no-param-reassign */ +import test from 'ava'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +Promise.all([ + import(`${root}/jws/flattened/sign`), + import(`${root}/jws/flattened/verify`), + import(`${root}/jwe/flattened/encrypt`), + import(`${root}/jwe/flattened/decrypt`), + import(`${root}/util/random`), + import(`${root}/jwk/parse`), +]).then( + ([ + { default: FlattenedSign }, + { default: flattenedVerify }, + { default: FlattenedEncrypt }, + { default: flattenedDecrypt }, + { default: random }, + { default: parseJwk }, + ]) => { + function pubjwk(jwk) { + const { d, p, q, dp, dq, qi, ...publicJwk } = jwk; + return publicJwk; + } + + test.before((t) => { + const encode = TextEncoder.prototype.encode.bind(new TextEncoder()); + t.context.payload = encode('It’s a dangerous business, Frodo, going out your door.'); + t.context.rsa2040 = { + e: 'AQAB', + n: + '4waoB9XUAsGc-bhkfY-v3hKEqmLYF4nS-8nji5R5KoOOeWC2hCkvbMfd2IlKRdMU7EmGXNx2BD2FVIqN9mWyZKJlzR2125lgJ-VxCymGv1A9057LEAFIrXsCUqwjPO07hCzZNv8IAAQzq53pnlAgb3TbfrxW24tamhCtaKHb5upAwo4jhYnfzex2--vD7mPxMoTuikno-eD_hxYmA52Uh1gu3wEWy44KA6aFJBpP7m4G5StuHSCXxiOWDaqMeFsMX1jqrom7SwbGJ7j0sf3ZqWrZR4x1pB3wk5Sixi_lmDfOkXhiizYnvJJ5rzr_f0bVdXeAe2U8vpEJSQeA36T7', + d: + 'T7ZPm2it50XZ-yiOSDQCWSQBZt4L57_hz7ykY6b_IDlO9jlJ_H-FgllvAI-7_2ZNC2YJgmN6IKUFQpjfnas5hvIqcmnDJ9bjlz6NgZDUGipvevVfcUAyJ49wUlzUhpj5c8BXiGLliTPwfIqWs5qIuPm78_TnPnDgoAXJDVr_njr_C6CJFVfWni_6MTeT8iSApGrIJ-tovLlUWSQAyKfWT0QK8dclmREla6-B4YPFwMuBViiSI8dGFpw1O-sEn7D1aMWRepWKr-dgvukuksdL39LxBeGz-iHpI_DMdSB63t5kyjT7GPlbBkD__4ie_Vl4bG30dUZvH_Vt6nXxyXEh', + p: + 'D0TqaIEyAQHzW1SnC_b1AM9sehg6baMhw4mwSQHqVQreS6a2FKor2xVUdWzT3EurRJ-NThGyi81b30MsKjV_eZ1pIA2r5ulab5CgsV4pkk9LZPZYtz4Rylv9RY3ArtBxziF_BPhTbyy5LXUr5TZUpTQn-LGPOc2sjDaB80uD9XE', + q: + 'Dt5ET14bw-tNwsgBK-IuhuPzxeCYSi6AkiDqdJuykcN8z8Of-OyPbQSVgTNbvQSZ1anaV0-pvrkER5ilIjcaGtaBmQmCUZe0vKBynakRWXR16SE2mqJAjAmO6VD25cxdnNghdg8ue5XsdyjuQ0dnTXibsIcVyjfaIZgjbhi6mys', + dp: + 'BD0cWXBsAi2ZceQZD1A6CUSLl4U8Sw07JT4Gyu2WMI940EVyTGBFFmdgb8yLL59t5vnnzyFIkFisxVivXPRG8-rHsRc6fjqPWWMryLEcFzqd8mQUkqHPbH6G25UTRTQmM5PG4AlTmAwxR7Y8PkAL1WSaKAaafPBkkvPatUBkXHE', + dq: + 'Bv-nBfkVdr6PRu2gZ4i7P_GTMQTMirai_KYT1rnnb2emm6HI7oJj7PwoZ73GJA5DX2jphwnPrCApHI6ExLtNRW7NaD0qo7-WaufXq9EGgqYoTom8y0MuwPxK0hazcW4mborqDUmOJsxml5yjsvWscbIhDxI3No3d1sxneQ6Y4Cs', + qi: + 'AkpKJwYKvaB73G7IQK5yxXCOvypwSEUK1bOcbhOZSQPPNtKvov11dVsGs-pqHo0Su06IXQv0Ayyy3uxXvsY8CyZ3CbPWMXM06Z3Gr0kZWWfNu8NiFwXvkbe24P-KeXIQGFTfdqSMTfm2an1YNE9e9F36rZ0EkhdKzmwzudA7jtw', + kty: 'RSA', + }; + t.context.rsa2048 = { + e: 'AQAB', + n: + '3egkthDOqRIif9azx83Q-HKcVNUeDALom8e5L1rjljB82EKYt5zgfKlgLW4NuJQgLDx5jA7Ez_nz-8lIcVTez-C75_M-Thv2wLhk4ZAYAZZPEmZr76zH8-lClnhxcqFnkOABqLmopr2gF1gBG_IkqEnH_h_yH486YkCd0G2ZNJAzjCOCQMR5pzBnIxC4YUAX7r_-9ilQ8Lv3MSJ0MLv6cujJTneyjWnoh_SfOXRsY6f3gkfR9APj9Q5A8PA8gvbYyN8EHr4OYb1KwNjs_0_X0Aq0e1NJx3H5eiZe6UaFleIbEVZYoNtlNJO3kmGESaxepkWTRAqBZVTfj4KnKX_9Ow', + d: + 'Q17sbl4x8ACyeq97i4jADf312oeNhMYJSupbHbZxbDKyZJHrfatiOFbP_VrxTX2jOurtWAlP1Xiki2fz13yV3PT095nQ67PvuVkCP70YnLq-rO5tjKmfVz0VW0ub3dqE7-YietBLFLxzc0Ljq1FbscAcuNmID-7TIetOPm5X2i3wxOuiEV2xz1nHVuys3yoO3z4rAitGFl943k71P4FKxK9mp9oTQTnDfKauP0eSOD10L2NiYLkUTg9YC8A0EQopdZatDVAz3hWitNpJg28fWe7rp7yR2YBb4nFcNuygZmzEzp7x0r87NnTt9t4Hjd1rNFbd3hdT6Dy9_pejkmdU2Q', + p: + '8_HZDF8wp0ujYxiyvAXOL6Xsnv08bQ80uzDOGCnHWWKeFn8n43gc49AdBiJ2ljmfQxExiK0wmetR76zdxTJBIWQdGI2ZJkb6lAIOEBhrXzrWXUSMPgc3qYbQRkmexrAAdwG1nWUymMDd36K5d_YEmL172a-gyEAXMGGW81AaeVU', + q: + '6N9-STJXjcrwedkJpmmjKLBpU_Nw0UfpKAkh3Xf6jpaF-A2Cvr07JqDVzExMfpYDCcki7IW8SLK5wXVfWCZqXXl4bsb5LAJLnRIglgnDxItlmRf5CWHw7lmBD6BguEIhXU3xPiNrK3XiBVS4k2yDaYHHoAPYXDfTCGpbts7SXE8', + dp: + 'k_OmtH43P__8BGpCXQ8YUoXL0VG9iFekn7OmC7mrEmdhgjt0sd1ziCf8sm_MhKhGE6Ml68M-qtuyQi8SAjvMjLfvfajDrhd2erYUWWa2GHfS85ZTiHtQIx2EzFxyVAcDASqkP-XUnhi7eJt06XDosMqbhxeh6FIWvl0x9DgtFlE', + dq: + 'UqK8VY0ftJlHLHXwDrV9yHqRZdEFP76c5jAXbFee-epAL_3bX4QW8WYxeAW7P1BMU7SkR_pNDh8d-6CC7Oz04aaxLd49nXhTDLHaDmP4rE4rB2CSZtnyfSIVwk3PBJOy80EtUjePWCTEx8-AkA_5sf7zr7ytkkvc_yd-1CggTdE', + qi: + 'd72eV7EbpvaSA3ZiQdGXpMMr41o0ih1WnV80Bxraugj1vMqxLlhVdDhDCVoF3LEoXVz8n2NEl1F6k2o3Gt9C5pXUDJwRGS41FwYVp8RN-aWviJM43mM0oQndJomZyDzjOKzpTzlNlAkFQQbfoagc4sbg-0JxK9rWdnMDW5AR1BU', + kty: 'RSA', + }; + }); + + async function testHMAC(t, alg) { + const size = parseInt(alg.substr(-3), 10); + const message = `${alg} requires symmetric keys to be ${size} bits or larger`; + const secret = random(new Uint8Array((size >> 3) - 1)); + await t.throwsAsync( + new FlattenedSign(t.context.payload).setProtectedHeader({ alg }).sign(secret), + { instanceOf: TypeError, message }, + ); + + const jws = await new FlattenedSign(t.context.payload) + .setProtectedHeader({ alg }) + .sign(random(new Uint8Array(size >> 3))); + + await t.throwsAsync(flattenedVerify(jws, secret), { instanceOf: TypeError, message }); + } + testHMAC.title = (title, alg) => + `${alg} requires symmetric keys to be ${alg.substr(-3)} bits or larger`; + + test(testHMAC, 'HS256'); + test(testHMAC, 'HS384'); + test(testHMAC, 'HS512'); + + async function testRSAsig(t, alg) { + const message = `${alg} requires key modulusLength to be 2048 bits or larger`; + const keyBad = t.context.rsa2040; + const keyOk = t.context.rsa2048; + await t.throwsAsync( + new FlattenedSign(t.context.payload) + .setProtectedHeader({ alg }) + .sign(await parseJwk(keyBad, alg)), + { instanceOf: TypeError, message }, + ); + + const jws = await new FlattenedSign(t.context.payload) + .setProtectedHeader({ alg }) + .sign(await parseJwk(keyOk, alg)); + + await t.throwsAsync(flattenedVerify(jws, await parseJwk(pubjwk(keyBad), alg)), { + instanceOf: TypeError, + message, + }); + } + testRSAsig.title = (title, alg) => + `${alg} requires key modulusLength to be 2048 bits or larger`; + + async function testRSAenc(t, alg) { + const message = `${alg} requires key modulusLength to be 2048 bits or larger`; + const keyBad = t.context.rsa2040; + const keyOk = t.context.rsa2048; + await t.throwsAsync( + new FlattenedEncrypt(t.context.payload) + .setProtectedHeader({ alg, enc: 'A256GCM' }) + .encrypt(await parseJwk(pubjwk(keyBad), alg)), + { instanceOf: TypeError, message }, + ); + + const jwe = await new FlattenedEncrypt(t.context.payload) + .setProtectedHeader({ alg, enc: 'A256GCM' }) + .encrypt(await parseJwk(pubjwk(keyOk), alg)); + + await t.throwsAsync(flattenedDecrypt(jwe, await parseJwk(keyBad, alg)), { + instanceOf: TypeError, + message, + }); + } + testRSAenc.title = (title, alg) => + `${alg} requires key modulusLength to be 2048 bits or larger`; + + test(testRSAsig, 'RS256'); + test(testRSAsig, 'PS256'); + test(testRSAsig, 'RS384'); + test(testRSAsig, 'PS384'); + test(testRSAsig, 'RS512'); + test(testRSAsig, 'PS512'); + + test(testRSAenc, 'RSA-OAEP'); + test(testRSAenc, 'RSA-OAEP-256'); + test(testRSAenc, 'RSA-OAEP-384'); + test(testRSAenc, 'RSA-OAEP-512'); + + let conditional; + if ('WEBCRYPTO' in process.env) { + conditional = test.failing; + } else { + conditional = test; + } + conditional(testRSAenc, 'RSA1_5'); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jws/sanity.test.js b/test/jws/sanity.test.js deleted file mode 100644 index 07b658b77a..0000000000 --- a/test/jws/sanity.test.js +++ /dev/null @@ -1,281 +0,0 @@ -const test = require('ava') - -const base64url = require('../../lib/help/base64url') -const { JWKS, JWK: { generateSync }, JWS, errors } = require('../..') - -test('algorithms option be an array of strings', t => { - ;[{}, new Object(), false, null, Infinity, 0, '', Buffer.from('foo')].forEach((val) => { // eslint-disable-line no-new-object - t.throws(() => { - JWS.verify({ - header: { alg: 'HS256' }, - payload: 'foo', - signature: 'bar' - }, generateSync('oct'), { algorithms: val }) - }, { instanceOf: TypeError, message: '"algorithms" option must be an array of non-empty strings' }) - t.throws(() => { - JWS.verify({ - header: { alg: 'HS256' }, - payload: 'foo', - signature: 'bar' - }, generateSync('oct'), { algorithms: [val] }) - }, { instanceOf: TypeError, message: '"algorithms" option must be an array of non-empty strings' }) - }) -}) - -test('compact parts length check', t => { - t.throws(() => { - JWS.verify('', generateSync('oct')) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'JWS malformed or invalid serialization' }) - t.throws(() => { - JWS.verify('.', generateSync('oct')) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'JWS malformed or invalid serialization' }) - t.throws(() => { - JWS.verify('...', generateSync('oct')) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'JWS malformed or invalid serialization' }) -}) - -test('JWS sign accepts buffer', t => { - const k = generateSync('oct') - JWS.sign(Buffer.from('foo'), k) - t.pass() -}) - -test('JWS sign accepts string', t => { - const k = generateSync('oct') - JWS.sign('foo', k) - t.pass() -}) - -test('JWS sign accepts object', t => { - const k = generateSync('oct') - JWS.sign({}, k) - t.pass() -}) - -test('JWS sign rejects other', t => { - const k = generateSync('oct') - ;[[], false, true, undefined, null, Infinity, 0].forEach((val) => { - t.throws(() => { - JWS.sign(val, k) - }, { instanceOf: TypeError, message: 'payload argument must be a Buffer, string or an object' }) - }) -}) - -test('JWS sign protectedHeader rejects non objects or undefined', t => { - const k = generateSync('oct') - ;[[], false, true, null, Infinity, 0, Buffer.from('foo')].forEach((val) => { - t.throws(() => { - JWS.sign('foo', k, val) - }, { instanceOf: TypeError, message: 'protectedHeader argument must be a plain object when provided' }) - }) -}) - -test('JWS sign unprotectedHeader rejects non objects or undefined', t => { - const k = generateSync('oct') - const sign = new JWS.Sign('foo') - ;[[], false, true, null, Infinity, 0, Buffer.from('foo')].forEach((val) => { - t.throws(() => { - sign.recipient(k, undefined, val) - }, { instanceOf: TypeError, message: 'unprotectedHeader argument must be a plain object when provided' }) - }) -}) - -test('JWS prot and unprot headers must be disjoint', t => { - const k = generateSync('oct') - const sign = new JWS.Sign('foo') - t.throws(() => { - sign.recipient(k, { foo: 1 }, { foo: 0 }) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'JWS Protected and JWS Unprotected Header Parameter names must be disjoint' }) -}) - -test('JWS must have recipients', t => { - const sign = new JWS.Sign('foo') - t.throws(() => { - sign.sign('compact') - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'missing recipients' }) -}) - -test('JWS valid serialization must be provided', t => { - ;[[], false, true, null, Infinity, 0, 'foo', ''].forEach((val) => { - const sign = new JWS.Sign('foo') - t.throws(() => { - sign.sign(val) - }, { instanceOf: TypeError, message: 'serialization must be one of "compact", "flattened", "general"' }) - }) -}) - -test('JWS compact does not support multiple recipients', t => { - const k = generateSync('oct') - const k2 = generateSync('EC') - const sign = new JWS.Sign('foo') - sign.recipient(k) - sign.recipient(k2) - t.throws(() => { - sign.sign('compact') - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'JWS Compact Serialization doesn\'t support multiple recipients or JWS unprotected headers' }) -}) - -test('JWS compact does not support unprotected header', t => { - const k = generateSync('oct') - const sign = new JWS.Sign('foo') - sign.recipient(k, undefined, { foo: 1 }) - t.throws(() => { - sign.sign('compact') - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'JWS Compact Serialization doesn\'t support multiple recipients or JWS unprotected headers' }) -}) - -test('JWS flattened does not support multiple recipients', t => { - const k = generateSync('oct') - const k2 = generateSync('EC') - const sign = new JWS.Sign('foo') - sign.recipient(k) - sign.recipient(k2) - t.throws(() => { - sign.sign('flattened') - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'Flattened JWS JSON Serialization doesn\'t support multiple recipients' }) -}) - -test('JWS no alg specified but cannot resolve', t => { - const k1 = generateSync('oct', undefined, { key_ops: ['encrypt'] }) - t.throws(() => { - JWS.sign({}, k1) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'could not resolve a usable "alg" for a recipient' }) -}) - -test('JWS verify must be able to parse the protected header', t => { - const k = generateSync('oct') - const sign = new JWS.Sign('foo').recipient(k) - const jws = sign.sign('flattened') - jws.protected = jws.protected.substr(4) - t.throws(() => { - JWS.verify(jws, k) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'could not parse JWS protected header' }) -}) - -test('JWS verify must have disjoint header members', t => { - const k = generateSync('oct') - const sign = new JWS.Sign('foo').recipient(k) - const jws = sign.sign('flattened') - jws.header = { alg: 'HS256' } - t.throws(() => { - JWS.verify(jws, k) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'JWS Protected and JWS Unprotected Header Parameter names must be disjoint' }) -}) - -test('JWS no alg specified (multi recipient)', t => { - const sign = new JWS.Sign({}) - sign.recipient(generateSync('RSA')) - sign.recipient(generateSync('EC')) - sign.recipient(generateSync('oct', 256)) - - const jws = sign.sign('general') - t.deepEqual(base64url.JSON.decode(jws.signatures[0].protected), { alg: 'PS256' }) - t.deepEqual(base64url.JSON.decode(jws.signatures[1].protected), { alg: 'ES256' }) - t.deepEqual(base64url.JSON.decode(jws.signatures[2].protected), { alg: 'HS256' }) -}) - -test('JWS no alg specified (multi recipient) with per-recipient protected headers', t => { - const sign = new JWS.Sign({}) - const k1 = generateSync('RSA', undefined, { kid: 'kid_1' }) - sign.recipient(k1, { kid: k1.kid }) - const k2 = generateSync('EC', undefined, { kid: 'kid_2' }) - sign.recipient(k2, { kid: k2.kid }) - const k3 = generateSync('oct', undefined, { kid: 'kid_3' }) - sign.recipient(k3, { kid: k3.kid }) - - const jws = sign.sign('general') - t.deepEqual(base64url.JSON.decode(jws.signatures[0].protected), { alg: 'PS256', kid: 'kid_1' }) - t.deepEqual(base64url.JSON.decode(jws.signatures[1].protected), { alg: 'ES256', kid: 'kid_2' }) - t.deepEqual(base64url.JSON.decode(jws.signatures[2].protected), { alg: 'HS256', kid: 'kid_3' }) -}) - -test('JWS keystore match multi but fails with verification error', t => { - const k = generateSync('oct') - const ks = new JWKS.KeyStore(generateSync('oct'), generateSync('oct')) - const jws = JWS.sign({}, k) - - t.throws(() => { - JWS.verify(jws, ks) - }, { instanceOf: errors.JWSVerificationFailed, code: 'ERR_JWS_VERIFICATION_FAILED' }) -}) - -test('JWS general fails with decryption error', t => { - const k = generateSync('oct') - const k2 = generateSync('oct') - const k3 = generateSync('oct') - const sign = new JWS.Sign('foo') - sign.recipient(k) - sign.recipient(k2) - const jws = sign.sign('general') - - t.throws(() => { - JWS.verify(jws, k3) - }, { instanceOf: errors.JWSVerificationFailed, code: 'ERR_JWS_VERIFICATION_FAILED' }) -}) - -test('JWS verify algorithms whitelist', t => { - const k = generateSync('oct') - const jws = JWS.sign({}, k, { alg: 'HS512' }) - JWS.verify(jws, k, { algorithms: ['HS256', 'HS512'] }) - - t.throws(() => { - JWS.verify(jws, k, { algorithms: ['RS256'] }) - }, { instanceOf: errors.JOSEAlgNotWhitelisted, code: 'ERR_JOSE_ALG_NOT_WHITELISTED', message: 'alg not whitelisted' }) -}) - -test('JWS verify algorithms whitelist (with keystore)', t => { - const k = generateSync('oct') - const k2 = generateSync('oct') - const ks = new JWKS.KeyStore(k, k2) - - const jws = JWS.sign({}, k2, { alg: 'HS512' }) - JWS.verify(jws, ks, { algorithms: ['HS256', 'HS512'] }) - - t.throws(() => { - JWS.verify(jws, ks, { algorithms: ['RS256'] }) - }, { instanceOf: errors.JOSEAlgNotWhitelisted, code: 'ERR_JOSE_ALG_NOT_WHITELISTED', message: 'alg not whitelisted' }) -}) - -test('JWS verify algorithms whitelist (multi-recipient)', t => { - const k = generateSync('oct') - const k2 = generateSync('RSA') - - const sign = new JWS.Sign({}) - sign.recipient(k) - sign.recipient(k2) - const jws = sign.sign('general') - - JWS.verify(jws, k, { algorithms: ['HS256', 'PS256'] }) - JWS.verify(jws, k2, { algorithms: ['HS256', 'PS256'] }) - - let err - - err = t.throws(() => { - JWS.verify(jws, k, { algorithms: ['RS256'] }) - }, { instanceOf: errors.JOSEMultiError, code: 'ERR_JOSE_MULTIPLE_ERRORS' }) - - ;[...err].forEach((e, i) => { - if (i === 0) { - t.is(e.constructor, errors.JOSEAlgNotWhitelisted) - } else { - t.is(e.constructor, errors.JOSEAlgNotWhitelisted) - } - }) - err = t.throws(() => { - JWS.verify(jws, k2, { algorithms: ['HS256'] }) - }, { instanceOf: errors.JOSEMultiError, code: 'ERR_JOSE_MULTIPLE_ERRORS' }) - ;[...err].forEach((e, i) => { - if (i === 0) { - t.is(e.constructor, errors.JWKKeySupport) - } else { - t.is(e.constructor, errors.JOSEAlgNotWhitelisted) - } - }) -}) - -test('"enc" key is not usable for signing', t => { - const k = generateSync('oct', 256, { use: 'enc' }) - t.throws(() => { - JWS.sign({}, k) - }, { instanceOf: TypeError, message: 'a key with "use":"enc" is not usable for signing' }) -}) diff --git a/test/jws/smoke.test.js b/test/jws/smoke.test.js deleted file mode 100644 index 2547c1017e..0000000000 --- a/test/jws/smoke.test.js +++ /dev/null @@ -1,60 +0,0 @@ -const test = require('ava') - -const { randomBytes } = require('crypto') - -const { edDSASupported, keyObjectSupported } = require('../../lib/help/runtime_support') -const { JWK: { asKey, generateSync } } = require('../..') - -const fixtures = require('../fixtures') - -const { JWS: { success, failure } } = require('../macros') - -Object.entries(fixtures.PEM).forEach(([type, { private: key, public: pub }]) => { - if ('electron' in process.versions && (type.startsWith('X') || type === 'Ed448' || type === 'secp256k1')) return - if (!edDSASupported && (type.startsWith('Ed') || type.startsWith('X'))) return - - const sKey = asKey(key) - const vKey = asKey(pub) - - sKey.algorithms('sign').forEach((alg) => { - test(`key ${type} > alg ${alg}`, success, sKey, vKey, alg) - test(`key ${type} > alg ${alg} (key as bare input)`, success, key, pub, alg) - if (keyObjectSupported) { - test(`key ${type} > alg ${alg} (key as keyObject)`, success, sKey.keyObject, vKey.keyObject, alg) - } - test(`key ${type} > alg ${alg} (key as JWK)`, success, sKey.toJWK(true), vKey.toJWK(false), alg) - test(`key ${type} > alg ${alg} (negative cases)`, failure, sKey, vKey, alg) - test(`key ${type} > alg ${alg} (negative cases, key as bare input)`, failure, key, pub, alg) - if (keyObjectSupported) { - test(`key ${type} > alg ${alg} (negative cases, key as keyObject)`, failure, sKey.keyObject, vKey.keyObject, alg) - } - test(`key ${type} > alg ${alg} (negative cases, key as JWK)`, failure, sKey.toJWK(true), vKey.toJWK(false), alg) - }) -}) - -const sk = randomBytes(32) -const sym = asKey(sk) -sym.algorithms('sign').forEach((alg) => { - test(`key oct > alg ${alg}`, success, sym, sym, alg) - test(`key oct > alg ${alg} (key as bare input)`, success, sk, sk, alg) - if (keyObjectSupported) { - test(`key oct > alg ${alg} (key as keyObject)`, success, sym.keyObject, sym.keyObject, alg) - } - test(`key oct > alg ${alg} (key as JWK)`, success, sym.toJWK(true), sym.toJWK(true), alg) - test(`key oct > alg ${alg} (negative cases)`, failure, sym, sym, alg) - test(`key oct > alg ${alg} (negative cases, key as bare input)`, failure, sk, sk, alg) - if (keyObjectSupported) { - test(`key oct > alg ${alg} (negative cases, key as keyObject)`, failure, sym.keyObject, sym.keyObject, alg) - } - test(`key oct > alg ${alg} (negative cases, key as JWK)`, failure, sym.toJWK(true), sym.toJWK(true), alg) -}) - -{ - const rsa = generateSync('RSA') - const sKey = asKey({ kty: 'RSA', e: rsa.e, n: rsa.n, d: rsa.d }, { calculateMissingRSAPrimes: true }) - const vKey = asKey({ kty: 'RSA', e: rsa.e, n: rsa.n }) - sKey.algorithms('sign').forEach((alg) => { - test(`key RSA (min) > alg ${alg}`, success, sKey, vKey, alg) - test(`key RSA (min) > alg ${alg} (negative cases)`, failure, sKey, vKey, alg) - }) -} diff --git a/test/jws/smoke.test.mjs b/test/jws/smoke.test.mjs new file mode 100644 index 0000000000..a0bd30488d --- /dev/null +++ b/test/jws/smoke.test.mjs @@ -0,0 +1,229 @@ +/* eslint-disable no-await-in-loop */ +/* eslint-disable no-restricted-syntax */ +/* eslint-disable no-bitwise */ +/* eslint-disable no-param-reassign */ + +import test from 'ava'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +Promise.all([ + import(`${root}/jws/flattened/sign`), + import(`${root}/jws/flattened/verify`), + import(`${root}/util/random`), + import(`${root}/util/base64url`), + import(`${root}/jwk/parse`), + import(`${root}/util/generate_key_pair`), + import(`${root}/util/generate_secret`), +]).then( + ([ + { default: FlattenedSign }, + { default: verifyFlattened }, + { default: random }, + { encode: base64url }, + { default: parseJwk }, + { default: generateKeyPair }, + { default: generateSecret }, + ]) => { + function pubjwk(jwk) { + const { d, p, q, dp, dq, qi, ...publicJwk } = jwk; + return publicJwk; + } + + test.before(async (t) => { + const p256 = { + ext: false, + crv: 'P-256', + x: 'Sp3KpzPjwcCF04_W2GvSSf-vGDvp3Iv2kQYqAjnMB-Y', + y: 'lZmecT2quXe0i9f7b4qHvDAFDpxs0oxCoJx4tOOqsks', + d: 'hRVo5TGE_d_4tQC1KEQIlCdo9rteZmLSmaMPpFOjeDI', + kty: 'EC', + }; + const p384 = { + ext: false, + crv: 'P-384', + x: 'H50cO3PJnVhAoF6_jPKpCl60cnvmoygN2u29jVN19x8C2PymixZS4Y5d1FfMMK3L', + y: 'ATQ-4QWyYTtEaBW3CFQZEX0NdDE5g_9F24B0y2xxQgVmWa5Uz0QerlhzFoYU7Z_F', + d: 'HDUcH8y8xr22EroPYBK3PvpNjA3pCJjvHpBXKejxOiQCoXhZ5PhX_nxb7lU0mlDE', + kty: 'EC', + }; + const p521 = { + ext: false, + crv: 'P-521', + x: + 'AFy8VTdHeJx7rrUajpeqIjGZsjtx0tftQ7pdL1qkTRpnvY0WVVKXjib3HINNLMA72gA7JujbvEtGvkvoo0P7pGVK', + y: + 'AfMRSFv9qfcH_XMHfPoltBMYLhDbS3Pw1GL7NO9SI_vF4JsiAta1Bq6teCl2z8klFtRCWXHfPqEF3cmXS8bDQVoT', + d: + 'AL123tYK7y-iViaReLOHe7XxKNSeoUMk4RRmcP6nSVuZrYJHtyYPak4gUmWB6A_GzED3zXkrkcssZEzHrYQILw5c', + kty: 'EC', + }; + const secp256k1 = { + ext: false, + crv: 'secp256k1', + x: 'Hr99bGFN0HWT3ZgNNAXvmz-6Wk1HIxwsyFqUZH8PBFc', + y: 'bonc3DRZe51NzuWetY336VmTYdUFvPK7DivSPHeu_CA', + d: 'jv_VrhPomm6_WOzb74xF4eMI0hu9p0W1Zlxi0nz8AFs', + kty: 'EC', + }; + const rsa = { + ext: false, + e: 'AQAB', + n: + 'rPOe2kdmQY1wN2ADn-EIKsPO_kXotIqPjbZQOoW6sIHPGS8xJqrR60JLTBir5jG8Prrp4_KoEDGm3zYlWb5EJr9BMAVHAUYB2ZMXjdojpIkKeJ_cMI0lLcSUTkKkOA6u2DnVJBlnQgeyVZ927h65cJ5zsnSqG6MHh5tVPAwocEsfH27Tik_Fp-dCidmr_-rCrPfoAuASadvuFr5oAa7aAKdlLz6P0GgmCs2KzTAR6FiBMm48hd1YkrIaGzljKOwCgh0KYA3tnetbOCFEuzsmn9wmQHUA0iPQqYGlFJVfQ64949hQk42uWxCXtaO_wlXqy_TVki5LTQ7hO4reUiMXpQ', + d: + 'qhn97b91khmS-dOkHPYNu0nUZv_JDPCOmhlqtPRcFkfFsYZZuCcfyVvthM1rHD9kXuolKf26UBsVfcnaWHaqvtUyPxGhsV3yadSiwPCAR85FDzhjLxlTLL2AA6zFqSC_1Iik2hlmFmpNeqsZJL_xMROWxTi7Ke1hdX1QCnwGtdF-Emdqgf1wqBWv6VTQVd2qslQySQN8RLTYmlkHBmOHU1jc0e2QP5xbLD4-pPr7RW17WbOkW2aLsC0YYebqFaqVgLNZJIVDKetRCCgi1RcdieQ0zSuUfRc9wzhZW7HHCECASqjeFqHopG05ge-DwAcc62-H7EbKr0XWz-7SLqjTrQ', + p: + '3wSG2cBBbo6FZ0GiRucHhJhSx1U6ZRhwhrbJmSpiFG5rvHvZn-DWnOmurvO5jc1V2Qj4QAEO4w7YQh3A9PFBry_42Od5zof1GIeAOVT3REiMTOSCxMVEMWQ74UBUM2T2R_TDrBgVSuaRmX14mcZM6_SYu7JLpqeSDzZEy2cqOBs', + q: + 'xoeWkL7oZ488PsJ6_lkjCmrlxouKJgHqMHI_RVE-MGSYHDNrJ_iS4wp8CK4xhAdGukqxDm5ChqFECgdg5QfdLoCseAIC-aHrrylYrmka5_8ke-ObpW9iGFcZy-5cEH5NCr6iSb-KS6fZkxJl7g3Az6XmLoEHHmyy8QxG9Yikaz8', + dp: + 'DKUxED-6dg5Wuhgan3KSFo6cgvjuKrVMDBdpLuocTZRFP5a2LD6PbK5DXWAscUHnUDsV-GsW8QDyei09t6XGV6ycq4_UdEV5PD7Som2S56hFbEa4s3eL-lD4pDkFjTR4UnQqdCOZcXnJX66hm_aGfgqMbngZmgV-XqZxGCdtWWk', + dq: + 'uX6ijefyWiCZF8K7DL_YX7l1q8dhcxXC7TUyLOA2DR1Qirj4XEaDaCO5tJqdpVDvIsz7FhKrkgNIAV7Xh-eLIBIWE6M9iGVkQyuMspl-DFp2ilMmcLLbowZvEf5KgxafgXSRSfrvirTwM9yy5HRxPRMzOSxRrHm_0D26Z1we1B0', + qi: + 'htPHLViOVG6QrldfuHn9evfdlD-UEuViOWNx8aKR3IBv0qegpJ78vYB4hdAcJZtBslKI97En5rzOAN3Y6Y8MbI4oN77WeiePJl2cMrS64evmlERvjJ6ZTs8jK0iV5q_gIZ9Qg9drmolUgb_CccQOBFbqSL6YkXwCBxlkCrzTlhc', + kty: 'RSA', + }; + const ed25519 = { + ext: false, + crv: 'Ed25519', + x: 'beguov5KuiEE0a9t_NaKRwnqLp0OIURn2BTYmdLMed4', + d: 'Z1Q1Hgl8PfBvypfTzQOklI5r0y4ImPfWHP4OoIKm_kA', + kty: 'OKP', + }; + const ed448 = { + ext: false, + crv: 'Ed448', + x: 'YecSEZalR2McQ2f0yU8mMwLXSzz7eHirRsv0o9lqGhCZMihCPjpLKJ9BHj3u2DTnLtcBXGYmJbYA', + d: 'epoLrq-y89h6gjCEZl39VGKQKqqHlTgt0gp7mMM1bbZOPkToOOusOvxwayZlVU8pRtLbAIxcTK7n', + kty: 'OKP', + }; + t.context.keys = { + rsa: { + public: pubjwk(rsa), + private: rsa, + algs: ['RS256', 'RS384', 'RS512', 'PS256', 'PS384', 'PS512'], + }, + ed25519: { + public: pubjwk(ed25519), + private: ed25519, + algs: ['EdDSA'], + generate: { crv: 'Ed25519' }, + }, + ed448: { + public: pubjwk(ed448), + private: ed448, + algs: ['EdDSA'], + generate: { crv: 'Ed448' }, + }, + p256: { + public: pubjwk(p256), + private: p256, + algs: ['ES256'], + }, + secp256k1: { + public: pubjwk(secp256k1), + private: secp256k1, + algs: ['ES256K'], + }, + p384: { + public: pubjwk(p384), + private: p384, + algs: ['ES384'], + }, + p521: { + public: pubjwk(p521), + private: p521, + algs: ['ES512'], + }, + oct256: { + secret: { ext: false, kty: 'oct', k: base64url(random(new Uint8Array(256 >> 3))) }, + algs: ['HS256'], + }, + oct384: { + secret: { ext: false, kty: 'oct', k: base64url(random(new Uint8Array(384 >> 3))) }, + algs: ['HS256', 'HS384'], + }, + oct512: { + secret: { ext: false, kty: 'oct', k: base64url(random(new Uint8Array(512 >> 3))) }, + algs: ['HS256', 'HS384', 'HS512'], + }, + }; + }); + + async function smoke(t, ref, octAsKeyObject = false) { + const fixtures = t.context.keys[ref]; + await Promise.all([ + ...fixtures.algs.map(async (alg) => { + let priv; + let pub; + if ('secret' in fixtures) { + const secret = await parseJwk(fixtures.secret, alg, octAsKeyObject); + if (octAsKeyObject) { + t.false(secret instanceof Uint8Array); + } else { + t.true(secret instanceof Uint8Array); + } + pub = secret; + priv = secret; + } else { + [pub, priv] = await Promise.all([ + parseJwk(fixtures.public, alg), + parseJwk(fixtures.private, alg), + ]); + } + + const jws = await new FlattenedSign(random(new Uint8Array(256 >> 3))) + .setProtectedHeader({ alg }) + .sign(priv); + await verifyFlattened(jws, pub); + }), + ...fixtures.algs.map(async (alg) => { + let priv; + let pub; + if ('secret' in fixtures) { + const secret = await generateSecret(alg); + pub = secret; + priv = secret; + } else { + ({ privateKey: priv, publicKey: pub } = await generateKeyPair(alg, fixtures.generate)); + } + + const jws = await new FlattenedSign(random(new Uint8Array(256 >> 3))) + .setProtectedHeader({ alg }) + .sign(priv); + await verifyFlattened(jws, pub); + }), + ]); + t.pass(); + } + smoke.title = (title, ref) => `${ref.toUpperCase()}${title ? ` ${title}` : ''}`; + + test(smoke, 'rsa'); + test(smoke, 'p256'); + test(smoke, 'p384'); + test(smoke, 'p521'); + test(smoke, 'oct256'); + test(smoke, 'oct384'); + test(smoke, 'oct512'); + test('as keyobject', smoke, 'oct256', true); + test('as keyobject', smoke, 'oct384', true); + test('as keyobject', smoke, 'oct512', true); + + let conditional; + if ('WEBCRYPTO' in process.env) { + conditional = test.failing; + } else { + conditional = test; + } + conditional(smoke, 'secp256k1'); + conditional(smoke, 'ed25519'); + conditional(smoke, 'ed448'); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jws/unsecured.test.js b/test/jws/unsecured.test.js deleted file mode 100644 index f5d1b13cbe..0000000000 --- a/test/jws/unsecured.test.js +++ /dev/null @@ -1,111 +0,0 @@ -const test = require('ava') - -const { errors, JWK: { generateSync, None, isKey }, JWS } = require('../..') - -const properKey = generateSync('oct') - -test('JWS.None is an instance of a key but not really', t => { - t.true(isKey(None)) - t.is(None.alg, 'none') - t.is(None.type, 'unsecured') - t.true(None.algorithms() instanceof Set) - t.deepEqual([...None.algorithms()], ['none']) - t.deepEqual([...None.algorithms('sign')], ['none']) - t.deepEqual([...None.algorithms('verify')], ['none']) - t.deepEqual([...None.algorithms('encrypt')], []) - t.deepEqual([...None.algorithms('foobar')], []) - t.is(None.thumbprint, undefined) - t.is(None.kid, undefined) -}) - -test('JWS.None "signs"', t => { - const unsignedJWS = JWS.sign('foo', None) - t.deepEqual( - JWS.verify(unsignedJWS, None, { complete: true }), - { - key: None, - payload: Buffer.from('foo'), - protected: { - alg: 'none' - } - } - ) -}) - -test('JWS.None "signs" flattened', t => { - const unsignedJWS = JWS.sign.flattened('foo', None) - t.deepEqual( - unsignedJWS, - { - payload: 'Zm9v', - protected: 'eyJhbGciOiJub25lIn0', - signature: '' - } - ) - t.deepEqual( - JWS.verify(unsignedJWS, None, { complete: true }), - { - key: None, - payload: Buffer.from('foo'), - protected: { - alg: 'none' - } - } - ) -}) - -test('JWS.None "signs" general', t => { - const sign = new JWS.Sign('foo') - sign.recipient(None) - sign.recipient(None) - const unsignedJWS = sign.sign('general') - - t.deepEqual( - unsignedJWS, - { - payload: 'Zm9v', - signatures: [ - { - protected: 'eyJhbGciOiJub25lIn0', - signature: '' - }, - { - protected: 'eyJhbGciOiJub25lIn0', - signature: '' - } - ] - } - ) - t.deepEqual( - JWS.verify(unsignedJWS, None, { complete: true }), - { - key: None, - payload: Buffer.from('foo'), - protected: { - alg: 'none' - } - } - ) -}) - -test('JWS.None fails to verify real tokens', t => { - const signedToken = JWS.sign('foo', properKey) - t.throws(() => { - JWS.verify(signedToken, None) - }, { - instanceOf: errors.JWKKeySupport, - code: 'ERR_JWK_KEY_SUPPORT', - message: 'the key does not support HS256 verify algorithm' - }) -}) - -test('JWS.None fails to verify None signed tokens with a signature', t => { - const unsignedJWS = JWS.sign('foo', None) - t.throws(() => { - JWS.verify(`${unsignedJWS}fooba`, None) - }, { - instanceOf: errors.JWSVerificationFailed, - code: 'ERR_JWS_VERIFICATION_FAILED', - message: 'signature verification failed' - }) -}) diff --git a/test/jwt/decode.test.js b/test/jwt/decode.test.js deleted file mode 100644 index 6e6a940331..0000000000 --- a/test/jwt/decode.test.js +++ /dev/null @@ -1,49 +0,0 @@ -const test = require('ava') - -const { JWT, errors } = require('../..') - -test('token must be a string', t => { - ;[{}, new Object(), false, null, Infinity, 0, '', Buffer.from('foo')].forEach((val) => { // eslint-disable-line no-new-object - t.throws(() => { - JWT.decode(val) - }, { instanceOf: TypeError, message: 'JWT must be a string' }) - }) -}) - -test('token must not be encrypted', t => { - t.throws(() => { - JWT.decode('....') - }, { instanceOf: TypeError, message: 'encrypted JWTs cannot be decoded' }) -}) - -test('token must have three components', t => { - t.throws(() => { - JWT.decode('.') - }, { instanceOf: errors.JWTMalformed, code: 'ERR_JWT_MALFORMED', message: 'JWTs must have three components' }) -}) - -test('token must have a valid base64url encoded JSON header', t => { - t.throws(() => { - JWT.decode('foo.e30.') - }, { instanceOf: errors.JWTMalformed, code: 'ERR_JWT_MALFORMED', message: 'JWT is malformed' }) -}) - -test('token must have a valid base64url encoded payload', t => { - t.throws(() => { - JWT.decode('e30.foo.') - }, { instanceOf: errors.JWTMalformed, code: 'ERR_JWT_MALFORMED', message: 'JWT is malformed' }) -}) - -test('returns the payload, header and signature', t => { - t.deepEqual(JWT.decode('eyJmb28iOiJiYXIifQ.e30.', { complete: true }), { - header: { foo: 'bar' }, - payload: {}, - signature: '' - }) -}) - -test('returns the payload', t => { - t.deepEqual(JWT.decode('e30.eyJmb28iOiJiYXIifQ.'), { - foo: 'bar' - }) -}) diff --git a/test/jwt/decrypt.test.mjs b/test/jwt/decrypt.test.mjs new file mode 100644 index 0000000000..a95aab6a18 --- /dev/null +++ b/test/jwt/decrypt.test.mjs @@ -0,0 +1,399 @@ +import test from 'ava'; +import timekeeper from 'timekeeper'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +Promise.all([ + import(`${root}/jwt/encrypt`), + import(`${root}/jwt/decrypt`), + import(`${root}/jwe/compact/encrypt`), +]).then( + ([{ default: EncryptJWT }, { default: jwtDecrypt }, { default: CompactEncrypt }]) => { + const now = 1604416038; + + test.before(async (t) => { + t.context.secret = new Uint8Array(32); + t.context.payload = { 'urn:example:claim': true }; + + timekeeper.freeze(now * 1000); + }); + + test.after(timekeeper.reset); + + test('Basic JWT Claims Set verification', async (t) => { + const issuer = 'urn:example:issuer'; + const subject = 'urn:example:subject'; + const audience = 'urn:example:audience'; + const jti = 'urn:example:jti'; + const nbf = now - 10; + const iat = now - 20; + const exp = now + 10; + const typ = 'urn:example:typ'; + const jwt = await new EncryptJWT(t.context.payload) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM', typ }) + .setIssuer(issuer) + .setSubject(subject) + .setAudience(audience) + .setJti(jti) + .setNotBefore(nbf) + .setExpirationTime(exp) + .setIssuedAt(iat) + .encrypt(t.context.secret); + + await t.notThrowsAsync( + jwtDecrypt(jwt, t.context.secret, { + issuer, + subject, + audience, + jti, + typ, + maxTokenAge: '30s', + }), + ); + }); + + test('Payload must be an object', async (t) => { + const encode = TextEncoder.prototype.encode.bind(new TextEncoder()); + for (const value of [0, 1, -1, true, false, null, [], '']) { + const token = await new CompactEncrypt(encode(JSON.stringify(value))) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' }) + .encrypt(t.context.secret); + await t.throwsAsync(jwtDecrypt(token, t.context.secret), { + code: 'ERR_JWT_INVALID', + message: 'JWT Claims Set must be a top-level JSON object', + }); + } + }); + + test('Payload must JSON parseable', async (t) => { + const encode = TextEncoder.prototype.encode.bind(new TextEncoder()); + const token = await new CompactEncrypt(encode('{')) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' }) + .encrypt(t.context.secret); + await t.throwsAsync(jwtDecrypt(token, t.context.secret), { + code: 'ERR_JWT_INVALID', + message: 'JWT Claims Set must be a top-level JSON object', + }); + }); + + test('contentEncryptionAlgorithms and keyManagementAlgorithms options', async (t) => { + const jwt = await new EncryptJWT(t.context.payload) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' }) + .encrypt(t.context.secret); + + await t.throwsAsync( + jwtDecrypt(jwt, t.context.secret, { + keyManagementAlgorithms: ['RSA-OAEP'], + }), + { + code: 'ERR_JOSE_ALG_NOT_ALLOWED', + message: '"alg" (Algorithm) Header Parameter not allowed', + }, + ); + await t.throwsAsync( + jwtDecrypt(jwt, t.context.secret, { + contentEncryptionAlgorithms: ['A128GCM'], + }), + { + code: 'ERR_JOSE_ALG_NOT_ALLOWED', + message: '"enc" (Encryption Algorithm) Header Parameter not allowed', + }, + ); + }); + + test('typ verification', async (t) => { + { + const typ = 'urn:example:typ'; + const jwt = await new EncryptJWT(t.context.payload) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM', typ }) + .encrypt(t.context.secret); + + await t.notThrowsAsync( + jwtDecrypt(jwt, t.context.secret, { + typ: 'application/urn:example:typ', + }), + ); + + await t.throwsAsync( + jwtDecrypt(jwt, t.context.secret, { + typ: 'urn:example:typ:2', + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "typ" JWT header value' }, + ); + + await t.throwsAsync( + jwtDecrypt(jwt, t.context.secret, { + typ: 'application/urn:example:typ:2', + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "typ" JWT header value' }, + ); + } + { + const typ = 'application/urn:example:typ'; + const jwt = await new EncryptJWT(t.context.payload) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM', typ }) + .encrypt(t.context.secret); + + await t.notThrowsAsync( + jwtDecrypt(jwt, t.context.secret, { + typ: 'urn:example:typ', + }), + ); + + await t.throwsAsync( + jwtDecrypt(jwt, t.context.secret, { + typ: 'application/urn:example:typ:2', + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "typ" JWT header value' }, + ); + + await t.throwsAsync( + jwtDecrypt(jwt, t.context.secret, { + typ: 'urn:example:typ:2', + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "typ" JWT header value' }, + ); + } + }); + + test('Issuer[] verification', async (t) => { + const issuer = 'urn:example:issuer'; + const jwt = await new EncryptJWT(t.context.payload) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' }) + .setIssuer(issuer) + .encrypt(t.context.secret); + + await t.notThrowsAsync( + jwtDecrypt(jwt, t.context.secret, { + issuer: [issuer], + }), + ); + }); + + test('Issuer[] verification failed', async (t) => { + const issuer = 'urn:example:issuer'; + const jwt = await new EncryptJWT(t.context.payload) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' }) + .setIssuer(issuer) + .encrypt(t.context.secret); + + await t.throwsAsync( + jwtDecrypt(jwt, t.context.secret, { + issuer: [], + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "iss" claim value' }, + ); + }); + + test('Issuer[] verification failed []', async (t) => { + const issuer = 'urn:example:issuer'; + const jwt = await new EncryptJWT(t.context.payload) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' }) + .setIssuer([issuer]) + .encrypt(t.context.secret); + + await t.throwsAsync( + jwtDecrypt(jwt, t.context.secret, { + issuer: [], + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "iss" claim value' }, + ); + }); + + test('Audience[] verification', async (t) => { + const audience = 'urn:example:audience'; + const jwt = await new EncryptJWT(t.context.payload) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' }) + .setAudience(audience) + .encrypt(t.context.secret); + + await t.notThrowsAsync( + jwtDecrypt(jwt, t.context.secret, { + audience: [audience], + }), + ); + }); + + test('Audience[] verification failed', async (t) => { + const audience = 'urn:example:audience'; + const jwt = await new EncryptJWT(t.context.payload) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' }) + .setAudience(audience) + .encrypt(t.context.secret); + + await t.throwsAsync( + jwtDecrypt(jwt, t.context.secret, { + audience: [], + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "aud" claim value' }, + ); + }); + + test('Audience[] verification failed []', async (t) => { + const audience = 'urn:example:audience'; + const jwt = await new EncryptJWT(t.context.payload) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' }) + .setAudience([audience]) + .encrypt(t.context.secret); + + await t.throwsAsync( + jwtDecrypt(jwt, t.context.secret, { + audience: [], + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "aud" claim value' }, + ); + }); + + test('Subject verification failed', async (t) => { + const subject = 'urn:example:subject'; + const jwt = await new EncryptJWT(t.context.payload) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' }) + .setSubject(subject) + .encrypt(t.context.secret); + + await t.throwsAsync( + jwtDecrypt(jwt, t.context.secret, { + subject: 'urn:example:subject:2', + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "sub" claim value' }, + ); + }); + + async function numericDateNumber(t, claim) { + const jwt = await new EncryptJWT({ [claim]: null }) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' }) + .encrypt(t.context.secret); + + await t.throwsAsync(jwtDecrypt(jwt, t.context.secret), { + code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', + message: `"${claim}" claim must be a number`, + }); + } + numericDateNumber.title = (t, claim) => `${claim} must be a number`; + + test('clockTolerance num', async (t) => { + const jwt = await new EncryptJWT({ exp: now }) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' }) + .encrypt(t.context.secret); + + await t.notThrowsAsync(jwtDecrypt(jwt, t.context.secret, { clockTolerance: 1 })); + await t.notThrowsAsync(jwtDecrypt(jwt, t.context.secret, { clockTolerance: '1s' })); + }); + + async function failingNumericDate(t, claims, assertion, decryptOptions) { + const jwt = await new EncryptJWT({ ...claims }) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM' }) + .encrypt(t.context.secret); + + await t.throwsAsync(jwtDecrypt(jwt, t.context.secret, { ...decryptOptions }), assertion); + } + + test( + 'exp must be in the future', + failingNumericDate, + { exp: now }, + { + code: 'ERR_JWT_EXPIRED', + message: '"exp" claim timestamp check failed', + }, + ); + + test( + 'nbf must be at least now', + failingNumericDate, + { nbf: now + 1 }, + { + code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', + message: '"nbf" claim timestamp check failed', + }, + ); + + test( + 'iat must be in the past (maxTokenAge, no exp)', + failingNumericDate, + { iat: now + 1 }, + { + code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', + message: '"iat" claim timestamp check failed (it should be in the past)', + }, + { + maxTokenAge: 5, + }, + ); + + test( + 'iat must be in the past (maxTokenAge, with exp)', + failingNumericDate, + { iat: now + 1, exp: now + 10 }, + { + code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', + message: '"iat" claim timestamp check failed (it should be in the past)', + }, + { + maxTokenAge: 5, + }, + ); + + test( + 'iat must be in the past (maxTokenAge, with exp, as a string)', + failingNumericDate, + { iat: now + 1, exp: now + 10 }, + { + code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', + message: '"iat" claim timestamp check failed (it should be in the past)', + }, + { + maxTokenAge: '5s', + }, + ); + + test( + 'maxTokenAge option', + failingNumericDate, + { iat: now - 31 }, + { + code: 'ERR_JWT_EXPIRED', + message: '"iat" claim timestamp check failed (too far in the past)', + }, + { + maxTokenAge: '30s', + }, + ); + + for (const claim of ['iat', 'nbf', 'exp']) { + test(numericDateNumber, claim); + } + + async function replicatedClaimCheck(t, claim) { + { + const jwt = await new EncryptJWT({ [claim]: 'urn:example' }) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM', [claim]: 'urn:example' }) + .encrypt(t.context.secret); + + await t.notThrowsAsync(jwtDecrypt(jwt, t.context.secret)); + } + { + const jwt = await new EncryptJWT({ [claim]: 'urn:example:mismatched' }) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM', [claim]: 'urn:example' }) + .encrypt(t.context.secret); + + await t.throwsAsync( + jwtDecrypt(jwt, t.context.secret, { + code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', + message: `replicated "${claim}" claim header parameter mismatch`, + }), + ); + } + } + replicatedClaimCheck.title = (t, claim) => `${claim} header claim must match the payload`; + + for (const claim of ['iss', 'sub', 'aud']) { + test(replicatedClaimCheck, claim); + } + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jwt/encrypt.test.mjs b/test/jwt/encrypt.test.mjs new file mode 100644 index 0000000000..b5e5d06129 --- /dev/null +++ b/test/jwt/encrypt.test.mjs @@ -0,0 +1,135 @@ +/* eslint-disable no-param-reassign */ +import test from 'ava'; +import timekeeper from 'timekeeper'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +Promise.all([import(`${root}/jwt/encrypt`), import(`${root}/jwe/compact/decrypt`)]).then( + ([{ default: EncryptJWT }, { default: compactDecrypt }]) => { + const now = 1604416038; + + test.before(async (t) => { + t.context.secret = new Uint8Array(16); + t.context.initializationVector = new Uint8Array(12); + t.context.payload = { 'urn:example:claim': true }; + + timekeeper.freeze(new Date(now * 1000)); + }); + + test.after(timekeeper.reset); + + test('EncryptJWT', async (t) => { + const jwt = await new EncryptJWT(t.context.payload) + .setInitializationVector(t.context.initializationVector) + .setProtectedHeader({ alg: 'dir', enc: 'A128GCM' }) + .encrypt(t.context.secret); + t.is( + jwt, + 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..AAAAAAAAAAAAAAAA.eKqvvA6MxuqSRbLVFIidFJb8x4lzPytWkoA.aglYAurAaFCoM8sCqaXSyw', + ); + }); + + test('new EncryptJWT', (t) => { + t.throws(() => new EncryptJWT(), { + instanceOf: TypeError, + message: 'JWT Claims Set MUST be an object', + }); + }); + + async function testJWTsetFunction( + t, + method, + claim, + value, + duplicate = false, + expected = value, + ) { + let enc = new EncryptJWT({}) + .setProtectedHeader({ alg: 'dir', enc: 'A128GCM' }) + [method](value); + + if (duplicate) { + enc = enc[`replicate${method.substr(3)}AsHeader`](); + } + + const jwt = await enc.encrypt(t.context.secret); + + const { plaintext, protectedHeader } = await compactDecrypt(jwt, async (header, token) => { + t.true('alg' in header); + t.true('enc' in header); + t.is(header.alg, 'dir'); + t.is(header.enc, 'A128GCM'); + t.true('ciphertext' in token); + t.true('iv' in token); + t.true('protected' in token); + t.true('tag' in token); + return t.context.secret; + }); + const payload = JSON.parse(new TextDecoder().decode(plaintext)); + t.is(payload[claim], expected); + if (duplicate) { + t.true(claim in protectedHeader); + t.is(protectedHeader[claim], expected); + } else { + t.false(claim in protectedHeader); + } + } + testJWTsetFunction.title = (title, method, claim, value) => + `EncryptJWT.prototype.${method} called with ${value}${title ? ` (${title})` : ''}`; + + test(testJWTsetFunction, 'setIssuer', 'iss', 'urn:example:issuer'); + test('duplicated', testJWTsetFunction, 'setIssuer', 'iss', 'urn:example:issuer', true); + test(testJWTsetFunction, 'setSubject', 'sub', 'urn:example:subject'); + test('duplicated', testJWTsetFunction, 'setSubject', 'sub', 'urn:example:subject', true); + test(testJWTsetFunction, 'setAudience', 'aud', 'urn:example:audience'); + test('duplicated', testJWTsetFunction, 'setAudience', 'aud', 'urn:example:audience', true); + test(testJWTsetFunction, 'setJti', 'jti', 'urn:example:jti'); + test(testJWTsetFunction, 'setIssuedAt', 'iat', 0); + test(testJWTsetFunction, 'setIssuedAt', 'iat', undefined, undefined, now); + test(testJWTsetFunction, 'setExpirationTime', 'exp', 0); + test(testJWTsetFunction, 'setExpirationTime', 'exp', '10s', undefined, now + 10); + test(testJWTsetFunction, 'setNotBefore', 'nbf', 0); + test(testJWTsetFunction, 'setNotBefore', 'nbf', '10s', undefined, now + 10); + + test('EncryptJWT.prototype.setProtectedHeader', (t) => { + t.throws( + () => new EncryptJWT(t.context.payload).setProtectedHeader({}).setProtectedHeader({}), + { + instanceOf: TypeError, + message: 'setProtectedHeader can only be called once', + }, + ); + }); + + test('EncryptJWT.prototype.setContentEncryptionKey', (t) => { + t.throws( + () => + new EncryptJWT(t.context.payload) + .setContentEncryptionKey(t.context.secret) + .setContentEncryptionKey(t.context.secret), + { + instanceOf: TypeError, + message: 'setContentEncryptionKey can only be called once', + }, + ); + }); + + test('EncryptJWT.prototype.setInitializationVector', (t) => { + t.throws( + () => + new EncryptJWT(t.context.payload) + .setInitializationVector(t.context.initializationVector) + .setInitializationVector(t.context.initializationVector), + { + instanceOf: TypeError, + message: 'setInitializationVector can only be called once', + }, + ); + }); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jwt/sign.test.js b/test/jwt/sign.test.js deleted file mode 100644 index 6de1f51d6d..0000000000 --- a/test/jwt/sign.test.js +++ /dev/null @@ -1,189 +0,0 @@ -const test = require('ava') - -const { JWT, JWK } = require('../..') - -const key = JWK.generateSync('oct') - -const string = (t, option) => { - ;['', false, [], {}, Buffer, Buffer.from('foo'), 0, Infinity].forEach((val) => { - t.throws(() => { - JWT.sign({}, key, { [option]: val }) - }, { instanceOf: TypeError, message: `options.${option} must be a string` }) - }) -} - -test('options must be an object', t => { - ;['', false, [], Buffer, Buffer.from('foo'), 0, Infinity].forEach((val) => { - t.throws(() => { - JWT.sign({}, key, val) - }, { instanceOf: TypeError, message: 'options must be an object' }) - }) -}) - -test('options.algorithm must be string', string, 'algorithm') -test('options.expiresIn must be string', string, 'expiresIn') -test('options.issuer must be string', string, 'issuer') -test('options.jti must be string', string, 'jti') -test('options.notBefore must be string', string, 'notBefore') -test('options.subject must be string', string, 'subject') - -const boolean = (t, option) => { - ;['', 'foo', [], {}, Buffer, Buffer.from('foo'), 0, Infinity].forEach((val) => { - t.throws(() => { - JWT.sign({}, key, { [option]: val }) - }, { instanceOf: TypeError, message: `options.${option} must be a boolean` }) - }) -} -test('options.iat must be boolean', boolean, 'iat') -test('options.kid must be boolean', boolean, 'kid') - -test('options.audience must be string or array of strings', t => { - ;['', false, [], Buffer, Buffer.from('foo'), 0, Infinity].forEach((val) => { - t.throws(() => { - JWT.sign({}, key, { audience: val }) - }, { instanceOf: TypeError, message: 'options.audience must be a string or an array of strings' }) - t.throws(() => { - JWT.sign({}, key, { audience: [val] }) - }, { instanceOf: TypeError, message: 'options.audience must be a string or an array of strings' }) - }) -}) - -test('options.header must be an object', t => { - ;['', 'foo', [], Buffer, Buffer.from('foo'), 0, Infinity, new Date('foo')].forEach((val) => { - t.throws(() => { - JWT.sign({}, key, { header: val }) - }, { instanceOf: TypeError, message: 'options.header must be an object' }) - }) -}) - -test('options.now must be a valid date', t => { - ;['', 'foo', [], {}, Buffer, Buffer.from('foo'), 0, Infinity, new Date('foo')].forEach((val) => { - t.throws(() => { - JWT.sign({}, key, { now: val }) - }, { instanceOf: TypeError, message: 'options.now must be a valid Date object' }) - }) -}) - -test('payload must be an object', t => { - ;['', 'foo', [], Buffer, Buffer.from('foo'), 0, Infinity, new Date('foo')].forEach((val) => { - t.throws(() => { - JWT.sign(val, key) - }, { instanceOf: TypeError, message: 'payload must be an object' }) - }) -}) - -test('payload is used', t => { - const { iat, ...payload } = JWT.decode(JWT.sign({ 'urn:example.com': false }, key)) - t.deepEqual(payload, { 'urn:example.com': false }) -}) - -test('options.header is used', t => { - const { header: { alg, kid, ...header } } = JWT.decode(JWT.sign({}, key, { header: { typ: 'JWT' } }), { complete: true }) - t.is(alg, 'HS256') - t.deepEqual(header, { typ: 'JWT' }) -}) - -test('options.kid for symmetric keys', t => { - let kid - - ;({ header: { kid } } = JWT.decode(JWT.sign({}, key), { complete: true })) - t.is(kid, undefined) - - ;({ header: { kid } } = JWT.decode(JWT.sign({}, key, { kid: false }), { complete: true })) - t.is(kid, undefined) - - ;({ header: { kid } } = JWT.decode(JWT.sign({}, key, { kid: true }), { complete: true })) - t.is(kid, key.kid) -}) - -test('options.kid for asymmetric keys', t => { - const key = JWK.generateSync('EC') - let kid - - ;({ header: { kid } } = JWT.decode(JWT.sign({}, key), { complete: true })) - t.is(kid, key.kid) - - ;({ header: { kid } } = JWT.decode(JWT.sign({}, key, { kid: false }), { complete: true })) - t.is(kid, undefined) - - ;({ header: { kid } } = JWT.decode(JWT.sign({}, key, { kid: true }), { complete: true })) - t.is(kid, key.kid) -}) - -test('options.subject', t => { - const subject = 'foo' - const { sub } = JWT.decode(JWT.sign({ sub: 'bar' }, key, { subject })) - t.is(sub, subject) -}) - -test('options.issuer', t => { - const issuer = 'foo' - const { iss } = JWT.decode(JWT.sign({ iss: 'bar' }, key, { issuer })) - t.is(iss, issuer) -}) - -test('options.jti', t => { - const jti = 'foo' - const decoded = JWT.decode(JWT.sign({ jti: 'bar' }, key, { jti })) - t.is(decoded.jti, jti) -}) - -const epoch = 1265328501 -const now = new Date(epoch * 1000) - -test('options.iat false', t => { - const iat = false - t.deepEqual(JWT.decode(JWT.sign({}, key, { iat })), {}) -}) - -test('options.iat', t => { - const decoded = JWT.decode(JWT.sign({ iat: 'bar' }, key, { iat: true, now })) - t.is(decoded.iat, epoch) -}) - -test('options.audience', t => { - const audience = 'foo' - const { aud } = JWT.decode(JWT.sign({}, key, { audience })) - t.deepEqual(aud, audience) -}) - -test('options.audience (array)', t => { - const audience = ['foo'] - const { aud } = JWT.decode(JWT.sign({ aud: 'bar' }, key, { audience })) - t.deepEqual(aud, audience) -}) - -test('options.now', t => { - const { iat } = JWT.decode(JWT.sign({}, key, { now })) - t.deepEqual(iat, epoch) -}) - -test('options.expiresIn', t => { - const { exp } = JWT.decode(JWT.sign({ exp: 'bar' }, key, { now, expiresIn: '20s' })) - t.deepEqual(exp, epoch + 20) -}) - -test('options.notBefore', t => { - const { nbf } = JWT.decode(JWT.sign({ nbf: 'bar' }, key, { now, notBefore: '20m' })) - t.deepEqual(nbf, epoch + 20 * 60) -}) - -test('when options arent in effect', t => { - const payload = { - sub: 0, - aud: 1, - iss: 2, - iat: 'iat', - nonce: 3, - exp: 'exp', - nbf: 'nbf' - } - t.deepEqual(payload, JWT.decode(JWT.sign(payload, key, { iat: false }))) -}) - -test('"enc" key is not usable for signing', t => { - const k = JWK.generateSync('oct', 256, { use: 'enc' }) - t.throws(() => { - JWT.sign({}, k) - }, { instanceOf: TypeError, message: 'a key with "use":"enc" is not usable for signing' }) -}) diff --git a/test/jwt/sign.test.mjs b/test/jwt/sign.test.mjs new file mode 100644 index 0000000000..32bc39ce98 --- /dev/null +++ b/test/jwt/sign.test.mjs @@ -0,0 +1,83 @@ +/* eslint-disable no-param-reassign */ +import test from 'ava'; +import timekeeper from 'timekeeper'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +Promise.all([import(`${root}/jwt/sign`), import(`${root}/jws/compact/verify`)]).then( + ([{ default: SignJWT }, { default: compactVerify }]) => { + const now = 1604416038; + + test.before(async (t) => { + t.context.secret = new Uint8Array(32); + t.context.payload = { 'urn:example:claim': true }; + + timekeeper.freeze(now * 1000); + }); + + test.after(timekeeper.reset); + + test('SignJWT', async (t) => { + const jwt = await new SignJWT(t.context.payload) + .setProtectedHeader({ alg: 'HS256' }) + .sign(t.context.secret); + t.is( + jwt, + 'eyJhbGciOiJIUzI1NiJ9.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6dHJ1ZX0.yPnOE--rxp3rJaYy0iZaW2Vswvus05G6_ZBdXqIdjGo', + ); + }); + + test('new SignJWT', (t) => { + t.throws(() => new SignJWT(), { + instanceOf: TypeError, + message: 'JWT Claims Set MUST be an object', + }); + }); + + test('Signed JWTs cannot use unencoded payload', async (t) => { + await t.throwsAsync( + () => + new SignJWT({}) + .setProtectedHeader({ alg: 'HS256', crit: ['b64'], b64: false }) + .sign(t.context.secret), + { code: 'ERR_JWT_INVALID', message: 'JWTs MUST NOT use unencoded payload' }, + ); + }); + + async function testJWTsetFunction(t, method, claim, value, expected = value) { + const jwt = await new SignJWT({}) + .setProtectedHeader({ alg: 'HS256' }) + [method](value) + .sign(t.context.secret); + const { payload } = await compactVerify(jwt, async (header, token) => { + t.true('alg' in header); + t.is(header.alg, 'HS256'); + t.true('payload' in token); + t.true('protected' in token); + t.true('signature' in token); + return t.context.secret; + }); + const claims = JSON.parse(new TextDecoder().decode(payload)); + t.true(claim in claims); + t.is(claims[claim], expected); + } + testJWTsetFunction.title = (title, method, claim, value) => + `SignJWT.prototype.${method} called with ${value}`; + + test(testJWTsetFunction, 'setIssuer', 'iss', 'urn:example:issuer'); + test(testJWTsetFunction, 'setSubject', 'sub', 'urn:example:subject'); + test(testJWTsetFunction, 'setAudience', 'aud', 'urn:example:audience'); + test(testJWTsetFunction, 'setJti', 'jti', 'urn:example:jti'); + test(testJWTsetFunction, 'setIssuedAt', 'iat', 0); + test(testJWTsetFunction, 'setIssuedAt', 'iat', undefined, now); + test(testJWTsetFunction, 'setExpirationTime', 'exp', 0); + test(testJWTsetFunction, 'setExpirationTime', 'exp', '10s', now + 10); + test(testJWTsetFunction, 'setNotBefore', 'nbf', 0); + test(testJWTsetFunction, 'setNotBefore', 'nbf', '10s', now + 10); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jwt/unsecured.test.js b/test/jwt/unsecured.test.js deleted file mode 100644 index 71d529ba1f..0000000000 --- a/test/jwt/unsecured.test.js +++ /dev/null @@ -1,46 +0,0 @@ -const test = require('ava') - -const { errors, JWK: { generateSync, None }, JWT } = require('../..') - -const properKey = generateSync('oct') - -const PAYLOAD = { sub: 'foobar', iat: 0 } - -test('JWS.None "signs" (JWT)', t => { - const unsignedJWS = JWT.sign(PAYLOAD, None, { iat: false }) - t.deepEqual( - JWT.verify(unsignedJWS, None, { complete: true }), - { - key: None, - payload: { - ...PAYLOAD - }, - header: { - alg: 'none' - }, - signature: '' - } - ) -}) - -test('JWS.None fails to verify real tokens (JWT)', t => { - const signedToken = JWT.sign(PAYLOAD, properKey) - t.throws(() => { - JWT.verify(signedToken, None) - }, { - instanceOf: errors.JWKKeySupport, - code: 'ERR_JWK_KEY_SUPPORT', - message: 'the key does not support HS256 verify algorithm' - }) -}) - -test('JWS.None fails to verify None signed tokens with a signature (JWT)', t => { - const unsignedJWS = JWT.sign(PAYLOAD, None) - t.throws(() => { - JWT.verify(`${unsignedJWS}fooba`, None) - }, { - instanceOf: errors.JWSVerificationFailed, - code: 'ERR_JWS_VERIFICATION_FAILED', - message: 'signature verification failed' - }) -}) diff --git a/test/jwt/unsecured.test.mjs b/test/jwt/unsecured.test.mjs new file mode 100644 index 0000000000..56a1654f80 --- /dev/null +++ b/test/jwt/unsecured.test.mjs @@ -0,0 +1,77 @@ +/* eslint-disable no-param-reassign */ +import test from 'ava'; +import timekeeper from 'timekeeper'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +import(`${root}/jwt/unsecured`).then( + ({ default: UnsecuredJWT }) => { + const now = 1604416038; + + test.before(async (t) => { + t.context.payload = { 'urn:example:claim': true }; + + timekeeper.freeze(now * 1000); + }); + + test.after(timekeeper.reset); + + test('UnsecuredJWT', async (t) => { + const jwt = new UnsecuredJWT(t.context.payload).encode(); + t.is(jwt, 'eyJhbGciOiJub25lIn0.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6dHJ1ZX0.'); + }); + + test('UnsecuredJWT validations', (t) => { + t.throws(() => UnsecuredJWT.decode(null), { + code: 'ERR_JWT_INVALID', + message: 'Unsecured JWT must be a string', + }); + t.throws(() => UnsecuredJWT.decode('....'), { + code: 'ERR_JWT_INVALID', + message: 'Invalid Unsecured JWT', + }); + t.throws(() => UnsecuredJWT.decode('..'), { + code: 'ERR_JWT_INVALID', + message: 'Invalid Unsecured JWT', + }); + t.throws(() => UnsecuredJWT.decode('..foo'), { + code: 'ERR_JWT_INVALID', + message: 'Invalid Unsecured JWT', + }); + t.throws( + () => UnsecuredJWT.decode('eyJhbGciOiJIUzI1NiJ9.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6dHJ1ZX0.'), + { code: 'ERR_JWT_INVALID', message: 'Invalid Unsecured JWT' }, + ); + }); + + test('new UnsecuredJWT', (t) => { + t.throws(() => new UnsecuredJWT(), { + instanceOf: TypeError, + message: 'JWT Claims Set MUST be an object', + }); + }); + + async function testJWTsetFunction(t, method, claim, value, expected = value) { + const jwt = new UnsecuredJWT({})[method](value).encode(); + const { payload: claims } = UnsecuredJWT.decode(jwt); + t.true(claim in claims); + t.is(claims[claim], expected); + } + testJWTsetFunction.title = (title, method, claim, value) => + `UnsecuredJWT.prototype.${method} called with ${value}`; + + test(testJWTsetFunction, 'setIssuer', 'iss', 'urn:example:issuer'); + test(testJWTsetFunction, 'setSubject', 'sub', 'urn:example:subject'); + test(testJWTsetFunction, 'setAudience', 'aud', 'urn:example:audience'); + test(testJWTsetFunction, 'setJti', 'jti', 'urn:example:jti'); + test(testJWTsetFunction, 'setIssuedAt', 'iat', 0); + test(testJWTsetFunction, 'setIssuedAt', 'iat', undefined, now); + test(testJWTsetFunction, 'setExpirationTime', 'exp', '10s', now + 10); + test(testJWTsetFunction, 'setNotBefore', 'nbf', 0); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/jwt/verify.test.js b/test/jwt/verify.test.js deleted file mode 100644 index 2eebc005c4..0000000000 --- a/test/jwt/verify.test.js +++ /dev/null @@ -1,937 +0,0 @@ -const test = require('ava') - -const { JWS, JWT, JWK, JWKS, errors } = require('../..') - -const key = JWK.generateSync('oct') -const token = JWT.sign({}, key, { iat: false }) - -const string = (t, option, opts, method = JWT.verify) => { - ;['', false, [], {}, Buffer, Buffer.from('foo'), 0, Infinity].forEach((val) => { - t.throws(() => { - method(token, key, { ...opts, [option]: val }) - }, { instanceOf: TypeError, message: `options.${option} must be a string` }) - }) -} - -test('options.complete true', t => { - const token = JWT.sign({}, key) - const completeResult = JWT.verify(token, key, { complete: true }) - t.is(completeResult.key, key) -}) - -test('options.complete with KeyStore', t => { - const ks = new JWKS.KeyStore(JWK.generateSync('oct'), key) - const token = JWT.sign({}, key, { kid: false }) - const completeResult = JWT.verify(token, ks, { complete: true }) - t.is(completeResult.key, key) -}) - -test('options must be an object', t => { - ;['', false, [], Buffer, Buffer.from('foo'), 0, Infinity].forEach((val) => { - t.throws(() => { - JWT.verify(token, key, val) - }, { instanceOf: TypeError, message: 'options must be an object' }) - }) -}) - -test('options.clockTolerance must be a string', string, 'clockTolerance') -test('options.jti must be a string', string, 'jti') -test('options.maxTokenAge must be a string', string, 'maxTokenAge') -test('options.subject must be a string', string, 'subject') - -const boolean = (t, option) => { - ;['', 'foo', [], {}, Buffer, Buffer.from('foo'), 0, Infinity].forEach((val) => { - t.throws(() => { - JWT.verify(token, key, { [option]: val }) - }, { instanceOf: TypeError, message: `options.${option} must be a boolean` }) - }) -} -test('options.complete must be boolean', boolean, 'complete') -test('options.ignoreExp must be boolean', boolean, 'ignoreExp') -test('options.ignoreNbf must be boolean', boolean, 'ignoreNbf') -test('options.ignoreIat must be boolean', boolean, 'ignoreIat') - -test('options.issuer must be string or array of strings', t => { - ;['', false, [], Buffer, Buffer.from('foo'), 0, Infinity].forEach((val) => { - t.throws(() => { - JWT.verify(token, key, { issuer: val }) - }, { instanceOf: TypeError, message: 'options.issuer must be a string or an array of strings' }) - t.throws(() => { - JWT.verify(token, key, { issuer: [val] }) - }, { instanceOf: TypeError, message: 'options.issuer must be a string or an array of strings' }) - }) -}) - -test('options.audience must be string or array of strings', t => { - ;['', false, [], Buffer, Buffer.from('foo'), 0, Infinity].forEach((val) => { - t.throws(() => { - JWT.verify(token, key, { audience: val }) - }, { instanceOf: TypeError, message: 'options.audience must be a string or an array of strings' }) - t.throws(() => { - JWT.verify(token, key, { audience: [val] }) - }, { instanceOf: TypeError, message: 'options.audience must be a string or an array of strings' }) - }) -}) - -test('options.algorithms must be string or array of strings', t => { - ;['', false, [], Buffer, Buffer.from('foo'), 0, Infinity].forEach((val) => { - t.throws(() => { - JWT.verify(token, key, { algorithms: val }) - }, { instanceOf: TypeError, message: 'options.algorithms must be an array of strings' }) - t.throws(() => { - JWT.verify(token, key, { algorithms: [val] }) - }, { instanceOf: TypeError, message: 'options.algorithms must be an array of strings' }) - }) -}) - -test('options.crit must be string or array of strings', t => { - ;['', false, [], Buffer, Buffer.from('foo'), 0, Infinity].forEach((val) => { - t.throws(() => { - JWT.verify(token, key, { crit: val }) - }, { instanceOf: TypeError, message: 'options.crit must be an array of strings' }) - t.throws(() => { - JWT.verify(token, key, { crit: [val] }) - }, { instanceOf: TypeError, message: 'options.crit must be an array of strings' }) - }) -}) - -test('options.now must be a valid date', t => { - ;['', 'foo', [], {}, Buffer, Buffer.from('foo'), 0, Infinity, new Date('foo')].forEach((val) => { - t.throws(() => { - JWT.verify(token, key, { now: val }) - }, { instanceOf: TypeError, message: 'options.now must be a valid Date object' }) - }) -}) - -test('options.ignoreIat & options.maxTokenAge may not be used together', t => { - t.throws(() => { - JWT.verify(token, key, { ignoreIat: true, maxTokenAge: '2d' }) - }, { instanceOf: TypeError, message: 'options.ignoreIat and options.maxTokenAge cannot used together' }) -}) - -;['iat', 'exp', 'nbf'].forEach((claim) => { - test(`"${claim} must be a timestamp when provided"`, t => { - ;['', 'foo', true, null, [], {}].forEach((val) => { - const err = t.throws(() => { - const invalid = JWS.sign({ [claim]: val }, key) - JWT.verify(invalid, key) - }, { instanceOf: errors.JWTClaimInvalid, message: `"${claim}" claim must be a JSON numeric value` }) - - t.is(err.claim, claim) - t.is(err.reason, 'invalid') - }) - }) -}) - -;['jti', 'sub'].forEach((claim) => { - test(`"${claim} must be a string when provided"`, t => { - ;['', 0, 1, true, null, [], {}].forEach((val) => { - const err = t.throws(() => { - const invalid = JWS.sign({ [claim]: val }, key) - JWT.verify(invalid, key) - }, { instanceOf: errors.JWTClaimInvalid, message: `"${claim}" claim must be a string` }) - - t.is(err.claim, claim) - t.is(err.reason, 'invalid') - }) - }) -}) - -;['aud', 'iss'].forEach((claim) => { - test(`"${claim} must be a string when provided"`, t => { - ;['', 0, 1, true, null, [], {}].forEach((val) => { - let err - err = t.throws(() => { - const invalid = JWS.sign({ [claim]: val }, key) - JWT.verify(invalid, key) - }, { instanceOf: errors.JWTClaimInvalid, message: `"${claim}" claim must be a string or array of strings` }) - t.is(err.claim, claim) - t.is(err.reason, 'invalid') - - err = t.throws(() => { - const invalid = JWS.sign({ [claim]: [val] }, key) - JWT.verify(invalid, key) - }, { instanceOf: errors.JWTClaimInvalid, message: `"${claim}" claim must be a string or array of strings` }) - t.is(err.claim, claim) - t.is(err.reason, 'invalid') - }) - }) -}) - -Object.entries({ - issuer: 'iss', - jti: 'jti', - subject: 'sub' -}).forEach(([option, claim]) => { - test(`option.${option} validation fails`, t => { - let err - err = t.throws(() => { - const invalid = JWS.sign({ [claim]: 'foo' }, key) - JWT.verify(invalid, key, { [option]: 'bar' }) - }, { instanceOf: errors.JWTClaimInvalid, message: `unexpected "${claim}" claim value` }) - t.is(err.claim, claim) - t.is(err.reason, 'check_failed') - - err = t.throws(() => { - const invalid = JWS.sign({ [claim]: undefined }, key) - JWT.verify(invalid, key, { [option]: 'bar' }) - }, { instanceOf: errors.JWTClaimInvalid, message: `"${claim}" claim is missing` }) - t.is(err.claim, claim) - t.is(err.reason, 'missing') - }) - - test(`option.${option} validation success`, t => { - const token = JWT.sign({ [claim]: 'foo' }, key) - JWT.verify(token, key, { [option]: 'foo' }) - t.pass() - }) -}) - -test('option.typ validation fails', t => { - let err - err = t.throws(() => { - const invalid = JWT.sign({}, key, { header: { typ: 'foo' } }) - JWT.verify(invalid, key, { typ: 'bar' }) - }, { instanceOf: errors.JWTClaimInvalid, message: 'unexpected "typ" JWT header value' }) - t.is(err.claim, 'typ') - t.is(err.reason, 'check_failed') - - err = t.throws(() => { - const invalid = JWS.sign({}, key, { header: { typ: undefined } }) - JWT.verify(invalid, key, { typ: 'bar' }) - }, { instanceOf: errors.JWTClaimInvalid, message: '"typ" header parameter is missing' }) - t.is(err.claim, 'typ') - t.is(err.reason, 'missing') -}) - -test('option.typ validation success', t => { - { - const token = JWT.sign({}, key, { header: { typ: 'foo' } }) - JWT.verify(token, key, { typ: 'foo' }) - } - { - const token = JWT.sign({}, key, { header: { typ: 'application/foo' } }) - JWT.verify(token, key, { typ: 'foo' }) - } - { - const token = JWT.sign({}, key, { header: { typ: 'foo' } }) - JWT.verify(token, key, { typ: 'application/foo' }) - } - { - const token = JWT.sign({}, key, { header: { typ: 'foO' } }) - JWT.verify(token, key, { typ: 'application/foo' }) - } - { - const token = JWT.sign({}, key, { header: { typ: 'application/foo' } }) - JWT.verify(token, key, { typ: 'fOo' }) - } - t.pass() -}) - -test('option.audience validation fails', t => { - let err - err = t.throws(() => { - const invalid = JWS.sign({ aud: 'foo' }, key) - JWT.verify(invalid, key, { audience: 'bar' }) - }, { instanceOf: errors.JWTClaimInvalid, message: 'unexpected "aud" claim value' }) - t.is(err.claim, 'aud') - t.is(err.reason, 'check_failed') - - err = t.throws(() => { - const invalid = JWS.sign({ aud: ['foo'] }, key) - JWT.verify(invalid, key, { audience: 'bar' }) - }, { instanceOf: errors.JWTClaimInvalid, message: 'unexpected "aud" claim value' }) - t.is(err.claim, 'aud') - t.is(err.reason, 'check_failed') -}) - -test('option.audience validation success', t => { - let token = JWT.sign({ aud: 'foo' }, key) - JWT.verify(token, key, { audience: 'foo' }) - token = JWT.sign({ aud: 'foo' }, key) - JWT.verify(token, key, { audience: ['foo'] }) - token = JWT.sign({ aud: 'foo' }, key) - JWT.verify(token, key, { audience: ['foo', 'bar'] }) - - token = JWT.sign({ aud: ['foo', 'bar'] }, key) - JWT.verify(token, key, { audience: 'foo' }) - token = JWT.sign({ aud: ['foo', 'bar'] }, key) - JWT.verify(token, key, { audience: ['foo'] }) - token = JWT.sign({ aud: ['foo', 'bar'] }, key) - JWT.verify(token, key, { audience: ['foo', 'bar'] }) - t.pass() -}) - -const epoch = 1265328501 -const now = new Date(epoch * 1000) - -test('option.maxTokenAge requires iat to be in the payload', t => { - const err = t.throws(() => { - const invalid = JWS.sign({}, key) - JWT.verify(invalid, key, { maxTokenAge: '30s' }) - }, { instanceOf: errors.JWTClaimInvalid, message: '"iat" claim is missing' }) - t.is(err.claim, 'iat') - t.is(err.reason, 'missing') -}) - -test('option.maxTokenAge checks iat elapsed time', t => { - const err = t.throws(() => { - const invalid = JWS.sign({ iat: epoch - 31 }, key) - JWT.verify(invalid, key, { maxTokenAge: '30s', now }) - }, { instanceOf: errors.JWTExpired, code: 'ERR_JWT_EXPIRED', message: '"iat" claim timestamp check failed (too far in the past)' }) - t.true(err instanceof errors.JWTClaimInvalid) - t.is(err.claim, 'iat') - t.is(err.reason, 'check_failed') -}) - -test('option.maxTokenAge checks iat (with tolerance)', t => { - const token = JWT.sign({ iat: epoch - 31 }, key, { now }) - JWT.verify(token, key, { maxTokenAge: '30s', now, clockTolerance: '1s' }) - t.pass() -}) - -test('iat check (pass)', t => { - const token = JWT.sign({ iat: epoch - 30 }, key, { iat: false }) - JWT.verify(token, key, { now }) - t.pass() -}) - -test('iat check (pass equal)', t => { - const token = JWT.sign({}, key, { now }) - JWT.verify(token, key, { now }) - t.pass() -}) - -test('iat check (pass with tolerance)', t => { - const token = JWT.sign({}, key, { now: new Date((epoch + 1) * 1000) }) - JWT.verify(token, key, { now, clockTolerance: '1s' }) - t.pass() -}) - -test('iat check (failed)', t => { - const token = JWT.sign({}, key, { now: new Date((epoch + 1) * 1000) }) - const err = t.throws(() => { - JWT.verify(token, key, { now }) - }, { instanceOf: errors.JWTClaimInvalid, message: '"iat" claim timestamp check failed (it should be in the past)' }) - t.is(err.claim, 'iat') - t.is(err.reason, 'check_failed') -}) - -test('iat future check (ignored since exp is also present)', t => { - const token = JWT.sign({}, key, { now: new Date((epoch + 1) * 1000), expiresIn: '2h' }) - JWT.verify(token, key, { now }) - t.pass() -}) - -test('iat future check (part of maxTokenAge)', t => { - const token = JWT.sign({}, key, { now: new Date((epoch + 1) * 1000), expiresIn: '2h' }) - const err = t.throws(() => { - JWT.verify(token, key, { now, maxTokenAge: '30s' }) - }, { instanceOf: errors.JWTClaimInvalid, message: '"iat" claim timestamp check failed (it should be in the past)' }) - t.is(err.claim, 'iat') - t.is(err.reason, 'check_failed') -}) - -test('iat future check with tolerance (part of maxTokenAge)', t => { - const token = JWT.sign({}, key, { now: new Date((epoch + 1) * 1000), expiresIn: '2h' }) - JWT.verify(token, key, { now, maxTokenAge: '30s', clockTolerance: '1s' }) - t.pass() -}) - -test('iat check (passed because of ignoreIat)', t => { - const token = JWT.sign({}, key, { now: new Date((epoch + 1) * 1000) }) - JWT.verify(token, key, { now, ignoreIat: true }) - t.pass() -}) - -test('exp check (pass)', t => { - const token = JWT.sign({ exp: epoch + 30 }, key, { iat: false }) - JWT.verify(token, key, { now }) - t.pass() -}) - -test('exp check (pass equal - 1)', t => { - const token = JWT.sign({ exp: epoch + 1 }, key, { iat: false }) - JWT.verify(token, key, { now }) - t.pass() -}) - -test('exp check (pass with tolerance)', t => { - const token = JWT.sign({ exp: epoch }, key, { iat: false }) - JWT.verify(token, key, { now, clockTolerance: '1s' }) - t.pass() -}) - -test('exp check (failed equal)', t => { - const token = JWT.sign({ exp: epoch }, key, { iat: false }) - const err = t.throws(() => { - JWT.verify(token, key, { now }) - }, { instanceOf: errors.JWTExpired, code: 'ERR_JWT_EXPIRED', message: '"exp" claim timestamp check failed' }) - t.true(err instanceof errors.JWTClaimInvalid) - t.is(err.claim, 'exp') - t.is(err.reason, 'check_failed') -}) - -test('exp check (failed normal)', t => { - const token = JWT.sign({ exp: epoch - 1 }, key, { iat: false }) - const err = t.throws(() => { - JWT.verify(token, key, { now }) - }, { instanceOf: errors.JWTExpired, code: 'ERR_JWT_EXPIRED', message: '"exp" claim timestamp check failed' }) - t.true(err instanceof errors.JWTClaimInvalid) - t.is(err.claim, 'exp') - t.is(err.reason, 'check_failed') -}) - -test('exp check (passed because of ignoreExp)', t => { - const token = JWT.sign({ exp: epoch - 10 }, key, { iat: false }) - JWT.verify(token, key, { now, ignoreExp: true }) - t.pass() -}) - -test('nbf check (pass)', t => { - const token = JWT.sign({ nbf: epoch - 30 }, key, { iat: false }) - JWT.verify(token, key, { now }) - t.pass() -}) - -test('nbf check (pass equal)', t => { - const token = JWT.sign({ nbf: epoch }, key, { iat: false }) - JWT.verify(token, key, { now }) - t.pass() -}) - -test('nbf check (pass with tolerance)', t => { - const token = JWT.sign({ nbf: epoch + 1 }, key, { iat: false }) - JWT.verify(token, key, { now, clockTolerance: '1s' }) - t.pass() -}) - -test('nbf check (failed)', t => { - const token = JWT.sign({ nbf: epoch + 10 }, key, { iat: false }) - const err = t.throws(() => { - JWT.verify(token, key, { now }) - }, { instanceOf: errors.JWTClaimInvalid, message: '"nbf" claim timestamp check failed' }) - t.is(err.claim, 'nbf') - t.is(err.reason, 'check_failed') -}) - -test('nbf check (passed because of ignoreIat)', t => { - const token = JWT.sign({ nbf: epoch + 10 }, key, { iat: false }) - JWT.verify(token, key, { now, ignoreNbf: true }) - t.pass() -}) - -{ - const token = JWT.sign({ }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', audience: 'client_id' }) - - test('IdToken.verify options must be an object', t => { - t.throws(() => { - JWT.IdToken.verify(token, key, []) - }, { instanceOf: TypeError, message: 'options must be an object' }) - }) - - test('IdToken.verify options.maxAuthAge must be a string', string, 'maxAuthAge', { issuer: 'foo', audience: 'bar' }, JWT.IdToken.verify) - test('IdToken.verify options.nonce must be a string', string, 'nonce', { issuer: 'foo', audience: 'bar' }, JWT.IdToken.verify) - - test('IdToken.verify', t => { - JWT.IdToken.verify(token, key, { issuer: 'issuer', audience: 'client_id' }) - t.pass() - }) - - test('IdToken.verify requires issuer option too', t => { - t.throws(() => { - JWT.IdToken.verify(token, key) - }, { instanceOf: TypeError, message: '"issuer" option is required to validate an ID Token' }) - }) - - test('IdToken.verify requires audience option too', t => { - t.throws(() => { - JWT.IdToken.verify(token, key, { issuer: 'issuer' }) - }, { instanceOf: TypeError, message: '"audience" option is required to validate an ID Token' }) - }) - - test('IdToken.verify mandates exp to be present', t => { - const err = t.throws(() => { - JWT.IdToken.verify( - JWT.sign({ }, key, { subject: 'subject', issuer: 'issuer', audience: 'client_id' }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"exp" claim is missing' }) - t.is(err.claim, 'exp') - t.is(err.reason, 'missing') - }) - - test('IdToken.verify mandates iat to be present', t => { - const err = t.throws(() => { - JWT.IdToken.verify( - JWT.sign({ }, key, { expiresIn: '10m', iat: false, subject: 'subject', issuer: 'issuer', audience: 'client_id' }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"iat" claim is missing' }) - t.is(err.claim, 'iat') - t.is(err.reason, 'missing') - }) - - test('IdToken.verify mandates sub to be present', t => { - const err = t.throws(() => { - JWT.IdToken.verify( - JWT.sign({ }, key, { expiresIn: '10m', issuer: 'issuer', audience: 'client_id' }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"sub" claim is missing' }) - t.is(err.claim, 'sub') - t.is(err.reason, 'missing') - }) - - test('IdToken.verify mandates iss to be present', t => { - const err = t.throws(() => { - JWT.IdToken.verify( - JWT.sign({ }, key, { expiresIn: '10m', subject: 'subject', audience: 'client_id' }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"iss" claim is missing' }) - t.is(err.claim, 'iss') - t.is(err.reason, 'missing') - }) - - test('IdToken.verify mandates aud to be present', t => { - const err = t.throws(() => { - JWT.IdToken.verify( - JWT.sign({ }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer' }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"aud" claim is missing' }) - t.is(err.claim, 'aud') - t.is(err.reason, 'missing') - }) - - test('IdToken.verify mandates azp to be present when multiple audiences are used', t => { - const err = t.throws(() => { - JWT.IdToken.verify( - JWT.sign({ }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', audience: ['client_id', 'another audience'] }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"azp" claim is missing' }) - t.is(err.claim, 'azp') - t.is(err.reason, 'missing') - }) - - test('IdToken.verify mandates azp to match the audience when required', t => { - const err = t.throws(() => { - JWT.IdToken.verify( - JWT.sign({ azp: 'mismatched' }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', audience: ['client_id', 'another audience'] }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: 'unexpected "azp" claim value' }) - t.is(err.claim, 'azp') - t.is(err.reason, 'check_failed') - }) - - test('IdToken.verify validates full id tokens', t => { - t.notThrows(() => { - JWT.IdToken.verify( - JWT.sign({ azp: 'client_id' }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', audience: ['client_id', 'another audience'] }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }) - }) - - test('IdToken.verify option.maxAuthAge requires auth_time to be in the payload', t => { - const err = t.throws(() => { - const invalid = JWT.sign({}, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', audience: 'client' }) - JWT.IdToken.verify(invalid, key, { maxAuthAge: '30s', issuer: 'issuer', audience: 'client' }) - }, { instanceOf: errors.JWTClaimInvalid, message: '"auth_time" claim is missing' }) - t.is(err.claim, 'auth_time') - t.is(err.reason, 'missing') - }) - - test('IdToken.verify option.maxAuthAge checks auth_time', t => { - const err = t.throws(() => { - const invalid = JWT.sign({ auth_time: epoch - 31 }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', audience: 'client' }) - JWT.IdToken.verify(invalid, key, { maxAuthAge: '30s', now, issuer: 'issuer', audience: 'client' }) - }, { instanceOf: errors.JWTClaimInvalid, message: '"auth_time" claim timestamp check failed (too much time has elapsed since the last End-User authentication)' }) - t.is(err.claim, 'auth_time') - t.is(err.reason, 'check_failed') - }) - - test('IdToken.verify option.maxAuthAge checks auth_time (with tolerance)', t => { - const token = JWT.sign({ auth_time: epoch - 31 }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', audience: 'client' }) - JWT.IdToken.verify(token, key, { maxAuthAge: '30s', now, clockTolerance: '1s', issuer: 'issuer', audience: 'client' }) - t.pass() - }) - - test('IdToken.verify auth_time must be a timestamp when provided', t => { - ;['', 'foo', true, null, [], {}].forEach((val) => { - const err = t.throws(() => { - const invalid = JWT.sign({ auth_time: val }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', audience: 'client' }) - JWT.IdToken.verify(invalid, key, { issuer: 'issuer', audience: 'client' }) - }, { instanceOf: errors.JWTClaimInvalid, message: '"auth_time" claim must be a JSON numeric value' }) - - t.is(err.claim, 'auth_time') - t.is(err.reason, 'invalid') - }) - }) - - test('IdToken.verify option.nonce checks nonce value', t => { - const token = JWT.sign({ nonce: 'foobar' }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', audience: 'client' }) - JWT.IdToken.verify(token, key, { now, issuer: 'issuer', audience: 'client', nonce: 'foobar' }) - const err = t.throws(() => { - JWT.IdToken.verify(token, key, { now, issuer: 'issuer', audience: 'client', nonce: 'baz' }) - }, { instanceOf: errors.JWTClaimInvalid, message: 'unexpected "nonce" claim value' }) - - t.is(err.claim, 'nonce') - t.is(err.reason, 'check_failed') - }) -} - -{ - const token = JWT.sign({ - events: { - 'http://schemas.openid.net/event/backchannel-logout': {} - } - }, key, { jti: 'foo', subject: 'subject', issuer: 'issuer', audience: 'client_id' }) - - test('LogoutToken.verify options must be an object', t => { - t.throws(() => { - JWT.LogoutToken.verify(token, key, []) - }, { instanceOf: TypeError, message: 'options must be an object' }) - }) - - test('LogoutToken.verify', t => { - JWT.LogoutToken.verify(token, key, { issuer: 'issuer', audience: 'client_id' }) - t.pass() - }) - - test('LogoutToken.verify requires issuer option too', t => { - t.throws(() => { - JWT.LogoutToken.verify(token, key) - }, { instanceOf: TypeError, message: '"issuer" option is required to validate a Logout Token' }) - }) - - test('LogoutToken.verify requires audience option too', t => { - t.throws(() => { - JWT.LogoutToken.verify(token, key, { issuer: 'issuer' }) - }, { instanceOf: TypeError, message: '"audience" option is required to validate a Logout Token' }) - }) - - test('LogoutToken.verify mandates jti to be present', t => { - const err = t.throws(() => { - JWT.LogoutToken.verify( - JWT.sign({ }, key, { subject: 'subject', issuer: 'issuer', audience: 'client_id' }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"jti" claim is missing' }) - t.is(err.claim, 'jti') - t.is(err.reason, 'missing') - }) - - test('LogoutToken.verify mandates events to be present', t => { - const err = t.throws(() => { - JWT.LogoutToken.verify( - JWT.sign({ }, key, { jti: 'foo', subject: 'subject', issuer: 'issuer', audience: 'client_id' }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"events" claim is missing' }) - t.is(err.claim, 'events') - t.is(err.reason, 'missing') - }) - - test('LogoutToken.verify mandates events to be an object', t => { - const err = t.throws(() => { - JWT.LogoutToken.verify( - JWT.sign({ - events: [] - }, key, { jti: 'foo', subject: 'subject', issuer: 'issuer', audience: 'client_id' }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"events" claim must be an object' }) - t.is(err.claim, 'events') - t.is(err.reason, 'invalid') - }) - - test('LogoutToken.verify mandates events to have the backchannel logout member', t => { - const err = t.throws(() => { - JWT.LogoutToken.verify( - JWT.sign({ - events: {} - }, key, { jti: 'foo', subject: 'subject', issuer: 'issuer', audience: 'client_id' }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"http://schemas.openid.net/event/backchannel-logout" member is missing in the "events" claim' }) - t.is(err.claim, 'events') - t.is(err.reason, 'invalid') - }) - - test('LogoutToken.verify mandates events to have the backchannel logout member thats an object', t => { - const err = t.throws(() => { - JWT.LogoutToken.verify( - JWT.sign({ - events: { - 'http://schemas.openid.net/event/backchannel-logout': [] - } - }, key, { jti: 'foo', subject: 'subject', issuer: 'issuer', audience: 'client_id' }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"http://schemas.openid.net/event/backchannel-logout" member in the "events" claim must be an object' }) - t.is(err.claim, 'events') - t.is(err.reason, 'invalid') - }) - - test('LogoutToken.verify mandates iat to be present', t => { - const err = t.throws(() => { - JWT.LogoutToken.verify( - JWT.sign({ }, key, { jti: 'foo', iat: false, subject: 'subject', issuer: 'issuer', audience: 'client_id' }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"iat" claim is missing' }) - t.is(err.claim, 'iat') - t.is(err.reason, 'missing') - }) - - test('LogoutToken.verify mandates sub or sid to be present', t => { - const err = t.throws(() => { - JWT.LogoutToken.verify( - JWT.sign({ }, key, { jti: 'foo', issuer: 'issuer', audience: 'client_id' }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: 'either "sid" or "sub" (or both) claims must be present' }) - t.is(err.claim, 'unspecified') - t.is(err.reason, 'unspecified') - }) - - test('LogoutToken.verify mandates sid to be a string when present', t => { - const err = t.throws(() => { - JWT.LogoutToken.verify( - JWT.sign({ sid: true }, key, { jti: 'foo', issuer: 'issuer', audience: 'client_id' }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"sid" claim must be a string' }) - t.is(err.claim, 'sid') - t.is(err.reason, 'invalid') - }) - - test('LogoutToken.verify prohibits nonce', t => { - const err = t.throws(() => { - JWT.LogoutToken.verify( - JWT.sign({ nonce: 'foo' }, key, { subject: 'subject', jti: 'foo', issuer: 'issuer', audience: 'client_id' }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"nonce" claim is prohibited' }) - t.is(err.claim, 'nonce') - t.is(err.reason, 'prohibited') - }) - - test('LogoutToken.verify mandates iss to be present', t => { - const err = t.throws(() => { - JWT.LogoutToken.verify( - JWT.sign({ }, key, { jti: 'foo', subject: 'subject', audience: 'client_id' }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"iss" claim is missing' }) - t.is(err.claim, 'iss') - t.is(err.reason, 'missing') - }) - - test('LogoutToken.verify mandates aud to be present', t => { - const err = t.throws(() => { - JWT.LogoutToken.verify( - JWT.sign({ }, key, { jti: 'foo', subject: 'subject', issuer: 'issuer' }), - key, - { issuer: 'issuer', audience: 'client_id' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"aud" claim is missing' }) - t.is(err.claim, 'aud') - t.is(err.reason, 'missing') - }) -} - -{ - const token = JWT.sign({ client_id: 'client_id' }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', audience: 'RS', jti: 'random', header: { typ: 'at+JWT' } }) - - test('AccessToken.verify options must be an object', t => { - t.throws(() => { - JWT.AccessToken.verify(token, key, []) - }, { instanceOf: TypeError, message: 'options must be an object' }) - }) - - test('AccessToken.verify options.maxAuthAge must be a string', string, 'maxAuthAge', { issuer: 'foo', audience: 'bar' }, JWT.AccessToken.verify) - - test('AccessToken.verify', t => { - JWT.AccessToken.verify(token, key, { issuer: 'issuer', audience: 'RS' }) - t.pass() - }) - - test('AccessToken.verify requires issuer option too', t => { - t.throws(() => { - JWT.AccessToken.verify(token, key) - }, { instanceOf: TypeError, message: '"issuer" option is required to validate a JWT Access Token' }) - }) - - test('AccessToken.verify requires audience option too', t => { - t.throws(() => { - JWT.AccessToken.verify(token, key, { issuer: 'issuer' }) - }, { instanceOf: TypeError, message: '"audience" option is required to validate a JWT Access Token' }) - }) - - test('AccessToken.verify mandates exp to be present', t => { - const err = t.throws(() => { - JWT.AccessToken.verify( - JWT.sign({ client_id: 'client_id' }, key, { subject: 'subject', issuer: 'issuer', audience: 'RS', jti: 'random', header: { typ: 'at+JWT' } }), - key, - { issuer: 'issuer', audience: 'RS' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"exp" claim is missing' }) - t.is(err.claim, 'exp') - t.is(err.reason, 'missing') - }) - - test('AccessToken.verify mandates client_id to be present', t => { - const err = t.throws(() => { - JWT.AccessToken.verify( - JWT.sign({ }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', audience: 'RS', jti: 'random', header: { typ: 'at+JWT' } }), - key, - { issuer: 'issuer', audience: 'RS' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"client_id" claim is missing' }) - t.is(err.claim, 'client_id') - t.is(err.reason, 'missing') - }) - - test('AccessToken.verify mandates jti to be present', t => { - const err = t.throws(() => { - JWT.AccessToken.verify( - JWT.sign({ }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', audience: 'RS', header: { typ: 'at+JWT' } }), - key, - { issuer: 'issuer', audience: 'RS' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"jti" claim is missing' }) - t.is(err.claim, 'jti') - t.is(err.reason, 'missing') - }) - - test('AccessToken.verify mandates iat to be present', t => { - const err = t.throws(() => { - JWT.AccessToken.verify( - JWT.sign({ }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', audience: 'RS', iat: false, header: { typ: 'at+JWT' } }), - key, - { issuer: 'issuer', audience: 'RS' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"iat" claim is missing' }) - t.is(err.claim, 'iat') - t.is(err.reason, 'missing') - }) - - test('AccessToken.verify mandates sub to be present', t => { - const err = t.throws(() => { - JWT.AccessToken.verify( - JWT.sign({ client_id: 'client_id' }, key, { expiresIn: '10m', issuer: 'issuer', audience: 'RS', jti: 'random', header: { typ: 'at+JWT' } }), - key, - { issuer: 'issuer', audience: 'RS' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"sub" claim is missing' }) - t.is(err.claim, 'sub') - t.is(err.reason, 'missing') - }) - - test('AccessToken.verify mandates iss to be present', t => { - const err = t.throws(() => { - JWT.AccessToken.verify( - JWT.sign({ client_id: 'client_id' }, key, { expiresIn: '10m', subject: 'subject', audience: 'RS', jti: 'random', header: { typ: 'at+JWT' } }), - key, - { issuer: 'issuer', audience: 'RS' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"iss" claim is missing' }) - t.is(err.claim, 'iss') - t.is(err.reason, 'missing') - }) - - test('AccessToken.verify mandates aud to be present', t => { - const err = t.throws(() => { - JWT.AccessToken.verify( - JWT.sign({ client_id: 'client_id' }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', jti: 'random', header: { typ: 'at+JWT' } }), - key, - { issuer: 'issuer', audience: 'RS' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"aud" claim is missing' }) - t.is(err.claim, 'aud') - t.is(err.reason, 'missing') - }) - - test('AccessToken.verify mandates header typ to be present', t => { - const err = t.throws(() => { - JWT.AccessToken.verify( - JWT.sign({ client_id: 'client_id' }, key, { expiresIn: '10m', subject: 'subject', audience: 'RS', jti: 'random', issuer: 'issuer' }), - key, - { issuer: 'issuer', audience: 'RS' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: '"typ" header parameter is missing' }) - t.is(err.claim, 'typ') - t.is(err.reason, 'missing') - }) - - test('AccessToken.verify mandates header typ to be present and of the right value', t => { - const err = t.throws(() => { - JWT.AccessToken.verify( - JWT.sign({ client_id: 'client_id' }, key, { expiresIn: '10m', subject: 'subject', audience: 'RS', jti: 'random', issuer: 'issuer', header: { typ: 'JWT' } }), - key, - { issuer: 'issuer', audience: 'RS' } - ) - }, { instanceOf: errors.JWTClaimInvalid, message: 'unexpected "typ" JWT header value' }) - t.is(err.claim, 'typ') - t.is(err.reason, 'check_failed') - }) - - test('AccessToken.verify option.maxAuthAge requires auth_time to be in the payload', t => { - const err = t.throws(() => { - const invalid = JWT.sign({ client_id: 'client' }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', audience: 'RS', jti: 'random', header: { typ: 'at+JWT' } }) - JWT.AccessToken.verify(invalid, key, { maxAuthAge: '30s', issuer: 'issuer', audience: 'RS' }) - }, { instanceOf: errors.JWTClaimInvalid, message: '"auth_time" claim is missing' }) - t.is(err.claim, 'auth_time') - t.is(err.reason, 'missing') - }) - - test('AccessToken.verify option.maxAuthAge checks auth_time', t => { - const err = t.throws(() => { - const invalid = JWT.sign({ auth_time: epoch - 31, client_id: 'client' }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', audience: 'RS', jti: 'random', header: { typ: 'at+JWT' } }) - JWT.AccessToken.verify(invalid, key, { maxAuthAge: '30s', now, issuer: 'issuer', audience: 'RS' }) - }, { instanceOf: errors.JWTClaimInvalid, message: '"auth_time" claim timestamp check failed (too much time has elapsed since the last End-User authentication)' }) - t.is(err.claim, 'auth_time') - t.is(err.reason, 'check_failed') - }) - - test('AccessToken.verify option.maxAuthAge checks auth_time (with tolerance)', t => { - const token = JWT.sign({ auth_time: epoch - 31, client_id: 'client' }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', audience: 'RS', jti: 'random', header: { typ: 'at+JWT' } }) - JWT.AccessToken.verify(token, key, { maxAuthAge: '30s', now, clockTolerance: '1s', issuer: 'issuer', audience: 'RS' }) - t.pass() - }) - - test('AccessToken.verify auth_time must be a timestamp when provided', t => { - ;['', 'foo', true, null, [], {}].forEach((val) => { - const err = t.throws(() => { - const invalid = JWT.sign({ auth_time: val, client_id: 'client' }, key, { expiresIn: '10m', subject: 'subject', issuer: 'issuer', audience: 'RS', jti: 'random', header: { typ: 'at+JWT' } }) - JWT.AccessToken.verify(invalid, key, { issuer: 'issuer', audience: 'RS' }) - }, { instanceOf: errors.JWTClaimInvalid, message: '"auth_time" claim must be a JSON numeric value' }) - - t.is(err.claim, 'auth_time') - t.is(err.reason, 'invalid') - }) - }) -} diff --git a/test/jwt/verify.test.mjs b/test/jwt/verify.test.mjs new file mode 100644 index 0000000000..dd3d7e5641 --- /dev/null +++ b/test/jwt/verify.test.mjs @@ -0,0 +1,363 @@ +import test from 'ava'; +import timekeeper from 'timekeeper'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +Promise.all([ + import(`${root}/jwt/sign`), + import(`${root}/jwt/verify`), + import(`${root}/jws/compact/sign`), +]).then( + ([{ default: SignJWT }, { default: jwtVerify }, { default: CompactSign }]) => { + const now = 1604416038; + + test.before(async (t) => { + t.context.secret = new Uint8Array(32); + t.context.payload = { 'urn:example:claim': true }; + + timekeeper.freeze(now * 1000); + }); + + test.after(timekeeper.reset); + + test('Basic JWT Claims Set verification', async (t) => { + const issuer = 'urn:example:issuer'; + const subject = 'urn:example:subject'; + const audience = 'urn:example:audience'; + const jti = 'urn:example:jti'; + const nbf = now - 10; + const iat = now - 20; + const exp = now + 10; + const typ = 'urn:example:typ'; + const jwt = await new SignJWT(t.context.payload) + .setProtectedHeader({ alg: 'HS256', typ }) + .setIssuer(issuer) + .setSubject(subject) + .setAudience(audience) + .setJti(jti) + .setNotBefore(nbf) + .setExpirationTime(exp) + .setIssuedAt(iat) + .sign(t.context.secret); + + await t.notThrowsAsync( + jwtVerify(jwt, t.context.secret, { + issuer, + subject, + audience, + jti, + typ, + maxTokenAge: '30s', + }), + ); + }); + + test('Payload must be an object', async (t) => { + const encode = TextEncoder.prototype.encode.bind(new TextEncoder()); + for (const value of [0, 1, -1, true, false, null, [], '']) { + const token = await new CompactSign(encode(JSON.stringify(value))) + .setProtectedHeader({ alg: 'HS256' }) + .sign(t.context.secret); + await t.throwsAsync(jwtVerify(token, t.context.secret), { + code: 'ERR_JWT_INVALID', + message: 'JWT Claims Set must be a top-level JSON object', + }); + } + }); + + test('Payload must JSON parseable', async (t) => { + const encode = TextEncoder.prototype.encode.bind(new TextEncoder()); + const token = await new CompactSign(encode('{')) + .setProtectedHeader({ alg: 'HS256' }) + .sign(t.context.secret); + await t.throwsAsync(jwtVerify(token, t.context.secret), { + code: 'ERR_JWT_INVALID', + message: 'JWT Claims Set must be a top-level JSON object', + }); + }); + + test('algorithms options', async (t) => { + const jwt = await new SignJWT(t.context.payload) + .setProtectedHeader({ alg: 'HS256' }) + .sign(t.context.secret); + + await t.throwsAsync( + jwtVerify(jwt, t.context.secret, { + algorithms: ['PS256'], + }), + { + code: 'ERR_JOSE_ALG_NOT_ALLOWED', + message: '"alg" (Algorithm) Header Parameter not allowed', + }, + ); + }); + + test('typ verification', async (t) => { + { + const typ = 'urn:example:typ'; + const jwt = await new SignJWT(t.context.payload) + .setProtectedHeader({ alg: 'HS256', typ }) + .sign(t.context.secret); + + await t.notThrowsAsync( + jwtVerify(jwt, t.context.secret, { + typ: 'application/urn:example:typ', + }), + ); + + await t.throwsAsync( + jwtVerify(jwt, t.context.secret, { + typ: 'urn:example:typ:2', + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "typ" JWT header value' }, + ); + + await t.throwsAsync( + jwtVerify(jwt, t.context.secret, { + typ: 'application/urn:example:typ:2', + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "typ" JWT header value' }, + ); + } + { + const typ = 'application/urn:example:typ'; + const jwt = await new SignJWT(t.context.payload) + .setProtectedHeader({ alg: 'HS256', typ }) + .sign(t.context.secret); + + await t.notThrowsAsync( + jwtVerify(jwt, t.context.secret, { + typ: 'urn:example:typ', + }), + ); + + await t.throwsAsync( + jwtVerify(jwt, t.context.secret, { + typ: 'application/urn:example:typ:2', + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "typ" JWT header value' }, + ); + + await t.throwsAsync( + jwtVerify(jwt, t.context.secret, { + typ: 'urn:example:typ:2', + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "typ" JWT header value' }, + ); + } + }); + + test('Issuer[] verification', async (t) => { + const issuer = 'urn:example:issuer'; + const jwt = await new SignJWT(t.context.payload) + .setProtectedHeader({ alg: 'HS256' }) + .setIssuer(issuer) + .sign(t.context.secret); + + await t.notThrowsAsync( + jwtVerify(jwt, t.context.secret, { + issuer: [issuer], + }), + ); + }); + + test('Issuer[] verification failed', async (t) => { + const issuer = 'urn:example:issuer'; + const jwt = await new SignJWT(t.context.payload) + .setProtectedHeader({ alg: 'HS256' }) + .setIssuer(issuer) + .sign(t.context.secret); + + await t.throwsAsync( + jwtVerify(jwt, t.context.secret, { + issuer: [], + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "iss" claim value' }, + ); + }); + + test('Issuer[] verification failed []', async (t) => { + const issuer = 'urn:example:issuer'; + const jwt = await new SignJWT(t.context.payload) + .setProtectedHeader({ alg: 'HS256' }) + .setIssuer([issuer]) + .sign(t.context.secret); + + await t.throwsAsync( + jwtVerify(jwt, t.context.secret, { + issuer: [], + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "iss" claim value' }, + ); + }); + + test('Audience[] verification', async (t) => { + const audience = 'urn:example:audience'; + const jwt = await new SignJWT(t.context.payload) + .setProtectedHeader({ alg: 'HS256' }) + .setAudience(audience) + .sign(t.context.secret); + + await t.notThrowsAsync( + jwtVerify(jwt, t.context.secret, { + audience: [audience], + }), + ); + }); + + test('Audience[] verification failed', async (t) => { + const audience = 'urn:example:audience'; + const jwt = await new SignJWT(t.context.payload) + .setProtectedHeader({ alg: 'HS256' }) + .setAudience(audience) + .sign(t.context.secret); + + await t.throwsAsync( + jwtVerify(jwt, t.context.secret, { + audience: [], + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "aud" claim value' }, + ); + }); + + test('Audience[] verification failed []', async (t) => { + const audience = 'urn:example:audience'; + const jwt = await new SignJWT(t.context.payload) + .setProtectedHeader({ alg: 'HS256' }) + .setAudience([audience]) + .sign(t.context.secret); + + await t.throwsAsync( + jwtVerify(jwt, t.context.secret, { + audience: [], + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "aud" claim value' }, + ); + }); + + test('Subject verification failed', async (t) => { + const subject = 'urn:example:subject'; + const jwt = await new SignJWT(t.context.payload) + .setProtectedHeader({ alg: 'HS256' }) + .setSubject(subject) + .sign(t.context.secret); + + await t.throwsAsync( + jwtVerify(jwt, t.context.secret, { + subject: 'urn:example:subject:2', + }), + { code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', message: 'unexpected "sub" claim value' }, + ); + }); + + async function numericDateNumber(t, claim) { + const jwt = await new SignJWT({ [claim]: null }) + .setProtectedHeader({ alg: 'HS256' }) + .sign(t.context.secret); + + await t.throwsAsync(jwtVerify(jwt, t.context.secret), { + code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', + message: `"${claim}" claim must be a number`, + }); + } + numericDateNumber.title = (t, claim) => `${claim} must be a number`; + + test('clockTolerance num', async (t) => { + const jwt = await new SignJWT({ exp: now }) + .setProtectedHeader({ alg: 'HS256' }) + .sign(t.context.secret); + + await t.notThrowsAsync(jwtVerify(jwt, t.context.secret, { clockTolerance: 1 })); + await t.notThrowsAsync(jwtVerify(jwt, t.context.secret, { clockTolerance: '1s' })); + }); + + async function failingNumericDate(t, claims, assertion, verifyOptions) { + const jwt = await new SignJWT({ ...claims }) + .setProtectedHeader({ alg: 'HS256' }) + .sign(t.context.secret); + + await t.throwsAsync(jwtVerify(jwt, t.context.secret, { ...verifyOptions }), assertion); + } + + test( + 'exp must be in the future', + failingNumericDate, + { exp: now }, + { + code: 'ERR_JWT_EXPIRED', + message: '"exp" claim timestamp check failed', + }, + ); + + test( + 'nbf must be at least now', + failingNumericDate, + { nbf: now + 1 }, + { + code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', + message: '"nbf" claim timestamp check failed', + }, + ); + + test( + 'iat must be in the past (maxTokenAge, no exp)', + failingNumericDate, + { iat: now + 1 }, + { + code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', + message: '"iat" claim timestamp check failed (it should be in the past)', + }, + { + maxTokenAge: 5, + }, + ); + + test( + 'iat must be in the past (maxTokenAge, with exp)', + failingNumericDate, + { iat: now + 1, exp: now + 10 }, + { + code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', + message: '"iat" claim timestamp check failed (it should be in the past)', + }, + { + maxTokenAge: 5, + }, + ); + + test( + 'iat must be in the past (maxTokenAge, with exp, as a string)', + failingNumericDate, + { iat: now + 1, exp: now + 10 }, + { + code: 'ERR_JWT_CLAIM_VALIDATION_FAILED', + message: '"iat" claim timestamp check failed (it should be in the past)', + }, + { + maxTokenAge: '5s', + }, + ); + + test( + 'maxTokenAge option', + failingNumericDate, + { iat: now - 31 }, + { + code: 'ERR_JWT_EXPIRED', + message: '"iat" claim timestamp check failed (too far in the past)', + }, + { + maxTokenAge: '30s', + }, + ); + + for (const claim of ['iat', 'nbf', 'exp']) { + test(numericDateNumber, claim); + } + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/test/macros/generate.js b/test/macros/generate.js deleted file mode 100644 index f1c36b6a39..0000000000 --- a/test/macros/generate.js +++ /dev/null @@ -1,20 +0,0 @@ -const { generateKeyPairSync } = require('crypto') - -const { keyObjectSupported } = require('../../lib/help/runtime_support') -const { createPublicKey, createPrivateKey } = require('../../lib/help/key_object') - -module.exports = { - generateKeyPairSync (type, options) { - if (keyObjectSupported) { - return generateKeyPairSync(type, options) - } - - const { privateKey, publicKey } = generateKeyPairSync(type, { - publicKeyEncoding: { type: 'spki', format: 'pem' }, - privateKeyEncoding: { type: 'pkcs8', format: 'pem' }, - ...options - }) - - return { privateKey: createPrivateKey(privateKey), publicKey: createPublicKey(publicKey) } - } -} diff --git a/test/macros/index.js b/test/macros/index.js deleted file mode 100644 index 25506d8737..0000000000 --- a/test/macros/index.js +++ /dev/null @@ -1,194 +0,0 @@ -const { inspect } = require('util') -const { randomBytes } = require('crypto') - -const errors = require('../../lib/errors') -const base64url = require('../../lib/help/base64url') -const { encrypt, decrypt } = require('../../lib/jwe') -const { sign, verify } = require('../../lib/jws') - -const hasProperty = (t, obj, property, value, assertion = 'is') => { - t.true(property in obj) - if (value !== undefined) { - t[assertion](obj[property], value) - } -} - -hasProperty.title = (title, obj, property, value) => `${title} has property \`${property}\` with value ${inspect(value)}` - -const hasNoProperties = (t, obj, ...properties) => { - t.plan(properties.length) - for (const property of new Set(properties)) { - if (property in obj) { - t.fail(`expected property "${property}" not to be found`) - } else { - t.pass() - } - } -} -hasNoProperties.title = (title, obj, ...properties) => `${title} does not have properties ${properties.map(x => `\`${x}\``).join(', ')}` - -const hasProperties = (t, obj, ...properties) => { - t.plan(properties.length) - for (const property of new Set(properties)) { - if (property in obj) { - t.pass() - } else { - t.fail(`expected property "${property}" to be found`) - } - } -} -hasProperties.title = (title, obj, ...properties) => `${title} has properties ${properties.map(x => `\`${x}\``).join(', ')}` - -const compactJwt = (t, jwt, eHeader, ePayload) => { - let [aHeader, aPayload] = jwt().split('.') - aHeader = base64url.JSON.decode(aHeader) - aPayload = base64url.JSON.decode(aPayload) - - t.deepEqual(aHeader, eHeader) - t.deepEqual(aPayload, ePayload) -} - -const JWSPAYLOAD = randomBytes(10) -const JWS = { - success (t, sKey, vKey, alg) { - const signed = sign(JWSPAYLOAD, sKey, { alg }) - t.truthy(signed) - const verified = verify(signed, vKey) - t.deepEqual(verified, JWSPAYLOAD) - }, - failure (t, sKey, vKey, alg) { - const signed = sign.flattened(JWSPAYLOAD, sKey, { alg }) - t.truthy(signed) - - ;(() => { - const orig = signed.protected - - if (signed.protected.startsWith('-')) { - signed.protected = `Q${signed.protected.substr(1)}` - } else { - signed.protected = `-${signed.protected.substr(1)}` - } - t.throws(() => { - verify(signed, vKey) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'could not parse JWS protected header' }) - signed.protected = orig - })() - - ;(() => { - const orig = signed.protected - delete signed.protected - t.throws(() => { - verify(signed, vKey) - }, { instanceOf: errors.JWSInvalid, code: 'ERR_JWS_INVALID', message: 'missing JWS signature algorithm' }) - signed.protected = orig - })() - - ;(() => { - const orig = signed.signature - - if (signed.signature.startsWith('-')) { - signed.signature = `Q${signed.signature.substr(1)}` - } else { - signed.signature = `-${signed.signature.substr(1)}` - } - t.throws(() => { - verify(signed, vKey) - }, { instanceOf: errors.JWSVerificationFailed, code: 'ERR_JWS_VERIFICATION_FAILED' }) - signed.signature = signed.signature.substr(4) - t.throws(() => { - verify(signed, vKey) - }, { instanceOf: errors.JWSVerificationFailed, code: 'ERR_JWS_VERIFICATION_FAILED' }) - signed.signature = orig - })() - } -} - -const JWEPAYLOAD = randomBytes(10) -const JWE = { - success (t, eKey, dKey, alg, enc) { - const encrypted = encrypt(JWEPAYLOAD, eKey, { alg, enc }) - t.truthy(encrypted) - const decrypted = decrypt(encrypted, dKey) - t.deepEqual(decrypted, Buffer.from(JWEPAYLOAD)) - const encrypted2 = encrypt(JWEPAYLOAD, dKey, { alg, enc }) - t.truthy(encrypted2) - const decrypted2 = decrypt(encrypted, dKey) - t.deepEqual(decrypted2, Buffer.from(JWEPAYLOAD)) - }, - - failure (t, eKey, dKey, alg, enc) { - const encrypted = encrypt.flattened(JWEPAYLOAD, eKey, { alg, enc }) - t.truthy(encrypted) - if (encrypted.encrypted_key) { - const orig = encrypted.encrypted_key - - if (encrypted.encrypted_key.startsWith('-')) { - encrypted.encrypted_key = `Q${encrypted.encrypted_key.substr(1)}` - } else { - encrypted.encrypted_key = `-${encrypted.encrypted_key.substr(1)}` - } - t.throws(() => { - decrypt(encrypted, dKey) - }, { instanceOf: errors.JWEDecryptionFailed, code: 'ERR_JWE_DECRYPTION_FAILED' }) - encrypted.encrypted_key = encrypted.encrypted_key.substr(4) - t.throws(() => { - decrypt(encrypted, dKey) - }, { instanceOf: errors.JWEDecryptionFailed, code: 'ERR_JWE_DECRYPTION_FAILED' }) - encrypted.encrypted_key = orig - } - - (() => { - const orig = encrypted.protected - - if (encrypted.protected.startsWith('-')) { - encrypted.protected = `Q${encrypted.protected.substr(1)}` - } else { - encrypted.protected = `-${encrypted.protected.substr(1)}` - } - t.throws(() => { - decrypt(encrypted, dKey) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'could not parse JWE protected header' }) - encrypted.protected = orig - })() - - ;(() => { - const orig = encrypted.protected - delete encrypted.protected - t.throws(() => { - decrypt(encrypted, dKey) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID', message: 'missing Key Management algorithm' }) - encrypted.protected = orig - })() - - ;['iv', 'ciphertext', 'tag'].forEach((prop) => { - const orig = encrypted[prop] - - if (encrypted[prop].startsWith('-')) { - encrypted[prop] = `Q${encrypted[prop].substr(1)}` - } else { - encrypted[prop] = `-${encrypted[prop].substr(1)}` - } - t.throws(() => { - decrypt(encrypted, dKey) - }, { instanceOf: errors.JWEDecryptionFailed, code: 'ERR_JWE_DECRYPTION_FAILED' }) - encrypted[prop] = orig - }) - - ;['iv', 'tag'].forEach((prop) => { - const orig = encrypted[prop] - - encrypted[prop] = encrypted[prop].substr(4) - t.throws(() => { - decrypt(encrypted, dKey) - }, { instanceOf: errors.JWEInvalid, code: 'ERR_JWE_INVALID' }) - encrypted[prop] = orig - }) - } -} - -module.exports.compactJwt = compactJwt -module.exports.hasNoProperties = hasNoProperties -module.exports.hasProperties = hasProperties -module.exports.hasProperty = hasProperty -module.exports.JWE = JWE -module.exports.JWS = JWS diff --git a/test/macros/test_asymm_enc.js b/test/macros/test_asymm_enc.js deleted file mode 100644 index 45d36b9f0f..0000000000 --- a/test/macros/test_asymm_enc.js +++ /dev/null @@ -1,36 +0,0 @@ -const test = require('ava') - -const { keyObjectSupported } = require('../../lib/help/runtime_support') -const { JWK: { asKey } } = require('../..') -const registry = require('../../lib/registry') - -const fixtures = require('../fixtures') -const { JWE: { success, failure } } = require('../macros') - -const ENCS = [...registry.JWA.encrypt.keys()] - -module.exports = (type) => { - const { private: key, public: pub, testEnc = true } = fixtures.PEM[type] - - if (!testEnc) return - - const eKey = asKey(pub) - const dKey = asKey(key) - - ;[...eKey.algorithms('wrapKey'), ...eKey.algorithms('deriveKey')].forEach((alg) => { - ENCS.forEach((enc) => { - test(`key ${type} > alg ${alg} > ${enc}`, success, eKey, dKey, alg, enc) - test(`key ${type} > alg ${alg} > ${enc} (key as bare input)`, success, pub, key, alg, enc) - if (keyObjectSupported) { - test(`key ${type} > alg ${alg} > ${enc} (key as keyObject)`, success, eKey.keyObject, dKey.keyObject, alg, enc) - } - test(`key ${type} > alg ${alg} > ${enc} (key as JWK)`, success, eKey.toJWK(false), dKey.toJWK(true), alg, enc) - test(`key ${type} > alg ${alg} > ${enc} (negative cases)`, failure, eKey, dKey, alg, enc) - test(`key ${type} > alg ${alg} > ${enc} (negative cases, key as bare input)`, failure, pub, key, alg, enc) - if (keyObjectSupported) { - test(`key ${type} > alg ${alg} > ${enc} (negative cases, key as keyObject)`, failure, eKey.keyObject, dKey.keyObject, alg, enc) - } - test(`key ${type} > alg ${alg} > ${enc} (negative cases, key as JWK)`, failure, eKey.toJWK(false), dKey.toJWK(true), alg, enc) - }) - }) -} diff --git a/test/util/generators.test.mjs b/test/util/generators.test.mjs new file mode 100644 index 0000000000..436aa8a02a --- /dev/null +++ b/test/util/generators.test.mjs @@ -0,0 +1,136 @@ +import test from 'ava'; + +const root = !('WEBCRYPTO' in process.env) ? '#dist' : '#dist/webcrypto'; +Promise.all([ + import(`${root}/util/generate_key_pair`), + import(`${root}/util/generate_secret`), +]).then( + ([{ default: generateKeyPair }, { default: generateSecret }]) => { + async function testKeyPair(t, alg, options) { + return t.notThrowsAsync(async () => { + const { privateKey, publicKey } = await generateKeyPair(alg, options); + t.true('type' in privateKey); + t.is(privateKey.type, 'private'); + t.true('type' in publicKey); + t.is(publicKey.type, 'public'); + + for (const key of [publicKey, privateKey]) { + // Test CryptoKey curves are set properly + if ('algorithm' in key) { + if (key.algorithm.name === 'ECDH') { + t.is(key.algorithm.namedCurve, (options && options.crv) || 'P-256'); + } + + switch (alg) { + case 'ES256': + t.is(key.algorithm.namedCurve, 'P-256'); + break; + case 'ES348': + t.is(key.algorithm.namedCurve, 'P-384'); + break; + case 'ES512': + t.is(key.algorithm.namedCurve, 'P-521'); + break; + } + } + + // Test OKP KeyObject types are set properly + if ( + 'asymmetricKeyType' in key && + key.asymmetricKeyType !== 'ec' && + key.asymmetricKeyType !== 'rsa' + ) { + t.is(key.asymmetricKeyType, (options && options.crv.toLowerCase()) || 'ed25519'); + } + } + }); + } + testKeyPair.title = (title, alg) => `generate ${alg} key pair${title ? ` ${title}` : ''}`; + + test(testKeyPair, 'PS256'); + test(testKeyPair, 'PS384'); + test(testKeyPair, 'PS512'); + test(testKeyPair, 'RS256'); + test(testKeyPair, 'RS384'); + test(testKeyPair, 'RS512'); + test(testKeyPair, 'RSA-OAEP'); + test(testKeyPair, 'RSA-OAEP-256'); + test(testKeyPair, 'RSA-OAEP-384'); + test(testKeyPair, 'RSA-OAEP-512'); + test(testKeyPair, 'ES256'); + test(testKeyPair, 'ES384'); + test(testKeyPair, 'ES512'); + test(testKeyPair, 'ECDH-ES'); + test(testKeyPair, 'ECDH-ES+A128KW'); + test(testKeyPair, 'ECDH-ES+A192KW'); + test(testKeyPair, 'ECDH-ES+A256KW'); + + for (const crv of ['P-256', 'P-384', 'P-521']) { + test(`crv: ${crv}`, testKeyPair, 'ECDH-ES', { crv }); + test(`crv: ${crv}`, testKeyPair, 'ECDH-ES+A128KW', { crv }); + test(`crv: ${crv}`, testKeyPair, 'ECDH-ES+A192KW', { crv }); + test(`crv: ${crv}`, testKeyPair, 'ECDH-ES+A256KW', { crv }); + } + + let conditional; + if ('WEBCRYPTO' in process.env) { + conditional = test.failing; + } else { + conditional = test; + } + conditional(testKeyPair, 'EdDSA'); + conditional('crv: Ed25519', testKeyPair, 'EdDSA', { crv: 'Ed25519' }); + conditional('crv: Ed448', testKeyPair, 'EdDSA', { crv: 'Ed448' }); + conditional(testKeyPair, 'ES256K'); + conditional(testKeyPair, 'RSA1_5'); + for (const crv of ['X25519', 'X448']) { + conditional(`crv: ${crv}`, testKeyPair, 'ECDH-ES', { crv }); + conditional(`crv: ${crv}`, testKeyPair, 'ECDH-ES+A128KW', { crv }); + conditional(`crv: ${crv}`, testKeyPair, 'ECDH-ES+A192KW', { crv }); + conditional(`crv: ${crv}`, testKeyPair, 'ECDH-ES+A256KW', { crv }); + } + + async function testSecret(t, alg, expectedLength) { + return t.notThrowsAsync(async () => { + const secret = await generateSecret(alg); + + if ('symmetricKeySize' in secret) { + t.is(secret.symmetricKeySize, expectedLength >> 3); + t.true('type' in secret); + t.is(secret.type, 'secret'); + } else if ('algorithm' in secret) { + t.is(secret.algorithm.length, expectedLength); + t.true('type' in secret); + t.is(secret.type, 'secret'); + } else if (secret instanceof Uint8Array) { + t.is(secret.length, expectedLength >> 3); + } else { + t.fail('unexpected type returned'); + } + }); + } + testSecret.title = (title, alg) => `generate ${alg} secret${title ? ` ${title}` : ''}`; + + test(testSecret, 'HS256', 256); + test(testSecret, 'HS384', 384); + test(testSecret, 'HS512', 512); + test(testSecret, 'A128CBC-HS256', 256); + test(testSecret, 'A192CBC-HS384', 384); + test(testSecret, 'A256CBC-HS512', 512); + test(testSecret, 'A128KW', 128); + test(testSecret, 'A192KW', 192); + test(testSecret, 'A256KW', 256); + test(testSecret, 'A128GCMKW', 128); + test(testSecret, 'A192GCMKW', 192); + test(testSecret, 'A256GCMKW', 256); + test(testSecret, 'A128GCM', 128); + test(testSecret, 'A192GCM', 192); + test(testSecret, 'A256GCM', 256); + }, + (err) => { + test('failed to import', (t) => { + console.error(err); + t.fail(); + }); + }, +); diff --git a/tools/docs.postbump.js b/tools/docs.postbump.js new file mode 100755 index 0000000000..b3a3df42d6 --- /dev/null +++ b/tools/docs.postbump.js @@ -0,0 +1,30 @@ +require("./explode-exports"); +const { execSync } = require("child_process"); +const { readFileSync, writeFileSync } = require("fs"); +const { version } = require("../package.json"); +const { sync: glob } = require("glob"); + +const readme = readFileSync("docs/README.md"); +const tagName = `v${version}`; + +execSync('find docs -type d | grep "docs/" | xargs rm -r'); +writeFileSync( + "node_modules/typedoc-plugin-markdown/dist/resources/partials/member.sources.hbs", + readFileSync("tools/member.sources.hbs") +); +writeFileSync( + "node_modules/typedoc-plugin-markdown/dist/resources/templates/reflection.hbs", + readFileSync("tools/reflection.hbs") +); +execSync(`npm run docs:generate -- --gitRevision ${tagName}`); +glob("docs/**/*.md").forEach((md) => { + writeFileSync( + md, + readFileSync(md) + .toString() + .replace(/```\n\/\//g, "```js\n//") + .replace(/undefined \\\| /g, '') + ); +}); +writeFileSync("docs/README.md", readme); +execSync("git add docs/**/*.md"); diff --git a/tools/explode-exports.js b/tools/explode-exports.js new file mode 100755 index 0000000000..e437033467 --- /dev/null +++ b/tools/explode-exports.js @@ -0,0 +1,48 @@ +const { writeFileSync } = require("fs"); +const package = require("../package.json"); +const glob = require("glob"); + +const modules = [ + "src/jwe", + "src/jwk", + "src/jwks", + "src/jws", + "src/jwt", + "src/util", +]; + +const all = modules.map((path) => glob.sync(`${path}/**/*.ts`)).flat(Infinity); + +const exp = all.reduce((acc, mod) => { + const len = mod.length; + const foo = mod.substring(4, len - 3); + acc["./" + foo] = { + browser: "./dist/browser/" + foo + ".js", + import: "./dist/node/esm/" + foo + ".js", + require: "./dist/node/cjs/" + foo + ".js", + }; + acc["./webcrypto/" + foo] = { + import: "./dist/node/webcrypto/esm/" + foo + ".js", + require: "./dist/node/webcrypto/cjs/" + foo + ".js", + }; + return acc; +}, {}); + +const imp = all.reduce((acc, mod) => { + const len = mod.length; + const foo = mod.substring(4, len - 3); + acc["#dist/" + foo] = { + import: "./dist/node/esm/" + foo + ".js", + require: "./dist/node/cjs/" + foo + ".js", + }; + acc["#dist/webcrypto/" + foo] = { + import: "./dist/node/webcrypto/esm/" + foo + ".js", + require: "./dist/node/webcrypto/cjs/" + foo + ".js", + }; + return acc; +}, {}); + +package.imports = imp; +package.exports = exp; + +writeFileSync("package.json", JSON.stringify(package, null, 2) + "\n"); diff --git a/tools/member.sources.hbs b/tools/member.sources.hbs new file mode 100644 index 0000000000..eaa6625687 --- /dev/null +++ b/tools/member.sources.hbs @@ -0,0 +1,33 @@ +{{#if implementationOf}} + +*Implementation of {{#with implementationOf}}{{typeAndParent}}{{/with}}* + +{{/if}} + +{{#if overwrites}} + +*Overrides {{#with overwrites}}{{typeAndParent}}{{/with}}* + +{{/if}} + +{{#ifShowSources}} + +{{#if sources}} + +{{#each sources}} + +{{#if url}} + +*Defined in [{{fileName}}:{{line}}]({{url}})* + +{{else}} + +*Defined in {{fileName}}:{{line}}* + +{{/if}} + +{{/each}} + +{{/if}} + +{{/ifShowSources}} diff --git a/tools/reflection.hbs b/tools/reflection.hbs new file mode 100644 index 0000000000..b3d12a2006 --- /dev/null +++ b/tools/reflection.hbs @@ -0,0 +1,83 @@ +{{> header showTitle=true}} + +{{#with model}} + +{{#if hasComment}} + +{{> comment}} + +{{/if}} + +{{/with}} + +{{#if model.typeParameters}} + +## Type parameters + +{{#with model.typeParameters}} + +{{{parameterTable 'typeParameters'}}} + +{{/with}} + +{{/if}} + +{{#if model.implementedTypes}} + +## Implements + +{{#each model.implementedTypes}} +* {{{type false}}} +{{/each}} + +{{/if}} + +{{#if model.implementedBy}} + +## Implemented by + +{{#each model.implementedBy}} +* {{{type false}}} +{{/each}} + +{{/if}} + +{{#if model.signatures}} + +## Callable + +{{#with model}} + +{{#each signatures}} + +{{> member.signature }} + +{{/each}} + +{{/with}} + +{{/if}} + +{{#if model.indexSignature}} + +## Indexable + +{{#with model}} + +{{#with indexSignature}} + +{{{indexSignatureTitle}}} + +{{> comment}} + +{{/with}} + +{{/with}} + +{{/if}} + +{{#with model}} + +{{> main}} + +{{/with}} diff --git a/tsconfig/base.json b/tsconfig/base.json new file mode 100644 index 0000000000..758016641f --- /dev/null +++ b/tsconfig/base.json @@ -0,0 +1,39 @@ +{ + "files": [ + "../src/jwe/compact/encrypt.ts", + "../src/jwe/compact/decrypt.ts", + "../src/jwe/flattened/encrypt.ts", + "../src/jwe/flattened/decrypt.ts", + + "../src/jws/compact/sign.ts", + "../src/jws/compact/verify.ts", + "../src/jws/flattened/sign.ts", + "../src/jws/flattened/verify.ts", + + "../src/jwk/parse.ts", + "../src/jwk/thumbprint.ts", + "../src/jwk/embedded.ts", + + "../src/jwks/remote.ts", + + "../src/jwt/sign.ts", + "../src/jwt/verify.ts", + "../src/jwt/encrypt.ts", + "../src/jwt/decrypt.ts", + "../src/jwt/unsecured.ts", + + "../src/util/base64url.ts", + "../src/util/errors.ts", + "../src/util/generate_key_pair.ts", + "../src/util/generate_secret.ts", + "../src/util/random.ts" + ], + "compilerOptions": { + "strict": true, + "forceConsistentCasingInFileNames": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "sourceMap": false, + "removeComments": true + } +} diff --git a/tsconfig/browser.json b/tsconfig/browser.json new file mode 100644 index 0000000000..5689a70f84 --- /dev/null +++ b/tsconfig/browser.json @@ -0,0 +1,8 @@ +{ + "extends": "./base.json", + "compilerOptions": { + "target": "ES2018", + "module": "ES6", + "outDir": "../dist/browser" + } +} diff --git a/tsconfig/node-cjs.json b/tsconfig/node-cjs.json new file mode 100644 index 0000000000..a2b8840983 --- /dev/null +++ b/tsconfig/node-cjs.json @@ -0,0 +1,8 @@ +{ + "extends": "./base.json", + "compilerOptions": { + "target": "ES2019", + "module": "CommonJS", + "outDir": "../dist/node/cjs" + } +} diff --git a/tsconfig/node-esm.json b/tsconfig/node-esm.json new file mode 100644 index 0000000000..5f7122d424 --- /dev/null +++ b/tsconfig/node-esm.json @@ -0,0 +1,8 @@ +{ + "extends": "./base.json", + "compilerOptions": { + "target": "ES2019", + "module": "ES2020", + "outDir": "../dist/node/esm" + } +} diff --git a/tsconfig/node-webcrypto-cjs.json b/tsconfig/node-webcrypto-cjs.json new file mode 100644 index 0000000000..efdada1849 --- /dev/null +++ b/tsconfig/node-webcrypto-cjs.json @@ -0,0 +1,7 @@ +{ + "extends": "./node-cjs.json", + "compilerOptions": { + "target": "ESNext", + "outDir": "../dist/node/webcrypto/cjs" + } +} diff --git a/tsconfig/node-webcrypto-esm.json b/tsconfig/node-webcrypto-esm.json new file mode 100644 index 0000000000..c811d3e535 --- /dev/null +++ b/tsconfig/node-webcrypto-esm.json @@ -0,0 +1,7 @@ +{ + "extends": "./node-esm.json", + "compilerOptions": { + "target": "ESNext", + "outDir": "../dist/node/webcrypto/esm" + } +} diff --git a/types/index.d.ts b/types/index.d.ts deleted file mode 100644 index 9c4ff9af4d..0000000000 --- a/types/index.d.ts +++ /dev/null @@ -1,543 +0,0 @@ -/// -// TypeScript Version: 3.6 - -import { KeyObject, PrivateKeyInput, PublicKeyInput } from 'crypto'; - -export type use = 'sig' | 'enc'; -export type keyOperation = 'sign' | 'verify' | 'encrypt' | 'decrypt' | 'wrapKey' | 'unwrapKey' | 'deriveKey'; -export interface BasicParameters { - alg?: string; - use?: use; - kid?: string; - key_ops?: keyOperation[]; -} -export interface KeyParameters extends BasicParameters { - x5c?: string[]; - x5t?: string; - 'x5t#S256'?: string; -} -export type ECCurve = 'P-256' | 'secp256k1' | 'P-384' | 'P-521'; -export type OKPCurve = 'Ed25519' | 'Ed448' | 'X25519' | 'X448'; -export type Curves = OKPCurve | ECCurve; -export type keyType = 'RSA' | 'EC' | 'OKP' | 'oct'; -export type asymmetricKeyObjectTypes = 'private' | 'public'; -export type keyObjectTypes = asymmetricKeyObjectTypes | 'secret'; -export type KeyInput = PrivateKeyInput | PublicKeyInput | string | Buffer; -export type ProduceKeyInput = JWK.Key | KeyObject | KeyInput | JWKOctKey | JWKRSAKey | JWKECKey | JWKOKPKey; -export type ConsumeKeyInput = ProduceKeyInput | JWKS.KeyStore; -export type NoneKey = JWK.NoneKey; -export type EmbeddedJWK = JWK.EmbeddedJWK; -export type EmbeddedX5C = JWK.EmbeddedX5C; -export type EmbeddedVerifyKeys = EmbeddedJWK | EmbeddedX5C; -export type ProduceKeyInputWithNone = ProduceKeyInput | NoneKey; -export type ConsumeKeyInputWithNone = ConsumeKeyInput | NoneKey; - -export interface JWKOctKey extends BasicParameters { // no x5c - kty: 'oct'; - k?: string; -} - -export interface JWKECKey extends KeyParameters { - kty: 'EC'; - crv: ECCurve; - x: string; - y: string; - d?: string; -} - -export interface JWKOKPKey extends KeyParameters { - kty: 'OKP'; - crv: OKPCurve; - x: string; - d?: string; -} - -export interface JWKRSAKey extends KeyParameters { - kty: 'RSA'; - e: string; - n: string; - d?: string; - p?: string; - q?: string; - dp?: string; - dq?: string; - qi?: string; -} - -export type JSONWebKey = JWKRSAKey | JWKOKPKey | JWKECKey | JWKOctKey; - -export interface JSONWebKeySet { - keys: JSONWebKey[]; -} - -export interface ImportOptions { - calculateMissingRSAPrimes?: boolean; -} - -export namespace JWK { - interface pemEncodingOptions { - type?: string; - cipher?: string; - passphrase?: string; - } - - interface Key { - readonly private: boolean; - readonly public: boolean; - readonly secret: boolean; - readonly type: keyObjectTypes; - - readonly kty: keyType; - readonly alg?: string; - readonly use?: use; - readonly key_ops?: ReadonlyArray; - readonly kid: string; - readonly thumbprint: string; - readonly x5c?: ReadonlyArray; - readonly x5t?: string; - readonly 'x5t#S256'?: string; - readonly keyObject: KeyObject; - - readonly crv?: ECCurve | OKPCurve; - readonly d?: string; - readonly dp?: string; - readonly dq?: string; - readonly e?: string; - readonly k?: string; - readonly n?: string; - readonly p?: string; - readonly q?: string; - readonly qi?: string; - readonly x?: string; - readonly y?: string; - - toPEM(private?: boolean, encoding?: pemEncodingOptions): string; - - algorithms(operation?: keyOperation): Set; - } - - interface RSAKey extends Key { - readonly secret: false; - readonly type: asymmetricKeyObjectTypes; - - readonly kty: 'RSA'; - - readonly e: string; - readonly n: string; - readonly d?: string; - readonly p?: string; - readonly q?: string; - readonly dp?: string; - readonly dq?: string; - readonly qi?: string; - - readonly crv: undefined; - readonly k: undefined; - readonly x: undefined; - readonly y: undefined; - - toJWK(private?: boolean): JWKRSAKey; - } - - interface ECKey extends Key { - readonly secret: false; - readonly type: asymmetricKeyObjectTypes; - - readonly kty: 'EC'; - - readonly crv: ECCurve; - readonly x: string; - readonly y: string; - readonly d?: string; - - readonly dp: undefined; - readonly dq: undefined; - readonly e: undefined; - readonly k: undefined; - readonly n: undefined; - readonly p: undefined; - readonly q: undefined; - readonly qi: undefined; - - toJWK(private?: boolean): JWKECKey; - } - - interface OKPKey extends Key { - readonly secret: false; - readonly type: asymmetricKeyObjectTypes; - - readonly kty: 'OKP'; - - readonly crv: OKPCurve; - readonly x: string; - readonly d?: string; - - readonly dp: undefined; - readonly dq: undefined; - readonly e: undefined; - readonly k: undefined; - readonly n: undefined; - readonly p: undefined; - readonly q: undefined; - readonly qi: undefined; - readonly y: undefined; - - toJWK(private?: boolean): JWKOKPKey; - } - - interface OctKey extends Key { - readonly private: false; - readonly public: false; - readonly secret: true; - readonly type: 'secret'; - - readonly kty: 'oct'; - - readonly k?: string; - - readonly crv: undefined; - readonly d: undefined; - readonly dp: undefined; - readonly dq: undefined; - readonly e: undefined; - readonly n: undefined; - readonly p: undefined; - readonly q: undefined; - readonly qi: undefined; - readonly x: undefined; - readonly y: undefined; - - toJWK(private?: boolean): JWKOctKey; - } - - interface NoneKey { - readonly type: 'unsecured'; - readonly alg: 'none'; - algorithms(operation?: keyOperation): Set; - } - - const None: NoneKey; - - interface EmbeddedJWK { - readonly type: 'embedded'; - algorithms(operation?: keyOperation): Set; - } - - const EmbeddedJWK: EmbeddedJWK; - - interface EmbeddedX5C { - readonly type: 'embedded'; - algorithms(operation?: keyOperation): Set; - } - - const EmbeddedX5C: EmbeddedX5C; - - function isKey(object: any): boolean; - - function asKey(key: KeyObject | KeyInput, parameters?: KeyParameters): RSAKey | ECKey | OKPKey | OctKey; - function asKey(jwk: JWKOctKey): OctKey; - function asKey(jwk: JWKRSAKey, options?: ImportOptions): RSAKey; - function asKey(jwk: JWKECKey): ECKey; - function asKey(jwk: JWKOKPKey): OKPKey; - - /* - * @deprecated in favor of asKey - */ - function importKey(key: KeyObject | KeyInput, parameters?: KeyParameters): RSAKey | ECKey | OKPKey | OctKey; - function importKey(jwk: JWKOctKey): OctKey; - function importKey(jwk: JWKRSAKey): RSAKey; - function importKey(jwk: JWKECKey): ECKey; - function importKey(jwk: JWKOKPKey): OKPKey; - - function generate(kty: keyType, crvOrSize?: Curves | number, parameters?: BasicParameters, private?: boolean): Promise; - function generate(kty: 'EC', crv?: ECCurve, parameters?: BasicParameters, private?: boolean): Promise; - function generate(kty: 'OKP', crv?: OKPCurve, parameters?: BasicParameters, private?: boolean): Promise; - function generate(kty: 'RSA', bitlength?: number, parameters?: BasicParameters, private?: boolean): Promise; - function generate(kty: 'oct', bitlength?: number, parameters?: BasicParameters): Promise; - - function generateSync(kty: keyType, crvOrSize?: Curves | number, parameters?: BasicParameters, private?: boolean): JWK.Key; - function generateSync(kty: 'EC', crv?: ECCurve, parameters?: BasicParameters, private?: boolean): ECKey; - function generateSync(kty: 'OKP', crv?: OKPCurve, parameters?: BasicParameters, private?: boolean): OKPKey; - function generateSync(kty: 'RSA', bitlength?: number, parameters?: BasicParameters, private?: boolean): RSAKey; - function generateSync(kty: 'oct', bitlength?: number, parameters?: BasicParameters): OctKey; -} - -export namespace JWKS { - interface KeyQuery extends BasicParameters { - kty?: keyType; - x5t?: string; - 'x5t#S256'?: string; - crv?: string; - thumbprint?: string; - } - - class KeyStore { - constructor(keys?: JWK.Key[]); - - readonly size: number; - - add(key: JWK.Key): void; - remove(key: JWK.Key): void; - all(parameters?: KeyQuery): JWK.Key[]; - get(parameters?: KeyQuery): JWK.Key; - - toJWKS(private?: boolean): JSONWebKeySet; - - generate(kty: keyType, crvOrSize?: Curves | number, parameters?: BasicParameters, private?: boolean): Promise; - generate(kty: 'EC', crv?: ECCurve, parameters?: BasicParameters, private?: boolean): Promise; - generate(kty: 'OKP', crv?: OKPCurve, parameters?: BasicParameters, private?: boolean): Promise; - generate(kty: 'RSA', bitlength?: number, parameters?: BasicParameters, private?: boolean): Promise; - generate(kty: 'oct', bitlength?: number, parameters?: BasicParameters): Promise; - - generateSync(kty: keyType, crvOrSize?: Curves | number, parameters?: BasicParameters, private?: boolean): void; - generateSync(kty: 'EC', crv?: ECCurve, parameters?: BasicParameters, private?: boolean): void; - generateSync(kty: 'OKP', crv?: OKPCurve, parameters?: BasicParameters, private?: boolean): void; - generateSync(kty: 'RSA', bitlength?: number, parameters?: BasicParameters, private?: boolean): void; - generateSync(kty: 'oct', bitlength?: number, parameters?: BasicParameters): void; - - /* - * @deprecated in favor of JWKS.asKeyStore - */ - static fromJWKS(jwks: JSONWebKeySet): KeyStore; - } - - interface JWKSImportOptions extends ImportOptions { - ignoreErrors?: boolean; - } - - function asKeyStore(jwks: JSONWebKeySet, options?: JWKSImportOptions): KeyStore; -} - -export namespace JWS { - interface JWSJSON { - payload: string | Buffer; - } - - interface JWSRecipient { - signature: string; - protected?: string; - header?: object; - } - - interface FlattenedJWS extends JWSRecipient, JWSJSON {} - - interface GeneralJWS extends JWSJSON { - signatures: JWSRecipient[]; - } - - class Sign { - constructor(payload: string | Buffer | object); - - recipient(key: ProduceKeyInputWithNone, protected?: object, header?: object): void; - - sign(serialization: 'compact'): string; - sign(serialization: 'flattened'): FlattenedJWS; - sign(serialization: 'general'): GeneralJWS; - } - - function sign(payload: string | Buffer | object, key: ProduceKeyInputWithNone, protected?: object): string; - namespace sign { - function flattened(payload: string | Buffer | object, key: ProduceKeyInputWithNone, protected?: object, header?: object): FlattenedJWS; - function general(payload: string | Buffer | object, key: ProduceKeyInputWithNone, protected?: object, header?: object): GeneralJWS; - } - - interface VerifyOptions { - complete?: boolean; - crit?: string[]; - algorithms?: string[]; - } - - interface completeVerification { - payload: Buffer; - key: T; - protected?: object; - header?: object; - } - - function verify(jws: string | FlattenedJWS | GeneralJWS, key: ConsumeKeyInput | EmbeddedVerifyKeys, options: VerifyOptions & { complete: true }): completeVerification; - function verify(jws: string | FlattenedJWS | GeneralJWS, key: NoneKey, options: VerifyOptions & { complete: true }): completeVerification; - function verify(jws: string | FlattenedJWS | GeneralJWS, key: ConsumeKeyInputWithNone | EmbeddedVerifyKeys, options?: VerifyOptions): Buffer; -} - -export namespace JWE { - interface JWEJSON { - protected?: string; - unprotected?: object; - ciphertext: string; - tag: string; - iv: string; - aad?: string; - } - - interface JWERecipient { - header?: object; - encrypted_key: string; - } - - interface FlattenedJWE extends JWERecipient, JWEJSON {} - - interface GeneralJWE extends JWEJSON { - recipients: JWERecipient[]; - } - - class Encrypt { - constructor(cleartext: string | Buffer, protected?: object, aad?: string, unprotected?: object); - - recipient(key: ProduceKeyInput, header?: object): void; - - encrypt(serialization: 'compact'): string; - encrypt(serialization: 'flattened'): FlattenedJWE; - encrypt(serialization: 'general'): GeneralJWE; - } - - function encrypt(payload: string | Buffer, key: ProduceKeyInput, protected?: object): string; - namespace encrypt { - function flattened(payload: string | Buffer, key: ProduceKeyInput, protected?: object, aad?: string, header?: object): FlattenedJWE; - function general(payload: string | Buffer, key: ProduceKeyInput, protected?: object, aad?: string, header?: object): GeneralJWE; - } - - interface DecryptOptions { - complete?: boolean; - crit?: string[]; - contentEncryptionAlgorithms?: string[]; - keyManagementAlgorithms?: string[]; - } - - interface completeDecrypt { - cleartext: Buffer; - key: JWK.Key; - cek: JWK.OctKey; - aad?: string; - header?: object; - unprotected?: object; - protected?: object; - } - - function decrypt(jwe: string | FlattenedJWE | GeneralJWE, key: ConsumeKeyInput, options: DecryptOptions & { complete: true }): completeDecrypt; - function decrypt(jwe: string | FlattenedJWE | GeneralJWE, key: ConsumeKeyInput, options?: DecryptOptions): Buffer; -} - -export namespace JWT { - interface completeResult { - payload: object; - header: object; - signature: string; - key: T; - } - - interface DecodeOptions { - complete?: boolean; - } - - /** - * Decodes the JWT **without verifying the token**. For JWT verification/validation use - * `jose.JWT.verify`. - */ - function decode(jwt: string, options: DecodeOptions & { complete: true }): completeResult; - function decode(jwt: string, options?: DecodeOptions): object; - - interface VerifyOptions { - complete?: boolean; - ignoreExp?: boolean; - ignoreNbf?: boolean; - ignoreIat?: boolean; - maxTokenAge?: string; - subject?: string; - issuer?: string | string[]; - jti?: string; - clockTolerance?: string; - audience?: string | string[]; - algorithms?: string[]; - typ?: string; - now?: Date; - crit?: string[]; - } - - function verify(jwt: string, key: NoneKey, options: VerifyOptions & { complete: true }): completeResult; - function verify(jwt: string, key: ConsumeKeyInput | EmbeddedVerifyKeys, options: VerifyOptions & { complete: true }): completeResult; - function verify(jwt: string, key: ConsumeKeyInputWithNone | EmbeddedVerifyKeys, options?: VerifyOptions): object; - - interface SignOptions { - iat?: boolean; - kid?: boolean; - subject?: string; - issuer?: string; - audience?: string | string[]; - header?: object; - algorithm?: string; - expiresIn?: string; - notBefore?: string; - jti?: string; - now?: Date; - } - - function sign(payload: object, key: ProduceKeyInputWithNone, options?: SignOptions): string; - - interface ProfiledVerifyOptions { - issuer: string | string[]; - audience: string | string[]; - } - - interface IdTokenVerifyOptions extends ProfiledVerifyOptions { - nonce?: string; - maxAuthAge?: string; - } - - interface AccessTokenVerifyOptions extends ProfiledVerifyOptions { - maxAuthAge?: string; - } - - interface LogoutTokenVerifyOptions extends ProfiledVerifyOptions {} - - namespace IdToken { - function verify(jwt: string, key: ConsumeKeyInput | EmbeddedVerifyKeys, options: VerifyOptions & { complete: true } & IdTokenVerifyOptions): completeResult; - function verify(jwt: string, key: NoneKey, options: VerifyOptions & { complete: true } & IdTokenVerifyOptions): completeResult; - function verify(jwt: string, key: ConsumeKeyInputWithNone | EmbeddedVerifyKeys, options: VerifyOptions & IdTokenVerifyOptions): object; - } - - namespace LogoutToken { - function verify(jwt: string, key: ConsumeKeyInput | EmbeddedVerifyKeys, options: VerifyOptions & { complete: true } & LogoutTokenVerifyOptions): completeResult; - function verify(jwt: string, key: NoneKey, options: VerifyOptions & { complete: true } & LogoutTokenVerifyOptions): completeResult; - function verify(jwt: string, key: ConsumeKeyInputWithNone | EmbeddedVerifyKeys, options: VerifyOptions & LogoutTokenVerifyOptions): object; - } - - namespace AccessToken { - function verify(jwt: string, key: ConsumeKeyInput | EmbeddedVerifyKeys, options: VerifyOptions & { complete: true } & AccessTokenVerifyOptions): completeResult; - function verify(jwt: string, key: NoneKey, options: VerifyOptions & { complete: true } & AccessTokenVerifyOptions): completeResult; - function verify(jwt: string, key: ConsumeKeyInputWithNone | EmbeddedVerifyKeys, options: VerifyOptions & AccessTokenVerifyOptions): object; - } -} - -export namespace errors { - class JOSEError extends Error { - code: T; - } - - class JOSEInvalidEncoding extends JOSEError<'ERR_JOSE_INVALID_ENCODING'> {} - class JOSEMultiError extends JOSEError<'ERR_JOSE_MULTIPLE_ERRORS'> {} - - class JOSEAlgNotWhitelisted extends JOSEError<'ERR_JOSE_ALG_NOT_WHITELISTED'> {} - class JOSECritNotUnderstood extends JOSEError<'ERR_JOSE_CRIT_NOT_UNDERSTOOD'> {} - class JOSENotSupported extends JOSEError<'ERR_JOSE_NOT_SUPPORTED'> {} - - class JWEDecryptionFailed extends JOSEError<'ERR_JWE_DECRYPTION_FAILED'> {} - class JWEInvalid extends JOSEError<'ERR_JWE_INVALID'> {} - - class JWKImportFailed extends JOSEError<'ERR_JWK_IMPORT_FAILED'> {} - class JWKInvalid extends JOSEError<'ERR_JWK_INVALID'> {} - class JWKKeySupport extends JOSEError<'ERR_JWK_KEY_SUPPORT'> {} - - class JWKSNoMatchingKey extends JOSEError<'ERR_JWKS_NO_MATCHING_KEY'> {} - - class JWSInvalid extends JOSEError<'ERR_JWS_INVALID'> {} - class JWSVerificationFailed extends JOSEError<'ERR_JWS_VERIFICATION_FAILED'> {} - - class JWTClaimInvalid extends JOSEError { - constructor(message?: string, claim?: string, reason?: string); - - claim: string; - reason: 'prohibited' | 'missing' | 'invalid' | 'check_failed' | 'unspecified'; - } - class JWTExpired extends JWTClaimInvalid<'ERR_JWT_EXPIRED'> {} - class JWTMalformed extends JOSEError<'ERR_JWT_MALFORMED'> {} -} diff --git a/types/jose-tests.ts b/types/jose-tests.ts deleted file mode 100644 index 15bfc4191f..0000000000 --- a/types/jose-tests.ts +++ /dev/null @@ -1,120 +0,0 @@ -import * as jose from './index.d'; - -jose.errors.JOSEError -jose.errors.JOSEAlgNotWhitelisted -jose.errors.JOSECritNotUnderstood -jose.errors.JOSEInvalidEncoding -jose.errors.JOSEMultiError -jose.errors.JOSENotSupported -jose.errors.JWEDecryptionFailed -jose.errors.JWEInvalid -jose.errors.JWKImportFailed -jose.errors.JWKInvalid -jose.errors.JWKKeySupport -jose.errors.JWKSNoMatchingKey -jose.errors.JWSInvalid -jose.errors.JWSVerificationFailed -jose.errors.JWTClaimInvalid -jose.errors.JWTExpired -jose.errors.JWTMalformed - -jose.JWK.asKey('foo') -jose.JWK.asKey(Buffer.from('foo')) -jose.JWK.asKey({ kty: 'RSA', e: 'AQAB', n: 'foo' }) -jose.JWK.asKey({ kty: 'RSA', e: 'AQAB', n: 'foo', use: 'enc' }) -jose.JWK.asKey({ kty: 'RSA', e: 'AQAB', n: 'foo', use: 'sig' }) -jose.JWK.asKey({ kty: 'RSA', e: 'AQAB', n: 'foo', key_ops: ['decrypt'] }) -jose.JWK.asKey({ kty: 'RSA', e: 'AQAB', n: 'foo', kid: 'foo' }) -jose.JWK.asKey({ kty: 'RSA', e: 'AQAB', n: 'foo' }) -jose.JWK.asKey({ kty: 'oct', k: 'foo' }) -jose.JWK.asKey({ kty: 'EC', crv: 'P-256', x: 'foo', y: 'foo' }) -jose.JWK.asKey({ kty: 'EC', crv: 'P-256', x: 'foo', y: 'foo', d: 'foo' }) -jose.JWK.asKey({ kty: 'OKP', crv: 'Ed25519', x: 'foo' }) -const key = jose.JWK.asKey({ kty: 'OKP', crv: 'Ed25519', x: 'foo', d: 'foo' }) - -;(async () => { - ;(await jose.JWK.generate('EC', 'P-256')).toJWK() - ;(await jose.JWK.generate('OKP', 'X448', { kid: 'foo' })).toJWK() - ;(await jose.JWK.generate('RSA', 2048)).toJWK() - ;(await jose.JWK.generate('oct', 256)).toJWK() -})() - -;(jose.JWK.generateSync('EC', 'P-256')).toJWK() -;(jose.JWK.generateSync('OKP', 'X448', { kid: 'foo' })).toJWK() -;(jose.JWK.generateSync('RSA', 2048)).toJWK() -;(jose.JWK.generateSync('oct', 256)).toJWK() - -new jose.JWKS.KeyStore() -const keystore = new jose.JWKS.KeyStore([jose.JWK.generateSync('RSA')]) - -jose.JWS.sign({}, key) -jose.JWS.sign({}, jose.JWK.None) -jose.JWS.sign('foo', key) -jose.JWS.sign(Buffer.from('foo'), key) - -{ - new jose.JWS.Sign('foo') - new jose.JWS.Sign(Buffer.from('foo')) - const sign = new jose.JWS.Sign({}) - - sign.recipient(key, { alg: 'foo' }, { foo: 'bar' }) - sign.sign('compact').substring(0) - { - const { header, payload, protected: prot, signature } = sign.sign('flattened') - if (typeof payload === 'string') { - payload.substring(0) - } else if (Buffer.isBuffer(payload)) { - payload.byteOffset - } - signature.substring(0) - if (header) Object.entries(header) - if (prot) Object.entries(prot) - } - { - const { payload, signatures } = sign.sign('general') - if (typeof payload === 'string') { - payload.substring(0) - } else if (Buffer.isBuffer(payload)) { - payload.byteOffset - } - signatures.forEach(({ header, protected: prot, signature }) => { - signature.substring(0) - if (header) Object.entries(header) - if (prot) Object.entries(prot) - }) - } - - jose.JWS.sign.flattened({}, key, { alg: 'foo' }, {}) - jose.JWS.sign.general({}, key, { alg: 'foo' }, {}) -} - -{ - jose.JWS.verify(jose.JWS.sign('', key), key) - jose.JWS.verify(jose.JWS.sign.flattened('', key), key) - jose.JWS.verify(jose.JWS.sign.general('', key), key) - jose.JWS.verify('', keystore) - jose.JWS.verify('', key, { algorithms: ['PS256'], crit: ['foo'] }) -} - -{ - const key = jose.JWK.generateSync('RSA') - key.toJWK(true) - key.toJWK(false) - key.toJWK() - - key.toPEM() - key.toPEM(true) - key.toPEM(false) - key.toPEM(true, { type: 'pkcs1', passphrase: 'foo', cipher: 'aes-256-cbc' }) - - key.type === 'private' - key.type === 'public' - key.secret - - key.use - jose.JWK.asKey(key.keyObject) - key.kid - key.thumbprint -} - -// TODO: add more diff --git a/types/tsconfig.json b/types/tsconfig.json deleted file mode 100644 index 37f9ad6e72..0000000000 --- a/types/tsconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "lib": [ - "es6" - ], - "noImplicitAny": true, - "noImplicitThis": true, - "strictNullChecks": true, - "strictFunctionTypes": true, - "baseUrl": "../", - "typeRoots": [ - "../" - ], - "types": [], - "noEmit": true, - "forceConsistentCasingInFileNames": true - }, - "files": [ - "index.d.ts", - "jose-tests.ts" - ] -} diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000000..8b2901447b --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,14 @@ +const path = require("path"); +const { sync: glob } = require("glob"); + +module.exports = { + entry: glob("test-browser/*.js").reduce((acc, x) => { + acc[x.slice(13, -3)] = `./${x}`; + return acc; + }, {}), + mode: "development", + output: { + filename: "[name].js", + path: path.resolve(__dirname, "dist-browser-tests"), + }, +}; From 076eea11bb6e3f9e284663e53923747a2a6f6c3e Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Sat, 14 Nov 2020 18:28:54 +0100 Subject: [PATCH 2/2] chore(release): 3.0.0 --- CHANGELOG.md | 15 ++++++ .../_jwe_compact_encrypt_.compactencrypt.md | 12 ++--- ...jwe_flattened_encrypt_.flattenedencrypt.md | 18 ++++---- .../classes/_jws_compact_sign_.compactsign.md | 6 +-- .../_jws_flattened_sign_.flattenedsign.md | 8 ++-- docs/classes/_jwt_encrypt_.encryptjwt.md | 32 ++++++------- docs/classes/_jwt_sign_.signjwt.md | 20 ++++---- docs/classes/_jwt_unsecured_.unsecuredjwt.md | 20 ++++---- .../_util_errors_.josealgnotallowed.md | 4 +- docs/classes/_util_errors_.joseerror.md | 4 +- .../classes/_util_errors_.josenotsupported.md | 4 +- .../_util_errors_.jwedecryptionfailed.md | 6 +-- docs/classes/_util_errors_.jweinvalid.md | 4 +- docs/classes/_util_errors_.jwkinvalid.md | 4 +- docs/classes/_util_errors_.jwksinvalid.md | 4 +- .../_util_errors_.jwksmultiplematchingkeys.md | 6 +-- .../_util_errors_.jwksnomatchingkey.md | 6 +-- docs/classes/_util_errors_.jwsinvalid.md | 4 +- ..._errors_.jwssignatureverificationfailed.md | 6 +-- .../_util_errors_.jwtclaimvalidationfailed.md | 8 ++-- docs/classes/_util_errors_.jwtexpired.md | 8 ++-- docs/classes/_util_errors_.jwtinvalid.md | 4 +- .../_jwe_compact_decrypt_.compactdecrypt.md | 2 +- ...jwe_flattened_decrypt_.flatteneddecrypt.md | 2 +- docs/functions/_jwk_embedded_.embeddedjwk.md | 2 +- docs/functions/_jwk_parse_.parsejwk.md | 2 +- .../_jwk_thumbprint_.calculatethumbprint.md | 2 +- .../_jwks_remote_.createremotejwkset.md | 2 +- .../_jws_compact_verify_.compactverify.md | 2 +- .../_jws_flattened_verify_.flattenedverify.md | 2 +- docs/functions/_jwt_decrypt_.jwtdecrypt.md | 2 +- docs/functions/_jwt_verify_.jwtverify.md | 2 +- ...util_generate_key_pair_.generatekeypair.md | 2 +- .../_util_generate_secret_.generatesecret.md | 2 +- ...e_compact_decrypt_.compactdecryptgetkey.md | 2 +- ...attened_decrypt_.flatteneddecryptgetkey.md | 2 +- .../_jwks_remote_.remotejwksetoptions.md | 4 +- ...jws_compact_verify_.compactverifygetkey.md | 2 +- ...flattened_verify_.flattenedverifygetkey.md | 2 +- .../_jwt_decrypt_.jwtdecryptgetkey.md | 2 +- .../_jwt_decrypt_.jwtdecryptoptions.md | 20 ++++---- .../_jwt_verify_.jwtverifygetkey.md | 2 +- .../_jwt_verify_.jwtverifyoptions.md | 16 +++---- .../_types_d_.compactdecryptresult.md | 4 +- .../_types_d_.compactverifyresult.md | 4 +- docs/interfaces/_types_d_.decryptoptions.md | 6 +-- docs/interfaces/_types_d_.deflatefunction.md | 2 +- docs/interfaces/_types_d_.encryptoptions.md | 2 +- .../_types_d_.flatteneddecryptresult.md | 10 ++-- docs/interfaces/_types_d_.flattenedjwe.md | 16 +++---- docs/interfaces/_types_d_.flattenedjws.md | 4 +- .../interfaces/_types_d_.flattenedjwsinput.md | 8 ++-- .../_types_d_.flattenedverifyresult.md | 6 +-- docs/interfaces/_types_d_.getkeyfunction.md | 2 +- docs/interfaces/_types_d_.inflatefunction.md | 2 +- .../_types_d_.joseheaderparameters.md | 14 +++--- .../_types_d_.jweheaderparameters.md | 22 ++++----- ...pes_d_.jwekeymanagementheaderparameters.md | 12 ++--- docs/interfaces/_types_d_.jwk.md | 46 +++++++++---------- .../_types_d_.jwsheaderparameters.md | 20 ++++---- .../_types_d_.jwtclaimverificationoptions.md | 14 +++--- docs/interfaces/_types_d_.jwtdecryptresult.md | 4 +- docs/interfaces/_types_d_.jwtpayload.md | 14 +++--- docs/interfaces/_types_d_.jwtverifyresult.md | 4 +- docs/interfaces/_types_d_.verifyoptions.md | 2 +- ...nerate_key_pair_.generatekeypairoptions.md | 2 +- docs/types/_types_d_.keylike.md | 2 +- package.json | 2 +- 68 files changed, 259 insertions(+), 244 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a11c33cb52..54cb6a78b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [3.0.0](https://github.com/panva/jose/compare/v2.0.3...v3.0.0) (2020-11-14) + + +### ⚠ BREAKING CHANGES + +* Revised, Promise-based API +* No dependencies +* Browser support (using [Web Cryptography API](https://www.w3.org/TR/WebCryptoAPI/)) +* Support for verification using a remote JWKS endpoint +* Experimental Node.js libuv thread pool based runtime (non-blocking 🎉) + +### Features + +* Revised API, No dependencies, Browser Support, Promises ([357fe0b](https://github.com/panva/jose/commit/357fe0b964903e8c84ab49f0f27ddf0447d44c84)) + ## [2.0.3](https://github.com/panva/jose/compare/v2.0.2...v2.0.3) (2020-10-29) diff --git a/docs/classes/_jwe_compact_encrypt_.compactencrypt.md b/docs/classes/_jwe_compact_encrypt_.compactencrypt.md index 63845aa87d..5a82b24f96 100644 --- a/docs/classes/_jwe_compact_encrypt_.compactencrypt.md +++ b/docs/classes/_jwe_compact_encrypt_.compactencrypt.md @@ -54,7 +54,7 @@ console.log(jwe) \+ **new CompactEncrypt**(`plaintext`: Uint8Array): [CompactEncrypt](_jwe_compact_encrypt_.compactencrypt.md) -*Defined in [src/jwe/compact/encrypt.ts:45](https://github.com/panva/jose/blob/v3.x/src/jwe/compact/encrypt.ts#L45)* +*Defined in [src/jwe/compact/encrypt.ts:45](https://github.com/panva/jose/blob/v3.0.0/src/jwe/compact/encrypt.ts#L45)* #### Parameters: @@ -70,7 +70,7 @@ Name | Type | Description | ▸ **encrypt**(`key`: [KeyLike](../types/_types_d_.keylike.md), `options?`: [EncryptOptions](../interfaces/_types_d_.encryptoptions.md)): Promise\ -*Defined in [src/jwe/compact/encrypt.ts:108](https://github.com/panva/jose/blob/v3.x/src/jwe/compact/encrypt.ts#L108)* +*Defined in [src/jwe/compact/encrypt.ts:108](https://github.com/panva/jose/blob/v3.0.0/src/jwe/compact/encrypt.ts#L108)* Encrypts and resolves the value of the Compact JWE string. @@ -89,7 +89,7 @@ ___ ▸ **setContentEncryptionKey**(`cek`: Uint8Array): this -*Defined in [src/jwe/compact/encrypt.ts:62](https://github.com/panva/jose/blob/v3.x/src/jwe/compact/encrypt.ts#L62)* +*Defined in [src/jwe/compact/encrypt.ts:62](https://github.com/panva/jose/blob/v3.0.0/src/jwe/compact/encrypt.ts#L62)* Sets a content encryption key to use, by default a random suitable one is generated for the JWE enc" (Encryption Algorithm) Header Parameter. @@ -110,7 +110,7 @@ ___ ▸ **setInitializationVector**(`iv`: Uint8Array): this -*Defined in [src/jwe/compact/encrypt.ts:75](https://github.com/panva/jose/blob/v3.x/src/jwe/compact/encrypt.ts#L75)* +*Defined in [src/jwe/compact/encrypt.ts:75](https://github.com/panva/jose/blob/v3.0.0/src/jwe/compact/encrypt.ts#L75)* Sets the JWE Initialization Vector to use for content encryption, by default a random suitable one is generated for the JWE enc" (Encryption Algorithm) @@ -131,7 +131,7 @@ ___ ▸ **setKeyManagementParameters**(`parameters`: [JWEKeyManagementHeaderParameters](../interfaces/_types_d_.jwekeymanagementheaderparameters.md)): this -*Defined in [src/jwe/compact/encrypt.ts:97](https://github.com/panva/jose/blob/v3.x/src/jwe/compact/encrypt.ts#L97)* +*Defined in [src/jwe/compact/encrypt.ts:97](https://github.com/panva/jose/blob/v3.0.0/src/jwe/compact/encrypt.ts#L97)* Sets the JWE Key Management parameters to be used when encrypting the Content Encryption Key. You do not need to invoke this method, it is only really @@ -151,7 +151,7 @@ ___ ▸ **setProtectedHeader**(`protectedHeader`: [JWEHeaderParameters](../interfaces/_types_d_.jweheaderparameters.md)): this -*Defined in [src/jwe/compact/encrypt.ts:85](https://github.com/panva/jose/blob/v3.x/src/jwe/compact/encrypt.ts#L85)* +*Defined in [src/jwe/compact/encrypt.ts:85](https://github.com/panva/jose/blob/v3.0.0/src/jwe/compact/encrypt.ts#L85)* Sets the JWE Protected Header on the CompactEncrypt object. diff --git a/docs/classes/_jwe_flattened_encrypt_.flattenedencrypt.md b/docs/classes/_jwe_flattened_encrypt_.flattenedencrypt.md index ac4a1ea4c7..29785944fc 100644 --- a/docs/classes/_jwe_flattened_encrypt_.flattenedencrypt.md +++ b/docs/classes/_jwe_flattened_encrypt_.flattenedencrypt.md @@ -58,7 +58,7 @@ console.log(jwe) \+ **new FlattenedEncrypt**(`plaintext`: Uint8Array): [FlattenedEncrypt](_jwe_flattened_encrypt_.flattenedencrypt.md) -*Defined in [src/jwe/flattened/encrypt.ts:75](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L75)* +*Defined in [src/jwe/flattened/encrypt.ts:75](https://github.com/panva/jose/blob/v3.0.0/src/jwe/flattened/encrypt.ts#L75)* #### Parameters: @@ -74,7 +74,7 @@ Name | Type | Description | ▸ **encrypt**(`key`: [KeyLike](../types/_types_d_.keylike.md), `options?`: [EncryptOptions](../interfaces/_types_d_.encryptoptions.md)): Promise\<[FlattenedJWE](../interfaces/_types_d_.flattenedjwe.md)> -*Defined in [src/jwe/flattened/encrypt.ts:187](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L187)* +*Defined in [src/jwe/flattened/encrypt.ts:187](https://github.com/panva/jose/blob/v3.0.0/src/jwe/flattened/encrypt.ts#L187)* Encrypts and resolves the value of the Flattened JWE object. @@ -93,7 +93,7 @@ ___ ▸ **setAdditionalAuthenticatedData**(`aad`: Uint8Array): this -*Defined in [src/jwe/flattened/encrypt.ts:144](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L144)* +*Defined in [src/jwe/flattened/encrypt.ts:144](https://github.com/panva/jose/blob/v3.0.0/src/jwe/flattened/encrypt.ts#L144)* Sets the Additional Authenticated Data on the FlattenedEncrypt object. @@ -111,7 +111,7 @@ ___ ▸ **setContentEncryptionKey**(`cek`: Uint8Array): this -*Defined in [src/jwe/flattened/encrypt.ts:157](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L157)* +*Defined in [src/jwe/flattened/encrypt.ts:157](https://github.com/panva/jose/blob/v3.0.0/src/jwe/flattened/encrypt.ts#L157)* Sets a content encryption key to use, by default a random suitable one is generated for the JWE enc" (Encryption Algorithm) Header Parameter. @@ -132,7 +132,7 @@ ___ ▸ **setInitializationVector**(`iv`: Uint8Array): this -*Defined in [src/jwe/flattened/encrypt.ts:173](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L173)* +*Defined in [src/jwe/flattened/encrypt.ts:173](https://github.com/panva/jose/blob/v3.0.0/src/jwe/flattened/encrypt.ts#L173)* Sets the JWE Initialization Vector to use for content encryption, by default a random suitable one is generated for the JWE enc" (Encryption Algorithm) @@ -153,7 +153,7 @@ ___ ▸ **setKeyManagementParameters**(`parameters`: [JWEKeyManagementHeaderParameters](../interfaces/_types_d_.jwekeymanagementheaderparameters.md)): this -*Defined in [src/jwe/flattened/encrypt.ts:92](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L92)* +*Defined in [src/jwe/flattened/encrypt.ts:92](https://github.com/panva/jose/blob/v3.0.0/src/jwe/flattened/encrypt.ts#L92)* Sets the JWE Key Management parameters to be used when encrypting. Use of this is method is really only needed for ECDH-ES based algorithms @@ -174,7 +174,7 @@ ___ ▸ **setProtectedHeader**(`protectedHeader`: [JWEHeaderParameters](../interfaces/_types_d_.jweheaderparameters.md)): this -*Defined in [src/jwe/flattened/encrypt.ts:105](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L105)* +*Defined in [src/jwe/flattened/encrypt.ts:105](https://github.com/panva/jose/blob/v3.0.0/src/jwe/flattened/encrypt.ts#L105)* Sets the JWE Protected Header on the FlattenedEncrypt object. @@ -192,7 +192,7 @@ ___ ▸ **setSharedUnprotectedHeader**(`sharedUnprotectedHeader`: [JWEHeaderParameters](../interfaces/_types_d_.jweheaderparameters.md)): this -*Defined in [src/jwe/flattened/encrypt.ts:118](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L118)* +*Defined in [src/jwe/flattened/encrypt.ts:118](https://github.com/panva/jose/blob/v3.0.0/src/jwe/flattened/encrypt.ts#L118)* Sets the JWE Shared Unprotected Header on the FlattenedEncrypt object. @@ -210,7 +210,7 @@ ___ ▸ **setUnprotectedHeader**(`unprotectedHeader`: [JWEHeaderParameters](../interfaces/_types_d_.jweheaderparameters.md)): this -*Defined in [src/jwe/flattened/encrypt.ts:131](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/encrypt.ts#L131)* +*Defined in [src/jwe/flattened/encrypt.ts:131](https://github.com/panva/jose/blob/v3.0.0/src/jwe/flattened/encrypt.ts#L131)* Sets the JWE Per-Recipient Unprotected Header on the FlattenedEncrypt object. diff --git a/docs/classes/_jws_compact_sign_.compactsign.md b/docs/classes/_jws_compact_sign_.compactsign.md index 158237c8ef..b75260aff8 100644 --- a/docs/classes/_jws_compact_sign_.compactsign.md +++ b/docs/classes/_jws_compact_sign_.compactsign.md @@ -53,7 +53,7 @@ console.log(jws) \+ **new CompactSign**(`payload`: Uint8Array): [CompactSign](_jws_compact_sign_.compactsign.md) -*Defined in [src/jws/compact/sign.ts:44](https://github.com/panva/jose/blob/v3.x/src/jws/compact/sign.ts#L44)* +*Defined in [src/jws/compact/sign.ts:44](https://github.com/panva/jose/blob/v3.0.0/src/jws/compact/sign.ts#L44)* #### Parameters: @@ -69,7 +69,7 @@ Name | Type | Description | ▸ **setProtectedHeader**(`protectedHeader`: [JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md)): this -*Defined in [src/jws/compact/sign.ts:58](https://github.com/panva/jose/blob/v3.x/src/jws/compact/sign.ts#L58)* +*Defined in [src/jws/compact/sign.ts:58](https://github.com/panva/jose/blob/v3.0.0/src/jws/compact/sign.ts#L58)* Sets the JWS Protected Header on the Sign object. @@ -87,7 +87,7 @@ ___ ▸ **sign**(`key`: [KeyLike](../types/_types_d_.keylike.md)): Promise\ -*Defined in [src/jws/compact/sign.ts:68](https://github.com/panva/jose/blob/v3.x/src/jws/compact/sign.ts#L68)* +*Defined in [src/jws/compact/sign.ts:68](https://github.com/panva/jose/blob/v3.0.0/src/jws/compact/sign.ts#L68)* Signs and resolves the value of the Compact JWS string. diff --git a/docs/classes/_jws_flattened_sign_.flattenedsign.md b/docs/classes/_jws_flattened_sign_.flattenedsign.md index d6f984ca1c..76589e6e09 100644 --- a/docs/classes/_jws_flattened_sign_.flattenedsign.md +++ b/docs/classes/_jws_flattened_sign_.flattenedsign.md @@ -53,7 +53,7 @@ console.log(jws) \+ **new FlattenedSign**(`payload`: Uint8Array): [FlattenedSign](_jws_flattened_sign_.flattenedsign.md) -*Defined in [src/jws/flattened/sign.ts:56](https://github.com/panva/jose/blob/v3.x/src/jws/flattened/sign.ts#L56)* +*Defined in [src/jws/flattened/sign.ts:56](https://github.com/panva/jose/blob/v3.0.0/src/jws/flattened/sign.ts#L56)* #### Parameters: @@ -69,7 +69,7 @@ Name | Type | Description | ▸ **setProtectedHeader**(`protectedHeader`: [JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md)): this -*Defined in [src/jws/flattened/sign.ts:70](https://github.com/panva/jose/blob/v3.x/src/jws/flattened/sign.ts#L70)* +*Defined in [src/jws/flattened/sign.ts:70](https://github.com/panva/jose/blob/v3.0.0/src/jws/flattened/sign.ts#L70)* Sets the JWS Protected Header on the FlattenedSign object. @@ -87,7 +87,7 @@ ___ ▸ **setUnprotectedHeader**(`unprotectedHeader`: [JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md)): this -*Defined in [src/jws/flattened/sign.ts:83](https://github.com/panva/jose/blob/v3.x/src/jws/flattened/sign.ts#L83)* +*Defined in [src/jws/flattened/sign.ts:83](https://github.com/panva/jose/blob/v3.0.0/src/jws/flattened/sign.ts#L83)* Sets the JWS Unprotected Header on the FlattenedSign object. @@ -105,7 +105,7 @@ ___ ▸ **sign**(`key`: [KeyLike](../types/_types_d_.keylike.md)): Promise\<[FlattenedJWS](../interfaces/_types_d_.flattenedjws.md)> -*Defined in [src/jws/flattened/sign.ts:96](https://github.com/panva/jose/blob/v3.x/src/jws/flattened/sign.ts#L96)* +*Defined in [src/jws/flattened/sign.ts:96](https://github.com/panva/jose/blob/v3.0.0/src/jws/flattened/sign.ts#L96)* Signs and resolves the value of the Flattened JWS object. diff --git a/docs/classes/_jwt_encrypt_.encryptjwt.md b/docs/classes/_jwt_encrypt_.encryptjwt.md index fd9e9e8efd..90aae1dfad 100644 --- a/docs/classes/_jwt_encrypt_.encryptjwt.md +++ b/docs/classes/_jwt_encrypt_.encryptjwt.md @@ -64,7 +64,7 @@ console.log(jwt) \+ **new EncryptJWT**(`payload`: [JWTPayload](../interfaces/_types_d_.jwtpayload.md)): [EncryptJWT](_jwt_encrypt_.encryptjwt.md) -*Defined in [src/lib/jwt_producer.ts:10](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L10)* +*Defined in [src/lib/jwt_producer.ts:10](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L10)* #### Parameters: @@ -80,7 +80,7 @@ Name | Type | Description | ▸ **encrypt**(`key`: [KeyLike](../types/_types_d_.keylike.md), `options?`: [EncryptOptions](../interfaces/_types_d_.encryptoptions.md)): Promise\ -*Defined in [src/jwt/encrypt.ts:160](https://github.com/panva/jose/blob/v3.x/src/jwt/encrypt.ts#L160)* +*Defined in [src/jwt/encrypt.ts:160](https://github.com/panva/jose/blob/v3.0.0/src/jwt/encrypt.ts#L160)* Encrypts and returns the JWT. @@ -99,7 +99,7 @@ ___ ▸ **replicateAudienceAsHeader**(): this -*Defined in [src/jwt/encrypt.ts:149](https://github.com/panva/jose/blob/v3.x/src/jwt/encrypt.ts#L149)* +*Defined in [src/jwt/encrypt.ts:149](https://github.com/panva/jose/blob/v3.0.0/src/jwt/encrypt.ts#L149)* Replicates the "aud" (Audience) Claim as a JWE Protected Header Parameter as per [RFC7519#section-5.3](https://tools.ietf.org/html/rfc7519#section-5.3). @@ -112,7 +112,7 @@ ___ ▸ **replicateIssuerAsHeader**(): this -*Defined in [src/jwt/encrypt.ts:131](https://github.com/panva/jose/blob/v3.x/src/jwt/encrypt.ts#L131)* +*Defined in [src/jwt/encrypt.ts:131](https://github.com/panva/jose/blob/v3.0.0/src/jwt/encrypt.ts#L131)* Replicates the "iss" (Issuer) Claim as a JWE Protected Header Parameter as per [RFC7519#section-5.3](https://tools.ietf.org/html/rfc7519#section-5.3). @@ -125,7 +125,7 @@ ___ ▸ **replicateSubjectAsHeader**(): this -*Defined in [src/jwt/encrypt.ts:140](https://github.com/panva/jose/blob/v3.x/src/jwt/encrypt.ts#L140)* +*Defined in [src/jwt/encrypt.ts:140](https://github.com/panva/jose/blob/v3.0.0/src/jwt/encrypt.ts#L140)* Replicates the "sub" (Subject) Claim as a JWE Protected Header Parameter as per [RFC7519#section-5.3](https://tools.ietf.org/html/rfc7519#section-5.3). @@ -138,7 +138,7 @@ ___ ▸ **setAudience**(`audience`: string \| string[]): this -*Defined in [src/lib/jwt_producer.ts:47](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L47)* +*Defined in [src/lib/jwt_producer.ts:47](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L47)* Set "aud" (Audience) Claim. @@ -156,7 +156,7 @@ ___ ▸ **setContentEncryptionKey**(`cek`: Uint8Array): this -*Defined in [src/jwt/encrypt.ts:103](https://github.com/panva/jose/blob/v3.x/src/jwt/encrypt.ts#L103)* +*Defined in [src/jwt/encrypt.ts:103](https://github.com/panva/jose/blob/v3.0.0/src/jwt/encrypt.ts#L103)* Sets a content encryption key to use, by default a random suitable one is generated for the JWE enc" (Encryption Algorithm) Header Parameter. @@ -177,7 +177,7 @@ ___ ▸ **setExpirationTime**(`input`: number \| string): this -*Defined in [src/lib/jwt_producer.ts:85](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L85)* +*Defined in [src/lib/jwt_producer.ts:85](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L85)* Set "exp" (Expiration Time) Claim. @@ -195,7 +195,7 @@ ___ ▸ **setInitializationVector**(`iv`: Uint8Array): this -*Defined in [src/jwt/encrypt.ts:119](https://github.com/panva/jose/blob/v3.x/src/jwt/encrypt.ts#L119)* +*Defined in [src/jwt/encrypt.ts:119](https://github.com/panva/jose/blob/v3.0.0/src/jwt/encrypt.ts#L119)* Sets the JWE Initialization Vector to use for content encryption, by default a random suitable one is generated for the JWE enc" (Encryption Algorithm) @@ -216,7 +216,7 @@ ___ ▸ **setIssuedAt**(`input?`: number): this -*Defined in [src/lib/jwt_producer.ts:100](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L100)* +*Defined in [src/lib/jwt_producer.ts:100](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L100)* Set "iat" (Issued At) Claim. @@ -234,7 +234,7 @@ ___ ▸ **setIssuer**(`issuer`: string): this -*Defined in [src/lib/jwt_producer.ts:27](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L27)* +*Defined in [src/lib/jwt_producer.ts:27](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L27)* Set "iss" (Issuer) Claim. @@ -252,7 +252,7 @@ ___ ▸ **setJti**(`jwtId`: string): this -*Defined in [src/lib/jwt_producer.ts:57](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L57)* +*Defined in [src/lib/jwt_producer.ts:57](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L57)* Set "jti" (JWT ID) Claim. @@ -270,7 +270,7 @@ ___ ▸ **setKeyManagementParameters**(`parameters`: [JWEKeyManagementHeaderParameters](../interfaces/_types_d_.jwekeymanagementheaderparameters.md)): this -*Defined in [src/jwt/encrypt.ts:87](https://github.com/panva/jose/blob/v3.x/src/jwt/encrypt.ts#L87)* +*Defined in [src/jwt/encrypt.ts:87](https://github.com/panva/jose/blob/v3.0.0/src/jwt/encrypt.ts#L87)* Sets the JWE Key Management parameters to be used when encrypting. Use of this is method is really only needed for ECDH-ES based algorithms @@ -291,7 +291,7 @@ ___ ▸ **setNotBefore**(`input`: number \| string): this -*Defined in [src/lib/jwt_producer.ts:69](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L69)* +*Defined in [src/lib/jwt_producer.ts:69](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L69)* Set "nbf" (Not Before) Claim. @@ -309,7 +309,7 @@ ___ ▸ **setProtectedHeader**(`protectedHeader`: [JWEHeaderParameters](../interfaces/_types_d_.jweheaderparameters.md)): this -*Defined in [src/jwt/encrypt.ts:71](https://github.com/panva/jose/blob/v3.x/src/jwt/encrypt.ts#L71)* +*Defined in [src/jwt/encrypt.ts:71](https://github.com/panva/jose/blob/v3.0.0/src/jwt/encrypt.ts#L71)* Sets the JWE Protected Header on the EncryptJWT object. @@ -327,7 +327,7 @@ ___ ▸ **setSubject**(`subject`: string): this -*Defined in [src/lib/jwt_producer.ts:37](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L37)* +*Defined in [src/lib/jwt_producer.ts:37](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L37)* Set "sub" (Subject) Claim. diff --git a/docs/classes/_jwt_sign_.signjwt.md b/docs/classes/_jwt_sign_.signjwt.md index 2e02106582..747770227a 100644 --- a/docs/classes/_jwt_sign_.signjwt.md +++ b/docs/classes/_jwt_sign_.signjwt.md @@ -63,7 +63,7 @@ console.log(jwt) \+ **new SignJWT**(`payload`: [JWTPayload](../interfaces/_types_d_.jwtpayload.md)): [SignJWT](_jwt_sign_.signjwt.md) -*Defined in [src/lib/jwt_producer.ts:10](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L10)* +*Defined in [src/lib/jwt_producer.ts:10](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L10)* #### Parameters: @@ -79,7 +79,7 @@ Name | Type | Description | ▸ **setAudience**(`audience`: string \| string[]): this -*Defined in [src/lib/jwt_producer.ts:47](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L47)* +*Defined in [src/lib/jwt_producer.ts:47](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L47)* Set "aud" (Audience) Claim. @@ -97,7 +97,7 @@ ___ ▸ **setExpirationTime**(`input`: number \| string): this -*Defined in [src/lib/jwt_producer.ts:85](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L85)* +*Defined in [src/lib/jwt_producer.ts:85](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L85)* Set "exp" (Expiration Time) Claim. @@ -115,7 +115,7 @@ ___ ▸ **setIssuedAt**(`input?`: number): this -*Defined in [src/lib/jwt_producer.ts:100](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L100)* +*Defined in [src/lib/jwt_producer.ts:100](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L100)* Set "iat" (Issued At) Claim. @@ -133,7 +133,7 @@ ___ ▸ **setIssuer**(`issuer`: string): this -*Defined in [src/lib/jwt_producer.ts:27](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L27)* +*Defined in [src/lib/jwt_producer.ts:27](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L27)* Set "iss" (Issuer) Claim. @@ -151,7 +151,7 @@ ___ ▸ **setJti**(`jwtId`: string): this -*Defined in [src/lib/jwt_producer.ts:57](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L57)* +*Defined in [src/lib/jwt_producer.ts:57](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L57)* Set "jti" (JWT ID) Claim. @@ -169,7 +169,7 @@ ___ ▸ **setNotBefore**(`input`: number \| string): this -*Defined in [src/lib/jwt_producer.ts:69](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L69)* +*Defined in [src/lib/jwt_producer.ts:69](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L69)* Set "nbf" (Not Before) Claim. @@ -187,7 +187,7 @@ ___ ▸ **setProtectedHeader**(`protectedHeader`: [JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md)): this -*Defined in [src/jwt/sign.ts:57](https://github.com/panva/jose/blob/v3.x/src/jwt/sign.ts#L57)* +*Defined in [src/jwt/sign.ts:57](https://github.com/panva/jose/blob/v3.0.0/src/jwt/sign.ts#L57)* Sets the JWS Protected Header on the SignJWT object. @@ -205,7 +205,7 @@ ___ ▸ **setSubject**(`subject`: string): this -*Defined in [src/lib/jwt_producer.ts:37](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L37)* +*Defined in [src/lib/jwt_producer.ts:37](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L37)* Set "sub" (Subject) Claim. @@ -223,7 +223,7 @@ ___ ▸ **sign**(`key`: [KeyLike](../types/_types_d_.keylike.md)): Promise\ -*Defined in [src/jwt/sign.ts:67](https://github.com/panva/jose/blob/v3.x/src/jwt/sign.ts#L67)* +*Defined in [src/jwt/sign.ts:67](https://github.com/panva/jose/blob/v3.0.0/src/jwt/sign.ts#L67)* Signs and returns the JWT. diff --git a/docs/classes/_jwt_unsecured_.unsecuredjwt.md b/docs/classes/_jwt_unsecured_.unsecuredjwt.md index 1b5553a2e3..5294d22f47 100644 --- a/docs/classes/_jwt_unsecured_.unsecuredjwt.md +++ b/docs/classes/_jwt_unsecured_.unsecuredjwt.md @@ -64,7 +64,7 @@ console.log(payload) \+ **new UnsecuredJWT**(`payload`: [JWTPayload](../interfaces/_types_d_.jwtpayload.md)): [UnsecuredJWT](_jwt_unsecured_.unsecuredjwt.md) -*Defined in [src/lib/jwt_producer.ts:10](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L10)* +*Defined in [src/lib/jwt_producer.ts:10](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L10)* #### Parameters: @@ -80,7 +80,7 @@ Name | Type | Description | ▸ **encode**(): string -*Defined in [src/jwt/unsecured.ts:55](https://github.com/panva/jose/blob/v3.x/src/jwt/unsecured.ts#L55)* +*Defined in [src/jwt/unsecured.ts:55](https://github.com/panva/jose/blob/v3.0.0/src/jwt/unsecured.ts#L55)* Encodes the Unsecured JWT. @@ -92,7 +92,7 @@ ___ ▸ **setAudience**(`audience`: string \| string[]): this -*Defined in [src/lib/jwt_producer.ts:47](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L47)* +*Defined in [src/lib/jwt_producer.ts:47](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L47)* Set "aud" (Audience) Claim. @@ -110,7 +110,7 @@ ___ ▸ **setExpirationTime**(`input`: number \| string): this -*Defined in [src/lib/jwt_producer.ts:85](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L85)* +*Defined in [src/lib/jwt_producer.ts:85](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L85)* Set "exp" (Expiration Time) Claim. @@ -128,7 +128,7 @@ ___ ▸ **setIssuedAt**(`input?`: number): this -*Defined in [src/lib/jwt_producer.ts:100](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L100)* +*Defined in [src/lib/jwt_producer.ts:100](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L100)* Set "iat" (Issued At) Claim. @@ -146,7 +146,7 @@ ___ ▸ **setIssuer**(`issuer`: string): this -*Defined in [src/lib/jwt_producer.ts:27](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L27)* +*Defined in [src/lib/jwt_producer.ts:27](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L27)* Set "iss" (Issuer) Claim. @@ -164,7 +164,7 @@ ___ ▸ **setJti**(`jwtId`: string): this -*Defined in [src/lib/jwt_producer.ts:57](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L57)* +*Defined in [src/lib/jwt_producer.ts:57](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L57)* Set "jti" (JWT ID) Claim. @@ -182,7 +182,7 @@ ___ ▸ **setNotBefore**(`input`: number \| string): this -*Defined in [src/lib/jwt_producer.ts:69](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L69)* +*Defined in [src/lib/jwt_producer.ts:69](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L69)* Set "nbf" (Not Before) Claim. @@ -200,7 +200,7 @@ ___ ▸ **setSubject**(`subject`: string): this -*Defined in [src/lib/jwt_producer.ts:37](https://github.com/panva/jose/blob/v3.x/src/lib/jwt_producer.ts#L37)* +*Defined in [src/lib/jwt_producer.ts:37](https://github.com/panva/jose/blob/v3.0.0/src/lib/jwt_producer.ts#L37)* Set "sub" (Subject) Claim. @@ -218,7 +218,7 @@ ___ ▸ `Static`**decode**(`jwt`: string, `options?`: [JWTClaimVerificationOptions](../interfaces/_types_d_.jwtclaimverificationoptions.md)): object -*Defined in [src/jwt/unsecured.ts:77](https://github.com/panva/jose/blob/v3.x/src/jwt/unsecured.ts#L77)* +*Defined in [src/jwt/unsecured.ts:77](https://github.com/panva/jose/blob/v3.0.0/src/jwt/unsecured.ts#L77)* Decodes an unsecured JWT. diff --git a/docs/classes/_util_errors_.josealgnotallowed.md b/docs/classes/_util_errors_.josealgnotallowed.md index 338c8b67ee..1b40f7b0fc 100644 --- a/docs/classes/_util_errors_.josealgnotallowed.md +++ b/docs/classes/_util_errors_.josealgnotallowed.md @@ -21,7 +21,7 @@ An error subclass thrown when a JOSE Algorithm is not allowed per developer pref \+ **new JOSEAlgNotAllowed**(`message?`: string): [JOSEAlgNotAllowed](_util_errors_.josealgnotallowed.md) -*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L11)* #### Parameters: @@ -39,7 +39,7 @@ Name | Type | *Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* -*Defined in [src/util/errors.ts:49](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L49)* +*Defined in [src/util/errors.ts:49](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L49)* ___ diff --git a/docs/classes/_util_errors_.joseerror.md b/docs/classes/_util_errors_.joseerror.md index d986cf1df9..28d232710e 100644 --- a/docs/classes/_util_errors_.joseerror.md +++ b/docs/classes/_util_errors_.joseerror.md @@ -23,7 +23,7 @@ JOSE Error subclasses inherit from. \+ **new JOSEError**(`message?`: string): [JOSEError](_util_errors_.joseerror.md) -*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L11)* #### Parameters: @@ -39,7 +39,7 @@ Name | Type | • **code**: string = "ERR\_JOSE\_GENERIC" -*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L11)* A unique error code for the particular error subclass. diff --git a/docs/classes/_util_errors_.josenotsupported.md b/docs/classes/_util_errors_.josenotsupported.md index 4d036aa831..34a4d2c5a5 100644 --- a/docs/classes/_util_errors_.josenotsupported.md +++ b/docs/classes/_util_errors_.josenotsupported.md @@ -22,7 +22,7 @@ implementation or JOSE in general. \+ **new JOSENotSupported**(`message?`: string): [JOSENotSupported](_util_errors_.josenotsupported.md) -*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L11)* #### Parameters: @@ -40,7 +40,7 @@ Name | Type | *Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* -*Defined in [src/util/errors.ts:57](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L57)* +*Defined in [src/util/errors.ts:57](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L57)* ___ diff --git a/docs/classes/_util_errors_.jwedecryptionfailed.md b/docs/classes/_util_errors_.jwedecryptionfailed.md index 4e521a0969..59c55d5784 100644 --- a/docs/classes/_util_errors_.jwedecryptionfailed.md +++ b/docs/classes/_util_errors_.jwedecryptionfailed.md @@ -21,7 +21,7 @@ An error subclass thrown when a JWE ciphertext decryption fails. \+ **new JWEDecryptionFailed**(`message?`: string): [JWEDecryptionFailed](_util_errors_.jwedecryptionfailed.md) -*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L11)* #### Parameters: @@ -39,7 +39,7 @@ Name | Type | *Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* -*Defined in [src/util/errors.ts:64](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L64)* +*Defined in [src/util/errors.ts:64](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L64)* ___ @@ -49,7 +49,7 @@ ___ *Overrides [JOSEError](_util_errors_.joseerror.md).[message](_util_errors_.joseerror.md#message)* -*Defined in [src/util/errors.ts:66](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L66)* +*Defined in [src/util/errors.ts:66](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L66)* ___ diff --git a/docs/classes/_util_errors_.jweinvalid.md b/docs/classes/_util_errors_.jweinvalid.md index 00b1564b60..10a35becc3 100644 --- a/docs/classes/_util_errors_.jweinvalid.md +++ b/docs/classes/_util_errors_.jweinvalid.md @@ -21,7 +21,7 @@ An error subclass thrown when a JWE is invalid. \+ **new JWEInvalid**(`message?`: string): [JWEInvalid](_util_errors_.jweinvalid.md) -*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L11)* #### Parameters: @@ -39,7 +39,7 @@ Name | Type | *Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* -*Defined in [src/util/errors.ts:73](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L73)* +*Defined in [src/util/errors.ts:73](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L73)* ___ diff --git a/docs/classes/_util_errors_.jwkinvalid.md b/docs/classes/_util_errors_.jwkinvalid.md index 72e919de84..309bc5ab30 100644 --- a/docs/classes/_util_errors_.jwkinvalid.md +++ b/docs/classes/_util_errors_.jwkinvalid.md @@ -21,7 +21,7 @@ An error subclass thrown when a JWK is invalid. \+ **new JWKInvalid**(`message?`: string): [JWKInvalid](_util_errors_.jwkinvalid.md) -*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L11)* #### Parameters: @@ -39,7 +39,7 @@ Name | Type | *Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* -*Defined in [src/util/errors.ts:94](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L94)* +*Defined in [src/util/errors.ts:94](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L94)* ___ diff --git a/docs/classes/_util_errors_.jwksinvalid.md b/docs/classes/_util_errors_.jwksinvalid.md index ab78162a8d..32abc94406 100644 --- a/docs/classes/_util_errors_.jwksinvalid.md +++ b/docs/classes/_util_errors_.jwksinvalid.md @@ -21,7 +21,7 @@ An error subclass thrown when a JWKS is invalid. \+ **new JWKSInvalid**(`message?`: string): [JWKSInvalid](_util_errors_.jwksinvalid.md) -*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L11)* #### Parameters: @@ -39,7 +39,7 @@ Name | Type | *Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* -*Defined in [src/util/errors.ts:101](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L101)* +*Defined in [src/util/errors.ts:101](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L101)* ___ diff --git a/docs/classes/_util_errors_.jwksmultiplematchingkeys.md b/docs/classes/_util_errors_.jwksmultiplematchingkeys.md index e040782d5a..a07e65e459 100644 --- a/docs/classes/_util_errors_.jwksmultiplematchingkeys.md +++ b/docs/classes/_util_errors_.jwksmultiplematchingkeys.md @@ -21,7 +21,7 @@ An error subclass thrown when multiple keys match from a JWKS. \+ **new JWKSMultipleMatchingKeys**(`message?`: string): [JWKSMultipleMatchingKeys](_util_errors_.jwksmultiplematchingkeys.md) -*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L11)* #### Parameters: @@ -39,7 +39,7 @@ Name | Type | *Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* -*Defined in [src/util/errors.ts:117](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L117)* +*Defined in [src/util/errors.ts:117](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L117)* ___ @@ -49,7 +49,7 @@ ___ *Overrides [JOSEError](_util_errors_.joseerror.md).[message](_util_errors_.joseerror.md#message)* -*Defined in [src/util/errors.ts:119](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L119)* +*Defined in [src/util/errors.ts:119](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L119)* ___ diff --git a/docs/classes/_util_errors_.jwksnomatchingkey.md b/docs/classes/_util_errors_.jwksnomatchingkey.md index 61eaf2161f..d9fc0ff020 100644 --- a/docs/classes/_util_errors_.jwksnomatchingkey.md +++ b/docs/classes/_util_errors_.jwksnomatchingkey.md @@ -21,7 +21,7 @@ An error subclass thrown when no keys match from a JWKS. \+ **new JWKSNoMatchingKey**(`message?`: string): [JWKSNoMatchingKey](_util_errors_.jwksnomatchingkey.md) -*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L11)* #### Parameters: @@ -39,7 +39,7 @@ Name | Type | *Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* -*Defined in [src/util/errors.ts:108](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L108)* +*Defined in [src/util/errors.ts:108](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L108)* ___ @@ -49,7 +49,7 @@ ___ *Overrides [JOSEError](_util_errors_.joseerror.md).[message](_util_errors_.joseerror.md#message)* -*Defined in [src/util/errors.ts:110](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L110)* +*Defined in [src/util/errors.ts:110](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L110)* ___ diff --git a/docs/classes/_util_errors_.jwsinvalid.md b/docs/classes/_util_errors_.jwsinvalid.md index d8425a4913..0825608d79 100644 --- a/docs/classes/_util_errors_.jwsinvalid.md +++ b/docs/classes/_util_errors_.jwsinvalid.md @@ -21,7 +21,7 @@ An error subclass thrown when a JWS is invalid. \+ **new JWSInvalid**(`message?`: string): [JWSInvalid](_util_errors_.jwsinvalid.md) -*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L11)* #### Parameters: @@ -39,7 +39,7 @@ Name | Type | *Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* -*Defined in [src/util/errors.ts:80](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L80)* +*Defined in [src/util/errors.ts:80](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L80)* ___ diff --git a/docs/classes/_util_errors_.jwssignatureverificationfailed.md b/docs/classes/_util_errors_.jwssignatureverificationfailed.md index ee9af34f4b..2789421ae4 100644 --- a/docs/classes/_util_errors_.jwssignatureverificationfailed.md +++ b/docs/classes/_util_errors_.jwssignatureverificationfailed.md @@ -21,7 +21,7 @@ An error subclass thrown when JWS signature verification fails. \+ **new JWSSignatureVerificationFailed**(`message?`: string): [JWSSignatureVerificationFailed](_util_errors_.jwssignatureverificationfailed.md) -*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L11)* #### Parameters: @@ -39,7 +39,7 @@ Name | Type | *Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* -*Defined in [src/util/errors.ts:126](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L126)* +*Defined in [src/util/errors.ts:126](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L126)* ___ @@ -49,7 +49,7 @@ ___ *Overrides [JOSEError](_util_errors_.joseerror.md).[message](_util_errors_.joseerror.md#message)* -*Defined in [src/util/errors.ts:128](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L128)* +*Defined in [src/util/errors.ts:128](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L128)* ___ diff --git a/docs/classes/_util_errors_.jwtclaimvalidationfailed.md b/docs/classes/_util_errors_.jwtclaimvalidationfailed.md index 521124b196..2a1c3e55a8 100644 --- a/docs/classes/_util_errors_.jwtclaimvalidationfailed.md +++ b/docs/classes/_util_errors_.jwtclaimvalidationfailed.md @@ -25,7 +25,7 @@ An error subclass thrown when a JWT Claim Set member validation fails. *Overrides [JOSEError](_util_errors_.joseerror.md).[constructor](_util_errors_.joseerror.md#constructor)* -*Defined in [src/util/errors.ts:36](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L36)* +*Defined in [src/util/errors.ts:36](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L36)* #### Parameters: @@ -43,7 +43,7 @@ Name | Type | Default value | • **claim**: string -*Defined in [src/util/errors.ts:31](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L31)* +*Defined in [src/util/errors.ts:31](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L31)* The Claim for which the validation failed. @@ -55,7 +55,7 @@ ___ *Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* -*Defined in [src/util/errors.ts:26](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L26)* +*Defined in [src/util/errors.ts:26](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L26)* ___ @@ -79,7 +79,7 @@ ___ • **reason**: string -*Defined in [src/util/errors.ts:36](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L36)* +*Defined in [src/util/errors.ts:36](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L36)* Reason code for the validation failure. diff --git a/docs/classes/_util_errors_.jwtexpired.md b/docs/classes/_util_errors_.jwtexpired.md index 2d95e7ae13..cd54a637a3 100644 --- a/docs/classes/_util_errors_.jwtexpired.md +++ b/docs/classes/_util_errors_.jwtexpired.md @@ -25,7 +25,7 @@ An error subclass thrown when a JWT is expired. *Overrides [JOSEError](_util_errors_.joseerror.md).[constructor](_util_errors_.joseerror.md#constructor)* -*Defined in [src/util/errors.ts:36](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L36)* +*Defined in [src/util/errors.ts:36](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L36)* #### Parameters: @@ -43,7 +43,7 @@ Name | Type | Default value | • **claim**: string -*Defined in [src/util/errors.ts:31](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L31)* +*Defined in [src/util/errors.ts:31](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L31)* The Claim for which the validation failed. @@ -55,7 +55,7 @@ ___ *Overrides [JWTClaimValidationFailed](_util_errors_.jwtclaimvalidationfailed.md).[code](_util_errors_.jwtclaimvalidationfailed.md#code)* -*Defined in [src/util/errors.ts:135](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L135)* +*Defined in [src/util/errors.ts:135](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L135)* ___ @@ -79,7 +79,7 @@ ___ • **reason**: string -*Defined in [src/util/errors.ts:36](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L36)* +*Defined in [src/util/errors.ts:36](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L36)* Reason code for the validation failure. diff --git a/docs/classes/_util_errors_.jwtinvalid.md b/docs/classes/_util_errors_.jwtinvalid.md index 4eed358b28..296ab725d3 100644 --- a/docs/classes/_util_errors_.jwtinvalid.md +++ b/docs/classes/_util_errors_.jwtinvalid.md @@ -21,7 +21,7 @@ An error subclass thrown when a JWT is invalid. \+ **new JWTInvalid**(`message?`: string): [JWTInvalid](_util_errors_.jwtinvalid.md) -*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L11)* +*Defined in [src/util/errors.ts:11](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L11)* #### Parameters: @@ -39,7 +39,7 @@ Name | Type | *Overrides [JOSEError](_util_errors_.joseerror.md).[code](_util_errors_.joseerror.md#code)* -*Defined in [src/util/errors.ts:87](https://github.com/panva/jose/blob/v3.x/src/util/errors.ts#L87)* +*Defined in [src/util/errors.ts:87](https://github.com/panva/jose/blob/v3.0.0/src/util/errors.ts#L87)* ___ diff --git a/docs/functions/_jwe_compact_decrypt_.compactdecrypt.md b/docs/functions/_jwe_compact_decrypt_.compactdecrypt.md index 50573d666e..67752db651 100644 --- a/docs/functions/_jwe_compact_decrypt_.compactdecrypt.md +++ b/docs/functions/_jwe_compact_decrypt_.compactdecrypt.md @@ -2,7 +2,7 @@ ▸ **compactDecrypt**(`jwe`: string, `key`: [KeyLike](../types/_types_d_.keylike.md) \| [CompactDecryptGetKey](../interfaces/_jwe_compact_decrypt_.compactdecryptgetkey.md), `options?`: [DecryptOptions](../interfaces/_types_d_.decryptoptions.md)): Promise\<[CompactDecryptResult](../interfaces/_types_d_.compactdecryptresult.md)> -*Defined in [src/jwe/compact/decrypt.ts:62](https://github.com/panva/jose/blob/v3.x/src/jwe/compact/decrypt.ts#L62)* +*Defined in [src/jwe/compact/decrypt.ts:62](https://github.com/panva/jose/blob/v3.0.0/src/jwe/compact/decrypt.ts#L62)* Decrypts a Compact JWE. diff --git a/docs/functions/_jwe_flattened_decrypt_.flatteneddecrypt.md b/docs/functions/_jwe_flattened_decrypt_.flatteneddecrypt.md index 38acf834ec..b9c9654b69 100644 --- a/docs/functions/_jwe_flattened_decrypt_.flatteneddecrypt.md +++ b/docs/functions/_jwe_flattened_decrypt_.flatteneddecrypt.md @@ -2,7 +2,7 @@ ▸ **flattenedDecrypt**(`jwe`: [FlattenedJWE](../interfaces/_types_d_.flattenedjwe.md), `key`: [KeyLike](../types/_types_d_.keylike.md) \| [FlattenedDecryptGetKey](../interfaces/_jwe_flattened_decrypt_.flatteneddecryptgetkey.md), `options?`: [DecryptOptions](../interfaces/_types_d_.decryptoptions.md)): Promise\<[FlattenedDecryptResult](../interfaces/_types_d_.flatteneddecryptresult.md)> -*Defined in [src/jwe/flattened/decrypt.ts:92](https://github.com/panva/jose/blob/v3.x/src/jwe/flattened/decrypt.ts#L92)* +*Defined in [src/jwe/flattened/decrypt.ts:92](https://github.com/panva/jose/blob/v3.0.0/src/jwe/flattened/decrypt.ts#L92)* Decrypts a Flattened JWE. diff --git a/docs/functions/_jwk_embedded_.embeddedjwk.md b/docs/functions/_jwk_embedded_.embeddedjwk.md index 4fe6d2c45a..c9cc12114f 100644 --- a/docs/functions/_jwk_embedded_.embeddedjwk.md +++ b/docs/functions/_jwk_embedded_.embeddedjwk.md @@ -2,7 +2,7 @@ ▸ **EmbeddedJWK**(`protectedHeader`: [JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md), `token`: [FlattenedJWSInput](../interfaces/_types_d_.flattenedjwsinput.md)): Promise\ -*Defined in [src/jwk/embedded.ts:43](https://github.com/panva/jose/blob/v3.x/src/jwk/embedded.ts#L43)* +*Defined in [src/jwk/embedded.ts:43](https://github.com/panva/jose/blob/v3.0.0/src/jwk/embedded.ts#L43)* EmbeddedJWK is an implementation of a GetKeyFunction intended to be used with the JWS/JWT verify operations whenever you need to opt-in to verify signatures with diff --git a/docs/functions/_jwk_parse_.parsejwk.md b/docs/functions/_jwk_parse_.parsejwk.md index 08c15b0911..5751b1c8b8 100644 --- a/docs/functions/_jwk_parse_.parsejwk.md +++ b/docs/functions/_jwk_parse_.parsejwk.md @@ -2,7 +2,7 @@ ▸ **parseJwk**(`jwk`: [JWK](../interfaces/_types_d_.jwk.md), `alg?`: string, `octAsKeyObject?`: false \| true): Promise\<[KeyLike](../types/_types_d_.keylike.md)> -*Defined in [src/jwk/parse.ts:50](https://github.com/panva/jose/blob/v3.x/src/jwk/parse.ts#L50)* +*Defined in [src/jwk/parse.ts:50](https://github.com/panva/jose/blob/v3.0.0/src/jwk/parse.ts#L50)* Converts a JWK to a runtime-specific key representation. Either JWK "alg" (Algorithm) Parameter must be present or the optional "alg" argument. When running on a platform diff --git a/docs/functions/_jwk_thumbprint_.calculatethumbprint.md b/docs/functions/_jwk_thumbprint_.calculatethumbprint.md index 35b7802272..5c4b76372b 100644 --- a/docs/functions/_jwk_thumbprint_.calculatethumbprint.md +++ b/docs/functions/_jwk_thumbprint_.calculatethumbprint.md @@ -2,7 +2,7 @@ ▸ **calculateThumbprint**(`jwk`: [JWK](../interfaces/_types_d_.jwk.md), `digestAlgorithm?`: \"sha256\" \| \"sha384\" \| \"sha512\"): Promise\ -*Defined in [src/jwk/thumbprint.ts:47](https://github.com/panva/jose/blob/v3.x/src/jwk/thumbprint.ts#L47)* +*Defined in [src/jwk/thumbprint.ts:47](https://github.com/panva/jose/blob/v3.0.0/src/jwk/thumbprint.ts#L47)* Calculates a base64url-encoded JSON Web Key (JWK) Thumbprint as per [RFC7638](https://tools.ietf.org/html/rfc7638). diff --git a/docs/functions/_jwks_remote_.createremotejwkset.md b/docs/functions/_jwks_remote_.createremotejwkset.md index 4deef39a70..38b0ee81e7 100644 --- a/docs/functions/_jwks_remote_.createremotejwkset.md +++ b/docs/functions/_jwks_remote_.createremotejwkset.md @@ -2,7 +2,7 @@ ▸ **createRemoteJWKSet**(`url`: URL, `options?`: [RemoteJWKSetOptions](../interfaces/_jwks_remote_.remotejwksetoptions.md)): [GetKeyFunction](../interfaces/_types_d_.getkeyfunction.md)\<[JWSHeaderParameters](../interfaces/_types_d_.jwsheaderparameters.md), [FlattenedJWSInput](../interfaces/_types_d_.flattenedjwsinput.md)> -*Defined in [src/jwks/remote.ts:233](https://github.com/panva/jose/blob/v3.x/src/jwks/remote.ts#L233)* +*Defined in [src/jwks/remote.ts:233](https://github.com/panva/jose/blob/v3.0.0/src/jwks/remote.ts#L233)* Returns a function that resolves to a key object downloaded from a remote endpoint returning a JSON Web Key Set, that is, for example, diff --git a/docs/functions/_jws_compact_verify_.compactverify.md b/docs/functions/_jws_compact_verify_.compactverify.md index f93b90a837..177b6c7e4e 100644 --- a/docs/functions/_jws_compact_verify_.compactverify.md +++ b/docs/functions/_jws_compact_verify_.compactverify.md @@ -2,7 +2,7 @@ ▸ **compactVerify**(`jws`: string, `key`: [KeyLike](../types/_types_d_.keylike.md) \| [CompactVerifyGetKey](../interfaces/_jws_compact_verify_.compactverifygetkey.md), `options?`: [VerifyOptions](../interfaces/_types_d_.verifyoptions.md)): Promise\<[CompactVerifyResult](../interfaces/_types_d_.compactverifyresult.md)> -*Defined in [src/jws/compact/verify.ts:59](https://github.com/panva/jose/blob/v3.x/src/jws/compact/verify.ts#L59)* +*Defined in [src/jws/compact/verify.ts:59](https://github.com/panva/jose/blob/v3.0.0/src/jws/compact/verify.ts#L59)* Verifies the signature and format of and afterwards decodes the Compact JWS. diff --git a/docs/functions/_jws_flattened_verify_.flattenedverify.md b/docs/functions/_jws_flattened_verify_.flattenedverify.md index c956bc757c..a9af064fb1 100644 --- a/docs/functions/_jws_flattened_verify_.flattenedverify.md +++ b/docs/functions/_jws_flattened_verify_.flattenedverify.md @@ -2,7 +2,7 @@ ▸ **flattenedVerify**(`jws`: [FlattenedJWSInput](../interfaces/_types_d_.flattenedjwsinput.md), `key`: [KeyLike](../types/_types_d_.keylike.md) \| [FlattenedVerifyGetKey](../interfaces/_jws_flattened_verify_.flattenedverifygetkey.md), `options?`: [VerifyOptions](../interfaces/_types_d_.verifyoptions.md)): Promise\<[FlattenedVerifyResult](../interfaces/_types_d_.flattenedverifyresult.md)> -*Defined in [src/jws/flattened/verify.ts:75](https://github.com/panva/jose/blob/v3.x/src/jws/flattened/verify.ts#L75)* +*Defined in [src/jws/flattened/verify.ts:75](https://github.com/panva/jose/blob/v3.0.0/src/jws/flattened/verify.ts#L75)* Verifies the signature and format of and afterwards decodes the Flattened JWS. diff --git a/docs/functions/_jwt_decrypt_.jwtdecrypt.md b/docs/functions/_jwt_decrypt_.jwtdecrypt.md index 8cfe7be4f8..98d0ffae42 100644 --- a/docs/functions/_jwt_decrypt_.jwtdecrypt.md +++ b/docs/functions/_jwt_decrypt_.jwtdecrypt.md @@ -2,7 +2,7 @@ ▸ **jwtDecrypt**(`jwt`: string, `key`: [KeyLike](../types/_types_d_.keylike.md) \| [JWTDecryptGetKey](../interfaces/_jwt_decrypt_.jwtdecryptgetkey.md), `options?`: [JWTDecryptOptions](../interfaces/_jwt_decrypt_.jwtdecryptoptions.md)): Promise\<[JWTDecryptResult](../interfaces/_types_d_.jwtdecryptresult.md)> -*Defined in [src/jwt/decrypt.ts:65](https://github.com/panva/jose/blob/v3.x/src/jwt/decrypt.ts#L65)* +*Defined in [src/jwt/decrypt.ts:65](https://github.com/panva/jose/blob/v3.0.0/src/jwt/decrypt.ts#L65)* Verifies the JWT format (to be a JWE Compact format), decrypts the ciphertext, validates the JWT Claims Set. diff --git a/docs/functions/_jwt_verify_.jwtverify.md b/docs/functions/_jwt_verify_.jwtverify.md index 6db7d0df08..60bf49924e 100644 --- a/docs/functions/_jwt_verify_.jwtverify.md +++ b/docs/functions/_jwt_verify_.jwtverify.md @@ -2,7 +2,7 @@ ▸ **jwtVerify**(`jwt`: string, `key`: [KeyLike](../types/_types_d_.keylike.md) \| [JWTVerifyGetKey](../interfaces/_jwt_verify_.jwtverifygetkey.md), `options?`: [JWTVerifyOptions](../interfaces/_jwt_verify_.jwtverifyoptions.md)): Promise\<[JWTVerifyResult](../interfaces/_types_d_.jwtverifyresult.md)> -*Defined in [src/jwt/verify.ts:66](https://github.com/panva/jose/blob/v3.x/src/jwt/verify.ts#L66)* +*Defined in [src/jwt/verify.ts:66](https://github.com/panva/jose/blob/v3.0.0/src/jwt/verify.ts#L66)* Verifies the JWT format (to be a JWS Compact format), verifies the JWS signature, validates the JWT Claims Set. diff --git a/docs/functions/_util_generate_key_pair_.generatekeypair.md b/docs/functions/_util_generate_key_pair_.generatekeypair.md index 453fd054c9..6420b5b8a7 100644 --- a/docs/functions/_util_generate_key_pair_.generatekeypair.md +++ b/docs/functions/_util_generate_key_pair_.generatekeypair.md @@ -2,7 +2,7 @@ ▸ **generateKeyPair**(`alg`: string, `options?`: [GenerateKeyPairOptions](../interfaces/_util_generate_key_pair_.generatekeypairoptions.md)): Promise\<{ privateKey: CryptoKey \| KeyObject ; publicKey: CryptoKey \| KeyObject }> -*Defined in [src/util/generate_key_pair.ts:41](https://github.com/panva/jose/blob/v3.x/src/util/generate_key_pair.ts#L41)* +*Defined in [src/util/generate_key_pair.ts:41](https://github.com/panva/jose/blob/v3.0.0/src/util/generate_key_pair.ts#L41)* Generates a private and a public key for a given JWA algorithm identifier. This can only generate asymmetric key pairs. For symmetric secrets use the diff --git a/docs/functions/_util_generate_secret_.generatesecret.md b/docs/functions/_util_generate_secret_.generatesecret.md index 36c3b163f3..21f9f14204 100644 --- a/docs/functions/_util_generate_secret_.generatesecret.md +++ b/docs/functions/_util_generate_secret_.generatesecret.md @@ -2,7 +2,7 @@ ▸ **generateSecret**(`alg`: string): Promise\<[KeyLike](../types/_types_d_.keylike.md)> -*Defined in [src/util/generate_secret.ts:28](https://github.com/panva/jose/blob/v3.x/src/util/generate_secret.ts#L28)* +*Defined in [src/util/generate_secret.ts:28](https://github.com/panva/jose/blob/v3.0.0/src/util/generate_secret.ts#L28)* Generates a symmetric secret key for a given JWA algorithm identifier. diff --git a/docs/interfaces/_jwe_compact_decrypt_.compactdecryptgetkey.md b/docs/interfaces/_jwe_compact_decrypt_.compactdecryptgetkey.md index 275f987f3e..8c3a6bbe41 100644 --- a/docs/interfaces/_jwe_compact_decrypt_.compactdecryptgetkey.md +++ b/docs/interfaces/_jwe_compact_decrypt_.compactdecryptgetkey.md @@ -7,7 +7,7 @@ No token components have been verified at the time of this function call. ▸ (`protectedHeader`: [JWEHeaderParameters](_types_d_.jweheaderparameters.md), `token`: [FlattenedJWE](_types_d_.flattenedjwe.md)): Promise\<[KeyLike](../types/_types_d_.keylike.md)> -*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L75)* +*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L75)* Interface for Compact JWE Decryption dynamic key resolution. No token components have been verified at the time of this function call. diff --git a/docs/interfaces/_jwe_flattened_decrypt_.flatteneddecryptgetkey.md b/docs/interfaces/_jwe_flattened_decrypt_.flatteneddecryptgetkey.md index ad3ed42128..e47591c90f 100644 --- a/docs/interfaces/_jwe_flattened_decrypt_.flatteneddecryptgetkey.md +++ b/docs/interfaces/_jwe_flattened_decrypt_.flatteneddecryptgetkey.md @@ -7,7 +7,7 @@ No token components have been verified at the time of this function call. ▸ (`protectedHeader`: [JWEHeaderParameters](_types_d_.jweheaderparameters.md) \| undefined, `token`: [FlattenedJWE](_types_d_.flattenedjwe.md)): Promise\<[KeyLike](../types/_types_d_.keylike.md)> -*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L75)* +*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L75)* Interface for Flattened JWE Decryption dynamic key resolution. No token components have been verified at the time of this function call. diff --git a/docs/interfaces/_jwks_remote_.remotejwksetoptions.md b/docs/interfaces/_jwks_remote_.remotejwksetoptions.md index 332bac5b78..917904d034 100644 --- a/docs/interfaces/_jwks_remote_.remotejwksetoptions.md +++ b/docs/interfaces/_jwks_remote_.remotejwksetoptions.md @@ -15,7 +15,7 @@ Options for the remote JSON Web Key Set. • `Optional` **cooldownDuration**: number -*Defined in [src/jwks/remote.ts:45](https://github.com/panva/jose/blob/v3.x/src/jwks/remote.ts#L45)* +*Defined in [src/jwks/remote.ts:45](https://github.com/panva/jose/blob/v3.0.0/src/jwks/remote.ts#L45)* Duration for which no more HTTP requests will be triggered after a previous successful fetch. Default is 30000. @@ -26,7 +26,7 @@ ___ • `Optional` **timeoutDuration**: number -*Defined in [src/jwks/remote.ts:39](https://github.com/panva/jose/blob/v3.x/src/jwks/remote.ts#L39)* +*Defined in [src/jwks/remote.ts:39](https://github.com/panva/jose/blob/v3.0.0/src/jwks/remote.ts#L39)* Timeout for the HTTP request. When reached the request will be aborted and the verification will fail. Default is 5000. diff --git a/docs/interfaces/_jws_compact_verify_.compactverifygetkey.md b/docs/interfaces/_jws_compact_verify_.compactverifygetkey.md index 3e88aba16c..ad96ddba1a 100644 --- a/docs/interfaces/_jws_compact_verify_.compactverifygetkey.md +++ b/docs/interfaces/_jws_compact_verify_.compactverifygetkey.md @@ -7,7 +7,7 @@ No token components have been verified at the time of this function call. ▸ (`protectedHeader`: [JWSHeaderParameters](_types_d_.jwsheaderparameters.md), `token`: [FlattenedJWSInput](_types_d_.flattenedjwsinput.md)): Promise\<[KeyLike](../types/_types_d_.keylike.md)> -*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L75)* +*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L75)* Interface for Compact JWS Verification dynamic key resolution. No token components have been verified at the time of this function call. diff --git a/docs/interfaces/_jws_flattened_verify_.flattenedverifygetkey.md b/docs/interfaces/_jws_flattened_verify_.flattenedverifygetkey.md index f087651387..f1331550b1 100644 --- a/docs/interfaces/_jws_flattened_verify_.flattenedverifygetkey.md +++ b/docs/interfaces/_jws_flattened_verify_.flattenedverifygetkey.md @@ -7,7 +7,7 @@ No token components have been verified at the time of this function call. ▸ (`protectedHeader`: [JWSHeaderParameters](_types_d_.jwsheaderparameters.md) \| undefined, `token`: [FlattenedJWSInput](_types_d_.flattenedjwsinput.md)): Promise\<[KeyLike](../types/_types_d_.keylike.md)> -*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L75)* +*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L75)* Interface for Flattened JWS Verification dynamic key resolution. No token components have been verified at the time of this function call. diff --git a/docs/interfaces/_jwt_decrypt_.jwtdecryptgetkey.md b/docs/interfaces/_jwt_decrypt_.jwtdecryptgetkey.md index 6942667852..d39ff62b58 100644 --- a/docs/interfaces/_jwt_decrypt_.jwtdecryptgetkey.md +++ b/docs/interfaces/_jwt_decrypt_.jwtdecryptgetkey.md @@ -7,7 +7,7 @@ No token components have been verified at the time of this function call. ▸ (`protectedHeader`: [JWEHeaderParameters](_types_d_.jweheaderparameters.md), `token`: [FlattenedJWE](_types_d_.flattenedjwe.md)): Promise\<[KeyLike](../types/_types_d_.keylike.md)> -*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L75)* +*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L75)* Interface for JWT Decryption dynamic key resolution. No token components have been verified at the time of this function call. diff --git a/docs/interfaces/_jwt_decrypt_.jwtdecryptoptions.md b/docs/interfaces/_jwt_decrypt_.jwtdecryptoptions.md index ebe6546df0..78c451b59f 100644 --- a/docs/interfaces/_jwt_decrypt_.jwtdecryptoptions.md +++ b/docs/interfaces/_jwt_decrypt_.jwtdecryptoptions.md @@ -23,7 +23,7 @@ Combination of JWE Decryption options and JWT Claims Set verification options. • `Optional` **audience**: string \| string[] -*Defined in [src/types.d.ts:355](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L355)* +*Defined in [src/types.d.ts:355](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L355)* Expected JWT "aud" (Audience) Claim value(s). @@ -33,7 +33,7 @@ ___ • `Optional` **clockTolerance**: string \| number -*Defined in [src/types.d.ts:362](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L362)* +*Defined in [src/types.d.ts:362](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L362)* Expected clock tolerance - in seconds when number (e.g. 5) @@ -45,7 +45,7 @@ ___ • `Optional` **contentEncryptionAlgorithms**: string[] -*Defined in [src/types.d.ts:328](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L328)* +*Defined in [src/types.d.ts:328](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L328)* A list of accepted JWE "enc" (Encryption Algorithm) Header Parameter values. @@ -55,7 +55,7 @@ ___ • `Optional` **currentDate**: Date -*Defined in [src/types.d.ts:387](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L387)* +*Defined in [src/types.d.ts:387](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L387)* Date to use when comparing NumericDate claims, defaults to `new Date()`. @@ -65,7 +65,7 @@ ___ • `Optional` **inflateRaw**: [InflateFunction](_types_d_.inflatefunction.md) -*Defined in [src/types.d.ts:334](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L334)* +*Defined in [src/types.d.ts:334](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L334)* In a browser runtime you have to provide an implementation for Inflate Raw when you expect JWEs with compressed plaintext. @@ -76,7 +76,7 @@ ___ • `Optional` **issuer**: string \| string[] -*Defined in [src/types.d.ts:367](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L367)* +*Defined in [src/types.d.ts:367](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L367)* Expected JWT "iss" (Issuer) Claim value(s). @@ -86,7 +86,7 @@ ___ • `Optional` **keyManagementAlgorithms**: string[] -*Defined in [src/types.d.ts:323](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L323)* +*Defined in [src/types.d.ts:323](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L323)* A list of accepted JWE "alg" (Algorithm) Header Parameter values. @@ -96,7 +96,7 @@ ___ • `Optional` **maxTokenAge**: string -*Defined in [src/types.d.ts:372](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L372)* +*Defined in [src/types.d.ts:372](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L372)* Maximum time elapsed (in seconds) from the JWT "iat" (Issued At) Claim value. @@ -106,7 +106,7 @@ ___ • `Optional` **subject**: string -*Defined in [src/types.d.ts:377](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L377)* +*Defined in [src/types.d.ts:377](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L377)* Expected JWT "sub" (Subject) Claim value. @@ -116,6 +116,6 @@ ___ • `Optional` **typ**: string -*Defined in [src/types.d.ts:382](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L382)* +*Defined in [src/types.d.ts:382](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L382)* Expected JWT "typ" (Type) Header Parameter value. diff --git a/docs/interfaces/_jwt_verify_.jwtverifygetkey.md b/docs/interfaces/_jwt_verify_.jwtverifygetkey.md index 2c51dbefbd..f736f64ba9 100644 --- a/docs/interfaces/_jwt_verify_.jwtverifygetkey.md +++ b/docs/interfaces/_jwt_verify_.jwtverifygetkey.md @@ -7,7 +7,7 @@ No token components have been verified at the time of this function call. ▸ (`protectedHeader`: [JWSHeaderParameters](_types_d_.jwsheaderparameters.md), `token`: [FlattenedJWSInput](_types_d_.flattenedjwsinput.md)): Promise\<[KeyLike](../types/_types_d_.keylike.md)> -*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L75)* +*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L75)* Interface for JWT Verification dynamic key resolution. No token components have been verified at the time of this function call. diff --git a/docs/interfaces/_jwt_verify_.jwtverifyoptions.md b/docs/interfaces/_jwt_verify_.jwtverifyoptions.md index bd36dfcb7c..372bd7095d 100644 --- a/docs/interfaces/_jwt_verify_.jwtverifyoptions.md +++ b/docs/interfaces/_jwt_verify_.jwtverifyoptions.md @@ -21,7 +21,7 @@ Combination of JWS Verification options and JWT Claims Set verification options. • `Optional` **algorithms**: string[] -*Defined in [src/types.d.ts:397](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L397)* +*Defined in [src/types.d.ts:397](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L397)* A list of accepted JWS "alg" (Algorithm) Header Parameter values. @@ -31,7 +31,7 @@ ___ • `Optional` **audience**: string \| string[] -*Defined in [src/types.d.ts:355](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L355)* +*Defined in [src/types.d.ts:355](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L355)* Expected JWT "aud" (Audience) Claim value(s). @@ -41,7 +41,7 @@ ___ • `Optional` **clockTolerance**: string \| number -*Defined in [src/types.d.ts:362](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L362)* +*Defined in [src/types.d.ts:362](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L362)* Expected clock tolerance - in seconds when number (e.g. 5) @@ -53,7 +53,7 @@ ___ • `Optional` **currentDate**: Date -*Defined in [src/types.d.ts:387](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L387)* +*Defined in [src/types.d.ts:387](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L387)* Date to use when comparing NumericDate claims, defaults to `new Date()`. @@ -63,7 +63,7 @@ ___ • `Optional` **issuer**: string \| string[] -*Defined in [src/types.d.ts:367](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L367)* +*Defined in [src/types.d.ts:367](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L367)* Expected JWT "iss" (Issuer) Claim value(s). @@ -73,7 +73,7 @@ ___ • `Optional` **maxTokenAge**: string -*Defined in [src/types.d.ts:372](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L372)* +*Defined in [src/types.d.ts:372](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L372)* Maximum time elapsed (in seconds) from the JWT "iat" (Issued At) Claim value. @@ -83,7 +83,7 @@ ___ • `Optional` **subject**: string -*Defined in [src/types.d.ts:377](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L377)* +*Defined in [src/types.d.ts:377](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L377)* Expected JWT "sub" (Subject) Claim value. @@ -93,6 +93,6 @@ ___ • `Optional` **typ**: string -*Defined in [src/types.d.ts:382](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L382)* +*Defined in [src/types.d.ts:382](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L382)* Expected JWT "typ" (Type) Header Parameter value. diff --git a/docs/interfaces/_types_d_.compactdecryptresult.md b/docs/interfaces/_types_d_.compactdecryptresult.md index f7d1628e13..e35e370a9b 100644 --- a/docs/interfaces/_types_d_.compactdecryptresult.md +++ b/docs/interfaces/_types_d_.compactdecryptresult.md @@ -13,7 +13,7 @@ • **plaintext**: Uint8Array -*Defined in [src/types.d.ts:491](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L491)* +*Defined in [src/types.d.ts:491](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L491)* Plaintext. @@ -23,6 +23,6 @@ ___ • **protectedHeader**: [JWEHeaderParameters](_types_d_.jweheaderparameters.md) -*Defined in [src/types.d.ts:496](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L496)* +*Defined in [src/types.d.ts:496](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L496)* JWE Protected Header. diff --git a/docs/interfaces/_types_d_.compactverifyresult.md b/docs/interfaces/_types_d_.compactverifyresult.md index 451b82bff3..d49b872efd 100644 --- a/docs/interfaces/_types_d_.compactverifyresult.md +++ b/docs/interfaces/_types_d_.compactverifyresult.md @@ -13,7 +13,7 @@ • **payload**: Uint8Array -*Defined in [src/types.d.ts:520](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L520)* +*Defined in [src/types.d.ts:520](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L520)* JWS Payload. @@ -23,6 +23,6 @@ ___ • **protectedHeader**: [JWSHeaderParameters](_types_d_.jwsheaderparameters.md) -*Defined in [src/types.d.ts:525](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L525)* +*Defined in [src/types.d.ts:525](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L525)* JWS Protected Header. diff --git a/docs/interfaces/_types_d_.decryptoptions.md b/docs/interfaces/_types_d_.decryptoptions.md index 6e7af6a0b8..8d0a15d5d8 100644 --- a/docs/interfaces/_types_d_.decryptoptions.md +++ b/docs/interfaces/_types_d_.decryptoptions.md @@ -16,7 +16,7 @@ JWE Decryption options. • `Optional` **contentEncryptionAlgorithms**: string[] -*Defined in [src/types.d.ts:328](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L328)* +*Defined in [src/types.d.ts:328](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L328)* A list of accepted JWE "enc" (Encryption Algorithm) Header Parameter values. @@ -26,7 +26,7 @@ ___ • `Optional` **inflateRaw**: [InflateFunction](_types_d_.inflatefunction.md) -*Defined in [src/types.d.ts:334](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L334)* +*Defined in [src/types.d.ts:334](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L334)* In a browser runtime you have to provide an implementation for Inflate Raw when you expect JWEs with compressed plaintext. @@ -37,6 +37,6 @@ ___ • `Optional` **keyManagementAlgorithms**: string[] -*Defined in [src/types.d.ts:323](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L323)* +*Defined in [src/types.d.ts:323](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L323)* A list of accepted JWE "alg" (Algorithm) Header Parameter values. diff --git a/docs/interfaces/_types_d_.deflatefunction.md b/docs/interfaces/_types_d_.deflatefunction.md index 699468b4f5..ec4bd1ad53 100644 --- a/docs/interfaces/_types_d_.deflatefunction.md +++ b/docs/interfaces/_types_d_.deflatefunction.md @@ -6,7 +6,7 @@ Deflate Raw implementation, e.g. promisified [zlib.deflateRaw](https://nodejs.or ▸ (`input`: Uint8Array): Promise\ -*Defined in [src/types.d.ts:449](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L449)* +*Defined in [src/types.d.ts:449](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L449)* Deflate Raw implementation, e.g. promisified [zlib.deflateRaw](https://nodejs.org/api/zlib.html#zlib_zlib_deflateraw_buffer_options_callback). diff --git a/docs/interfaces/_types_d_.encryptoptions.md b/docs/interfaces/_types_d_.encryptoptions.md index c3d6250c2a..f0aed51d09 100644 --- a/docs/interfaces/_types_d_.encryptoptions.md +++ b/docs/interfaces/_types_d_.encryptoptions.md @@ -14,7 +14,7 @@ JWE Encryption options. • `Optional` **deflateRaw**: [DeflateFunction](_types_d_.deflatefunction.md) -*Defined in [src/types.d.ts:345](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L345)* +*Defined in [src/types.d.ts:345](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L345)* In a browser runtime you have to provide an implementation for Deflate Raw when you will be producing JWEs with compressed plaintext. diff --git a/docs/interfaces/_types_d_.flatteneddecryptresult.md b/docs/interfaces/_types_d_.flatteneddecryptresult.md index c7253c6cb0..440c624d7f 100644 --- a/docs/interfaces/_types_d_.flatteneddecryptresult.md +++ b/docs/interfaces/_types_d_.flatteneddecryptresult.md @@ -16,7 +16,7 @@ • `Optional` **additionalAuthenticatedData**: Uint8Array -*Defined in [src/types.d.ts:464](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L464)* +*Defined in [src/types.d.ts:464](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L464)* JWE AAD. @@ -26,7 +26,7 @@ ___ • **plaintext**: Uint8Array -*Defined in [src/types.d.ts:469](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L469)* +*Defined in [src/types.d.ts:469](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L469)* Plaintext. @@ -36,7 +36,7 @@ ___ • `Optional` **protectedHeader**: [JWEHeaderParameters](_types_d_.jweheaderparameters.md) -*Defined in [src/types.d.ts:474](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L474)* +*Defined in [src/types.d.ts:474](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L474)* JWE Protected Header. @@ -46,7 +46,7 @@ ___ • `Optional` **sharedUnprotectedHeader**: [JWEHeaderParameters](_types_d_.jweheaderparameters.md) -*Defined in [src/types.d.ts:479](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L479)* +*Defined in [src/types.d.ts:479](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L479)* JWE Shared Unprotected Header. @@ -56,6 +56,6 @@ ___ • `Optional` **unprotectedHeader**: [JWEHeaderParameters](_types_d_.jweheaderparameters.md) -*Defined in [src/types.d.ts:484](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L484)* +*Defined in [src/types.d.ts:484](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L484)* JWE Per-Recipient Unprotected Header. diff --git a/docs/interfaces/_types_d_.flattenedjwe.md b/docs/interfaces/_types_d_.flattenedjwe.md index a9be78dafd..986065431b 100644 --- a/docs/interfaces/_types_d_.flattenedjwe.md +++ b/docs/interfaces/_types_d_.flattenedjwe.md @@ -21,7 +21,7 @@ Flattened JWE definition. • `Optional` **aad**: string -*Defined in [src/types.d.ts:228](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L228)* +*Defined in [src/types.d.ts:228](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L228)* The "aad" member MUST be present and contain the value BASE64URL(JWE AAD)) when the JWE AAD value is non-empty; @@ -35,7 +35,7 @@ ___ • **ciphertext**: string -*Defined in [src/types.d.ts:234](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L234)* +*Defined in [src/types.d.ts:234](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L234)* The "ciphertext" member MUST be present and contain the value BASE64URL(JWE Ciphertext). @@ -46,7 +46,7 @@ ___ • `Optional` **encrypted\_key**: string -*Defined in [src/types.d.ts:241](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L241)* +*Defined in [src/types.d.ts:241](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L241)* The "encrypted_key" member MUST be present and contain the value BASE64URL(JWE Encrypted Key) when the JWE Encrypted Key value is @@ -58,7 +58,7 @@ ___ • `Optional` **header**: [JWEHeaderParameters](_types_d_.jweheaderparameters.md) -*Defined in [src/types.d.ts:251](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L251)* +*Defined in [src/types.d.ts:251](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L251)* The "header" member MUST be present and contain the value JWE Per- Recipient Unprotected Header when the JWE Per-Recipient @@ -73,7 +73,7 @@ ___ • **iv**: string -*Defined in [src/types.d.ts:258](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L258)* +*Defined in [src/types.d.ts:258](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L258)* The "iv" member MUST be present and contain the value BASE64URL(JWE Initialization Vector) when the JWE Initialization @@ -85,7 +85,7 @@ ___ • `Optional` **protected**: string -*Defined in [src/types.d.ts:266](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L266)* +*Defined in [src/types.d.ts:266](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L266)* The "protected" member MUST be present and contain the value BASE64URL(UTF8(JWE Protected Header)) when the JWE Protected @@ -98,7 +98,7 @@ ___ • **tag**: string -*Defined in [src/types.d.ts:273](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L273)* +*Defined in [src/types.d.ts:273](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L273)* The "tag" member MUST be present and contain the value BASE64URL(JWE Authentication Tag) when the JWE Authentication Tag @@ -110,7 +110,7 @@ ___ • `Optional` **unprotected**: [JWEHeaderParameters](_types_d_.jweheaderparameters.md) -*Defined in [src/types.d.ts:282](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L282)* +*Defined in [src/types.d.ts:282](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L282)* The "unprotected" member MUST be present and contain the value JWE Shared Unprotected Header when the JWE Shared Unprotected Header diff --git a/docs/interfaces/_types_d_.flattenedjws.md b/docs/interfaces/_types_d_.flattenedjws.md index efb4222574..7d9aef3436 100644 --- a/docs/interfaces/_types_d_.flattenedjws.md +++ b/docs/interfaces/_types_d_.flattenedjws.md @@ -17,7 +17,7 @@ is not returned when JWS Unencoded Payload Option • `Optional` **payload**: string -*Defined in [src/types.d.ts:136](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L136)* +*Defined in [src/types.d.ts:136](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L136)* ___ @@ -25,4 +25,4 @@ ___ • **signature**: string -*Defined in [src/types.d.ts:137](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L137)* +*Defined in [src/types.d.ts:137](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L137)* diff --git a/docs/interfaces/_types_d_.flattenedjwsinput.md b/docs/interfaces/_types_d_.flattenedjwsinput.md index 5b64d239e6..d1ce4a25ab 100644 --- a/docs/interfaces/_types_d_.flattenedjwsinput.md +++ b/docs/interfaces/_types_d_.flattenedjwsinput.md @@ -18,7 +18,7 @@ Uint8Array for detached signature validation. • `Optional` **header**: [JWSHeaderParameters](_types_d_.jwsheaderparameters.md) -*Defined in [src/types.d.ts:106](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L106)* +*Defined in [src/types.d.ts:106](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L106)* The "header" member MUST be present and contain the value JWS Unprotected Header when the JWS Unprotected Header value is non- @@ -32,7 +32,7 @@ ___ • **payload**: string \| Uint8Array -*Defined in [src/types.d.ts:113](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L113)* +*Defined in [src/types.d.ts:113](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L113)* The "payload" member MUST be present and contain the value BASE64URL(JWS Payload). When RFC7797 "b64": false is used @@ -44,7 +44,7 @@ ___ • `Optional` **protected**: string -*Defined in [src/types.d.ts:121](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L121)* +*Defined in [src/types.d.ts:121](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L121)* The "protected" member MUST be present and contain the value BASE64URL(UTF8(JWS Protected Header)) when the JWS Protected @@ -57,7 +57,7 @@ ___ • **signature**: string -*Defined in [src/types.d.ts:127](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L127)* +*Defined in [src/types.d.ts:127](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L127)* The "signature" member MUST be present and contain the value BASE64URL(JWS Signature). diff --git a/docs/interfaces/_types_d_.flattenedverifyresult.md b/docs/interfaces/_types_d_.flattenedverifyresult.md index 97ed5e1921..62381632d1 100644 --- a/docs/interfaces/_types_d_.flattenedverifyresult.md +++ b/docs/interfaces/_types_d_.flattenedverifyresult.md @@ -14,7 +14,7 @@ • **payload**: Uint8Array -*Defined in [src/types.d.ts:503](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L503)* +*Defined in [src/types.d.ts:503](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L503)* JWS Payload. @@ -24,7 +24,7 @@ ___ • `Optional` **protectedHeader**: [JWSHeaderParameters](_types_d_.jwsheaderparameters.md) -*Defined in [src/types.d.ts:508](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L508)* +*Defined in [src/types.d.ts:508](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L508)* JWS Protected Header. @@ -34,6 +34,6 @@ ___ • `Optional` **unprotectedHeader**: [JWSHeaderParameters](_types_d_.jwsheaderparameters.md) -*Defined in [src/types.d.ts:513](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L513)* +*Defined in [src/types.d.ts:513](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L513)* JWS Unprotected Header. diff --git a/docs/interfaces/_types_d_.getkeyfunction.md b/docs/interfaces/_types_d_.getkeyfunction.md index 8c7dbf8c7f..31e23603e9 100644 --- a/docs/interfaces/_types_d_.getkeyfunction.md +++ b/docs/interfaces/_types_d_.getkeyfunction.md @@ -14,7 +14,7 @@ Name | ▸ (`protectedHeader`: T, `token`: T2): Promise\<[KeyLike](../types/_types_d_.keylike.md)> -*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L75)* +*Defined in [src/types.d.ts:75](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L75)* Generic Interface for consuming operations dynamic key resolution. No token components have been verified at the time of this function call. diff --git a/docs/interfaces/_types_d_.inflatefunction.md b/docs/interfaces/_types_d_.inflatefunction.md index b3d8dfd1ef..83c9e9aaef 100644 --- a/docs/interfaces/_types_d_.inflatefunction.md +++ b/docs/interfaces/_types_d_.inflatefunction.md @@ -6,7 +6,7 @@ Inflate Raw implementation, e.g. promisified [zlib.inflateRaw](https://nodejs.or ▸ (`input`: Uint8Array): Promise\ -*Defined in [src/types.d.ts:456](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L456)* +*Defined in [src/types.d.ts:456](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L456)* Inflate Raw implementation, e.g. promisified [zlib.inflateRaw](https://nodejs.org/api/zlib.html#zlib_zlib_inflateraw_buffer_options_callback). diff --git a/docs/interfaces/_types_d_.joseheaderparameters.md b/docs/interfaces/_types_d_.joseheaderparameters.md index 0954a9d391..2a4061cb03 100644 --- a/docs/interfaces/_types_d_.joseheaderparameters.md +++ b/docs/interfaces/_types_d_.joseheaderparameters.md @@ -18,7 +18,7 @@ • `Optional` **cty**: string -*Defined in [src/types.d.ts:174](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L174)* +*Defined in [src/types.d.ts:174](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L174)* "cty" (Content Type) Header Parameter. @@ -28,7 +28,7 @@ ___ • `Optional` **jwk**: Pick\<[JWK](_types_d_.jwk.md), \"kty\" \| \"crv\" \| \"x\" \| \"y\" \| \"e\" \| \"n\"> -*Defined in [src/types.d.ts:164](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L164)* +*Defined in [src/types.d.ts:164](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L164)* "jwk" (JSON Web Key) Header Parameter. @@ -38,7 +38,7 @@ ___ • `Optional` **kid**: string -*Defined in [src/types.d.ts:144](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L144)* +*Defined in [src/types.d.ts:144](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L144)* "kid" (Key ID) Header Parameter. @@ -48,7 +48,7 @@ ___ • `Optional` **typ**: string -*Defined in [src/types.d.ts:169](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L169)* +*Defined in [src/types.d.ts:169](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L169)* "typ" (Type) Header Parameter. @@ -58,7 +58,7 @@ ___ • `Optional` **x5c**: string[] -*Defined in [src/types.d.ts:154](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L154)* +*Defined in [src/types.d.ts:154](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L154)* "x5c" (X.509 Certificate Chain) Header Parameter. @@ -68,7 +68,7 @@ ___ • `Optional` **x5t**: string -*Defined in [src/types.d.ts:149](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L149)* +*Defined in [src/types.d.ts:149](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L149)* "x5t" (X.509 Certificate SHA-1 Thumbprint) Header Parameter. @@ -78,6 +78,6 @@ ___ • `Optional` **x5u**: string -*Defined in [src/types.d.ts:159](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L159)* +*Defined in [src/types.d.ts:159](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L159)* "x5u" (X.509 URL) Header Parameter. diff --git a/docs/interfaces/_types_d_.jweheaderparameters.md b/docs/interfaces/_types_d_.jweheaderparameters.md index 4a0be0c59a..5ca0e04a10 100644 --- a/docs/interfaces/_types_d_.jweheaderparameters.md +++ b/docs/interfaces/_types_d_.jweheaderparameters.md @@ -31,7 +31,7 @@ Any other JWE Header member. • `Optional` **alg**: string -*Defined in [src/types.d.ts:293](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L293)* +*Defined in [src/types.d.ts:293](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L293)* JWE "alg" (Algorithm) Header Parameter. @@ -41,7 +41,7 @@ ___ • `Optional` **crit**: string[] -*Defined in [src/types.d.ts:303](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L303)* +*Defined in [src/types.d.ts:303](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L303)* JWE "crit" (Critical) Header Parameter. @@ -51,7 +51,7 @@ ___ • `Optional` **cty**: string -*Defined in [src/types.d.ts:174](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L174)* +*Defined in [src/types.d.ts:174](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L174)* "cty" (Content Type) Header Parameter. @@ -61,7 +61,7 @@ ___ • `Optional` **enc**: string -*Defined in [src/types.d.ts:298](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L298)* +*Defined in [src/types.d.ts:298](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L298)* JWE "enc" (Encryption Algorithm) Header Parameter. @@ -71,7 +71,7 @@ ___ • `Optional` **jwk**: Pick\<[JWK](_types_d_.jwk.md), \"kty\" \| \"crv\" \| \"x\" \| \"y\" \| \"e\" \| \"n\"> -*Defined in [src/types.d.ts:164](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L164)* +*Defined in [src/types.d.ts:164](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L164)* "jwk" (JSON Web Key) Header Parameter. @@ -81,7 +81,7 @@ ___ • `Optional` **kid**: string -*Defined in [src/types.d.ts:144](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L144)* +*Defined in [src/types.d.ts:144](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L144)* "kid" (Key ID) Header Parameter. @@ -91,7 +91,7 @@ ___ • `Optional` **typ**: string -*Defined in [src/types.d.ts:169](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L169)* +*Defined in [src/types.d.ts:169](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L169)* "typ" (Type) Header Parameter. @@ -101,7 +101,7 @@ ___ • `Optional` **x5c**: string[] -*Defined in [src/types.d.ts:154](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L154)* +*Defined in [src/types.d.ts:154](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L154)* "x5c" (X.509 Certificate Chain) Header Parameter. @@ -111,7 +111,7 @@ ___ • `Optional` **x5t**: string -*Defined in [src/types.d.ts:149](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L149)* +*Defined in [src/types.d.ts:149](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L149)* "x5t" (X.509 Certificate SHA-1 Thumbprint) Header Parameter. @@ -121,7 +121,7 @@ ___ • `Optional` **x5u**: string -*Defined in [src/types.d.ts:159](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L159)* +*Defined in [src/types.d.ts:159](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L159)* "x5u" (X.509 URL) Header Parameter. @@ -131,6 +131,6 @@ ___ • `Optional` **zip**: string -*Defined in [src/types.d.ts:308](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L308)* +*Defined in [src/types.d.ts:308](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L308)* JWE "zip" (Compression Algorithm) Header Parameter. diff --git a/docs/interfaces/_types_d_.jwekeymanagementheaderparameters.md b/docs/interfaces/_types_d_.jwekeymanagementheaderparameters.md index 2b9c918fee..c7667d087f 100644 --- a/docs/interfaces/_types_d_.jwekeymanagementheaderparameters.md +++ b/docs/interfaces/_types_d_.jwekeymanagementheaderparameters.md @@ -19,7 +19,7 @@ Recognized JWE Key Management-related Header Parameters. • `Optional` **apu**: Uint8Array -*Defined in [src/types.d.ts:209](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L209)* +*Defined in [src/types.d.ts:209](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L209)* ___ @@ -27,7 +27,7 @@ ___ • `Optional` **apv**: Uint8Array -*Defined in [src/types.d.ts:210](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L210)* +*Defined in [src/types.d.ts:210](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L210)* ___ @@ -35,7 +35,7 @@ ___ • `Optional` **epk**: [KeyLike](../types/_types_d_.keylike.md) -*Defined in [src/types.d.ts:211](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L211)* +*Defined in [src/types.d.ts:211](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L211)* ___ @@ -43,7 +43,7 @@ ___ • `Optional` **iv**: Uint8Array -*Defined in [src/types.d.ts:212](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L212)* +*Defined in [src/types.d.ts:212](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L212)* ___ @@ -51,7 +51,7 @@ ___ • `Optional` **p2c**: number -*Defined in [src/types.d.ts:213](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L213)* +*Defined in [src/types.d.ts:213](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L213)* ___ @@ -59,4 +59,4 @@ ___ • `Optional` **p2s**: Uint8Array -*Defined in [src/types.d.ts:214](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L214)* +*Defined in [src/types.d.ts:214](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L214)* diff --git a/docs/interfaces/_types_d_.jwk.md b/docs/interfaces/_types_d_.jwk.md index 03654e082f..4529a98674 100644 --- a/docs/interfaces/_types_d_.jwk.md +++ b/docs/interfaces/_types_d_.jwk.md @@ -37,7 +37,7 @@ JSON Web Key ([JWK](https://tools.ietf.org/html/rfc7517)). • `Optional` **alg**: string -*Defined in [src/types.d.ts:12](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L12)* +*Defined in [src/types.d.ts:12](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L12)* JWK "alg" (Algorithm) Parameter. @@ -47,7 +47,7 @@ ___ • `Optional` **crv**: string -*Defined in [src/types.d.ts:13](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L13)* +*Defined in [src/types.d.ts:13](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L13)* ___ @@ -55,7 +55,7 @@ ___ • `Optional` **d**: string -*Defined in [src/types.d.ts:14](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L14)* +*Defined in [src/types.d.ts:14](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L14)* ___ @@ -63,7 +63,7 @@ ___ • `Optional` **dp**: string -*Defined in [src/types.d.ts:15](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L15)* +*Defined in [src/types.d.ts:15](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L15)* ___ @@ -71,7 +71,7 @@ ___ • `Optional` **dq**: string -*Defined in [src/types.d.ts:16](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L16)* +*Defined in [src/types.d.ts:16](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L16)* ___ @@ -79,7 +79,7 @@ ___ • `Optional` **e**: string -*Defined in [src/types.d.ts:17](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L17)* +*Defined in [src/types.d.ts:17](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L17)* ___ @@ -87,7 +87,7 @@ ___ • `Optional` **ext**: false \| true -*Defined in [src/types.d.ts:21](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L21)* +*Defined in [src/types.d.ts:21](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L21)* JWK "ext" (Extractable) Parameter. @@ -97,7 +97,7 @@ ___ • `Optional` **k**: string -*Defined in [src/types.d.ts:22](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L22)* +*Defined in [src/types.d.ts:22](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L22)* ___ @@ -105,7 +105,7 @@ ___ • `Optional` **key\_ops**: string[] -*Defined in [src/types.d.ts:26](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L26)* +*Defined in [src/types.d.ts:26](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L26)* JWK "key_ops" (Key Operations) Parameter. @@ -115,7 +115,7 @@ ___ • `Optional` **kid**: string -*Defined in [src/types.d.ts:30](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L30)* +*Defined in [src/types.d.ts:30](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L30)* JWK "kid" (Key ID) Parameter. @@ -125,7 +125,7 @@ ___ • `Optional` **kty**: string -*Defined in [src/types.d.ts:34](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L34)* +*Defined in [src/types.d.ts:34](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L34)* JWK "kty" (Key Type) Parameter. @@ -135,7 +135,7 @@ ___ • `Optional` **n**: string -*Defined in [src/types.d.ts:35](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L35)* +*Defined in [src/types.d.ts:35](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L35)* ___ @@ -143,7 +143,7 @@ ___ • `Optional` **oth**: Array\<{ d?: string ; r?: string ; t?: string }> -*Defined in [src/types.d.ts:36](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L36)* +*Defined in [src/types.d.ts:36](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L36)* ___ @@ -151,7 +151,7 @@ ___ • `Optional` **p**: string -*Defined in [src/types.d.ts:41](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L41)* +*Defined in [src/types.d.ts:41](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L41)* ___ @@ -159,7 +159,7 @@ ___ • `Optional` **q**: string -*Defined in [src/types.d.ts:42](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L42)* +*Defined in [src/types.d.ts:42](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L42)* ___ @@ -167,7 +167,7 @@ ___ • `Optional` **qi**: string -*Defined in [src/types.d.ts:43](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L43)* +*Defined in [src/types.d.ts:43](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L43)* ___ @@ -175,7 +175,7 @@ ___ • `Optional` **use**: string -*Defined in [src/types.d.ts:47](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L47)* +*Defined in [src/types.d.ts:47](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L47)* JWK "use" (Public Key Use) Parameter. @@ -185,7 +185,7 @@ ___ • `Optional` **x**: string -*Defined in [src/types.d.ts:48](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L48)* +*Defined in [src/types.d.ts:48](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L48)* ___ @@ -193,7 +193,7 @@ ___ • `Optional` **x5c**: string[] -*Defined in [src/types.d.ts:53](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L53)* +*Defined in [src/types.d.ts:53](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L53)* JWK "x5c" (X.509 Certificate Chain) Parameter. @@ -203,7 +203,7 @@ ___ • `Optional` **x5t**: string -*Defined in [src/types.d.ts:57](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L57)* +*Defined in [src/types.d.ts:57](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L57)* JWK "x5t" (X.509 Certificate SHA-1 Thumbprint) Parameter. @@ -213,7 +213,7 @@ ___ • `Optional` **x5t#S256**: string -*Defined in [src/types.d.ts:61](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L61)* +*Defined in [src/types.d.ts:61](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L61)* "x5t#S256" (X.509 Certificate SHA-256 Thumbprint) Parameter. @@ -223,7 +223,7 @@ ___ • `Optional` **x5u**: string -*Defined in [src/types.d.ts:65](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L65)* +*Defined in [src/types.d.ts:65](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L65)* JWK "x5u" (X.509 URL) Parameter. @@ -233,4 +233,4 @@ ___ • `Optional` **y**: string -*Defined in [src/types.d.ts:49](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L49)* +*Defined in [src/types.d.ts:49](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L49)* diff --git a/docs/interfaces/_types_d_.jwsheaderparameters.md b/docs/interfaces/_types_d_.jwsheaderparameters.md index 445907b2bb..73c643abf2 100644 --- a/docs/interfaces/_types_d_.jwsheaderparameters.md +++ b/docs/interfaces/_types_d_.jwsheaderparameters.md @@ -30,7 +30,7 @@ Any other JWS Header member. • `Optional` **alg**: string -*Defined in [src/types.d.ts:185](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L185)* +*Defined in [src/types.d.ts:185](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L185)* JWS "alg" (Algorithm) Header Parameter. @@ -40,7 +40,7 @@ ___ • `Optional` **b64**: false \| true -*Defined in [src/types.d.ts:192](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L192)* +*Defined in [src/types.d.ts:192](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L192)* This JWS Extension Header Parameter modifies the JWS Payload representation and the JWS Signing Input computation as per @@ -52,7 +52,7 @@ ___ • `Optional` **crit**: string[] -*Defined in [src/types.d.ts:197](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L197)* +*Defined in [src/types.d.ts:197](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L197)* JWS "crit" (Critical) Header Parameter. @@ -62,7 +62,7 @@ ___ • `Optional` **cty**: string -*Defined in [src/types.d.ts:174](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L174)* +*Defined in [src/types.d.ts:174](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L174)* "cty" (Content Type) Header Parameter. @@ -72,7 +72,7 @@ ___ • `Optional` **jwk**: Pick\<[JWK](_types_d_.jwk.md), \"kty\" \| \"crv\" \| \"x\" \| \"y\" \| \"e\" \| \"n\"> -*Defined in [src/types.d.ts:164](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L164)* +*Defined in [src/types.d.ts:164](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L164)* "jwk" (JSON Web Key) Header Parameter. @@ -82,7 +82,7 @@ ___ • `Optional` **kid**: string -*Defined in [src/types.d.ts:144](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L144)* +*Defined in [src/types.d.ts:144](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L144)* "kid" (Key ID) Header Parameter. @@ -92,7 +92,7 @@ ___ • `Optional` **typ**: string -*Defined in [src/types.d.ts:169](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L169)* +*Defined in [src/types.d.ts:169](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L169)* "typ" (Type) Header Parameter. @@ -102,7 +102,7 @@ ___ • `Optional` **x5c**: string[] -*Defined in [src/types.d.ts:154](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L154)* +*Defined in [src/types.d.ts:154](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L154)* "x5c" (X.509 Certificate Chain) Header Parameter. @@ -112,7 +112,7 @@ ___ • `Optional` **x5t**: string -*Defined in [src/types.d.ts:149](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L149)* +*Defined in [src/types.d.ts:149](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L149)* "x5t" (X.509 Certificate SHA-1 Thumbprint) Header Parameter. @@ -122,6 +122,6 @@ ___ • `Optional` **x5u**: string -*Defined in [src/types.d.ts:159](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L159)* +*Defined in [src/types.d.ts:159](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L159)* "x5u" (X.509 URL) Header Parameter. diff --git a/docs/interfaces/_types_d_.jwtclaimverificationoptions.md b/docs/interfaces/_types_d_.jwtclaimverificationoptions.md index a444cb855e..a9692566b8 100644 --- a/docs/interfaces/_types_d_.jwtclaimverificationoptions.md +++ b/docs/interfaces/_types_d_.jwtclaimverificationoptions.md @@ -20,7 +20,7 @@ JWT Claims Set verification options. • `Optional` **audience**: string \| string[] -*Defined in [src/types.d.ts:355](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L355)* +*Defined in [src/types.d.ts:355](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L355)* Expected JWT "aud" (Audience) Claim value(s). @@ -30,7 +30,7 @@ ___ • `Optional` **clockTolerance**: string \| number -*Defined in [src/types.d.ts:362](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L362)* +*Defined in [src/types.d.ts:362](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L362)* Expected clock tolerance - in seconds when number (e.g. 5) @@ -42,7 +42,7 @@ ___ • `Optional` **currentDate**: Date -*Defined in [src/types.d.ts:387](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L387)* +*Defined in [src/types.d.ts:387](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L387)* Date to use when comparing NumericDate claims, defaults to `new Date()`. @@ -52,7 +52,7 @@ ___ • `Optional` **issuer**: string \| string[] -*Defined in [src/types.d.ts:367](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L367)* +*Defined in [src/types.d.ts:367](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L367)* Expected JWT "iss" (Issuer) Claim value(s). @@ -62,7 +62,7 @@ ___ • `Optional` **maxTokenAge**: string -*Defined in [src/types.d.ts:372](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L372)* +*Defined in [src/types.d.ts:372](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L372)* Maximum time elapsed (in seconds) from the JWT "iat" (Issued At) Claim value. @@ -72,7 +72,7 @@ ___ • `Optional` **subject**: string -*Defined in [src/types.d.ts:377](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L377)* +*Defined in [src/types.d.ts:377](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L377)* Expected JWT "sub" (Subject) Claim value. @@ -82,6 +82,6 @@ ___ • `Optional` **typ**: string -*Defined in [src/types.d.ts:382](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L382)* +*Defined in [src/types.d.ts:382](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L382)* Expected JWT "typ" (Type) Header Parameter value. diff --git a/docs/interfaces/_types_d_.jwtdecryptresult.md b/docs/interfaces/_types_d_.jwtdecryptresult.md index 76a32095c4..94054b4a33 100644 --- a/docs/interfaces/_types_d_.jwtdecryptresult.md +++ b/docs/interfaces/_types_d_.jwtdecryptresult.md @@ -13,7 +13,7 @@ • **payload**: [JWTPayload](_types_d_.jwtpayload.md) -*Defined in [src/types.d.ts:544](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L544)* +*Defined in [src/types.d.ts:544](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L544)* JWT Claims Set. @@ -23,6 +23,6 @@ ___ • **protectedHeader**: [JWEHeaderParameters](_types_d_.jweheaderparameters.md) -*Defined in [src/types.d.ts:549](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L549)* +*Defined in [src/types.d.ts:549](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L549)* JWE Protected Header. diff --git a/docs/interfaces/_types_d_.jwtpayload.md b/docs/interfaces/_types_d_.jwtpayload.md index 06db126500..593726a82d 100644 --- a/docs/interfaces/_types_d_.jwtpayload.md +++ b/docs/interfaces/_types_d_.jwtpayload.md @@ -27,7 +27,7 @@ Any other JWT Claim Set member. • `Optional` **aud**: string \| string[] -*Defined in [src/types.d.ts:418](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L418)* +*Defined in [src/types.d.ts:418](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L418)* JWT Audience [RFC7519#section-4.1.3](https://tools.ietf.org/html/rfc7519#section-4.1.3). @@ -37,7 +37,7 @@ ___ • `Optional` **exp**: number -*Defined in [src/types.d.ts:433](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L433)* +*Defined in [src/types.d.ts:433](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L433)* JWT Expiration Time - [RFC7519#section-4.1.4](https://tools.ietf.org/html/rfc7519#section-4.1.4). @@ -47,7 +47,7 @@ ___ • `Optional` **iat**: number -*Defined in [src/types.d.ts:438](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L438)* +*Defined in [src/types.d.ts:438](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L438)* JWT Issued At - [RFC7519#section-4.1.6](https://tools.ietf.org/html/rfc7519#section-4.1.6). @@ -57,7 +57,7 @@ ___ • `Optional` **iss**: string -*Defined in [src/types.d.ts:408](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L408)* +*Defined in [src/types.d.ts:408](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L408)* JWT Issuer - [RFC7519#section-4.1.1](https://tools.ietf.org/html/rfc7519#section-4.1.1). @@ -67,7 +67,7 @@ ___ • `Optional` **jti**: string -*Defined in [src/types.d.ts:423](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L423)* +*Defined in [src/types.d.ts:423](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L423)* JWT ID - [RFC7519#section-4.1.7](https://tools.ietf.org/html/rfc7519#section-4.1.7). @@ -77,7 +77,7 @@ ___ • `Optional` **nbf**: number -*Defined in [src/types.d.ts:428](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L428)* +*Defined in [src/types.d.ts:428](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L428)* JWT Not Before - [RFC7519#section-4.1.5](https://tools.ietf.org/html/rfc7519#section-4.1.5). @@ -87,6 +87,6 @@ ___ • `Optional` **sub**: string -*Defined in [src/types.d.ts:413](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L413)* +*Defined in [src/types.d.ts:413](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L413)* JWT Subject - [RFC7519#section-4.1.2](https://tools.ietf.org/html/rfc7519#section-4.1.2). diff --git a/docs/interfaces/_types_d_.jwtverifyresult.md b/docs/interfaces/_types_d_.jwtverifyresult.md index 49bcc90c1d..1989e88fc1 100644 --- a/docs/interfaces/_types_d_.jwtverifyresult.md +++ b/docs/interfaces/_types_d_.jwtverifyresult.md @@ -13,7 +13,7 @@ • **payload**: [JWTPayload](_types_d_.jwtpayload.md) -*Defined in [src/types.d.ts:532](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L532)* +*Defined in [src/types.d.ts:532](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L532)* JWT Claims Set. @@ -23,6 +23,6 @@ ___ • **protectedHeader**: [JWSHeaderParameters](_types_d_.jwsheaderparameters.md) -*Defined in [src/types.d.ts:537](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L537)* +*Defined in [src/types.d.ts:537](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L537)* JWS Protected Header. diff --git a/docs/interfaces/_types_d_.verifyoptions.md b/docs/interfaces/_types_d_.verifyoptions.md index eb55cfb7d4..f538bc67a1 100644 --- a/docs/interfaces/_types_d_.verifyoptions.md +++ b/docs/interfaces/_types_d_.verifyoptions.md @@ -14,6 +14,6 @@ JWS Verification options. • `Optional` **algorithms**: string[] -*Defined in [src/types.d.ts:397](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L397)* +*Defined in [src/types.d.ts:397](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L397)* A list of accepted JWS "alg" (Algorithm) Header Parameter values. diff --git a/docs/interfaces/_util_generate_key_pair_.generatekeypairoptions.md b/docs/interfaces/_util_generate_key_pair_.generatekeypairoptions.md index c92257bccb..3ab26312ee 100644 --- a/docs/interfaces/_util_generate_key_pair_.generatekeypairoptions.md +++ b/docs/interfaces/_util_generate_key_pair_.generatekeypairoptions.md @@ -12,7 +12,7 @@ • `Optional` **crv**: string -*Defined in [src/util/generate_key_pair.ts:10](https://github.com/panva/jose/blob/v3.x/src/util/generate_key_pair.ts#L10)* +*Defined in [src/util/generate_key_pair.ts:10](https://github.com/panva/jose/blob/v3.0.0/src/util/generate_key_pair.ts#L10)* The EC "crv" (Curve) or OKP "crv" (Subtype of Key Pair) value to generate. The curve must be both supported on the runtime as well as applicable for diff --git a/docs/types/_types_d_.keylike.md b/docs/types/_types_d_.keylike.md index f72a1948e3..78ce444fe6 100644 --- a/docs/types/_types_d_.keylike.md +++ b/docs/types/_types_d_.keylike.md @@ -2,7 +2,7 @@ Ƭ **KeyLike**: KeyObject \| CryptoKey \| Uint8Array -*Defined in [src/types.d.ts:92](https://github.com/panva/jose/blob/v3.x/src/types.d.ts#L92)* +*Defined in [src/types.d.ts:92](https://github.com/panva/jose/blob/v3.0.0/src/types.d.ts#L92)* KeyLike are platform-specific references to keying material. diff --git a/package.json b/package.json index 4640d1501c..10a5bf5fe4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jose", - "version": "2.0.3", + "version": "3.0.0", "description": "JSON Web Almost Everything - JWA, JWS, JWE, JWK, JWT, JWKS with no dependencies", "keywords": [ "compact",